shatov 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Таймер на Atmega8. Таймер должен считать дни, питание от 3В. При нажатии на кнопку INT0 высвечивается счет секунд (нужно для проверки работоспособности таймера), при повторном нажатии высвечиваются отсчитанные дни. В спящий режим таймер переходит при нажатии на кнопку в третий раз, либо по истечении 5 сек с момента нажатия на кнопку в первый раз: if (secL==5) {flagbutton=0;} if (secL>9) {secH++; secL=0; flagbutton=0;} Также необходим reset, но не замыканием соответствующего вывода на землю, а так, чтобы человек перепутав кнопки не сбросил свое насчитанное. Поэтому Reset осуществляется при последовательном нажатии int0 и зажимании PB5, т.е. нажав только PB5 таймер не сбросить. Два индикатора: на одном отображаются единицы (PORTC), на другом - десятки (PORTD). Т.к. питание от двух пальчиковых батареек, то необходим power save mode, поэтому ставлю внешний часовой кварц и по нему считает timer2. Из спящего режима МК выходит по низкому уровню на INT0. При симуляции всё работает, но при реализации на макетной плате ничего не выходит. Не пойму ошибку в коде. На этой же плате проверялась более простая версия прошивки (файл: as_work.c). Reset подтянул через 10k к питанию, кварц выдает что то похожее на нужную частоту с размахом около 0,5В. МК никак не реагирует на нажатие кнопки (INT0). Даже если бы совпадали моменты обнуления flagbutton и нажатия, то при повторном нажатии индикатор должен был бы показать число. МК обрабатывает нажатие INT0, т.к. ток потребления увеличивается (подключал к лабораторному БП), также варьировал с питанием (от 3 до 5В). Если кнопку не трогать, БП показывает ноль по потреблению тока, значит МК находится в режиме Powre Save и при нажатие обрабатывается прерывание... но почему ничего не выводится на сегменты, не могу понять. #include <mega8.h> #include <delay.h> char sec=0; int min=0; int hour=0; char secH=0, secL=0; int flagbutton=0; char dayH=0, dayL=0; interrupt [EXT_INT0] void ext_int0_isr(void) { flagbutton++; } interrupt [TIM2_OVF] void timer2_ovf_isr(void) { secL++; if (secL==5) {flagbutton=0;} if (secL>9) {secH++; secL=0; flagbutton=0;} if (secH>5) {secH=0;} if (sec>59) {min++; sec=0;} if (min>59) {hour++; min=0;} if (hour>23) {dayL++; hour=0;} if (dayL>9) {dayH++; dayL=0;} if (dayH>9) {dayH=0;} } void main(void) { PORTB=0x20; DDRB=0x1F; PORTD=0x04; DDRD=0x3B; PORTC=0x00; DDRC=0xFF; ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; GICR|=0x40; GIFR=0x40; MCUCR=0xB0; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x40; #asm("sei"); while (1) {while (flagbutton==1) { switch(secL) { case 0:{PORTC=~0xC0; PORTB.0=0; break;} case 1:{PORTC=~0xF9; break;} case 2:{PORTC=~0xA4; PORTB.0=1; break;} case 3:{PORTC=~0xB0; break;} case 4:{PORTC=~0x99; break;} case 5:{PORTC=~0x92; PORTB.0=1; break;} case 6:{PORTC=~0x82; break;} case 7:{PORTC=~0xF8; PORTB.0=0; break;} case 8:{PORTC=~0x80; PORTB.0=1; break;} case 9:{PORTC=~0x90; break;} }; switch(secH) { case 0:{PORTD=~0x40; break;} case 1:{PORTD=~0x79; break;} case 2:{PORTD=~0xA0; break;} case 3:{PORTD=~0x30; break;} case 4:{PORTD=~0x19; break;} case 5:{PORTD=~0x12; break;} case 6:{PORTD=~0x02; break;} case 7:{PORTD=~0x78; break;} case 8:{PORTD=~0x00; break;} case 9:{PORTD=~0x10; break;} }; } while (flagbutton==2) { switch(dayL) { case 0:{PORTC=~0xC0; PORTB.0=0; break;} case 1:{PORTC=~0xF9; break;} case 2:{PORTC=~0xA4; PORTB.0=1; break;} case 3:{PORTC=~0xB0; break;} case 4:{PORTC=~0x99; break;} case 5:{PORTC=~0x92; PORTB.0=1; break;} case 6:{PORTC=~0x82; break;} case 7:{PORTC=~0xF8; PORTB.0=0; break;} case 8:{PORTC=~0x80; PORTB.0=1; break;} case 9:{PORTC=~0x90; break;} }; switch(dayH) { case 0:{PORTD=~0x40; break;} case 1:{PORTD=~0x79; break;} case 2:{PORTD=~0xA0; break;} case 3:{PORTD=~0x30; break;} case 4:{PORTD=~0x19; break;} case 5:{PORTD=~0x12; break;} case 6:{PORTD=~0x02; break;} case 7:{PORTD=~0x78; break;} case 8:{PORTD=~0x00; break;} case 9:{PORTD=~0x10; break;} }; }; PORTD=0x04; PORTC=0x00; PORTB.0=0; #asm("sleep"); } } Timer_7sg.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 6 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба ... но почему ничего не выводится на сегменты, не могу понять.Вероятно, из-за дребезга контактов по однократному нажатию кнопки переменная flagbutton принимает значение гораздо больше единицы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abell 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба ... питание от 3В. ... Два индикатора: на одном отображаются единицы (PORTC), на другом - десятки (PORTD). Т.к. питание от двух пальчиковых батареек, то необходим power save mode, поэтому ставлю внешний часовой кварц и по нему считает timer2. Из спящего режима МК выходит по низкому уровню на INT0. При симуляции всё работает, но при реализации на макетной плате ничего не выходит. Не пойму ошибку в коде.... МК находится в режиме Powre Save и при нажатие обрабатывается прерывание... но почему ничего не выводится на сегменты, не могу понять. Если при симуляции все работает, зачем искать ошибку в коде? Попробуйте поискать ошибку в монтаже, о грамотной разводке земли недавно тема была. Опять же, два индикатора - это порядочный ток, как питание себя ведет? Ну и наконец - у меги 8-8 нижний предел питания 2.7в, у Вас какой? В крайнем случае, код можно проверить по кускам, отключите прерывание и проверьте циклический вывод индикации, а потом уже двигайтесь дальше. Кстати, fuse как определяете :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shatov 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Вероятно, из-за дребезга контактов по однократному нажатию кнопки переменная flagbutton принимает значение гораздо больше единицы. Чтобы исключить дребезг, замкнул вывод int0 на землю перемычкой еще до включения, тогда на индикаторе должен был бы отображаться ход секунд (идентично зажатому состоянию кнопки), но никаких изменений это не принесло. Если при симуляции все работает, зачем искать ошибку в коде? Попробуйте поискать ошибку в монтаже, о грамотной разводке земли недавно тема была. Опять же, два индикатора - это порядочный ток, как питание себя ведет? Ну и наконец - у меги 8-8 нижний предел питания 2.7в, у Вас какой? В крайнем случае, код можно проверить по кускам, отключите прерывание и проверьте циклический вывод индикации, а потом уже двигайтесь дальше. Кстати, fuse как определяете :) На одной и той же отладочной плате проверяю две прошивки. Ту, что привел, и ту, что попроще: #include <mega8.h> #include <delay.h> char sec=0; int min=0; int hour=0; int day=0; char secH=0, secL=0; int flagbutton=0; interrupt [EXT_INT0] void ext_int0_isr(void) { flagbutton=1; } interrupt [TIM2_OVF] void timer2_ovf_isr(void) { TCNT2=0x00; secL++; if (secL>9) {secH++; secL=0;} if (secH>5) {secH=0;} if (sec>59) {min++; sec=0;} if (min>59) {hour++; min=0;} if (hour>23) {day++; hour=0;} if (day>99) {day=0;} } void main(void) { PORTB=0x00; DDRB=0x3F; PORTD=0x04; DDRD=0xFB; PORTC=0x00; DDRC=0x01; ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; GICR|=0x40; GIFR=0x40; MCUCR=0xB0; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x40; #asm("sei") while (1) { if (flagbutton==1) {switch(secL) { case 0:{PORTB=~0xC0; break;} case 1:{PORTB=~0xF9; break;} case 2:{PORTB=~0xE4; PORTC.0=1; break;} case 3:{PORTB=~0xF0; PORTC.0=1; break;} case 4:{PORTB=~0xD9; PORTC.0=1; break;} case 5:{PORTB=~0xD2; PORTC.0=1; break;} case 6:{PORTB=~0xC2; PORTC.0=1; break;} case 7:{PORTB=~0xF8; PORTC=0x00; break;} case 8:{PORTB=~0xC0; PORTC.0=1; break;} case 9:{PORTB=~0xD0; PORTC.0=1; break;} }; switch(secH) { case 0:{PORTD=~0x40; break;} case 1:{PORTD=~0x79; break;} case 2:{PORTD=~0xA0; break;} case 3:{PORTD=~0x30; break;} case 4:{PORTD=~0x19; break;} case 5:{PORTD=~0x12; break;} case 6:{PORTD=~0x02; break;} case 7:{PORTD=~0x78; break;} case 8:{PORTD=~0x00; break;} case 9:{PORTD=~0x10; break;} }; } flagbutton=0; delay_ms(10); if (flagbutton==0) {PORTB=0x00; PORTD=0x04; PORTC.0=0x00;} #asm("sleep"); }} Эта работает как надо. Фьюзы в обоих случаях ставлю одинаково: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abell 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба На одной и той же отладочной плате проверяю две прошивки. Ту, что привел, и ту, что попроще: while (1) { if (flagbutton==1) {switch(secL) { }; switch(secH) { }; } flagbutton=0; delay_ms(10); if (flagbutton==0) {PORTB=0x00; PORTD=0x04; PORTC.0=0x00;} #asm("sleep"); }} Извиняюсь спросить, а если в первом варианте, который не работает, после свичей тоже обнулять flagbutton, и тоже выдержку поставить, изменения будут? Или я просто не заметил, где обнуление впендюрено и сколько времени индикатор отрабатывает, прежде чем контроллер заснет - тогда извиняюсь :laughing: ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shatov 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Извиняюсь спросить, а если в первом варианте, который не работает, после свичей тоже обнулять flagbutton, и тоже выдержку поставить, изменения будут? Или я просто не заметил, где обнуление впендюрено и сколько времени индикатор отрабатывает, прежде чем контроллер заснет - тогда извиняюсь :laughing: ... обнуление каждые пять секунд Проблема в строке: flagbutton++; Но т.к. дребезг был исключен замыканием INT0 на землю, то совсем не ясно, почему нет увеличения переменной по нажатию... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abell 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба обнуление каждые пять секунд Проблема в строке: flagbutton++; Но т.к. дребезг был исключен замыканием INT0 на землю, то совсем не ясно, почему нет увеличения переменной по нажатию... Да, уже разглядел. Ну как-то надо исключать дребезг, аппаратно или программно :laughing: А пока, если вообще отключить прерывание и присвоить flagbutton значение 1, то контроллер запускается и на индикаторе идет отсчет 5 секунд, правильно понял? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 6 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Проблема в строке: flagbutton++; Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
shatov 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Да, уже разглядел. Ну как-то надо исключать дребезг, аппаратно или программно :laughing: А пока, если вообще отключить прерывание и присвоить flagbutton значение 1, то контроллер запускается и на индикаторе идет отсчет 5 секунд, правильно понял? Даже если в прерывании записать flagbutton=1, то при нажатии кнопки будут отображаться 5 сек счета. Поняли правильно. Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня. Сделал MCUCR=0xB1, т.е. настроил на перепад, перемычку заменил кнопкой, но ничего не изменилось, индикаторы молчат. Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня. Но я понял, что исключив дребезг - зациклил программу. Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abell 0 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом? Как вариант. Или в обработчике прерывания сразу же запрещать INT0, генерить задержку по свободному таймеру и разрешать. Прерывание, естественно, по фронту. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 6 16 октября, 2013 Опубликовано 16 октября, 2013 · Жалоба Сделал MCUCR=0xB1, т.е. настроил на перепад Логичнее было бы применить "The falling edge of INT0 generates an interrupt request", т.е. прерывание по спаду. PS. Чтобы не мучать ни себя ни других людей, которые вызовутся Вам помочь, возмите себе за правило записывать значения в регистры таким образом: MCUCR= (1<<SE) | (1<<SM1) | (1<<SM0) | (1<<ISC10); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Tarbal 4 18 октября, 2013 Опубликовано 18 октября, 2013 · Жалоба Дребезг исключается другим образом. Во первых не следует использовать прерывание для чтения кнопки. Следует сделать автомат на 4 состояния и вызывать его каждые 10 миллисекунд void state_machine() { static int timeout; static int state = 0; switch(state) { default: case 0: if(button_pressed()) { state = 1; timeout = 5; } break; case 1: if(--timeout == 0) { if(button_pressed()) { state = 2; /* buton was pressed call button press handler */ buton_press_action(); } else { state = 0; } } break; case 2: if(button_pressed()) { state = 3; timeout = 5; } break; if(--timeout == 0) { if(button_pressed()) { state = 2; } else { state = 0; /* buton was released -- call button press handler */ buton_release_action(); } } break; } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexeyv 0 18 октября, 2013 Опубликовано 18 октября, 2013 · Жалоба 2 Tarbal: Где case 3: ?? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Abell 0 18 октября, 2013 Опубликовано 18 октября, 2013 · Жалоба Даже если в прерывании записать flagbutton=1, то при нажатии кнопки будут отображаться 5 сек счета. Поняли правильно. Сделал MCUCR=0xB1, т.е. настроил на перепад, перемычку заменил кнопкой, но ничего не изменилось, индикаторы молчат. Но я понял, что исключив дребезг - зациклил программу. Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом? От дребезга избавитесь потом, когда станет понятно, что только он - источник всех бед. Хорошо, если при этом станет понятно, что алгоритм работы устройства следует радикально пересмотреть. В частности, совершенно нет обработки критических ситуаций, ошибок. Микроконтроллер за Вас додумывать не будет, ему надо четко расписать, как себя вести в разных ситуациях :) Переменная flagbutton должна принимать только те значения, которые можно корректно обработать. Ну хотя бы в обработчик прерывания вставьте if, который при переполнении flugbutton будет сбрасывать в 0. В этом случае даже при сильном дребезге у Вас будет веселое перемигивание индикаторов, но оно - будет! А уж как дребезг устранить - дело десятое, повторяю - хоть программно, хоть аппаратно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Палыч 6 18 октября, 2013 Опубликовано 18 октября, 2013 · Жалоба Во первых не следует использовать прерывание для чтения кнопки. IMHO, вредный совет для разработки устройств с батарейным питанием. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться