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

 
 
 
Reply to this topicStart new topic
> Покритикуйте, код/устройство термометра 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
kovigor
сообщение Oct 22 2013, 19:24
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(Lyt @ Oct 22 2013, 21:18) *
Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13

Вместо Tiny13 возьмите что-нибудь посерьезнее, например, Tiny2313 или Mega88. Тогда и регистр не потребуется.
А почему у вас питание 6В, а не 5 ? И еще, последовательно с сегментами включите токоограничивающие резисторы, по килоому на сегмент, или около того. И еще, необходимость шунтирования базовых резисторов (которые можно было бы увеличить минимум до килоома) конденсаторами мне прдставляется в данном случае более чем сомнительной ...
Go to the top of the page
 
+Quote Post
Lyt
сообщение Oct 22 2013, 19:58
Сообщение #3


Участник
*

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



спасибо за ответ!
tiny2313 не имеет ацп, использую самые простые пока вещи, ну и что есть в наличии
питание я предполагал от 3х вольт (будет ли с ним работать? протеус не желает воспринимать 3 вольта как высокий уровень для подтяжки вверх свободного входа регистра.
токоограничивающие резисторы предполагаются, в протеусе не стал их вносить в проект.


резисторы в базах рассчитывал как
(Uh-Ue_b)/Ib=(3-0.7)/10^-2=230 ом
Uh - напряжение высокого уровня
Ue_b - падение напряжения на переходе эмиттер-база
Ib - ток базы

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

в теории, конденсаторы должны увеличить возможную частоту переключения транзисторов?
в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно
Go to the top of the page
 
+Quote Post
Ruslan1
сообщение Oct 22 2013, 20:55
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 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
kovigor
сообщение Oct 22 2013, 21:32
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(Lyt @ Oct 22 2013, 22:58) *
в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно

Зачем так много ????? Смело уменьшайте это значение раз эдак в 50 ...
Go to the top of the page
 
+Quote Post
Lyt
сообщение Oct 23 2013, 02:55
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 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
Сообщение #7


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

Группа: Свой
Сообщений: 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
Tarbal
сообщение Oct 23 2013, 12:43
Сообщение #8


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

Группа: Свой
Сообщений: 1 351
Регистрация: 21-05-10
Пользователь №: 57 439



Цитата(ARV @ Oct 23 2013, 10:08) *
все вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535


Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно.
Go to the top of the page
 
+Quote Post
ARV
сообщение Oct 23 2013, 15:10
Сообщение #9


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

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



Цитата(Tarbal @ Oct 23 2013, 16:43) *
Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно.
я рассчитываю не на подарки судьбы, а на соответствие компилятора стандарту языка Си, который абсолютно однозначно утверждает, что все операнды при вычислениях, размер которых меньше int, приводятся к этому типу, и только затем осуществляется вычисление.

если ваш компилятор не следует стандарту - выкиньте его. если вы считаете стандартные возможности языка недокументированными - повышайте свой образовательный уровень.




--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
Lyt
сообщение Oct 23 2013, 16:41
Сообщение #10


Участник
*

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



внезапно возник вопрос по схеме - по транзисторам. изначально я рассчитывал поставить n-p-n BC817; по высокому уровню на базе транзистор открывается и ток стекает от катода индикатора через коллектор в эмиттер на землю. Но код не менял с самого начала, когда ток стекал от катода индикатора обратно в контроллер, при симуляции в протеусе перепутал транзисторы и поставил p-n-p BC856 и все работало. Вопросы:
как работало в протеусе с p-n-p и будет ли работать как я хотел изначально с n-p-n (при соответствующем изменении программы
на
Код
#define dig_1_on() PORTB|=(1<<4)    //выключение 1 элемента индикатора
#define dig_1_off() PORTB&=(~(1<<4))    //включение 1 элемента индикатора
#define dig_2_on() PORTB|=(1<<0)    //выключение 2 элемента индикатора
#define dig_2_off() PORTB&=(~(1<<0))    //включение 2 элемента индикатора

??
Go to the top of the page
 
+Quote Post
kovigor
сообщение Oct 23 2013, 17:22
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(Lyt @ Oct 23 2013, 19:41) *
по высокому уровню на базе транзистор открывается и ток стекает от катода индикатора через коллектор в эмиттер на землю.

Все так, но тогда придется ставить индикаторы с общим катодом, а не с общим анодом, и npn - транзисторы, как вы и сказали ...
Go to the top of the page
 
+Quote Post
Lyt
сообщение Oct 23 2013, 17:58
Сообщение #12


Участник
*

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



с общим катодом и стоит - для зажигания сегмента выдается 1 на анод и 0 на катод

спасибо, работает!
Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт
И каков ток потребление 7-сегментного индикатора? в даташите указан лишь максимальный прямой ток в 30мА - это на сегмент,на цифру или на весь индикатор?
и насколько применимы такие индикаторы в устройствах с батарейным питанием?
Go to the top of the page
 
+Quote Post
kovigor
сообщение Oct 24 2013, 07:57
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(Lyt @ Oct 23 2013, 20:58) *
Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт

Не знаю, хватит ли этого напряжения датчику. МК и индикатору - хватит. Только индикаторы берите красные, они ярче, как правило. Из опыта: при 5-вольтовом питании и килоомных токоограничивающих резисторах сегментов красные индикаторы на две цифры светятся очень ярко. Индикаторы сейчас дома. Через пару часов там буду, посмотрю марку и сюда напишу ...
Go to the top of the page
 
+Quote Post

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

 


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


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