Проблемы при программировании AVR на Си

Обсуждение статей, технологий домашней автоматизации, программных и аппаратных решений
Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 12:02

Добрый день уважаемые!

Решил создать данную тему поскольку не нашел подходящей.
Предлагаю тут решать проблемы, возникающие, при программировании девайсов на основе AVR, относящихся к умному дому.

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 12:08

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

Предисловие: собран девайс на основе всем известного NetAlarm от многоуважаемого Корягина Андрея, который я назвал "Manager of CCTV". Устройство представляет собой контроллер для автономной системы видеонаблюдения загородного участка/дома с управлением через web-интерфейс. Его подробное описание - тема другого топика, однако в списке его возможностей есть следующее: "Позволяет перезагружать контроллер из веб-интерфейса в случае его некорректной работы". Столкнулся с тем, что придумал как перезагружать, а вот как сохранять и отображать количество перезагрузок контроллера на веб-странице - вроде бы просто, но...
Код самого действия на данном этапе такой:

Код: Выделить всё

// глобальные переменные
uint8_t			rstcount;
uint8_t			EEMEM EEMEM_RSTCOUNT;

// Hard reset Manager via watchdog
void HardReset()
{	rstcount++;
	eeprom_write_block(&rstcount, &EEMEM_RSTCOUNT, sizeof(rstcount));
	cli();						// disable interrupts
	wdt_enable(WDTO_15MS);		// enable watchdog
	while(1);					// wait for watchdog to reset processor
}

// Фрагмент функции анализа URL
{		...
		if (find_key_val(str,Strbuf,2,"a"))
		{	if (Strbuf[0]=='a')
			{	...
				//Reset RstCount of manager
				if (pg==5)
				{	if (find_key_val(str,Strbuf,3,"rstc"))
					rstcount = 0;
					eeprom_write_block(&rstcount, &EEMEM_RSTCOUNT, sizeof(rstcount));
				}
				}
			}
		}
		//Reset manager
		if (pg==5)
		{	if (find_key_val(str,Strbuf,3,"rstm"))
			HardReset();									// Reset Manager
		}
}

//Сама страница Control
	if (page==5)
	{	eeprom_read_block(&rstcount, &EEMEM_RSTCOUNT, sizeof(rstcount));
		//Reset count of Manager
		if (rstcount == 0xFF)
		{	rstcount = 0;
		}
		
		plen=fill_tcp_data_p(buf,plen,PSTR("<center><h2>Control</h2>Operation time - "));
		plen=fill_tcp_data_int(buf,plen,TIMER_DAY);
		plen=fill_tcp_data_p(buf,plen,PSTR(" day "));
		plen=fill_tcp_data_int(buf,plen,TIMER_HOUR);
		plen=fill_tcp_data_p(buf,plen,PSTR(":"));
		if(TIMER_MIN<10) plen=fill_tcp_data_p(buf,plen,PSTR("0"));
		plen=fill_tcp_data_int(buf,plen,TIMER_MIN);
		plen=fill_tcp_data_p(buf,plen,PSTR("<table border=\"0\" width=\"180\"><tr align=\"center\"><td>Count RST="));
		plen=fill_tcp_data_int(buf,plen,rstcount);
		plen=fill_tcp_data_p(buf,plen,PSTR("</td><form method=\"GET\"><td><input name=\"pg\" type=\"hidden\" value=\"5\">\
		<input name=\"a\" type=\"hidden\" value=\"a\"><input name=\"rstc\" type=\"hidden\" value=\"1\"><input type=\"submit\" value=\"Reset\"></td></form></tr></table>\
		<form method=\"GET\"><input name=\"pg\" type=\"hidden\" value=\"5\"><input name=\"rstm\" type=\"hidden\" value=\"1\"><input type=\"submit\" value=\"Reset manager\" onclick='ReLoadFunction()'></form></center>\
		<script>function ReLoadFunction() {setTimeout(function() {location.reload();}, 5000)}</script>"));
	}
Внешний вид веб-страницы такой:
Изображение

При первом включении устройства счетчик Count RST=0, после первого сброса равен 1, после второго, третьего и т.д. также равен 1!!! Не могу разобраться почему. Переменная глобальная, значит при первом входе на страничку "Control" она равна 255, поэтому добавлено условие чтобы она была равна 0. Кнопкой отправляем форму - начинается выполнение действия Reset manager, то есть функция HardReset() - в ней к глобальной переменной rstcount добавляется 1 и она записывается в EEPROM. По идее тоже должно происходить при повторной отправке формы, но нет - Count RST остается равен 1!

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 08 апр 2014, 14:15

обработчик вроде правильный
plen=fill_tcp_data_p(buf,plen,PSTR("</td><form method=\"GET\"><td><input name=\"pg\" type=\"hidden\" value=\"5\">\
<input name=\"a\" type=\"hidden\" value=\"a\"><input name=\"rstc\" type=\"hidden\" value=\"1\"><input type=\"submit\" value=\"Reset\"></td></form></tr></table>\
<form method=\"GET\"><input name=\"pg\" type=\"hidden\" value=\"5\"><input name=\"rstm\" type=\"hidden\" value=\"1\"><input type=\"submit\" value=\"Reset manager\" onclick='ReLoadFunction()'></form></center>\
<script>function ReLoadFunction() {setTimeout(function() {location.reload();}, 5000)}</script>"));
}
вот это в оригинале спрятано в один тег <form> и разделены plen=fill_tcp_data_p ,а что приходит на девайс при нажатии кнопок

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 14:26

alexsis_76 писал(а):вот это в оригинале спрятано в один тег <form> и разделены plen=fill_tcp_data_p ,а что приходит на девайс при нажатии кнопок
Так-с. В каком оригинале? В NetAlarm такой страницы нет совсем. Тут сделал специально 2 формы чтобы они по отдельности работали, к кнопке "Reset" претензий нет - счетчик реально обнуляет, да и "Reset manager" работает, однако счетчик не инкрементируется... Могу пробросить порт - сами попробуете.
Я грешу на запись в EERPROM:
пробовал в HardReset() перед инкрементированием счетчика читать его значение - eeprom_read_block(&rstcount, &EEMEM_RSTCOUNT, sizeof(rstcount));
в итоге - при каждом сбросе мэнеджера прибавляется +5!!! Откуда понять тоже не могу.

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 08 апр 2014, 14:36

