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

Електронне реле часу на мікроконтролері


У попередніх уроках я розповідав , як до микроконтроллерa підключити семисегментний індикатор , кнопки і як управляти навантаженням постійного і змінного струму . Давайте все це матеріалізуємо в який-небудь корисний пристрій , наприклад часовий таймер. Таймер повинен відраховувати якийсь час і після закінчення включати або відключати корисне навантаження , наприклад світлодіод. Скажу чесно , збирав я його на прохання друга , йому потрібно було включати глушилку вай фай . Схема електронного реле часу виглядає так

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

 # 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;
    }

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

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