Форум РадиоКот https://radiokot.ru/forum/ |
|
Attini13A АЦП на 2 канала... https://radiokot.ru/forum/viewtopic.php?f=57&t=146208 |
Страница 1 из 1 |
Автор: | Selfrock [ Вт июн 20, 2017 18:36:07 ] |
Заголовок сообщения: | Attini13A АЦП на 2 канала... |
В общем, понадобился мне простенький терморегулятор на 2 канала... и решено было его сделать на Attiny13A. датчик NTC термистор на 10 килоом от ноги тиньки с АЦП на +5. от той же ноги тиньки резистор на 4,7 килоом на землю... Код используется примерно такой (сильно не пинать, для контроллера пишу буквально второй раз в жизни)... #define F_CPU 9600000UL // 9.6 MHz #include <avr/io.h> #include <util/delay.h> int ohlajdatADC1PB1 = 0; int ohlajdatADC3PB0 = 0; int main(void) { DDRB = 0b00000011; PORTB = 0b00000000; ADCSRA=0b10000101; //разрешаем работу АЦП, (для 9,6 мегагерц лучше 0b10000110 т.е. на 64) //но не включаем его, //выставляем делитель на 32 while (1) { ADMUX=0b00000001; //назначаем ADC1 как вход АЦП //и напряжение питания ATTiny13A //для сравнения с нашим напряжением ADCSRA |= 0b01000000; //включаем АЦП (старт одного преобразования АЦП) while ((ADCSRA & (1 << ADIF)) == 0);//ждем окончания //преобразования, //только после этого //идем дальше if (ADCW > 510) //читаем датчик, если разогрелось выше порога... { ohlajdatADC1PB1 = 1; // ставим флаг необходимости охлаждения PORTB |= _BV(PB1); // включаем вентилятор _delay_ms(3000); // даем три секунды на разкрутку вентилятора } if (ADCW < 400) //если температура упала ниже порога выключения { if (ohlajdatADC1PB1 == 1) // а флаг охлаждения стоит { ohlajdatADC1PB1 = 0; // сбрасываем флаг охлаждения PORTB &= ~_BV(PB1); // выключаем вентилятор } } ADMUX=0b00000011; //назначаем ADC3 как вход АЦП ADCSRA |= 0b01000000; //включаем АЦП (старт одного преобразования АЦП) while ((ADCSRA & (1 << ADIF)) == 0);//ждем окончания //преобразования, //только после этого //идем дальше if (ADCW > 510) //читаем датчик, если разогрелось выше порога... { ohlajdatADC3PB0 = 1; // ставим флаг необходимости охлаждения PORTB |= _BV(PB0); // включаем вентилятор _delay_ms(3000); // даем три секунды на разкрутку вентилятора } if (ADCW < 400) //если температура упала ниже порога выключения { if (ohlajdatADC3PB0 == 1) // а флаг охлаждения стоит { ohlajdatADC3PB0 = 0; // сбрасываем флаг охлаждения PORTB &= ~_BV(PB0); // выключаем вентилятор } } } } Так вот, проблема в том, что данные от одного датчика попадают в другой канал... и наоборот. т.е. я грею один термистор, у меня включается один вентилятор и следом за ним второй, хотя второй датчик я не грею... наоборот, если греть другой датчик, такая же фигня... Собственно вопрос... что я делаю не так...? И почему после смены канала АЦП и запуска нового преобразования ADCW возвращает данные со старого преобразования ADCW = 0; перед новым преобразованием АЦП я пробовал, не помогает... все работает ровно так же как описано |
Автор: | Z_h_e [ Вт июн 20, 2017 23:46:02 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
На телефоне не удобно и нет Дш перед глазами. Похоже у вас нет сброса флага окончания преобразования АЦП |
Автор: | ARV [ Ср июн 21, 2017 07:05:19 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
Судя по всему это происходит потому, что опрашивая флаг запроса прерывания вы не сбрасываете его потом. И поэтому к моменту попытки измерить другой канал он уже стоит и вы думаете, что измерили, а на самом деле в ADCW (кстати, почему ADCW, а не просто ADC?) еще лежит прежнее значение... пока вы там все делаете между измерениями, проходит время и значение регистра обновляется вторым каналом, но вы-то уже думаете, что меряете первый... т.е. причина, по моему мнению, в неправильной раоте с АЦП. Я вообще всегда использую опрос флага ADSC - он падает сам, когда преобразование завершено. |
Автор: | Selfrock [ Ср июн 21, 2017 12:59:44 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
ADCW, потому что в примерах на основе которых я писал свой код (например из кодвайзера), сделано именно так. были еще варианты с ADCH и ADCL с последующим объединением данных в одном слове В общем, изменил в коде... while ((ADCSRA & (1 << ADIF)) == 0); на while ((ADCSRA & (1 << ADIF)) == 0); ADCSRA|=(1<<ADIF); и вроде как заработало как надо... только вот теперь я уже не понимаю почему... Насколько я понимаю конструкция while ждет и ничего не делает до момента выполнения условия, т.е. пока ADIF не перестанет содержать 0 , а затем выполняется код после while т.е. на строку после while выполнение переходит только если бит ADIF не равен 0 (очевидно, если это бит, то будучи не 0 он может быть только 1) так почему нормально работает только если ADIF принудительно снова поставить 1 ? или я не прав и что то не понимаю? |
Автор: | ARV [ Ср июн 21, 2017 13:22:30 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
Selfrock писал(а): или я не прав и что то не понимаю? вы правы в том, что касается работы оператора while, но слишком увлекаетесь кодвайзерами вместо изучения архитектуры выбранного микроконтроллера, и поэтому не знаете, что флаги запросов прерываний у AVR всегда сбрасываются путем записи единицы.
|
Автор: | Selfrock [ Ср июн 21, 2017 13:37:05 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
Спасибо за пояснение. Я действительно не предполагал что флаги могут ставится присвоением им нуля и сбрасываться единицей... Думал что такой подход реализован только при записи фьюзов, а уж во внутренних регистрах все как обычно... Пойду читать даташит на тиньку... |
Автор: | ARV [ Ср июн 21, 2017 14:19:04 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
Selfrock писал(а): не предполагал что флаги могут ставится присвоением им нуля такого, по-моему, никто никогда не предполагал. флаг запроса прерывания в архитектуре AVR8 вообще невозможно установить программными манипуляциями с регистром, где этот флаг расположен. запись 0 в такой флаг игнорируется, а запись 1 - обнуляет флаг.
|
Автор: | Z_h_e [ Чт июн 22, 2017 17:23:51 ] |
Заголовок сообщения: | Re: Attini13A АЦП на 2 канала... |
Selfrock писал(а): Думал что такой подход реализован только при записи фьюзов Сравнение неверное.Записывая во фьюз ноль, туда запишится ноль, записывая 1 запишется 1. Логический ноль во фьюзе значит запрограммировано. Это дань ПЗУ с пережигаемыми перемычками. Флаги в AVR. 0 - флаг невзведен. 1- флаг взведен. Флаг взвести может только событие. Запись нуля во флаг эффекта не дает. Запись 1 - сброс флага, т.е. его состояние будет 0. Так же в большинстве (но не во всех) случаев сброс флага осуществляется аппаратно при переходе в обработчик прерывания. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |