Перейти к содержанию
    

Таймер на 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... питание от 3В.

... Два индикатора: на одном отображаются единицы (PORTC), на другом - десятки (PORTD).

Т.к. питание от двух пальчиковых батареек, то необходим power save mode, поэтому ставлю внешний часовой кварц и по нему считает timer2.

Из спящего режима МК выходит по низкому уровню на INT0.

 

При симуляции всё работает, но при реализации на макетной плате ничего не выходит. Не пойму ошибку в коде.... МК находится в режиме Powre Save и при нажатие обрабатывается прерывание... но почему ничего не выводится на сегменты, не могу понять.

Если при симуляции все работает, зачем искать ошибку в коде? Попробуйте поискать ошибку в монтаже, о грамотной разводке земли недавно тема была. Опять же, два индикатора - это порядочный ток, как питание себя ведет? Ну и наконец - у меги 8-8 нижний предел питания 2.7в, у Вас какой?

В крайнем случае, код можно проверить по кускам, отключите прерывание и проверьте циклический вывод индикации, а потом уже двигайтесь дальше. Кстати, fuse как определяете :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вероятно, из-за дребезга контактов по однократному нажатию кнопки переменная 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");

}}

 

Эта работает как надо. Фьюзы в обоих случаях ставлю одинаково:

 

post-78360-1381900662_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На одной и той же отладочной плате проверяю две прошивки. Ту, что привел, и ту, что попроще:

 

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: ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Извиняюсь спросить, а если в первом варианте, который не работает, после свичей тоже обнулять flagbutton, и тоже выдержку поставить, изменения будут? Или я просто не заметил, где обнуление впендюрено и сколько времени индикатор отрабатывает, прежде чем контроллер заснет - тогда извиняюсь :laughing: ...

 

обнуление каждые пять секунд

 

Проблема в строке: flagbutton++;

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

обнуление каждые пять секунд

 

Проблема в строке: flagbutton++;

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

Да, уже разглядел. Ну как-то надо исключать дребезг, аппаратно или программно :laughing: А пока, если вообще отключить прерывание и присвоить flagbutton значение 1, то контроллер запускается и на индикаторе идет отсчет 5 секунд, правильно понял?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема в строке: flagbutton++;

Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, уже разглядел. Ну как-то надо исключать дребезг, аппаратно или программно :laughing: А пока, если вообще отключить прерывание и присвоить flagbutton значение 1, то контроллер запускается и на индикаторе идет отсчет 5 секунд, правильно понял?

 

Даже если в прерывании записать flagbutton=1, то при нажатии кнопки будут отображаться 5 сек счета. Поняли правильно.

 

Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня.

 

Сделал MCUCR=0xB1, т.е. настроил на перепад, перемычку заменил кнопкой, но ничего не изменилось, индикаторы молчат.

 

Не в самой строке, но - близко. Вы настроили прерывание по int0 на низкий уровень, и этот уровень в настоящее время постоянно присутствует - прерывания генерятся, переменная наращивается... Нажатие кнопки, как правило, фиксируют по перепаду уровня.

 

Но я понял, что исключив дребезг - зациклил программу. Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом?

Как вариант. Или в обработчике прерывания сразу же запрещать INT0, генерить задержку по свободному таймеру и разрешать. Прерывание, естественно, по фронту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал MCUCR=0xB1, т.е. настроил на перепад

Логичнее было бы применить "The falling edge of INT0 generates an interrupt request", т.е. прерывание по спаду.

 

PS. Чтобы не мучать ни себя ни других людей, которые вызовутся Вам помочь, возмите себе за правило записывать значения в регистры таким образом:

MCUCR= (1<<SE) | (1<<SM1) | (1<<SM0) | (1<<ISC10);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дребезг исключается другим образом.

Во первых не следует использовать прерывание для чтения кнопки.

 

Следует сделать автомат на 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;

}

}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Даже если в прерывании записать flagbutton=1, то при нажатии кнопки будут отображаться 5 сек счета. Поняли правильно.

 

Сделал MCUCR=0xB1, т.е. настроил на перепад, перемычку заменил кнопкой, но ничего не изменилось, индикаторы молчат.

 

Но я понял, что исключив дребезг - зациклил программу. Тогда нужно как то избавляться от дребезга. Пробовал сделать задержку в прерывании (10ms), но не помогло. Что можно еще сделать? Поставить параллельно 10нФ и последовательно резистор около 300Ом?

От дребезга избавитесь потом, когда станет понятно, что только он - источник всех бед. Хорошо, если при этом станет понятно, что алгоритм работы устройства следует радикально пересмотреть. В частности, совершенно нет обработки критических ситуаций, ошибок.

Микроконтроллер за Вас додумывать не будет, ему надо четко расписать, как себя вести в разных ситуациях :) Переменная flagbutton должна принимать только те значения, которые можно корректно обработать. Ну хотя бы в обработчик прерывания вставьте if, который при переполнении flugbutton будет сбрасывать в 0. В этом случае даже при сильном дребезге у Вас будет веселое перемигивание индикаторов, но оно - будет!

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во первых не следует использовать прерывание для чтения кнопки.

IMHO, вредный совет для разработки устройств с батарейным питанием.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...