понеділок, 12 січня 2015 р.

Годинник на індикаторі 7 segment AVR

Годинниковий кварцевий резонатор 
   Розглянемо приклад побудови цифрового годинника на семисегментному індикаторі, який буде відображати години : хвилини : секунди та розділові крапки між ними. Для написання програми скористаємось шаблоном який використовували для роботи із семисегментним індикатором (посилання). Для побудови проекту будемо використовувати шестирозрядний індикатор. Головна відмінність в тому, що для точного відрахування секунд не підходить вбудований 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);
  }
 }
}


Модель годинника в Proteus






Немає коментарів :

Дописати коментар