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

 
 
7 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> терморегулятор, помогите
Lost_Viking
сообщение Jul 30 2008, 12:01
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 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. Когда использовал прерывание АЦП, то у меня все работало. Но хочется упростить немного код (пусть хоть потребляет больше)
Схемку прилагаю.

Подскажите что не так, я уже не знаю чего делать.
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 30 2008, 12:31
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Lost_Viking @ Jul 30 2008, 18:01) *
почему-то в Proteus переменные e2,s2,d2 неправильно считаются. Залил в мегу - на индикаторе 409.

А сколько должно быть?

Смущает вот что:

Код
current_temp=current_temp/2.5; // преобразовываем (ADCH ADCL) в температуру. Т.к. используется внутренний ИОН 2560 мВ, то 2560/1024=2.5


Во-первых, current_temp у вас unsigned int, то есть это эквивалентно
current_temp=current_temp/2.
Во-вторых, не вижу здесь вычисления значения температуры, вижу только вычисление напряжения.

ЗЫ. Для форматирования кода - кнопочка "код", а не "цитата":)


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 30 2008, 12:40
Сообщение #3


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Код
current_temp=current_temp/2.5; // преобразовываем (ADCH ADCL) в температуру. Т.к. используется внутренний ИОН 2560 мВ, то 2560/1024=2.5

то есть 1 дискрет АЦП = 2,5 мВ.
Причём тогда тут деление?
Наверно, умножить надо? Получим Uadc в милливольтах
ещё такая штучка:
x*2.5=(x<<1)+(x>>1)


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
domowoj
сообщение Jul 30 2008, 15:26
Сообщение #4


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

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



Протеус 7.2 .2 с авр работает глючно!!!
Мегу 16 не проверял, а 8535 и тиньки - глюк, особенно что касаемо АЦП.
По заверениям разработчиков в версии 7.3 глюки обещали исправить.
Ждем-с.


--------------------
И на камнях растут деревья!
Go to the top of the page
 
+Quote Post
=GM=
сообщение Jul 30 2008, 15:50
Сообщение #5


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(Lost_Viking @ Jul 30 2008, 11:01) *
Подскажите что не так, я уже не знаю чего делать

У вас на самом деле последовательно с транзисторами стоят сопротивления 1 Ом? Не боитесь попалить МК и индикатор?

Последовательно с диодом D1 надо бы включить сопротивление, а то и здесь всё попалите.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Lost_Viking
сообщение Jul 30 2008, 17:04
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091



Цитата(=GM= @ Jul 30 2008, 19:50) *
У вас на самом деле последовательно с транзисторами стоят сопротивления 1 Ом? Не боитесь попалить МК и индикатор?

Последовательно с диодом D1 надо бы включить сопротивление, а то и здесь всё попалите.



нет, номиналы там от балды. Не от балды - катушка, емкости, и резистор к питанию АЦП

Цитата(domowoj @ Jul 30 2008, 19:26) *
Протеус 7.2 .2 с авр работает глючно!!!
Мегу 16 не проверял, а 8535 и тиньки - глюк, особенно что касаемо АЦП.
По заверениям разработчиков в версии 7.3 глюки обещали исправить.
Ждем-с.


АЦП в протеусе у меня работает, по крайней мере так говорит ADCL регистр. Но были замеченны другие глюки, например глюкаво работает динамическая индикация.

Цитата(MrYuran @ Jul 30 2008, 16:40) *
Код
current_temp=current_temp/2.5; // преобразовываем (ADCH ADCL) в температуру. Т.к. используется внутренний ИОН 2560 мВ, то 2560/1024=2.5

то есть 1 дискрет АЦП = 2,5 мВ.
Причём тогда тут деление?
Наверно, умножить надо? Получим Uadc в милливольтах

просто я это так назвал "температурой", ну то, что пропорционально.
Насчет деления ты прав. Это я что-то ступил, но сути все равно не изменит

Цитата(AHTOXA @ Jul 30 2008, 16:31) *
А сколько должно быть?


число от 0 до ...
Т.е. кручу переменник - меняется на нем падение напряжения, которое приложенно ко входу АЦП.
Заметил такую вещь: подал на вход АЦП напряжение (1;2;3 вольта) от блока питания - показания изменились. При напряжении 3 вольта опять выдало 409. По сути это 2,56 вольта. Поставил добавочное сопротивление ко входу АЦП, опять все вернул на места (по схеме) - ничего не изменилось, все равно 409. Как ни крути переменник. Померил напряжометром - напряжение действительно >2.56В, амперметр включенный между переменником и входом АЦП вообще ничего не показал. Чудеса.

Цитата(AHTOXA @ Jul 30 2008, 16:31) *
Смущает вот что:

Код
current_temp=current_temp/2.5; // преобразовываем (ADCH ADCL) в температуру. Т.к. используется внутренний ИОН 2560 мВ, то 2560/1024=2.5



Во-первых, current_temp у вас unsigned int, то есть это эквивалентно
current_temp=current_temp/2.

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

Цитата(AHTOXA @ Jul 30 2008, 16:31) *
Во-вторых, не вижу здесь вычисления значения температуры, вижу только вычисление напряжения.

Ну, блин! biggrin.gif Мне для теста хотя бы напряжение показать, а коэффициенты пересчета для температуры потом введу
Цитата(AHTOXA @ Jul 30 2008, 16:31) *
ЗЫ. Для форматирования кода - кнопочка "код", а не "цитата":)

писал на работе, юзая gprs internet Megafon. В целях экономии траффика отключил все картинки, и почему-то вместо (code) вставилось (quote). Сообщение не перечитывал, т.к. рабочий день подходил к концу. sorry 05.gif

Сообщение отредактировал Lost_Viking - Jul 30 2008, 17:10
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 30 2008, 17:31
Сообщение #7


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Lost_Viking @ Jul 30 2008, 23:04) *
Заметил такую вещь: подал на вход АЦП напряжение (1;2;3 вольта) от блока питания - показания изменились. При напряжении 3 вольта опять выдало 409. По сути это 2,56 вольта. Поставил добавочное сопротивление ко входу АЦП, опять все вернул на места (по схеме) - ничего не изменилось, все равно 409. Как ни крути переменник. Померил напряжометром - напряжение действительно >2.56В, амперметр включенный между переменником и входом АЦП вообще ничего не показал. Чудеса.


А как соотносятся номиналы R1 и переменника? Может переменник просто большой и не до конца выкручивается? smile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
defunct
сообщение Jul 30 2008, 17:45
Сообщение #8


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Lost_Viking @ Jul 30 2008, 20:04) *
нет, номиналы там от балды.

Уберите их вообще, вместо них поставьте резисторы 390-510om между пинами МК и сегментами индикатора (ABC..GH). Чтобы яркость цифр не менялась взависимости от заполнения. Транзисторы должны быть расчитаны на ток не менее 100ma.
Go to the top of the page
 
+Quote Post
Lost_Viking
сообщение Jul 30 2008, 18:56
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091



Цитата(AHTOXA @ Jul 30 2008, 21:31) *
А как соотносятся номиналы R1 и переменника? Может переменник просто большой и не до конца выкручивается? smile.gif


на работе у меня целая гора переменников разных номиналов. все перепробовал - ну ни как! а вот с блока питания напрямую напряжение на вход АЦП - все работает. чудеса. завтра поколдую.

Цитата(defunct @ Jul 30 2008, 21:45) *
Уберите их вообще, вместо них поставьте резисторы 390-510om между пинами МК и сегментами индикатора (ABC..GH). Чтобы яркость цифр не менялась взависимости от заполнения. Транзисторы должны быть расчитаны на ток не менее 100ma.


упс, извинясь. просто эта схема взята из Proteus'а, и я туда специально воткнул эти резисторы, т.к. без них в протеусе транзисторы не закрывались (чудеса протеуса!). в реале их у меня нет.

Люди, скажите как вычислить абсолютную погрешность, если учесть, что два младших разряда АЦП по даташиту грешат,плюс округление с real до integer?

Т.е. имеем результат измерения 0010101100, младшие 2 разряда могут быть любыми, т.к. по даташиту абсолютная погрещность АЦП +/- 2 младших разряда. Далее, этот результат (dec(172)) умножаем на коэф.пересчета напряжения в температуру, например 2.6, и заносим в переменную unsigned int, соответственно все, что после точки отбрасывается.


Пока попробую в Excel'e покумекать

на катодах у меня по 100 Ом в реале стоят (вроде бы). Завтра гляну. Транзюки нормальные стоят.

Короче, индикация работает на ура! А АЦП что-то мне в морду плюет

Сообщение отредактировал Lost_Viking - Jul 30 2008, 19:04
Go to the top of the page
 
+Quote Post
AVRdeveloper
сообщение Jul 31 2008, 06:26
Сообщение #10





Группа: Новичок
Сообщений: 11
Регистрация: 8-02-08
Пользователь №: 34 857



Цитата(Lost_Viking @ Jul 30 2008, 21:56) *
Короче, индикация работает на ура! А АЦП что-то мне в морду плюет


Если Вы пробовали подавать разное напряжение на вход АЦП, и на индикаторе отбражалость новое число, значит ваш девайс работает правильно..

