Lyt 0 22 октября, 2013 Опубликовано 22 октября, 2013 · Жалоба Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13, с индикацией на двух семисегметных индикаторах, подключенных через сдвиговой регистр 74HC164. Измеряю от 0 до 60 градусов. результат смотрю в старшем регистре, т.е. 8-битное измерение получается. При использовании внутреннего ИОН 1.1В, шаг получается ~4.3мВ. Результат из преобразованного значения вычисляю как (x-115)*4/10 - (при нуле градусов датчик дает 500мВ) - получаю значение температуры в градусах. В протеусе работает, но выдает ошибку в 1-3 градуса, чем больше температура тем больше ошибка. Как я понимаю ошибка эта возникает за-за того, что умножаю на 4, а не на 4.3. Что скажете в целом по схеме и программе? И будет ли все это работать от источника в 3 вольта? #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(); //***** } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kovigor 5 22 октября, 2013 Опубликовано 22 октября, 2013 · Жалоба Учусь работать с ацп - решил собрать простейший термометр на аналоговом датчике TC1047 и attiny13 Вместо Tiny13 возьмите что-нибудь посерьезнее, например, Tiny2313 или Mega88. Тогда и регистр не потребуется. А почему у вас питание 6В, а не 5 ? И еще, последовательно с сегментами включите токоограничивающие резисторы, по килоому на сегмент, или около того. И еще, необходимость шунтирования базовых резисторов (которые можно было бы увеличить минимум до килоома) конденсаторами мне прдставляется в данном случае более чем сомнительной ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lyt 0 22 октября, 2013 Опубликовано 22 октября, 2013 · Жалоба спасибо за ответ! tiny2313 не имеет ацп, использую самые простые пока вещи, ну и что есть в наличии питание я предполагал от 3х вольт (будет ли с ним работать? протеус не желает воспринимать 3 вольта как высокий уровень для подтяжки вверх свободного входа регистра. токоограничивающие резисторы предполагаются, в протеусе не стал их вносить в проект. резисторы в базах рассчитывал как (Uh-Ue_b)/Ib=(3-0.7)/10^-2=230 ом Uh - напряжение высокого уровня Ue_b - падение напряжения на переходе эмиттер-база Ib - ток базы шунтирования базовых резисторов (которые можно было бы увеличить минимум до килоома) конденсаторами мне прдставляется в данном случае более чем сомнительной в теории, конденсаторы должны увеличить возможную частоту переключения транзисторов? в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 16 22 октября, 2013 Опубликовано 22 октября, 2013 · Жалоба Как я понимаю ошибка эта возникает за-за того, что умножаю на 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-го порядка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kovigor 5 22 октября, 2013 Опубликовано 22 октября, 2013 · Жалоба в моем случае там около 10кГц должно получиться, конденсаторы и правда не нужны наверно Зачем так много ????? Смело уменьшайте это значение раз эдак в 50 ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lyt 0 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба Чтобы в рамках целочисленной арифметики умножить на 4.3 нужно сначала умножить на 43 а потом результат поделить на 10. (разумеется, при этом следить за отсутствием переполнения промежуточного результата). спасибо! оказалось все очень просто Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясен но в потеусе с этим простейшим изменением все заработало идеально Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба Но не меняя тип переменной unsigned char на unsigned int,все получилось без переполнения. Т.е. умножаю значение adc-115 на 43 и делю на 100 - все прекрасно работает. хотя переполнение должно возникнуть при adc-115 >5. Вот здесь момент не ясенвсе вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба все вычисления над char-ами на самом деле превращаются в вычисления над int-ами, а результат потом усекается до 8 бит, поэтому переполнения и не происходит, если результат умножения не выходит за значение 65535 Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ARV 0 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба Опасно рассчитывать на подарки судьбы. Лучше не писать код в рассчете на это, а произвести вычисления с интами или лонгами, а в конце преобразовать результат. Иначе при замене компилятора такие чудеса могут начаться. Да и если есть баги в очевидных местах, зачем подставляться там, где недокументированые? Тем более, что их имплементирование неоднозначно.я рассчитываю не на подарки судьбы, а на соответствие компилятора стандарту языка Си, который абсолютно однозначно утверждает, что все операнды при вычислениях, размер которых меньше int, приводятся к этому типу, и только затем осуществляется вычисление. если ваш компилятор не следует стандарту - выкиньте его. если вы считаете стандартные возможности языка недокументированными - повышайте свой образовательный уровень. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lyt 0 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба внезапно возник вопрос по схеме - по транзисторам. изначально я рассчитывал поставить 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 элемента индикатора ?? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kovigor 5 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба по высокому уровню на базе транзистор открывается и ток стекает от катода индикатора через коллектор в эмиттер на землю. Все так, но тогда придется ставить индикаторы с общим катодом, а не с общим анодом, и npn - транзисторы, как вы и сказали ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lyt 0 23 октября, 2013 Опубликовано 23 октября, 2013 · Жалоба с общим катодом и стоит - для зажигания сегмента выдается 1 на анод и 0 на катод спасибо, работает! Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт И каков ток потребление 7-сегментного индикатора? в даташите указан лишь максимальный прямой ток в 30мА - это на сегмент,на цифру или на весь индикатор? и насколько применимы такие индикаторы в устройствах с батарейным питанием? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kovigor 5 24 октября, 2013 Опубликовано 24 октября, 2013 · Жалоба Подскажите еще пожалуйста насчет питания - будет ли вся схема работать от 3 вольт Не знаю, хватит ли этого напряжения датчику. МК и индикатору - хватит. Только индикаторы берите красные, они ярче, как правило. Из опыта: при 5-вольтовом питании и килоомных токоограничивающих резисторах сегментов красные индикаторы на две цифры светятся очень ярко. Индикаторы сейчас дома. Через пару часов там буду, посмотрю марку и сюда напишу ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться