|
Годинниковий кварцевий резонатор |
Розглянемо приклад побудови цифрового годинника на семисегментному індикаторі, який буде відображати години : хвилини : секунди та розділові крапки між ними. Для написання програми скористаємось шаблоном який використовували для роботи із семисегментним індикатором (
посилання). Для побудови проекту будемо використовувати шестирозрядний індикатор. Головна відмінність в тому, що для точного відрахування секунд не підходить вбудований RC-генератор за рахунок своєї нестабільності, в мікроконтроллері можна для забезпечення необхідної точності використати таймер 2 в асинхронному режимі коли він тактується від окремого кварцевого високостабільного генератора з частотою 32768 Гц. Такий генератор ми можемо отримати, якщо до виводів контролера підєднати резонатор з частотою 32768 Гц. Такі резонатори ще називають годинникові. Як видно 32768 = (2^15) це число можна розписати як 32768 = 256*128 запамятаємо це значення. Нижче наведений текст програми в CodeVisionAVR. Налаштування таймера 2 в асинхронному режимі здійснюємо наступним чином: на вході ставимо подільник з коефіцієнтом ділення 256 коли вміст лічильника буде 127 (тобто 128 тіків від 0 до 127) мине рівно одна секунда, тоді генеруємо переривання в якому підраховуємо секунди, хвилини та години.
#include <mega8.h>
#include <delay.h>
#define DIGITS 6 // Кількість розрядів індикатора
unsigned char chislo[DIGITS]; //масив чисел, що відповідають кожному розряду
unsigned char numder[]= //масив, в якому індексу будут відповідати біти на порту D для кожної цифри
{
0b00111111, //цифра 0
0b00000110, //цифра 1
0b01011011, //цифра 2
0b01001111, //цифра 3
0b01100110, //цифра 4
0b01101101, //цифра 5
0b01111101, //цифра 6
0b00000111, //цифра 7
0b01111111, //цифра 8
0b01101111, //цифра 9
0b00000000, //пусто
};
// змінні, години:хвилини:секунди які виводиться на дисплей
unsigned short old_sek=1, sek=0, old_min=1, min=0, old_chas=5, chas=0;
unsigned short i=0; // змінна, що визначає номер розряду який виводиться
unsigned short k, dp; // змінні для крапки
// преривання по переповненню timer0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB=0x3f; // погасимо індикатор
if (i==2||i==4) dp=k;//виводимо крапку на 2 та 4 індикатор
else dp=0;
PORTD=((numder[ chislo[i]])|dp); // виведем поточне число
PORTB=~(1<<i); // вмикаємо відповідний розряд індикатора
if (i++>DIGITS) i=0; // якшо не дійшли до старшого розряду готуєм виведення наступного
} // якшо дійшли до старшого розряду готуєм виведення нульового
// Переривання по співпаданню таймера 2 (відбувається кожну секунду) )
interrupt [TIM2_COMP] void timer2_comp_isr(void){
sek++;// нарощення секунд
if(sek==60){
sek=0;
min++;// нарощення хвилин
}
if(min==60){
min=0;
chas++;// нарощення годин
}
if(chas==24){
chas=0;
}
}
void out_1(unsigned short num)//виведення першої пари знаків (для секунд)
{ chislo[0]=num%10; //одиниці секунд
chislo[1]=num/10; // десятки
k=(~k)&0b10000000;// крапка засвічується та гасне кожну секунду
}
void out_2(unsigned short num)//виведення другої пари знаків (для хвилин)
{ chislo[2]=num%10; //одиниці хвилин
chislo[3]=num/10; // десятки
}
void out_3(unsigned short num)//виведення третьої пари знаків (для годин)
{ chislo[4]=num%10; //одиниці годин
chislo[5]=num/10; // десятки
}
void main(void)
{
//Порт В
PORTB=0x00;
DDRB=0b00111111; //PB0-3 виходи (розряди)
//Порт С
PORTC=0x0f; //включимо підтягуючі резистори на PС0-3
DDRC=0b00000000; //PС0-3 входи (розряди)
//Порт Д
PORTD=0b0000000;
DDRD=0b11111111; //PD0-PD6 виходи (сегменти)
TCCR0=0x03; //встановлюємо подільник таймера 64
// кожне перерив приблизно 2 мс
//********* Налаштування таймера 2***************************
ASSR=0b00001000;// включили асинхронний режим
TCNT2=0x00; //занулення регістра лічильника
OCR2=127;// число з яким порівнюється вміст лічильника
TCCR2=0b00000110;//подільник частоти з коеф. 256
delay_ms(100);// затримка для введення асинхронного лічильника
TCCR2 |=(1<<WGM21);//обнулення лічильника при співпаданні
//************************************************************
TIMSK=0x81;//прерывания по переполнению таймера 0 та співпадання таймера 2
#asm("sei")// глобальний дозвіл перерывання
while (1) //основний цикл
{
if(old_sek!=sek) { //Якщо секунди змінились
out_1(sek); //виводимо на індикатор
old_sek=sek;
}
if(old_min!=min) { //Якщо хвилини змінились
out_2(min); //виводимо на індикатор
old_min=min;
}
if(old_chas!=chas) {//Якщо години змінились
out_3(chas); //виводимо на індикатор
old_chas=chas;
}
if (PINC.0==0){ //Якщо натиснена кнопка збільшення хвилин
min++; // збільшуємо хвилини кожні 200мс в діапазоні 0-60
if(min==60)min=0;
delay_ms(200);
}
if (PINC.1==0){ //Якщо натиснена кнопка збільшення годин
chas++; // збільшуємо години кожні 200мс в діапазоні 0-24
if(chas==24)chas=0;
delay_ms(200);
}
}
}
Немає коментарів :
Дописати коментар