Попробуйте замерять мультиметром напряжения на входе АЦП во время подключения к нему переменного резистора, если крутить ручку, и мультиметр будет показывать разные напряжения, то и девас покажет новое значение. Если нет, проверьте номинал переменного резистора он не должен быть слышком большим.. У меня для таких целей 5,1-33кОм прекрасно работают..


Странно, если вы убрали прерывания от АЦП, то где вы считываете текущее значение с регистра данных АЦП? Я бы поставил его в main. т.е. как я понял у вас данные считываються с АЦП только один раз при включении.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 31 2008, 06:42
Сообщение #11


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Lost_Viking @ Jul 30 2008, 22:56) *
Люди, скажите как вычислить абсолютную погрешность, если учесть, что два младших разряда АЦП по даташиту грешат

Я что-то вообще не понял, что за датчик, схема какая-то трудночитабельная. Вообще, имхо, на АВР очень хитро вывернувшись можно, наверно, получить погрешность в пределах +/- 1 градуса... Это при условии калибровки. Про нестабильность внутренней опоры тоже надо подумать...


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
Lost_Viking
сообщение Jul 31 2008, 10:08
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091



Цитата(AVRdeveloper @ Jul 31 2008, 10:26) *
Если Вы пробовали подавать разное напряжение на вход АЦП, и на индикаторе отбражалость новое число, значит ваш девайс работает правильно..

Попробуйте замерять мультиметром напряжения на входе АЦП во время подключения к нему переменного резистора, если крутить ручку, и мультиметр будет показывать разные напряжения, то и девас покажет новое значение. Если нет, проверьте номинал переменного резистора он не должен быть слышком большим.. У меня для таких целей 5,1-33кОм прекрасно работают..
Странно, если вы убрали прерывания от АЦП, то где вы считываете текущее значение с регистра данных АЦП? Я бы поставил его в main. т.е. как я понял у вас данные считываються с АЦП только один раз при включении.


Там сделано гораздо проще: АЦП преобразовывает все время, т.к. находится в режиме free run, и его не нужно все время запускать. Ну, а значения берутся из АЦП с частотой, равной частоте развертки, т.е. регулируется регистром OCR0. Там при каждом совпадении таймера с OCR0 вызывается фнукция обработчика прерывания:
Код
interrupt [TIM0_COMP] void timer0_comp_isr(void)

в ней есть комманда:
Код
PORTC=Dig[num()]

где num() - это функция, где при нажатой кнопке "нагрев" значения из ADCL и ADCH (ну или в CodevisionAvr - ADCW) помещаются в переменную current_temp. Далее это значение разбивается на 3 десятичных разряда.

Вобщем, я понял в чем ошибка. Смотрите схему. Слева - как было, справа - как стало. Т.е. теперь снимаю напряжение фактически с делителя. Может кто-нибудь объяснить почему при включении, что слева, АЦП не понимает в чем дело? Я не совсем понимаю.

Сообщение отредактировал Lost_Viking - Jul 31 2008, 10:26
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jul 31 2008, 10:53
Сообщение #13


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Lost_Viking @ Jul 31 2008, 16:08) *
Вобщем, я понял в чем ошибка. Смотрите схему. Слева - как было, справа - как стало. Т.е. теперь снимаю напряжение фактически с делителя. Может кто-нибудь объяснить почему при включении, что слева, АЦП не понимает в чем дело? Я не совсем понимаю.


А в исходной схеме нарисовано как справаsmile.gif
В левой схеме тоже получается делитель, но его нижнее сопротивление равно бесконечности. Потому на выходе получается всё время 5в.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Lost_Viking
сообщение Jul 31 2008, 10:55
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 168
Регистрация: 25-04-08
Пользователь №: 37 091



Цитата(MrYuran @ Jul 31 2008, 10:42) *
Я что-то вообще не понял, что за датчик, схема какая-то трудночитабельная. Вообще, имхо, на АВР очень хитро вывернувшись можно, наверно, получить погрешность в пределах +/- 1 градуса... Это при условии калибровки. Про нестабильность внутренней опоры тоже надо подумать...


датчиком будет какой-нибудь терморезистор, или транзистор. А пока для опытов вместо датчика использую обычный переменник на 2.4 кОм.
А такую погрешность можно получить и не выворачиваясь. Самое главное питание стабилизировать. Насчет внутренней опоры я не подумал. Насколько она нестабильна?
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jul 31 2008, 11:05
Сообщение #15


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Lost_Viking @ Jul 31 2008, 14:55) *
датчиком будет какой-нибудь терморезистор, или транзистор.
Какой именно? Платиновый точно не подойдёт, только термистор. У него характеристика покруче, но нелинейная.
Цитата
Насчет внутренней опоры я не подумал. Насколько она нестабильна?

по даташиту +/- 0,1В, то есть почти +/-5%


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post

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

 


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


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