13.10.2013 в 03:12
Секундомер на ATMega8 с семисегментным индикатором (окончание)
Здесь уже была абсолютно рабочая версия, но теперь кнопка остановки задерживает пройденное время на 5 секунд и программно ресетит секундомер, т.е. он автоматически перезапускается с нулевого отсчёта времени.
При рассмотрении различных вариантов решения поставленной в прошлый раз задачи встречено ряд трудностей. Например, повторное нажатие кнопки может быть обработано только после окончания выполнения процедуры текущего прерывания, что не даёт возможность снова нажать кнопку для ресета (наверняка это решается управлением приоритетами или масками прерываний, но это не та задача, чтобы лезть в такие дебри). Ещё один времяубийственный момент - при включении Атмеги сразу срабатывает некое "паразитное" прерывание по INT0, чего, кстати нет в Протеусе.
Для быстрого ресета оставлена и кнопка хардверной перезагрузки (она замыкает на землю вход Reset).
От дребезга контактов защищают (реально, см. видео - все нажатия в кассу) подключенные параллельно кнопкам конденсаторы на 0,1 мкФ (на схеме не отображены, как и кнопка аппаратного ресета).
Каждую секунду мигает светодиод. Другой LED мигает каждые 10 сек. (горит в течении 1 с). Каждые 100 сек на одну секунду подаётся единица на свободный при использовании внутреннего RC-генератора пин B6 (например, на третий светодиод или на пищалку (тогда ещё потребуется NPN-транзистор (см. схему), на видео этого нет)). Такие сложности с транзисторным включением буззера требует только Протеус (впрочем и Мультисим) (чтобы он издавал звук через аудиокарту (кстати, в Мультисиме звук идёт на встроенный динамик), а не просто числился на схеме), "в реале" же достаточно на одну ногу пищалки (+) подать сигнал от МК, а другую - заземлить.
Схема:
Листинг программы:
Код
#include <io.h>
#include <delay.h>
static int z=0, i,j,k,n;
static flash unsigned char digit[] =
{
(0b01000100), //0
(0b01111101), //1
(0b10100100), //2 // сегмент С теперь на месте DP, а DP - на PORTB.1
(0b00110100), //3
(0b00011101), //4
(0b00010110), //5
(0b00000110), //6
(0b01111100), //7
(0b00000100), //8
(0b00010100) //9
};
static flash unsigned char razryad[] =
{
(1), //0
(2), //1
(4), //2
(8), //3
};
void ResetAll()
{
// lampOff();
// z=0;
i=0;
j=0;
k=0;
n=0;
DDRB.2=0;
PORTB.2=0;
// return;
}
void StopIt()
{
int y;
PORTB.2=1;
for (y=0;y<200;y++)
{
PORTD=0xff;
PORTD=digit[n];
PORTC=razryad[0];
delay_ms(5);
PORTD=0xff;
PORTD=digit[i];
PORTC=razryad[1];
delay_ms(5);
PORTD=0xff;
PORTB.1=0; // точка
PORTC=razryad[2];
delay_ms(2);
PORTB.1=1; // выкл. точку
PORTD=digit[k];
PORTC=razryad[2]; // включать после каждого обновления сегмента надо!
delay_ms(3);
PORTD=0xff;
PORTD=digit[j/5]; // десятые доли
PORTC=razryad[3];
delay_ms(5);
}
PORTB.2=0;
ResetAll();
}
void FirstInt() // ненужное прерывание после включения
{
PORTB.0=1; // просто индикатор работы
}
interrupt [EXT_INT0] void ext_int0_isr(void)
{
z++;
if (z==1) FirstInt();
else
{
PORTB.2=1;
StopIt();
z=1;
}
}
void main(void)
{
// D2 := Int0 (вход для прерывания)
DDRB.2=1; // этот LED горит, когда таймер остановлен
DDRB.0=1; // горит всегда, кроме сотых секунд
SREG|= (1<<7); // разрешаем общие прерывания
GICR|=(1<<6); // разрешаем прерывание по INT0
MCUCR|=(1<<1); // прерывание по ниспадающему фронту сигнала на INT0
DDRB=0xFF;
PORTB=0b00000010;
PORTD=0x00;
DDRD=0b11111111;
PORTC=0xF;
DDRC=0xF;
while (1)
{
for(n=0;n<10;n++)
{
for(i=0;i<10;i++)
{
for(k=0;k<10;k++)
{
for(j=0;j<50;j++)
{
PORTD=0xff;
PORTD=digit[n];
PORTC=razryad[0];
delay_ms(5);
PORTD=0xff;
PORTD=digit[i];
PORTC=razryad[1];
delay_ms(5);
PORTD=0xff;
PORTB.1=0; // точка
PORTC=razryad[2];
delay_ms(2);
PORTB.1=1; // выкл. точку
PORTD=digit[k];
PORTC=razryad[2];
delay_ms(3);
PORTD=0xff;
PORTD=digit[j/5]; // десятые доли
PORTC=razryad[3];
delay_ms(5);
}
PORTB.6=0;
DDRB.6=0; // чтобы в протеусе Buzzer пищал только 1 секунду
PORTB.0=~PORTB.0;
}
DDRB.6=1;
PORTB.6=1; // так будет пикать каждые 10 сек.
}
// а если вставить сюда, то каждые 100 сек.
}
}
}
#include <delay.h>
static int z=0, i,j,k,n;
static flash unsigned char digit[] =
{
(0b01000100), //0
(0b01111101), //1
(0b10100100), //2 // сегмент С теперь на месте DP, а DP - на PORTB.1
(0b00110100), //3
(0b00011101), //4
(0b00010110), //5
(0b00000110), //6
(0b01111100), //7
(0b00000100), //8
(0b00010100) //9
};
static flash unsigned char razryad[] =
{
(1), //0
(2), //1
(4), //2
(8), //3
};
void ResetAll()
{
// lampOff();
// z=0;
i=0;
j=0;
k=0;
n=0;
DDRB.2=0;
PORTB.2=0;
// return;
}
void StopIt()
{
int y;
PORTB.2=1;
for (y=0;y<200;y++)
{
PORTD=0xff;
PORTD=digit[n];
PORTC=razryad[0];
delay_ms(5);
PORTD=0xff;
PORTD=digit[i];
PORTC=razryad[1];
delay_ms(5);
PORTD=0xff;
PORTB.1=0; // точка
PORTC=razryad[2];
delay_ms(2);
PORTB.1=1; // выкл. точку
PORTD=digit[k];
PORTC=razryad[2]; // включать после каждого обновления сегмента надо!
delay_ms(3);
PORTD=0xff;
PORTD=digit[j/5]; // десятые доли
PORTC=razryad[3];
delay_ms(5);
}
PORTB.2=0;
ResetAll();
}
void FirstInt() // ненужное прерывание после включения
{
PORTB.0=1; // просто индикатор работы
}
interrupt [EXT_INT0] void ext_int0_isr(void)
{
z++;
if (z==1) FirstInt();
else
{
PORTB.2=1;
StopIt();
z=1;
}
}
void main(void)
{
// D2 := Int0 (вход для прерывания)
DDRB.2=1; // этот LED горит, когда таймер остановлен
DDRB.0=1; // горит всегда, кроме сотых секунд
SREG|= (1<<7); // разрешаем общие прерывания
GICR|=(1<<6); // разрешаем прерывание по INT0
MCUCR|=(1<<1); // прерывание по ниспадающему фронту сигнала на INT0
DDRB=0xFF;
PORTB=0b00000010;
PORTD=0x00;
DDRD=0b11111111;
PORTC=0xF;
DDRC=0xF;
while (1)
{
for(n=0;n<10;n++)
{
for(i=0;i<10;i++)
{
for(k=0;k<10;k++)
{
for(j=0;j<50;j++)
{
PORTD=0xff;
PORTD=digit[n];
PORTC=razryad[0];
delay_ms(5);
PORTD=0xff;
PORTD=digit[i];
PORTC=razryad[1];
delay_ms(5);
PORTD=0xff;
PORTB.1=0; // точка
PORTC=razryad[2];
delay_ms(2);
PORTB.1=1; // выкл. точку
PORTD=digit[k];
PORTC=razryad[2];
delay_ms(3);
PORTD=0xff;
PORTD=digit[j/5]; // десятые доли
PORTC=razryad[3];
delay_ms(5);
}
PORTB.6=0;
DDRB.6=0; // чтобы в протеусе Buzzer пищал только 1 секунду
PORTB.0=~PORTB.0;
}
DDRB.6=1;
PORTB.6=1; // так будет пикать каждые 10 сек.
}
// а если вставить сюда, то каждые 100 сек.
}
}
}
Видео:
Количество просмотров: 9561. | |