Опубликовано 2013-05-23 09:25:41 автором MRS

Электронное реле времени на микроконтроллере


В предыдущих уроках я рассказывал, как к микроконтроллеру подключить семисегментный индикатор, кнопки и как управлять нагрузкой постоянного и переменного тока. Давайте все это материализуем в какое-нибудь полезное устройство, например часовой таймер.Таймер должен отсчитывать какое-то время и по истечении включать или отключать полезную нагрузку, например светодиод.Скажу честно, собирал я его по просьбе друга, ему нужно было включать глушылку вай фай. Схема электронного реле времени выглядит так

схема электронного реле времени
Код прошивки:

#include <mega8.h> 
#include <delay.h> 
 struct Stime 
 { 
  unsigned char second; 
  unsigned char minute; 
  unsigned char hour; 
 } time[3];  
 void TimerEvent() 
 { 
  PORTB.4=1; 
 } 
 unsigned char Zminute=0,Zhour=0;  
 unsigned char chislo[4]; //определяем массив из двух элементов типа char беззнаковый(unsigned) 
 unsigned char numder[]= //определяем массив, в котором индексу будут соответствовать бити на порте D 
{ 
0b11111100, //цифра 0 
0b01100000, //цифра 1 
0b11011010, //цифра 2 
0b11110010, //цифра 3 
0b01100110, //цифра 4 
0b10110110, //цифра 5 
0b10111110, //цифра 6 
0b11100000, //цифра 7 
0b11111110, //цифра 8 
0b11110110, //цифра 9 
}; 
void out(unsigned char hour,unsigned char minute) 
{ 
/*сначала нам нужно определить, из скольких десятков и единиц состоит выводимое число. 
Например, передали мы "45", нам надо его разложить на 4 и 5, чтобы на первый разряд семисегментника 
вывести цифру 4, а на второй - 5 */ 
chislo[1]=hour%10; //оператор % дает остаток от целочисленного деления, например 34%10 будет 4 
chislo[0]=hour/10; // узнаем, сколько десятков в числе 
 
chislo[3]=minute%10; 
chislo[2]=minute/10; 
} 
unsigned char i=0; // переменная для определения, на какой разряд семисегментника выводить число 
// прерывания по переполнению timer0 
interrupt [TIM0_OVF] void timer0_ovf_isr(void) 
{ 
PORTD=numder[ chislo[i] ]; 
if (i==1) PORTD.0=1; else PORTD.0=0; //включаем/выключаем точку 
PORTB = ( (PORTB & 0b11110000) | ( (~(1 <<i)) & 0b00001111 ) ); //включаем определённый разряд семисегментника 
if (++i>3) i=0; 
} 
/* прерывания таймера2 вызывается 1 раз в секунду, потому что таймер2 тактирует от часового кварца на 32768 герц 
 и в таймере установлен предделитель частоты 128, ето значит что 128 тактов считаются как один тоэсть 
 кварц в нас 32768 
 таймер в нас 8 битный максимальноэ число 255 
 мы выбераем пределитель 128   
 получается 32768/128=255, это значит что за секунду пременная  щета таймера (TCNT2) дойдет до 255 и таймер згенерирует прерывания 
 по переполнению переменной 
*/ 
unsigned char outMenu=0; 
interrupt [TIM2_OVF] void timer2_ovf_isr(void) 
{ 
  if (time[0].second++==60) 
  { 
    time[0].second=0; 
    if (time[0].minute++==60) 
    {  
    time[0].minute=0; 
     if (time[0].hour++==24)  
     { 
     time[0].hour=0; 
      
     } 
    } 
   out(time[outMenu].hour,time[outMenu].minute); 
   if ( (time[0].minute==Zminute) && (time[0].hour==Zhour) )  TimerEvent(); //если минуты и секунды равны заданым вызываем функцию TimerEvent  
  } 
} 
 
void main(void) 
{ 
PORTB=0x00; 
DDRB=0x1F; 
 
PORTD=0x00; 
DDRD=0b11111111; 
 
TCCR0=0x00; 
TCNT0=0x00; 
 
// Timer/Counter 0 initialization 
// Clock source: System Clock 
// Clock value: 0,977 kHz 
TCCR0=0x04; 
TCNT0=0x00; 
// Timer/Counter 2 initialization 
// Clock source: TOSC1 pin 
// Clock value: PCK2/128 
// Mode: Normal top=FFh 
// OC2 output: Disconnected 
ASSR=0x08; 
TCCR2=0x05; 
TCNT2=0x00; 
OCR2=0x00; 
 
// Timer(s)/Counter(s) Interrupt(s) initialization 
TIMSK=0x41; 
 
// Global enable interrupts 
#asm("sei") 
      
while (1) 
      { 
      if (!(PINC & 0b00000001)  && outMenu>0 ) // проверяем нажата ли кнопка 1 
      { 
       if (regim=true) time[outMenu].hour++; else time[outMenu].minute++; 
      } 
      if (!(PINC & 0b00000010)) // проверяем нажата ли кнопка 2  
      { 
        if (++outMenu>2) outMenu=0; 
      } 
      if (!(PINC & 0b00000100) && outMenu>0 )  // проверяем нажата ли кнопка 3    
      { 
         if (regim=true) time[outMenu].hour--; else time[outMenu].minute--; 
      } 
      delay_ms(200); 
        
   out(time[outMenu].hour,time[outMenu].minute); 
      }; 
      
} 

Файлы к проекту в архиве Timer.zip

Комментарии - (5)

  • Zanli23 говорит:
    Здравствуйте! Дайте пожалуйста код прошивки для этого таймера. Хочу собрать простое реле времени, примерно по такой схеме, но не могу найти ничего подходящего. Нужен реле периодического действия с выдержкой до 4 часов и работой 1 сек - 2 мин. Спасибо
    • AdminRu говорит:
      Добавил архив, возможно программу прийдется подкорректировать, так как финальная версия потерялась
  • Zanli23 говорит:
    Спасибо!
  • Zanli23 говорит:
    Не могу разобраться с кодом, когда прошиваю МК индикаторы поочередно начинают выводить нули. Помогите пожалуйста разобраться. P.S. Я недавно начал изучать мк )
  • AdminRu говорит:
    Индикатор по умолчанию просто выводит счет времени. Для того чтобы сегменты переключались быстрей нужно увеличить частоту таймера 0. Для этого уменьшаем предделитель таймера з TCCR0=0x04; на TCCR0=0x03;.
    Событие по совпадению времени вызывается а строке
    if ( (time[0].minute==Zminute) && (time[0].hour==Zhour) ) TimerEvent(); //если минуты и секунды равны заданым вызываем функцию TimerEvent
    попробуйте подставить вместо Zminute и Zhour константы. Например if ( (time[0].minute==1) && (time[0].hour==0) ) TimerEvent();. Дальше в функции TimerEvent() установите лог 1 на необходимой ножке мк например:
    void TimerEvent()
    {
    PORTB.4=1;
    }

Добавить комментарий

Для отправки комментария вы должны авторизоваться.