|
терморегулятор, помогите |
|
|
|
Jul 30 2008, 12:01
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Собираю терморегулятор. Готова динамическая индикация (спасибо форумчанам). Теперь проблема с АЦП. Цитата /***************************************************** Chip type : ATmega16 Clock frequency : 1,000000 MHz *****************************************************/ #include <mega16.h> char Dig[10]; // Массив, с кодами чисел для индикатора с общим анодом char i=0; // счетчик для переключения анодов char e=0; // единицы установленной температуры char d=0; // десятки char s=0; // сотни char s2=0; // единицы измеренной температуры char e2=0; // десятки char d2=0; // сотни char res=0; // в эту переменную поочереди записываются e,d,s или e2,d2,s2 char keys_prev=0; // две переменной для правильной работы кнопок char keys_now=0; // unsigned int current_temp=0; // измеренная температура short temp2=0; // временная переменная short set_temp=0; // установленная температура
char num (void) { // функция, для опроса клавиатуры, и вывода на катоды кода текущего разряда if (PINB.4!=0){ // если кнопка "нагрев" не нажата, то if ((keys_prev!=keys_now)&(PINB.0==0)) e++; // если нажата кнопка "единицы", то прибавить 1 к нулевому разряду (единицы) if (e==10) e=0; // если результат прибавления перевалил за 9, то сбросить его в нуль if ((keys_prev!=keys_now)&(PINB.1==0)) d++; // если нажата кнопка "десятки", то прибавить 1 к первому разряду (десятки) if (d==10) d=0; // если результат прибавления перевалил за 9, то сбросить его в нуль if ((keys_prev!=keys_now)&(PINB.2==0)) s++; // если нажата кнопка "сотни", то прибавить 1 к второму разряду (сотни) if (s==3) s=0; // если результат прибавления перевалил за 9, то сбросить его в нуль if (PINB.3==0) { // если нажата кнопка "сброс", то сбросить все разряды в нуль e=0; d=0; s=0;} switch (i) { // в зависимости от переменной i выбираем что показываем в текущий момент: единицы, десятки, или сотни case 0: res=e; break; case 1: res=d; break; case 2: res=s; break; } return res;} else { // если нажата кнопка "нагрев", то
current_temp=ADCL; // в переменную записываем значение из регистра ADCL current_temp+=((int)ADCH << 8); // прибавляем к переменной значение из регистра ADCH со сдвигом влево на 8 разрядов current_temp=current_temp/2.5; // преобразовываем (ADCH ADCL) в температуру. Т.к. используется внутренний ИОН 2560 мВ, то 2560/1024=2.5 e2=current_temp%10; // получаем единицы измеренной температуры temp2=current_temp/10; // промежуточная операция, для понижения степени d2=temp2%10; // получаем десятки измеренной температуры s2=temp2/10; // получаем сотни измеренной температуры // в зависимости от переменной i выбираем что показываем в текущий момент времени switch (i) { case 0: res=e2; break; case 1: res=d2; break; case 2: res=s2; break; } return res;
;}} // Timer 0 output compare interrupt service routine interrupt [TIM0_COMP] void timer0_comp_isr(void) //обработка прерывания таймера по совпадению с OCR0 { keys_prev=keys_now; //для клавиш keys_now=PINB; //читаем что нажато if (i==3) i=0; //если показатель текущего разряда перевалил за 2, то зажигаем нулевой разряд PORTC=Dig[num()]; //выставляем на катодах число, которое получаем из функции num() switch (i) { //в зависимости от переменной i поочередно подаем питание на аноды case 0: //если i=0, то включаем разряд для единиц PORTD.1=1; //гасим ненужные разряды PORTD.2=1; PORTD.0=0; //включаем нулевой разряд, активный уровень - 0,т.к. используются p-n-p break; case 1: // и т.д. PORTD.0=1; PORTD.2=1; PORTD.1=0; break; case 2: PORTD.0=1; PORTD.1=1; PORTD.2=0; break;} i++; }
// Declare your global variables here
void main(void) { PORTA=0x00; DDRA=0x00; PORTB=0xFF; DDRB=0x00; PORTC=0x00; DDRC=0xFF; PORTD=0x00; DDRD=0xFF;
// Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 0,977 kHz // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x0D; TCNT0=0x00; OCR0=0x03; //задаем частоту развертки. подбирал наглаз.
// Timer/Counter 1 initialization TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00;
// Timer/Counter 2 initialization ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00;
// External Interrupt(s) initialization MCUCR=0x00; MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x02;
// Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; // free running режим АЦП ADMUX=0xC0; // Внутренний источник опорного напряжения 2.56В REFS1..0=1; правое выравнивание ADLAR=0,вход ADC0 ADCSRA=0xE4; //ADEN=1(включили АЦП),ADSC=1(начали преобразование),ADATE:1(авто триггер включен),ADIE=0(прерывания от АЦП нам не нужны), делитель на 16
// заполняем массив комбинациями нулей/единиц для катодов Dig[0] = 0xC0; Dig[1] = 0xF9; Dig[2] = 0xA4; Dig[3] = 0xB0; Dig[4] = 0x99; Dig[5] = 0x92; Dig[6] = 0x82; Dig[7] = 0xF8; Dig[8] = 0x80; Dig[9] = 0x90;
#asm("sei") // включаем прерывания while (1) { if (PINB.4==0) { // если нажата кнопка "нагрев", то set_temp=e+d*10+s*100; // вычисляем установленную температуру, исходя из того, что в переменных e,d,s if (current_temp<(set_temp-1)) {PORTD.3=1;}; //если текущая температура ниже установленной на 1 градус, то включаем релюшку if (current_temp>=set_temp) {PORTD.3=0;};} //если текущая температура больше или равна установленной, то выключаем релюшку else {PORTD.3=0;}; }; //если кнопка "нагрев" не нажата, то реле должно быть выключенным. } // game over почему-то в Proteus переменные e2,s2,d2 неправильно считаются. Залил в мегу - на индикаторе 409. Когда использовал прерывание АЦП, то у меня все работало. Но хочется упростить немного код (пусть хоть потребляет больше) Схемку прилагаю. Подскажите что не так, я уже не знаю чего делать.
Эскизы прикрепленных изображений
|
|
|
|
|
 |
Ответов
(45 - 59)
|
Aug 1 2008, 17:30
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Lost_Viking @ Aug 1 2008, 17:46)  Заметил вот что: записал в ADMUX: Код REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0 0 0 1 0 0 0 0 0 Циферки перестали бегать, а АЦП все еще мерял что-то. Какая чушь! ADLAR=1! Вай-вай-вай! Лучше RTFM, чем вопросы.  По поводу усреднения - не забудьте, что отношение сигнал/шум растет пропорционально квадратному корню из числа N усредняемых выборок, т.е. для 256 отсчетов имеем с/ш выросла в 16 раз. Младший разряд должен стоять и бояться. Это если у нас мат. ожидание есть состоятельная оценка. В противном случае придеццо делать обработку медианой.
|
|
|
|
|
Aug 1 2008, 21:47
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Цитата(xemul @ Aug 1 2008, 22:01)  ADLAR=1 очень даже удобно, если читать только ADCH. Вот REFS0 = REFS1 = 0 только с кондюком на AVref гораздо прикольней - опора на входном токе ноги контроллера. Срочно патентовать!!!  Однако работает! Сам не понимаю. Собрал опору на TL431, и радуюсь.10Бит. Вот только наводки иногда проскакивают, теперь займусь ФНЧ, возможно применю цифровую фильтрацию. Как закончу - выложу полный код на Си с комментами и алгоритмом. Что бы такие же как я не наступали на грабли. Цитата(_Pasha @ Aug 1 2008, 22:19)  Дык автор хочет 10 бит, а получает 8 и радуется  Для меня и 8 бит хватило бы. Но мне пришла в голову мысль использовать сабж на даче для измерения сетевого напряжения, для регистрации (с записью в EEPROM,и дальнейшей пересылкой в ПК) температуры окружающей среды за промежуток времени, и т.п. Далее хотелось бы попробовать сделать датчик влажности грунта для автоматической поливалки... Вот так-то  Цитата(_Pasha @ Aug 1 2008, 21:30)  Это если у нас мат. ожидание есть состоятельная оценка. В противном случае придеццо делать обработку медианой. а можно без нецензурных выражений?
Сообщение отредактировал Lost_Viking - Aug 1 2008, 21:48
|
|
|
|
|
Aug 2 2008, 15:27
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Цитата(domowoj @ Aug 2 2008, 15:26)  Lost_Viking А мож Вам лучше DS18x20 применить, никаких АЦП и никаких тебе опорных. Дергай только ножками правильно, читай температуру в цифре и выводи на индикатор. Нет, все эти датчики до 125 градусов. Мне же нужно до 200, в реале регулировка будет в районе 160-170.
|
|
|
|
|
Aug 3 2008, 06:25
|

