01.10.2013 в 01:47
Секундомер на ATMega8A
В схеме пришлось освободить пин PD2 под прерывание INT0, сегмент С переброшен на PD7, а сегмент DP (десятичная точка) выкинут на PB1.
Соответственно лёгкая правка кода в этой части в комментариях не нуждается (тем более, что структуру цифр в виде массивов-слов одного порта удалось сохранить, а вот на битву с адекватной работой схемы в Протеусе ушло немало времени.
необходимо получить гашение на короткий период индикатора при смене разрядов, а произойти оно может при подаче уровней логических нулей на сегменты индикатора, т.е. во все разряды порта PortB, к которым они подключены.
Сделать это можно двумя командами:
Сделать это можно двумя командами:
Код
movlw b'00000000' ; записать все нули в регистр аккумулятор
movwf PortB ; записать содержимое аккумулятора в PortB
movwf PortB ; записать содержимое аккумулятора в PortB
Адаптируя к имеющимся условия, получаем, что PORTD надо выставлять в единицу (отключая тем самым все сегменты индикатора) перед каждым включением каждого разряда, как-то так:
PORTD=0xff;
PORTD=digit[n];
PORTC=razryad[0];
delay_ms(5);
PORTD=0xff;
PORTD=digit[i];
PORTC=razryad[1];
delay_ms(5);
...
Ну и весьма немало времени убито на "остановку времени", сорри за каламбур.
Но ведь, начав криэйтить, и подойдя столь близко к ожидаемому результату,
Алсо, схема:
Полный листинг программы в CodeVisionAVR:
#include <io.h>
#include <delay.h>
int i,j,k,n; // дякую тобі, Боже, що С - не C#
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 lampON()
{
PORTB.0=1;
DDRB.0=1;
}
void lampOff()
{
PORTB.0=0;
DDRB.0=1;
while (1)
{
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);
}
}
interrupt [EXT_INT0] void ext_int0_isr(void)
{
if (PINB.0==0) lampON();
else lampOff();
}
void main(void)
{
// DDRD.2=0; // теперь D2 - не сегмент, а вход для прерывания
// PORTD.2=1;
SREG|= (1<<7); //разрешаем общие прерывания
GICR|=(1<<6); //разрешаем прерывание по INT0
MCUCR|=(1<<1); //прерывание по ниспадающему фронту сигнала на INT0
DDRB=0x7;
PORTB=0b00000010;
PORTD=0x00;
DDRD=0b11111111;
PORTC=0xF;
DDRC=0xF;//0b11111111;
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);
}
}
}
}
}
}
Видео-свидетельство успеха прилагается
(дизайн прототипа платы, конечно, не для слабонервных:), но как для программиста - сойдёт)
В Протеусе тоже все добре:
Казалось бы, что тут ещё добавишь... но совершенству нет предела:), дребезг кнопки ресета, например, устранить можно (а то и вовсе оставить одну кнопку - ресет по второму нажатию после остановки), обратный отсчёт времени реализовать, так что to be continue...
(c) herozero.do.am
Количество просмотров: 4177. Комментариев: 2 | ||||
|