Делимся опытом Наступив на грабли - сообщи другим! Обмен опытом разработки и ремонта электронных устройств. |
01.08.2010, 18:59
|
#11
|
Почётный гражданин KAZUS.RU
Регистрация: 01.04.2009
Адрес: Рязань
Сообщений: 1,140
Сказал спасибо: 21
Сказали Спасибо 635 раз(а) в 344 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
1. Как я понял у Вас стоит задача разработать терморегулятор для теплицы. Если следовать логике Вашего алгоритма выходит что контроллер считывает температуру, сравнивает с порогом и включает/выключает нагреватель. Представте ситуацию контроллер считал температуру и она на 0.5 градуса ниже порога, он включил нагреватель и тут к прибору подошли Вы и начали листать температуру по датчикам и задавать новый порог, а нагреватель работает греет. Вас отвлекли или Вы вспоминаете нужную температуру, а нагрев идет. Цикл прерван. Здесь необходимо разделить регулировку и задачу температуры. Далее у Вас ключевое включение нагрузки, т.е. температура понизилась нагреватель включился - представте температура упала на 0.1 градуса нагреватель включился, через секунду новый замер - температура выше порога - выключился и т.д. - как результат быстрый износ пускателя и обгорание контактов. Что бы избежать этого обычно задают 2 порога температуры с разницей в 1 - 2 градуса и учитывают предыдущее измерение. Выглядит это так - 2 порога 1 порог = 24 С 2 порог = 25 С, текущая температура = 18 С. Контроллер сравнивает текущую температуру с 1 порогом, она ниже - нагрев, сохраняет замер, второй замер температура = 19 С, берет разницу между 2 и 1 замером - разница положительна - идет нагрев =› сравнение с 2 порогом - температура меньше 2 порога - нагрев и т.д....... 25 замер температура 25.1 С предыдущая = 24.9 С разница положительна, сравниваем с 2 порогом - выше - отключить нагреватель ..... 30 замер температура = 24.6 предыдущий замер = 24.8 - разница отрицательна - охлаждение =› сравнение с 1 порогом.... 40 замер температура = 23.9 предыдущий замер = 24.1 разница отрицательная - охлаждение - сравнение с 1 порогом - меньше - включить нагреватель и т.д. Более подробно можете прочесть в книге "Аналоговые интерфейсы микроконтроллеров" Стюарт Болл Р. по моему видел в разделе книги ( у меня она в бумаге).
Теперь по поводу шедевра.
Код:
|
ADCSRA = 0x8B; //0b10001011 - ADC Enable; ADC Interrupt Enable; ADC Prescaler-8;
#asm("sei") |
Эти строки кода разрешают прерывание по окончанию цикла преобразования АЦП, расположенного по адресу 0х01С. Тоесть как только закончиться преобразование и будет сброшен флаг ADSC в счетчик команд будет записано 0x01C и выполнение программы пойдет именно с этого адреса, т.к. у Вас обработчик данного прерывания не написан то одному Аллаху известно что произойдет, но скорее всего ребут системы т.к обычно компилятор помечает не используемые прерывания как ошибочные и пренудительно записывает в счетчик команд нулевой адрес, что по сути ребут. Вам же дабы избежать подобных проблем надо либо отказаться от прерывания и выбросить сей код, либо написать обработчик прерываний и переделать пол программы.
По поводу ожидания АЦП. Ждать фиксированные 25 тактов не надо, проще отслеживать состояние флага ADSC в регистре ADCSRA. Что кста у Вас и сделано.
|
|
|
Сказали "Спасибо" _guardianangel
|
|
|
01.08.2010, 19:20
|
#12
|
Частый гость
Регистрация: 15.01.2010
Сообщений: 16
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Возможно я ошибаюсь, но в этом коде далее прописанно:
результат АЦП разделить на 31 (40-10+1) таким образом 33 единицы АЦП равняются 1-му градусу цельсия. А дальше по программе (допустим Т_задан = 22 градуса), если текущая температура датчика n = 23 градуса, то на порт РСn подать 1 (отключить), если 21 градус то на РСn подать 0, если 22 градуса то состояние порта не менять.
Мне кажется это нормальное решение, регулирование в пределах одного градуса. (десятичные значения градуса игнорируются, АЦП/31).
Цитата:
|
Вам же дабы избежать подобных проблем надо либо отказаться от прерывания и выбросить сей код, либо написать обработчик прерываний и переделать пол программы.
|
Выбросить строчку вообще? Или изменить значение ADCSRA?
|
|
|
|
01.08.2010, 19:30
|
#13
|
Почётный гражданин KAZUS.RU
Регистрация: 01.04.2009
Адрес: Рязань
Сообщений: 1,140
Сказал спасибо: 21
Сказали Спасибо 635 раз(а) в 344 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Сообщение от grizko
|
Возможно я ошибаюсь, но в этом коде далее прописанно:
результат АЦП разделить на 31 (40-10+1) таким образом 33 единицы АЦП равняются 1-му градусу цельсия. А дальше по программе (допустим Т_задан = 22 градуса), если текущая температура датчика n = 23 градуса, то на порт РСn подать 1 (отключить), если 21 градус то на РСn подать 0, если 22 градуса то состояние порта не менять.
Мне кажется это нормальное решение, регулирование в пределах одного градуса. (десятичные значения градуса игнорируются, АЦП/31).
|
Согласен. Можно и так.
Сообщение от grizko
|
Выбросить строчку вообще? Или изменить значение ADCSRA?
|
Выбросить строчку #asm ("sei")
Изменить значение ADCSRA
|
|
|
Сказали "Спасибо" _guardianangel
|
|
|
01.08.2010, 19:31
|
#14
|
Частый гость
Регистрация: 15.01.2010
Сообщений: 16
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Я всё таки приведу код программы полностью, наверно так будет удобнее.
PHP код:
|
/************************************************** ***
Программа управления тепличными нагревателями, в диапазоне температур от 10 до 40 градусов цельсия.
Управляет 8-ю нагревателями по сигналам датчиков, а также отображает температуру выбранного датчика.
Chip type : ATmega16
Program type : Application
AVR Core Clock frequency: 1.000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
************************************************** ***/
#include ‹mega16.h›
#include ‹stdio.h›
#include ‹delay.h›
#include ‹io.h›
#asm
.equ __lcd_port=0x18 ;PORTB
#endasm
#include ‹lcd.h›
//Подпрограммы
void Zad_temp();
void Chek_Botton();
void Check_bounds();
void Check_OK();
void ADC_IN();
void Temp_Ind();
void Out_ON();
void Out_OFF();
//Объявление переменных
volatile short ADC_VALUE;
volatile char D6_OK;
volatile char T_MIN;
volatile char COUNTER;
volatile char D4_UP;
volatile char T_MAX;
volatile char D5_DOWN;
volatile char SENSOR_SEL;
volatile char SENSOR;
volatile char TEMP_def;
volatile char T_ZAD;
//LCD
char lcd_buffer[33];
//Определение функций АЦП
static void __ADC_SampleADC();
static short __ADC_ReadAsInt();
/*************************************
//ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned int iRetVal;
// Read the AD conversion result
iRetVal=ADCW;
// Place your code here
}
**************************************/
//Реализация АЦП
void __ADC_SampleADC()
{
volatile char cnt;
//[U]char dda;[/U]
//[U]dda = DDRA;[/U]
//[U]//Включить выбранный АЦП[/U]
//[U]DDRA &= ~(1 ‹‹ COUNTER);[/U]
ADCSRA = 0x83; //0b10000011 - ADC Enable; [U]ADC Interrupt Enable;[/U] ADC Prescaler-8;
//[U]#asm("sei")[/U]
ADMUX = 0x20 | COUNTER; //0b00100xxx - ADC Left Adjust Result
//начать преобразование
ADCSRA |= 0x40;
while(ADCSRA & 0x40);
//время АЦП 25 тактов
cnt = 0;
while (cnt ‹ 0x19) cnt++;
//[U]DDRA = dda;[/U]
}
static short __ADC_ReadAsInt()
{
int iRetVal;
__ADC_SampleADC();
iRetVal = (ADCL ›› 6);
iRetVal |= (ADCH ‹‹ 2);
return (iRetVal);
}
void Zad_temp()
{
T_MIN = 10; // T_min = 10 нижняя граница диапазона
T_MAX = 40; // T_max = 40 верхняя граница диапазона
T_ZAD = (T_MAX - T_MIN) / 2 + T_MIN; // Середина диапазона для начальной настройки:
}
void Chek_Botton()
{
//Вход D4
DDRD = DDRD & 0x10;
D4_UP = (PIND.4 == 0);
//Вход D5
DDRD = DDRD & 0x20;
D5_DOWN = (PIND.5 == 0);
//Вход D6
DDRD = DDRD & 0x40;
D6_OK = (PIND == 0);
//Опрос пина D4_UP? Увеличение заданной температуры
if (D4_UP == 0)
{
//Устранение дребезга. Delay: 200 ms
delay_ms(200);
//Нажата "+"?
if (D4_UP == 0)
{
T_ZAD = T_ZAD + 1;
}
}
//Опрос пина D5_DOWN? Понижение заданной температуры
if (D5_DOWN == 0)
{
//Устранение дребезга. Delay: 200 ms
delay_ms(200);
//Нажата "-"?
if (D5_DOWN == 0)
{
T_ZAD = T_ZAD - 1;
}
}
}
void Check_bounds()
{
// Проверка верхней границы T_zad›T_max?
if (T_ZAD›T_MAX)
{
T_ZAD = T_MAX;
}
// Проверка нижней границы T_zad‹T_min?
if (T_ZAD‹T_MIN)
{
T_ZAD = T_MIN;
}
}
void Check_OK()
{
//Очистка дисплея
lcd_clear();
B__Check_OK:
//Цикл проверки "OK"
if (D6_OK == 0)
{
//Устранение дребезга. Delay: 200 ms
delay_ms(200);
//Нажата D6_OK?
if (D6_OK == 0)
{
//Переход на метку
goto A__Check_OK;
}
}
else
{
//Вызов подпрограммы: Chek_Botton
Chek_Botton();
//Вызов подпрограммы: Check_bounds
Check_bounds();
};
//Вывод на дисплей заданной температуры
sprintf(lcd_buffer," Set temp %u grd",T_ZAD);
lcd_init(16);
lcd_gotoxy(0, 0);
lcd_puts(lcd_buffer);
//Переход на метку
goto B__Check_OK;
//Выход из цикла
A__Check_OK:
//Очистка дисплея
lcd_clear();
}
void ADC_IN()
{
//Организация цикла опроса АЦП
while (COUNTER‹8)
{
//Выбор датчика
DDRD = DDRD & 0x07;
SENSOR_SEL = PIND & 0x07;
//Вызов функции: __ADC_ReadAsInt()
__ADC_ReadAsInt();
ADC_VALUE = __ADC_ReadAsInt();
//Temp_Ind
//Вызов подпрограммы: Temp_Ind
Temp_Ind();
//АЦП Counter
if (COUNTER==7)
{
//Сброс счетчика
COUNTER = 0;
}
else
{
//Инкремент счетчика
COUNTER = COUNTER + 1;
}
}
}
void Temp_Ind()
{
//Преобразование данных АЦП в градусы
TEMP_def = ADC_VALUE / 33 + T_MIN;
//Включение нагревателей
if (TEMP_def‹T_ZAD)
{
//Вызов подпрограммы: Out_ON
Out_ON();
}
//Выключение нагревателей
if (TEMP_def›T_ZAD)
{
//Вызов подпрограммы: Out_OFF
Out_OFF();
}
//Индикация температуры выбранного датчика
if (COUNTER==SENSOR_SEL)
{
SENSOR = SENSOR_SEL + 1;
delay_ms(50);
sprintf(lcd_buffer," Temp sensor %u %u grd",SENSOR,TEMP_def);
lcd_init(16);
lcd_gotoxy(1, 0);
lcd_puts(lcd_buffer);
delay_ms(200);
}
}
void Out_ON()
{
//Output_ON
DDRC = DDRC | (1‹‹COUNTER);
PORTC = PORTC & ~(1 ‹‹ COUNTER);
}
void Out_OFF()
{
//Output_ON
DDRC = DDRC | (1‹‹COUNTER);
PORTC = (PORTC & (1 ‹‹ COUNTER));
}
void main(void)
{
//Инициализация
MCUCSR=0x00;
#asm("wdr")
//Вызов подпрограммы: Zad_temp
Zad_temp();
//Вызов подпрограммы: Check_OK
Check_OK();
// Установка сетчика. Counter = 0
COUNTER = 0;
//Вызов подпрограммы: ADC_IN
ADC_IN();
}
|
Последний раз редактировалось grizko; 02.08.2010 в 17:57.
|
|
|
|
01.08.2010, 19:34
|
#15
|
Почётный гражданин KAZUS.RU
Регистрация: 01.04.2009
Адрес: Рязань
Сообщений: 1,140
Сказал спасибо: 21
Сказали Спасибо 635 раз(а) в 344 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Было бы не плохо указать каким компилятором пользуетесь.
|
|
|
|
01.08.2010, 19:47
|
#16
|
Частый гость
Регистрация: 15.01.2010
Сообщений: 16
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Сообщение от _guardianangel
|
Было бы не плохо указать каким компилятором пользуетесь.
|
Компилятор CodeVisionAVR V2.04.4a но туда я напихал разного кода. В частности изначально код был сгенерирован "Flowcode V4 for AVR", в нём я писал алгоритм (да и хотел сэкономить в написании текста программы). Кстати в "Flowcode V4 for AVR" он работал, но он там несколько специфичен, если есть возможность просмотреть файлы Flowcode V4 for AVR могу выложить проект. Но я хотел бы разобраться на С, на Ассемблере многовато писанины, хотя на асме мне кажется понятнее.
|
|
|
|
01.08.2010, 19:51
|
#17
|
Частый гость
Регистрация: 15.01.2010
Сообщений: 16
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Сообщение от _guardianangel
|
Выбросить строчку #asm ("sei")
|
Мне кажется данная строчка разрешает прерывания глобально, в данном случае и для АЦП. Или я опять что-то недопонял?
|
|
|
|
01.08.2010, 23:07
|
#18
|
Почётный гражданин KAZUS.RU
Регистрация: 01.04.2009
Адрес: Рязань
Сообщений: 1,140
Сказал спасибо: 21
Сказали Спасибо 635 раз(а) в 344 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
У Вас разрешено только одно прерывание - от АЦП и то, как мы разобрались, без обработчика. Ежели Вы не используете прерывания то лучше их запретить глобально, а точнее просто не разрешать - по дефолту они запрещены.
|
|
|
|
02.08.2010, 06:41
|
#19
|
Частый гость
Регистрация: 15.01.2010
Сообщений: 16
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Сообщение от _guardianangel
|
У Вас разрешено только одно прерывание - от АЦП и то, как мы разобрались, без обработчика. Ежели Вы не используете прерывания то лучше их запретить глобально, а точнее просто не разрешать - по дефолту они запрещены.
|
А в этом случае АЦП будет выполнятся? Если запретить прерывания глобально?
А как будет лучше (правильней), отказаться от прерываний или написать обработчик?
Последний раз редактировалось grizko; 02.08.2010 в 06:44.
|
|
|
|
03.08.2010, 14:05
|
#20
|
Почётный гражданин KAZUS.RU
Регистрация: 01.04.2009
Адрес: Рязань
Сообщений: 1,140
Сказал спасибо: 21
Сказали Спасибо 635 раз(а) в 344 сообщении(ях)
|
Re: ATmega16 Устройство управления тепличными нагревателями
Сообщение от grizko
|
А в этом случае АЦП будет выполнятся? Если запретить прерывания глобально?
|
Будет.
Сообщение от grizko
|
А как будет лучше (правильней), отказаться от прерываний или написать обработчик?
|
А эт Вам уже решать. От это будет зависить как Вы реализуете алгоритм. Реализация возможна как с использованием прерываний так и без них.
|
|
|
Сказали "Спасибо" _guardianangel
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 22:20.
|
|