точно такой нет но есть вот такая
// Save settings
///////////
if (find_key_val(str,Strbuf,2,"a")) {
if (Strbuf[0]=='a') {
///////////
// Settings
///////////
if (pg==2) {
if (!find_key_val(str,netsettings.myname,TITLE_LENGTH,"name")) {
netsettings.myname[0]='\0';
}

// convert URL spase ('+') to normal space ' '
for (i=0;i<TITLE_LENGTH;i++) {
if (netsettings.myname == '+') {
netsettings.myname = ' ';
}
}

if (find_key_val(str,Strbuf,30,"mac")) {
if (UART_GET_ARG(Strbuf, RXbyte, 0, '-') == 6) {
for (i=0;i<6;i++) {
netsettings.mymac = RXbyte;
}
}

}

примерно как у вас
вместо eeprom_read_block можно использывать eeprom_write_byte у вас uint8_t однобайтовая

void eeprom_write_byte(uint8_t *addr, uint8_t value)

Этот девайс (NetAlarm)я использую тоже , естественно доработанный
а зачем
cli(); // disable interrupts
Последний раз редактировалось alexsis_76 08 апр 2014, 14:59, всего редактировалось 1 раз.

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 14:57

Понял, спасибо за совет! Вечером попробую. Даже как-то не подумал об этом - слепо скопипастил.

Кстати, раз вы тоже используете клон NetAlarm, то проблему "подвисания" устройства при быстром переключении выходов (вкл./выкл.) не решили? У меня если быстро переключать выход оно начинает тормозить - пинги растягиваются до 4-7 секунд (как раз из-за этого сделал страницу "Control")! Думаю, что это возникает из-за прерывания в прерывании, соответственно в регистры записывается чушь.
cli(); // disable interrupts
Я не тестировал без запрета прерываний, но, думаю, ничего хорошего не будет - в какой-то момент выполнение данной функции может прерваться прерыванием :) тавталогия... в итоге сброса не будет. Вообще случайно нашел данную связку на просторах инета, когда задался поиском софтового варианта сброса AVR.

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 08 апр 2014, 15:05

насчет сторожевого таймера
При разрешении сторожевого таймера его состояние неизвестно и прежде, чем разрешать сторожевой таймер, необходимо выполнить команду WDR

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 08 апр 2014, 15:10

в какой-то момент выполнение данной функции может прерваться прерыванием
строжевой таймер его все равно сбросит там внизу бесконечный цикл while(1) из него нет выхода кроме сброса я делал без CLI
проблему "подвисания" устройства при быстром переключении выходов
я как то не пробывал их быстро включать выключать , завтра попробую

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 08 апр 2014, 15:25

проблему "подвисания" устройства при быстром переключении выходов
а вы датчики оставили возможно дело в этом
delay_ms(DS18B20_TCONV_12BIT);
, даем команду измерения и ждем DS18B20_TCONV_12BIT , потом идем дальше
Думаю, что это возникает из-за прерывания в прерывании,
это где

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 20:18

alexsis_76 писал(а):насчет сторожевого таймера
Я оставил так как в исходниках - показалось логичным: настройка на сброс через 1 с при инициализации устройства и после входа в основной цикл сразу сброс Watchdog-а. В функции же сброса мы просто уменьшаем время сброса до минимума и ждем. На самом деле от запрета прерываний в данном случае хуже не будет!
alexsis_76 писал(а):а вы датчики оставили возможно дело в этом
Датчики конечно оставил, на данный момент 3 шт., однако переписал немного код считывания температуры, поскольку иначе даже пинг каждую 5-ю секунду жутко тормозил (проверьте у себя, кстати) - теперь все ровненько и читается любой датчик из любой партии (помню были какие-то проблемы):

Код: Выделить всё

		// Time to read temperature
		if (TIMER_DS18B20 == 1)
		{	read_temp_meas();
		}
		if (TIMER_DS18B20 == 3)
		{	start_temp_meas();
		}
Соответственно таймер:

Код: Выделить всё

ISR(TIMER1_OVF_vect)
{	// 100 Hz
	TCNT1 = 0x10000 - (F_CPU/1024/100);
    
	// Time correction
	if (++TIMER_CORRECT > 13)
	{	TIMER_CORRECT = 0;
		TCNT1--;
	}

	// Time of one second
	if (++TIMER_ONESEC > 99)
	{	TIMER_ONESEC = 0;

		// Timer for DS18B20
		if (++TIMER_DS18B20 > 5)
		{	TIMER_DS18B20 = 0;
		}
alexsis_76 писал(а):это где
Это когда микроконтроллер по первому прерыванию от ENC28J60 еще дает ответ (выводит страницу с обновленным состоянием выхода), от ENC28J60 приходит снова прерывание с новым запросом.

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 08 апр 2014, 21:32

Ну в общем перепробовал все... записывал, читал байт. Переменную уже определил как static volatile uint8_t RstCount. И все равно - счетчик останавливается на 1!

Единственное что попробовал - дополнительно читать значение счетчика в функции HardReset(), инкрементировать его и снова записывать в EEPROM:

Код: Выделить всё

// Hard reset Manager via watchdog
void HardReset()
{	RstCount=eeprom_read_byte(&EEMEM_RSTCOUNT);
	if (RstCount == 0xFF)
	{	RstCount = 0;
	}

	RstCount++;
	//eeprom_write_block(&RstCount, &EEMEM_RSTCOUNT, sizeof(RstCount));
	eeprom_write_byte(&EEMEM_RSTCOUNT, RstCount);
	cli();						// disable interrupts
	wdt_enable(WDTO_15MS);		// enable watchdog
	while(1);					// wait for watchdog to reset processor
}
В итоге при первом сбросе Count RST=5, при втором - Count RST=10, третьем - Count RST=15 и т.д. ОТКУДА ЭТО??? У меня мыслей нет...

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 09 апр 2014, 03:27

так там вроде нет(не было)прерываний , сплошной polling,у меня вроде не виснет, хотя может нажимаю не так быстро
жутко тормозил
я тоже переделал только у меня после старта измерений и завершения преобразования датчики опрашиваются все скопом
//################# ЧТЕНИЕ ТЕМПЕРАТУРНОГО ДАТЧИКА #########################################
if (FLAG_DS18B20) {
if ( DS18X20_start_meas( DS18X20_POWER_EXTERN,NULL ) == DS18X20_OK ) {//стартуем
FLAG_DS18B20=0;
TIMER_CONERTIONS_DS=DELAY_DS_READY_TEMPERATURE;//ПОСЛЕ ОКОНЧАНИЯ ОПРАШИВАЕМ ДАТЧИКИ
delay_ds_enable=1;// РАЗРЕШАЕМ ТАЙМЕР
}
}
if(DELAY_DS_READY_FLAG){//время ожидания истекло 1 с
for(empty_buf=0;empty_buf<MAXSENSORS;empty_buf++){
DS18B20SensorsValues[empty_buf] = 0;// записуем 0 в буфера
}
for(i=0;i<MAXSENSORS;i++){// перебираем все датчики
if ( DS18X20_read_meas( &gSensorIDs[0], &subzero, &cel, &cel_frac_bits) == DS18X20_OK ) {
DS18B20SensorsValues = (int)cel;
if (subzero == 1)
DS18B20SensorsValues = -1*DS18B20SensorsValues;// если температура отрицательна
}
}
DELAY_DS_READY_FLAG=0;
}
//###############################################################################

если не жалко скиньте код, посмотрю у себя

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 09 апр 2014, 07:44

alexsis_76 писал(а):так там вроде нет(не было)прерываний , сплошной polling
Вот теперь и я начал думать - ведь в основной программе прерывания по INT0 не заданы и в ENC28J60.c тоже нет! Видно проектом ошибся, но точно помню что в каком-то проекте (tuxgraphics, наверное) в ENC28J60.c настраивались прерывания по INT0, оттуда и предположения что возникает прерывание в прерывании.
alexsis_76 писал(а):датчики опрашиваются все скопом
А можно скрин как у вас бесконечный пинг идет?
alexsis_76 писал(а):если не жалко скиньте код, посмотрю у себя
Конечно не жалко, тем более GPL2. Напишите адрес в личке.

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 09 апр 2014, 08:08

А можно скрин как у вас бесконечный пинг идет?
это какой пинг
точно помню что в каком-то проекте (tuxgraphics, наверное)
не все проекты tuxgraphics сделаны как под копирку без обработчика

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 09 апр 2014, 09:22

alexsis_76 писал(а):это какой пинг
Обычный бесконечный пинг из консоли к вашему устройству: ping -t X.X.X.X


alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 10 апр 2014, 03:17

Вот , правда датчик всего 1 , остальные взял для другого проекта(дефицит), но с 3 работает точно так же , устройство во время пинка само пингует IP, правда как можно видеть тот на пинг не отвечает,пинг раз в секунду, посылает LOG на сервер, в это время я еще нажимал "кнопки" на форме , вроде все нормально,сейчас загружу Вашу программу
Вложения
ping.rar
(21.52 КБ) 485 скачиваний

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 10 апр 2014, 06:14

Ну да - все красиво, хотя все же надо с 3-мя датчиками пробовать (желательно из разных партий), поскольку авторский вариант с 1 датчиком работал тоже хорошо! У меня с авторским вариантом прошивки (с ожиданием после считывания данных с DS18B20 - delay_ms(DS18B20_TCONV_12BIT)) каждый 5-й пинг растягивался. Были проблемы когда DS18B20 из разных партий ("новый" датчик не читался), после убирания задержки, все стало отлично работать. Ах, да еще библиотеки ds18b20 поменял - как раз после этого стало работать замечательно! Так что закупайтесь на том же aliexpess датчиками, последний раз купил десяток за 50 р/шт.
Вечером попробую тоже сделать прямой пинг (непосредственно подключу устройство к PC, сейчас весь трафик через 3G по VPN до домашнего VPN-сервера, затем домашний wi-fi) с "полной" загрузкой устройства.

PS: чувствую надо переименовывать тему в "Делаем клоны NetAlarm под свои нужды" :)

alexsis_76

Re: Проблемы при программировании AVR на Си

Сообщение alexsis_76 » 10 апр 2014, 09:30

Попробывал загрузить Вашу прошивку , результата ниже
поменял ip адреса , прошил , жуткие тормоза , пинги через раз, при нажатии на ссылки ,открываются те же ссылки ниже,
если сделать вот так
if (TIMER_DS18B20 == 1)
{ //read_temp_meas();
}
, тормоза пропадают , но страница по прежнему отображается криво, попробывал в 3 браузерах

Alex_Jet
Сообщения: 1251
Зарегистрирован: 12 янв 2014, 18:00
Откуда: Россия, г.Томск

Re: Проблемы при программировании AVR на Си

Сообщение Alex_Jet » 10 апр 2014, 09:41

Попробывал загрузить Вашу прошивку , результат ниже
Написал вам в личку, потестируйте.
Пинг вечером сделаю на своей версии устройства. У меня ничего подобного не было. Видимо тут компилятор что-то совсем оптимизировал. Каким пользуетесь? Я по старинке WinAVR 2010.
Также попробую отключить оптимизацию в avrdude - главное чтобы размер программы за 32768 байт не вылез!

Ответить