Профессионал
    
Группа: Участник
Сообщений: 1 548
Регистрация: 20-12-07
Из: г.Новосибирск
Пользователь №: 33 486

|
Цитата(_Pasha @ Jul 31 2008, 18:57)  1. TL431 ему в опору, чтоб не баловался. 2. Noise canceler ему в мозги, иначе у младшего разряда нервный тик не пройдет. 3. Накопление методом скользящего среднего вне зависимости от того, удался ли п.2. 1.ТЛка - слабовато для опорного по точности 2.Это -сомо собой необходимо 3.Может быть применить какой-нибудь вероятностный критерий вместо скользящего среднего. И провести темпер. диапазон изменения входного к опорному. На каком датчике остановился?
--------------------
И на камнях растут деревья!
|
|
|
|
|
Aug 3 2008, 14:01
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Цитата(domowoj @ Aug 3 2008, 10:25)  1.ТЛка - слабовато для опорного по точности Уже заметил. На чем посоветуешь опорное сделать? Цитата(domowoj @ Aug 3 2008, 10:25)  2.Это -сомо собой необходимо Еще бы сделать небольшую паузу между переключением анодов индикатора, и в эту паузу мерить температуру с подавителем шумов.Тлько с синхронизацией замучаюсь. Цитата(domowoj @ Aug 3 2008, 10:25)  3.Может быть применить какой-нибудь вероятностный критерий вместо скользящего среднего. брр, только если на голодный желудок. Цитата(domowoj @ Aug 3 2008, 10:25)  И провести темпер. диапазон изменения входного к опорному. что-что? Цитата(domowoj @ Aug 3 2008, 10:25)  На каком датчике остановился? Что-нибудь из этого. Пока еще не занимался конкретным выбором датчика.Как мозги доделаю, так датчик буду искать. Кстати, такой вопрос: как правильно рассчитать значение на выходе АЦП? Судя по этой формуле:  На выходе получится максимум 1024, что никак не 10 бит, а все 11. т.е. 10000000000. Так как правильно считать?
Сообщение отредактировал Lost_Viking - Aug 3 2008, 14:10
|
|
|
|
|
Aug 3 2008, 15:18
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Цитата(domowoj @ Aug 3 2008, 19:05)  а 1024 - это кол-во дискрет от 0 до 1023. А для рассчета в EXCEL ставить что? 1024 или 1023? Думаю, что 1023.
|
|
|
|
|
Aug 3 2008, 15:46
|
Частый гость
 
Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091

|
Цитата(domowoj @ Aug 3 2008, 19:31)  Lost_Viking Может лучше применить ЖК индикатор. Не хочу тратиться на него. В принципе, у меня есть дома индикатор, но я не знаю как им управлять. Посмотри, может ты подскажешь? P.S. Так все-таки что мне ставить в EXCEL для рассчета значения на выходе АЦП?1024 или 1023?
Сообщение отредактировал Lost_Viking - Aug 3 2008, 15:52
|
|
|
|
|
Aug 3 2008, 17:34
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Lost_Viking @ Aug 3 2008, 21:46)  P.S. Так все-таки что мне ставить в EXCEL для рассчета значения на выходе АЦП?1024 или 1023? Вас в школе пропорцию составлять учили? Когда Vin=Vref получаем максимальное число которое можно представить 10-ю разрядами: 1023, т.е. Vref соответствует максимальному коду АЦП - 1023. Составляем пропорцию Код ADC Vin ---- = ----- отсюда следует 1023 Vref ADC=Vin/Vref*1023
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|