реклама на сайте
подробности

 
 
> Покритикуйте, код/устройство термометра TC1047 и attiny13
Lyt
сообщение Oct 22 2013, 18:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 38
Регистрация: 7-07-12
Пользователь №: 72 660



Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13, с индикацией на двух семисегметных индикаторах, подключенных через сдвиговой регистр 74HC164. Измеряю от 0 до 60 градусов. результат смотрю в старшем регистре, т.е. 8-битное измерение получается. При использовании внутреннего ИОН 1.1В, шаг получается ~4.3мВ. Результат из преобразованного значения вычисляю как
(x-115)*4/10 - (при нуле градусов датчик дает 500мВ) - получаю значение температуры в градусах. В протеусе работает, но выдает ошибку в 1-3 градуса, чем больше температура тем больше ошибка. Как я понимаю ошибка эта возникает за-за того, что умножаю на 4, а не на 4.3.
Что скажете в целом по схеме и программе? И будет ли все это работать от источника в 3 вольта?
Прикрепленное изображение

CODE
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define _0 0b11111100 // 0 на индикаторе
#define _1 0b01100000 // 1 на индикаторе
#define _2 0b11011010 // 2 на индикаторе
#define _3 0b11110010 // 3 на индикаторе
#define _4 0b01100110 // 4 на индикаторе
#define _5 0b10110110 // 5 на индикаторе
#define _6 0b10111110 // 6 на индикаторе
#define _7 0b11100000 // 7 на индикаторе
#define _8 0b11111110 // 8 на индикаторе
#define _9 0b11110110 // 9 на индикаторе

#define ADC_start() ADCSRA|=(1<<6)
#define dig_1_off() PORTB|=(1<<4) //выключение 1 элемента индикатора
#define dig_1_on() PORTB&=(~(1<<4)) //включение 1 элемента индикатора
#define dig_2_off() PORTB|=(1<<0) //выключение 2 элемента индикатора
#define dig_2_on() PORTB&=(~(1<<0)) //включение 2 элемента индикатора
#define strob_h() PORTB|=(1<<1) //строб на регистр в 1
#define strob_l() PORTB&=(~(1<<1)) //строб на регистр в 0
static unsigned char temperature_dig_h=0;
static unsigned char temperature_dig_l=0;
ISR(ADC_vect)
{
volatile unsigned char temp=0,temp_h=0,temp_l=0;
temp=ADCH-115; //из полученного значения вычли значение при 0 градусов
if (temp>=17) temp++;
if (temp>=24) temp++;
if (temp>=31) temp++;
if (temp>=38) temp++;
if (temp>=50) temp++;
if (temp>=60) temp++;
temp=(temp*4)/10; //умножаем на шаг преобр. ацп (~4мВ) и делим на шаг преобр. датчика (10мВ/градус)

temp_h=temp/10;
temp_l=temp-(temp_h*10);
switch (temp_h)
{
case 0: temperature_dig_h=_0; break;
case 1: temperature_dig_h=_1; break;
case 2: temperature_dig_h=_2; break;
case 3: temperature_dig_h=_3; break;
case 4: temperature_dig_h=_4; break;
case 5: temperature_dig_h=_5; break;
case 6: temperature_dig_h=_6; break;
break;
}
switch (temp_l)
{
case 0: temperature_dig_l=_0; break;
case 1: temperature_dig_l=_1; break;
case 2: temperature_dig_l=_2; break;
case 3: temperature_dig_l=_3; break;
case 4: temperature_dig_l=_4; break;
case 5: temperature_dig_l=_5; break;
case 6: temperature_dig_l=_6; break;
case 7: temperature_dig_l=_7; break;
case 8: temperature_dig_l=_8; break;
case 9: temperature_dig_l=_9; break;
break;
}
}

int main(void)
{
//Начальная инициализация
//Инициализация АЦП
ADCSRA=0b11101110; //включение ацп, режим однократного преобразования, разрешение прерывания от ацп,
ADCSRB=0b00000000; //частота преобразования clk/128=9.6MHz/128=75KHz
ADMUX=0b01100011; //опорное напряжение - внутренний ИОН 1.1В, рез-т выравнивается влево, вх. канал - ADC3
//Настройка ввода/вывода
DDRB=0b00010111;
sei();
_delay_us(100);
cli();
while(1)
{
//вывод данных на 7-сегм. индикаторы. сначала выводится старшая цифра, затем младшая
//*****
for (unsigned char counter=1; counter!=0; counter=counter<<1 )
{
if ((temperature_dig_h & counter)==0)
PORTB&=(~(1<<2));
else
PORTB|=(1<<2);
strob_h();
_delay_us(1);
strob_l();
}
dig_1_on(); //активирована 1 цифра
//sei();
_delay_us(100);
//cli();
dig_1_off();
for (unsigned char counter=1; counter!=0; counter=counter<<1 )
{
if ((temperature_dig_l & counter)==0)
PORTB&=(~(1<<2));
else
PORTB|=(1<<2);
strob_h();
_delay_us(10);
strob_l();
}

dig_2_on();
sei();
_delay_us(100);
dig_2_off();
cli();
//*****
}
}
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Lyt
сообщение Oct 23 2013, 02:55
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 38
Регистрация: 7-07-12
Пользователь №: 72 660



Цитата
Чтобы в рамках целочисленной арифметики умножить на 4.3 нужно сначала умножить на 43 а потом результат поделить на 10. (разумеется, при этом следить за отсутствием переполнения промежуточного результата).

спасибо! оказалось все очень просто
Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясен

но в потеусе с этим простейшим изменением все заработало идеально
Go to the top of the page
 
+Quote Post
ARV
сообщение Oct 23 2013, 06:08
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



Цитата(Lyt @ Oct 23 2013, 06:55) *
Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясен
все вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 15:36
Рейтинг@Mail.ru


Страница сгенерированна за 0.01385 секунд с 7
ELECTRONIX ©2004-2016