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

 
 
> Покритикуйте, код/устройство термометра 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
Ответов
Ruslan1
сообщение Oct 22 2013, 20:55
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025



Цитата(Lyt @ Oct 22 2013, 21:18) *
Как я понимаю ошибка эта возникает за-за того, что умножаю на 4, а не на 4.3.
Что скажете в целом по схеме и программе? И будет ли все это работать от источника в 3 вольта?

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

Но у Вас проще: для повышения точности сначала все перемножаем, и только потом делим, следим за переполнением.

И я бы советовал переписать формулу с использованием дефайнов. собственно код не должен содержать никаких неименованных чисел(констант), только их имена.

Код
#define UrefmV  5000   //опорное напряжение АЦП в милливольтах
#define VoltageSlopeOutputResponsemV  10 //милливольт на градус цельсия.
#define NADC  256   //количество отчетов ADC для указанного UrefmV


temperatureC = ((adcCode *  UrefmV) / NADC) /  VoltageSlopeOutputResponsemV;



Если совсем плохо с вычислительными ресурсами- сделайте предварительно вычисленную табличку на 256 значений, в которой по индексу [adcCode] находится величина temperatureC

тогда все вычисление сведется к
Код
temperatureC = TabTemp[adcCode];


Кстати, данная таблица может учесть и дополнительные коррекции для этого TC1047, кажется был специальный аппнот с формулой 2-го или 3-го порядка.
Go to the top of the page
 
+Quote Post



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

 


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


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