Часы на микроконтроллере PIC16F887 с будильником, днем недели и резервным питанием
Крушневич С.П. .
ВВЕДЕНИЕ.
Конструкция выходного дня. В один прекрасный выходной день
возникло сильное желание собрать часы на 7-ми сегментных индикаторах, с
указанием дня недели, будильником и главное... способные сохранять работу без
электричества (это после очередного кратковременного отключения света). Тут и на
радиорынок ехал, купил индикаторы и пошло-поехало
Паять или программировать?
Так как это конструкция выходного дня, я решил сделать всю схему на
макетной плате. Дабы минимизировать количество внешних компонентов, я установил
недорогой МК PIC16F887 (усовершенствованный аналог
PIC16F877A) и распаял все вокруг него.
Схема электрическая принципиальная
Схема получилась достаточно простая, так как вся логика
работы спряталась в прошивке.
Нажмите для увеличения
UPD 18.08.2017: Схема отрисованна на чистовике. Предыдущий вариант содержал неточности и находится здесь .
Энергонезависимость обеспечивает ионистор 1 Ф 5,5 В. Во
время испытаний ионистор успешно питал часы в течении суток. Так как вариант
питания от ионистора разрабатывался позже, я не учел возможного упрощения схемы
подачи питания и пришлось городить схему контроля напряжения питания на оптопаре
для того, чтобы вовремя погасить индикаторы. Анализ наличия напряжения питания я
провожу в функции динамической индикации, перед выводом очередного символа. Как
только я замечаю, что сигнал на ножке пропал, я сразу гашу все сегменты и
вспомогательные светодиоды. Далее в основной функции (когда приходит время) я
отправляю МК в режим спячки. Будит МК прерывание от таймера
TMR1 с интервалом в 2 сек. После увеличения значения числа секунд, в
основной функции снова проверяется наличие напряжения питания и МК снова
засыпает на 2 секунды.
Корпус
После долгих раздумий я решился на металлический корпус и
прозрачную переднюю панель.
Корпус оклеен самоклейкой
Описание
В нормальном режиме на часах отображается текущее время и день недели (светодиодным столбиком).
Нажатие на кнопку "Часы" переводит часы в режим установки часов, минут и дня недели. Выбор осуществляется кнопкой "часы", изменение - кнопками "+" и "-".
Нажатие на кнопку "Будильник" переводит часы в режим установки будильника. Вначале отображается состояние будильника "включенно-On" или "выключенно-OF", далее указывается часы и минуты срабатывания.
Прошивка для микроконтроллера PIC16F887
Прошивка от 17.10.2009, скачать .hex , скачать исходный код
Листинг прошивки (версия 17.10.2009)
   1:   #include "16F887.h"
   2:   
   3:   #device *=16
   4:   #device adc=10
   5:   
   6:   #FUSES NOWDT                  //No Watch Dog Timer
   7:   #FUSES INTRC_IO               //Internal RC Osc, no CLKOUT
   8:   #FUSES PUT                    //Power Up Timer
   9:   #FUSES MCLR                   //Master Clear pin enabled
  10:   #FUSES NOPROTECT              //Code not protected from reading
  11:   #FUSES NOCPD                  //No EE protection
  12:   #FUSES NOBROWNOUT             //No brownout reset
  13:   #FUSES NOIESO                 //Internal External Switch Over mode disabled
  14:   #FUSES NOFCMEN                //Fail-safe clock monitor disabled
  15:   #FUSES NOLVP                  //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
  16:   #FUSES NODEBUG                //No Debug mode for ICD
  17:   #FUSES NOWRT                  //Program memory not write protected
  18:   #FUSES BORV21                 //Brownout reset at 2.1V
  19:   
  20:   #use delay(clock=4000000,RESTART_WDT)
  21:   #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,restart_wdt,errors)
  22:   //#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3,restart_wdt,force_hw)
  23:   #use fast_io(A)                 // Работа с портами без переключения
  24:   #use fast_io(B)                 // каждый раз регистров TRIS
  25:   //#use fast_io(C) //*
  26:   //#use fast_io(D) //*
  27:   //#use fast_io(E) //*
  28:   
  29:   unsigned char Segment1,Segment2,Segment3,Segment4;  //Отображаемая цифра
  30:   unsigned char ShowSegment=0,Blick=0;
  31:   unsigned char Segment1blick, Segment2blick, Segment3blick, Segment4blick; // Мигание сегмента
  32:   #define BlickRate 256
  33:   
  34:   unsigned char rtc_day,rtc_mon,rtc_year,rtc_hour,rtc_min,rtc_sec; //Время в формате часов DS1307
  35:   unsigned char RefreshClock=1;
  36:   unsigned char year;
  37:   unsigned char mon,day,hour,min,sec,msec,week;
  38:   
  39:   #byte PORTA = 0x05
  40:   #byte PORTB = 0x06
  41:   #byte PORTC = 0x07
  42:   #byte PORTD = 0x08
  43:   #byte PORTE = 0x09
  44:   #byte TRISA = 0x85
  45:   #byte TRISB = 0x86
  46:   #byte TRISC = 0x87
  47:   #byte TRISD = 0x88
  48:   
  49:   unsigned char KeyStatus=0;
  50:   #bit KeyTime  = KeyStatus.1
  51:   #bit KeyAlarm = KeyStatus.0
  52:   #bit KeyPlus  = KeyStatus.2
  53:   #bit KeyMinus = KeyStatus.3
  54:   
  55:   unsigned char ClockMode=0;
  56:   //Нормальный режим. Отображение текущего времени
  57:   #define ClockModeNormal 0
  58:   //Режим настройки
  59:   #define ClockModeTune   1
  60:   
  61:   //Светодиоды секунд (нижнее двоеточье)
  62:   #bit  SecLED = PORTE.0
  63:   //Светодиоды секунд/Часы идут (верхнее двоеточье)
  64:   #bit  TimeLED = PORTE.1
  65:   //Будильник включен
  66:   #bit  AlarmLED = PORTC.1
  67:   unsigned char BlickTimeSecLed=0;
  68:   
  69:   //Светодиоды дней недели
  70:   #bit PNLED = PORTC.5
  71:   #bit VTLED = PORTC.4
  72:   #bit SRLED = PORTC.3
  73:   #bit CHLED = PORTA.7
  74:   #bit PTLED = PORTA.6
  75:   #bit SBLED = PORTA.5
  76:   #bit VSLED = PORTA.4
  77:   unsigned char WeekBlick=0;
  78:   
  79:   #bit SavePower = PORTE.2
  80:   
  81:   
  82:   #define nota_Start 255
  83:   #define nota_steep 10
  84:   
  85:   #define nota_DO nota_Start
  86:   #define nota_RE nota_DO-nota_steep
  87:   #define nota_MI nota_RE-nota_steep
  88:   #define nota_FA nota_MI-nota_steep
  89:   #define nota_SO nota_FA-nota_steep
  90:   #define nota_LA nota_SO-nota_steep
  91:   #define nota_SI nota_LA-nota_steep
  92:   #define nota_DL nota_SI-nota_steep
  93:   
  94:   //Нота для сигнала ОК
  95:   #define OK_SND nota_DL
  96:   //Длительность сигнала ОК
  97:   #define OK_delay 250
  98:   
  99:   unsigned char AlarmOn,AlarmMin,AlarmHour,DisableCurAlarm;
 100:   
 101:   void StartInit(void)
 102:   {
 103:      set_tris_a(0b00001111);
 104:      set_tris_b(0b00000000);
 105:      set_tris_c(0b11000011);
 106:      set_tris_d(0b00001111);
 107:      set_tris_e(0b11111100);
 108:      //port_d_pullups(true);
 109:      setup_timer_0(RTCC_INTERNAL); //|RTCC_DIV_256
 110:      setup_wdt(WDT_18MS|WDT_TIMES_128);
 111:      setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);
 112:      setup_timer_2(T2_DIV_BY_1,127,1);
 113:   //   setup_oscillator(OSC_4MHZ);
 114:      setup_ccp1(CCP_OFF);
 115:   //   set_pwm1_duty(512); // 1/2 Периода - меандр
 116:      setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
 117:      setup_adc_ports(NO_ANALOGS|VSS_VDD);
 118:      setup_adc(ADC_OFF);
 119:      enable_interrupts(INT_TIMER0);
 120:      enable_interrupts(INT_TIMER1);
 121:      enable_interrupts(GLOBAL);
 122:      sec=min=hour=0;
 123:   }
 124:   
 125:   unsigned char ValueToSegment(unsigned char val)
 126:   {
 127:   char res=242;
 128:   
 129:   switch(val)
 130:    {  
 131:         case 0: res=0b00111111; break; 
 132:         case 1: res=0b00000110; break; 
 133:         case 2: res=0b01011011; break; 
 134:         case 3: res=0b01001111; break; 
 135:         case 4: res=0b01100110; break; 
 136:         case 5: res=0b01101101; break; 
 137:         case 6: res=0b01111100; break; 
 138:         case 7: res=0b00000111; break; 
 139:         case 8: res=0b01111111; break; 
 140:         case 9: res=0b01100111; break; 
 141:         case 45: res=0b01000000; break; 
 142:         case 65: res=0b01110111; break; // A      
 143:         case 67: res=0b00111001; break; // C
 144:         case 70: res=0b01110001; break; // F
 145:         case 72: res=0b01110110; break; // H
 146:         case 79: res=0b00111111; break; // O
 147:         case 80: res=0b01110011; break; // P      
 148:         case 110: res=0b01010100; break; // n
 149:         case 193: res=0b01111101; break; // Б      
 150:         case 195: res=0b00110001; break; // Г
 151:         case 207: res=0b00110111; break; // П
 152:         case 215: res=0b01100110; break; // Ч
 153:         case 228: res=0b01011111; break; // д
 154:         case 116: res=0b01111000; break; // t
 155:   
 156:         default: res=0; // Символ, выводимый по умолчанию
 157:    } 
 158:   return res;
 159:   }
 160:   
 161:   
 162:   #int_TIMER1
 163:   void  TIMER1_isr(void) 
 164:   {
 165:   sec+=2;
 166:   if (sec>=60)
 167:      { sec=0;
 168:        min++;
 169:      if (min>59)
 170:        { min=0;
 171:          hour++;
 172:          if (hour>23)
 173:           { hour=0;
 174:             week++;
 175:             if (week>7) week=1;
 176:           }
 177:          DisableCurAlarm=0; //Защита от повторного срабатывания будильника
 178:        }                    //+ заранее можно выключить будильник
 179:      }
 180:   
 181:   if (BlickTimeSecLed==1)
 182:    { if ((secLed==0)&&(SavePower==1))
 183:       { secLed=TimeLED=1; }
 184:      else
 185:       { secLed=TimeLED=0; }
 186:    }
 187:   }
 188:   
 189:   #define Seg1sel 0b00011111
 190:   #define Seg2sel 0b00101111
 191:   #define Seg3sel 0b01001111
 192:   #define Seg4sel 0b10001111
 193:   #define SegMask 0b00001111
 194:   
 195:   
 196:   #int_TIMER0
 197:   void TIMER0_isr(void) 
 198:   {
 199:   KeyStatus=PORTD|0b11110000; //Маскируем ненужные 
 200:   #asm
 201:          comf KeyStatus,1
 202:   #endasm
 203:   
 204:   if (SavePower==0) 
 205:    { PORTB=0;
 206:         PORTD = (PORTD&SegMask);
 207:         secLed=TimeLED=0;
 208:         PNLED=VTLED=SRLED=CHLED=PTLED=SBLED=VSLED=0;   
 209:         ShowSegment=10;
 210:       }
 211:   
 212:   //PORTD=(PORTD&SegMask); Без транзисторов
 213:   PORTD=0b00001111;
 214:   if (ShowSegment==0)
 215:    { 
 216:         if ( (Segment1blick==1) && (Blick<(BlickRate/2)) )
 217:          PORTB = 0;
 218:            else
 219:             PORTB = Segment1;
 220:      PORTD = (PORTD&SegMask)|Seg1sel;
 221:    } 
 222:   
 223:   if (ShowSegment==1)
 224:    {    
 225:         if((Segment2blick==1)&&(Blick<(BlickRate/2)))
 226:          PORTB = 0;
 227:            else
 228:             PORTB = Segment2;
 229:         PORTD = (PORTD&SegMask)|Seg2sel; 
 230:    }
 231:   
 232:   if (ShowSegment==2)
 233:    { 
 234:         if((Segment3blick==1)&&(Blick<(BlickRate/2)))
 235:          PORTB = 0;
 236:            else
 237:             PORTB = Segment3;
 238:   
 239:      PORTD = (PORTD&SegMask)|Seg3sel;
 240:    }
 241:   if (ShowSegment==3)
 242:    { 
 243:         if((Segment4blick==1)&&(Blick<(BlickRate/2)))
 244:          PORTB = 0;
 245:            else
 246:             PORTB = Segment4;
 247:   
 248:      PORTD = (PORTD&SegMask)|Seg4sel;
 249:    }
 250:   
 251:   
 252:   ShowSegment++;
 253:   if (ShowSegment>=4) ShowSegment=0;
 254:   
 255:   Blick++;
 256:   if (Blick>BlickRate) Blick=0;
 257:   }
 258:   
 259:   
 260:   //Преобразования из двоичной системы в двоично-десятичную
 261:   unsigned char rtc_format(unsigned char rtc_data)
 262:   {
 263:   unsigned char buf[2],rtc_res_data;
 264:   
 265:   sprintf(buf,"%2d",rtc_data);
 266:   if (buf[0]==0x20) buf[0]=48;
 267:   rtc_res_data=(buf[0]-48)<<4;
 268:   rtc_res_data+=(buf[1]-48);
 269:   
 270:   return rtc_res_data;
 271:   }
 272:   
 273:   
 274:   #define ttTime 0
 275:   #define ttAlarm 1
 276:   
 277:   void ShowCyrTime(unsigned char tt)
 278:   {
 279:   unsigned char HourH,HourL,MinH,MinL;
 280:   
 281:   if (tt==ttTime) 
 282:     { rtc_min=rtc_format(min);
 283:       rtc_hour=rtc_format(hour);
 284:     }
 285:   if (tt==ttAlarm) 
 286:     { rtc_min=rtc_format(Alarmmin);
 287:       rtc_hour=rtc_format(Alarmhour);
 288:     }
 289:   
 290:   
 291:   HourH=(rtc_hour&0b11110000)>>4;
 292:   HourL=rtc_hour&0b00001111;
 293:   
 294:   MinH =(rtc_min&0b11110000)>>4;
 295:   MinL =rtc_min&0b00001111;
 296:   
 297:   
 298:   
 299:   //if ((Year>=9)||(ClockMode!=ClockModeNormal))
 300:    {
 301:   //Гашение незначущего нуля
 302:   if (HourH==0) Segment1=ValueToSegment(' ');
 303:         else
 304:                 Segment1=ValueToSegment(HourH);
 305:   Segment2=ValueToSegment(HourL);
 306:   Segment3=ValueToSegment(MinH);
 307:   Segment4=ValueToSegment(MinL);
 308:    }
 309:   /*  else
 310:    {
 311:   Segment1=ValueToSegment("-");
 312:   Segment2=ValueToSegment("-");
 313:   Segment3=ValueToSegment("-");
 314:   Segment4=ValueToSegment("-");
 315:    }
 316:   */
 317:   }
 318:   
 319:   void WaitKeyUp(void)
 320:   {
 321:   while (KeyStatus!=0)
 322:     { KeyStatus=0;
 323:       delay_ms(255); 
 324:       delay_ms(255);
 325:     }
 326:   }
 327:   
 328:   void WaitKeyDown(void)
 329:   {
 330:   while (KeyStatus==0)
 331:     { KeyStatus=0;
 332:       delay_ms(255); 
 333:       delay_ms(255);
 334:     }
 335:   }
 336:   
 337:   void sound(unsigned int8 nota, unsigned int8 delayF)
 338:   {
 339:   //F - частота
 340:   //delayF - длительность, мс
 341:   
 342:   setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM
 343:   setup_timer_2(T2_DIV_BY_1, nota, 1);
 344:   set_pwm1_duty(nota/2);
 345:   //enable_interrupts(INT_TIMER2);
 346:   
 347:   delay_ms(delayF);
 348:   
 349:   //disable_interrupts(INT_TIMER2);
 350:   setup_ccp1(CCP_OFF);
 351:   }
 352:   
 353:   void ShowCyrWeek(void)
 354:   {
 355:   PNLED=VTLED=SRLED=CHLED=PTLED=SBLED=VSLED=0;
 356:   
 357:   if (week==1) { PNLED=1; 
 358:                  Segment3=ValueToSegment('П');
 359:                  Segment4=ValueToSegment('H'); }
 360:   if (week==2) { VTLED=1; 
 361:                  Segment3=ValueToSegment(8);
 362:                  Segment4=ValueToSegment('H'); }
 363:   if (week==3) { SRLED=1; 
 364:                  Segment3=ValueToSegment('C');
 365:                  Segment4=ValueToSegment('P'); }
 366:   if (week==4) { CHLED=1; 
 367:                  Segment3=ValueToSegment('Ч');
 368:                  Segment4=ValueToSegment('Г'); }
 369:   if (week==5) { PTLED=1; 
 370:                  Segment3=ValueToSegment('П');
 371:                  Segment4=ValueToSegment('A'); }
 372:   if (week==6) { SBLED=1; 
 373:                  Segment3=ValueToSegment('C');
 374:                  Segment4=ValueToSegment('Б'); }
 375:   if (week==7) { VSLED=1; 
 376:                  Segment3=ValueToSegment('H');
 377:                  Segment4=ValueToSegment('д'); }
 378:   
 379:   if (week>7)  { VSLED=1; 
 380:                  Segment3=ValueToSegment('-');
 381:                  Segment4=ValueToSegment('-'); }
 382:   
 383:   }
 384:   
 385:   
 386:   void SetTime(void)
 387:   {
 388:   unsigned char NeedWriteTime=0;
 389:   
 390:   BlickTimeSecLed=0;
 391:   SecLED=1;
 392:   TimeLED=1;
 393:   
 394:   ClockMode=ClockModeTune;
 395:   
 396:   sound(OK_SND,OK_delay);
 397:   WaitKeyUp();
 398:   
 399:   //Наводим часы
 400:   
 401:   Segment1blick=1;
 402:   Segment2blick=1;
 403:   Segment3blick=0;
 404:   Segment4blick=0;
 405:   
 406:   //DS1307ReadTime();
 407:   
 408:   while (KeyTime!=1)
 409:     {
 410:      KeyStatus=0;
 411:   
 412:      ShowCyrTime(ttTime); 
 413:      delay_ms(255); delay_ms(255); 
 414:      if (KeyPlus==1) 
 415:         { Hour++; 
 416:           if (Hour>23) hour=0;
 417:           NeedWriteTime=1; }
 418:      if (KeyMinus==1) 
 419:         { Hour--; 
 420:           if(Hour>23) Hour=23; 
 421:           NeedWriteTime=1; }
 422:      rtc_Hour=rtc_format(Hour); // Переводим в формат часов
 423:     }
 424:   
 425:   sound(OK_SND,OK_delay);
 426:   WaitKeyUp();
 427:   
 428:   //Наводим минуты
 429:   
 430:   Segment1blick=0;
 431:   Segment2blick=0;
 432:   Segment3blick=1;
 433:   Segment4blick=1;
 434:   
 435:   while (KeyTime!=1)
 436:     {
 437:      KeyStatus=0;
 438:      ShowCyrTime(ttTime); 
 439:      delay_ms(255); delay_ms(255); 
 440:      if (KeyPlus==1) 
 441:         { Min++; 
 442:           if (Min>59) Min=0;
 443:           NeedWriteTime=1; }
 444:      if (KeyMinus==1) 
 445:         { Min--; 
 446:           if(Min>59) Min=59; 
 447:           NeedWriteTime=1; }
 448:   
 449:      rtc_Min=rtc_format(Min); // Переводим в формат часов
 450:     }
 451:   
 452:   Segment1blick=0;
 453:   Segment2blick=0;
 454:   Segment3blick=1;
 455:   Segment4blick=1;
 456:   
 457:   sound(OK_SND,OK_delay);
 458:   WaitKeyUp();
 459:   
 460:   //Наводим день недели
 461:   Segment1=ValueToSegment('H');
 462:   Segment2=ValueToSegment('-');
 463:   //Segment3=ValueToSegment('');
 464:   //Segment4=ValueToSegment(MinL);
 465:   
 466:   while (KeyTime!=1)
 467:     {
 468:      KeyStatus=0;
 469:      ShowCyrWeek(); 
 470:      delay_ms(255); delay_ms(255); 
 471:      if (KeyPlus==1) 
 472:         { week++; 
 473:           if (week>7) week=1;
 474:           NeedWriteTime=1; }
 475:      if (KeyMinus==1) 
 476:         { week--; 
 477:           if(week==0) week=7; 
 478:           NeedWriteTime=1; }
 479:     }
 480:   
 481:   Year=9;
 482:   
 483:   //if (NeedWriteTime==1) DS1307SetTime();
 484:   
 485:   Segment1blick=0;
 486:   Segment2blick=0;
 487:   Segment3blick=0;
 488:   Segment4blick=0;
 489:   
 490:   sound(OK_SND,OK_delay);
 491:   WaitKeyUp();
 492:   
 493:   BlickTimeSecLed=1;
 494:   }
 495:   
 496:   void ShowWeek(void)
 497:   {
 498:   unsigned char tweek;
 499:   tweek=week;
 500:   
 501:   if ((WeekBlick==1) && (Blick<(BlickRate/2))) tweek=10;
 502:   
 503:   if (tweek==1) PNLED=1; else PNLED=0;
 504:   if (tweek==2) VTLED=1; else VTLED=0;
 505:   if (tweek==3) SRLED=1; else SRLED=0;
 506:   if (tweek==4) CHLED=1; else CHLED=0;
 507:   if (tweek==5) PTLED=1; else PTLED=0;
 508:   if (tweek==6) SBLED=1; else SBLED=0;
 509:   if (tweek==7) VSLED=1; else VSLED=0;
 510:   }
 511:   
 512:   void ReadAlarm(void)
 513:   { 
 514:     AlarmOn   = read_eeprom(0x01);
 515:     AlarmMin  = read_eeprom(0x02);
 516:     AlarmHour = read_eeprom(0x03);
 517:   }
 518:   
 519:   void WriteAlarm(void)
 520:   { 
 521:     write_eeprom(0x01,AlarmOn);
 522:     write_eeprom(0x02,AlarmMin);
 523:     write_eeprom(0x03,AlarmHour);
 524:   }
 525:   /*
 526:   #int_TIMER2
 527:   void  TIMER2_isr(void) 
 528:   {
 529:   //output_toggle(PIN_E0);
 530:   }
 531:   */
 532:   
 533:   
 534:   
 535:   void SetAlarm(void)
 536:   { 
 537:   unsigned char NeedWriteTime=0;
 538:   
 539:   BlickTimeSecLed=0;
 540:   SecLED=1;
 541:   TimeLED=1;
 542:   
 543:   ClockMode=ClockModeTune;
 544:   
 545:   sound(OK_SND,OK_delay);
 546:   
 547:   WaitKeyUp();
 548:   
 549:   //Вывести диалог: "Будильник вкл/выкл"
 550:   Segment1blick=0;
 551:   Segment2blick=0;
 552:   Segment3blick=1;
 553:   Segment4blick=1;
 554:   
 555:   Segment1=ValueToSegment('Б');
 556:   Segment2=ValueToSegment('-');
 557:   
 558:   while (KeyAlarm!=1)
 559:    { KeyStatus=0;
 560:         if (AlarmOn==1)
 561:            { Segment3=ValueToSegment('O');
 562:              Segment4=ValueToSegment('n');
 563:            }
 564:           else
 565:            { Segment3=ValueToSegment('O');
 566:              Segment4=ValueToSegment('F');
 567:            }
 568:   
 569:      delay_ms(255); delay_ms(255); 
 570:      if (KeyPlus==1) 
 571:         { AlarmOn=1;         
 572:           NeedWriteTime=1; }
 573:      if (KeyMinus==1) 
 574:         { AlarmOn=0;
 575:           NeedWriteTime=1; }
 576:       }
 577:   sound(OK_SND,OK_delay);
 578:   WaitKeyUp();
 579:   
 580:   if (AlarmOn==0) goto NoAlarm;
 581:   
 582:   Segment1blick=1;
 583:   Segment2blick=1;
 584:   Segment3blick=0;
 585:   Segment4blick=0;
 586:   
 587:   //DS1307ReadTime();
 588:   
 589:   while (KeyAlarm!=1)
 590:     {
 591:      KeyStatus=0;
 592:   
 593:      ShowCyrTime(ttAlarm); 
 594:      delay_ms(255); delay_ms(255); 
 595:      if (KeyPlus==1) 
 596:         { AlarmHour++; 
 597:           if (AlarmHour>23) AlarmHour=0;
 598:           NeedWriteTime=1; }
 599:      if (KeyMinus==1) 
 600:         { AlarmHour--; 
 601:           if(AlarmHour>23) AlarmHour=23; 
 602:           NeedWriteTime=1; }
 603:     }
 604:   sound(OK_SND,OK_delay);
 605:   WaitKeyUp();
 606:   
 607:   Segment1blick=0;
 608:   Segment2blick=0;
 609:   Segment3blick=1;
 610:   Segment4blick=1;
 611:   
 612:   while (KeyAlarm!=1)
 613:     {
 614:      KeyStatus=0;
 615:      ShowCyrTime(ttAlarm); 
 616:      delay_ms(255); delay_ms(255); 
 617:      if (KeyPlus==1) 
 618:         { AlarmMin++; 
 619:           if (AlarmMin>59) AlarmMin=0;
 620:           NeedWriteTime=1; }
 621:      if (KeyMinus==1) 
 622:         { AlarmMin--; 
 623:           if(AlarmMin>59) AlarmMin=59; 
 624:           NeedWriteTime=1; }
 625:     }
 626:   
 627:   Segment1blick=1;
 628:   Segment2blick=1;
 629:   Segment3blick=1;
 630:   Segment4blick=1;
 631:   
 632:   NoAlarm:
 633:   
 634:   if (NeedWriteTime==1)  
 635:      {
 636:        WriteAlarm();
 637:      }
 638:   
 639:   sound(OK_SND,OK_delay);
 640:   WaitKeyUp();
 641:   
 642:   
 643:     Segment1blick=0;
 644:     Segment2blick=0;
 645:     Segment3blick=0;
 646:     Segment4blick=0;
 647:   
 648:     BlickTimeSecLed=1;
 649:   
 650:   }
 651:   
 652:   void Alarm(void)
 653:   {
 654:   unsigned char i;
 655:   Segment1blick=1;
 656:   Segment2blick=1;
 657:   Segment3blick=1;
 658:   Segment4blick=1;
 659:   
 660:    //Подаю короткий пик
 661:   sound(128,100);
 662:   
 663:   //*********
 664:   i=1;
 665:   while (i<7)
 666:    { sound(nota_SI,150);
 667:      i++;
 668:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 669:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 670:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 671:      if (KeyStatus!=0) i=7;
 672:    }
 673:   //*********
 674:   
 675:   
 676:   //KeyStatus=0;
 677:   //Пауза
 678:   delay_ms(255);
 679:   delay_ms(255);
 680:   //Даю 3 коротких ПИКа
 681:   if (KeyStatus==0)
 682:     { sound(1000,100);
 683:       delay_ms(100);
 684:       sound(1000,100);
 685:       delay_ms(255);
 686:       sound(1000,100);
 687:       delay_ms(255);
 688:       //Пауза
 689:       delay_ms(255);
 690:       delay_ms(255);    
 691:     }
 692:   //Пауза
 693:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 694:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 695:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 696:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 697:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 698:      delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 699:   
 700:   
 701:   while(KeyStatus==0)
 702:     { 
 703:   //Музон
 704:       //ми до ми до , фа ми ре 
 705:   sound(nota_MI,200); delay_ms(5);
 706:   sound(nota_DO,200); delay_ms(5);
 707:   sound(nota_MI,200); delay_ms(5);
 708:   sound(nota_DO,200); delay_ms(5);
 709:   sound(nota_FA,200); delay_ms(5);
 710:   sound(nota_MI,200); delay_ms(5);
 711:   sound(nota_RE,200); delay_ms(5);
 712:       if (KeyStatus!=0) goto keyPressed;
 713:   //соль соль ля си до до до 
 714:   sound(nota_SO,200); delay_ms(5);
 715:   sound(nota_SO,200); delay_ms(5);
 716:   sound(nota_LA,200); delay_ms(5);
 717:   sound(nota_SI,200); delay_ms(5);
 718:   sound(nota_DO,200); delay_ms(5);
 719:   sound(nota_DO,200); delay_ms(5);
 720:   sound(nota_DO,200); delay_ms(5);
 721:     keyPressed:;
 722:   
 723:     ShowCyrTime(ttTime);
 724:     delay_ms(255);
 725:     delay_ms(255);
 726:     }
 727:   
 728:   Segment1blick=0;
 729:   Segment2blick=0;
 730:   Segment3blick=0;
 731:   Segment4blick=0;
 732:   
 733:   DisableCurAlarm=1;
 734:   WaitKeyUp();
 735:   }
 736:   
 737:   void ShowTemperature()
 738:   {
 739:   signed int16 Temperature,t; 
 740:   
 741:   BlickTimeSecLed=SecLED=0;
 742:   Segment1=ValueToSegment('t');
 743:   Segment2=ValueToSegment(' ');
 744:   Segment3=ValueToSegment(' ');
 745:   Segment4=ValueToSegment(' ');
 746:   
 747:   // Настройка АЦП
 748:   setup_adc_ports(sAN0|sAN1|VSS_VDD);
 749:   setup_adc(ADC_CLOCK_INTERNAL);
 750:   set_adc_channel( 0 );
 751:   delay_ms(100);
 752:   
 753:   //Измерение температуры
 754:   Temperature = read_adc(ADC_START_AND_READ);
 755:   
 756:   //Отключение АЦП
 757:   setup_adc_ports(NO_ANALOGS|VSS_VDD);
 758:   setup_adc(ADC_OFF);
 759:   
 760:   //Отображение температуры 
 761:   { unsigned char buf[4];
 762:   
 763:    if (Temperature>=0) t=Temperature;
 764:    if (Temperature<0)  t=Temperature*-1;
 765:     sprintf(buf,"%3ld",t);
 766:   
 767:   Segment2=ValueToSegment(buf[0]-48);
 768:   Segment3=ValueToSegment(buf[1]-48);
 769:   Segment4=ValueToSegment(buf[2]-48);
 770:   Segment3|=0b10000000; // Десятичная точка
 771:   if (t<10) Segment3=ValueToSegment('0'); // "ноль" целых.
 772:   //Выводим знак минус
 773:   if ((Temperature<0)&&(Temperature>-200)) Segment2|=0b01000000;
 774:   if ((Temperature<=-200)) Segment1=ValueToSegment('-');
 775:   }
 776:   
 777:   //Выходим
 778:   delay_ms(250);delay_ms(250);
 779:   delay_ms(250);delay_ms(250);
 780:   delay_ms(250);delay_ms(250);
 781:   delay_ms(250);delay_ms(250);
 782:   WaitKeyUp();
 783:   BlickTimeSecLed=1;
 784:   }
 785:   
 786:   void main(void)
 787:   {
 788:   StartInit();
 789:   Segment1=ValueToSegment(45);
 790:   Segment2=ValueToSegment(45);
 791:   Segment3=ValueToSegment(45);
 792:   Segment4=ValueToSegment(45);
 793:   delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);delay_ms(255);
 794:   ReadAlarm(); //Чтение установок будильника
 795:   DisableCurAlarm=0;
 796:   /*
 797:   sound(nota_DO,700);
 798:   sound(nota_RE,700);
 799:   sound(nota_MI,700);
 800:   sound(nota_FA,700);
 801:   sound(nota_SO,700);
 802:   sound(nota_LA,700);
 803:   sound(nota_SI,700);
 804:   sound(nota_DL,700);
 805:   */
 806:   
 807:   //ми до ми до , фа ми ре 
 808:   sound(nota_MI,200); delay_ms(50);
 809:   sound(nota_DO,200); delay_ms(50);
 810:   sound(nota_MI,200); delay_ms(50);
 811:   sound(nota_DO,200); delay_ms(50);
 812:   sound(nota_FA,200); delay_ms(50);
 813:   sound(nota_MI,200); delay_ms(50);
 814:   sound(nota_RE,200); delay_ms(50);
 815:   //соль соль ля си до до до 
 816:   sound(nota_SO,200); delay_ms(50);
 817:   sound(nota_SO,200); delay_ms(50);
 818:   sound(nota_LA,200); delay_ms(50);
 819:   sound(nota_SI,200); delay_ms(50);
 820:   sound(nota_DO,200); delay_ms(50);
 821:   sound(nota_DO,200); delay_ms(50);
 822:   sound(nota_DO,200); delay_ms(50);
 823:   
 824:   WaitKeyDown();
 825:   delay_ms(255);
 826:   WaitKeyUp();
 827:   
 828:   while(1)
 829:    { 
 830:     ClockMode=ClockModeNormal;
 831:     BlickTimeSecLed=1;
 832:   //  DS1307ReadTime();
 833:     ShowCyrTime(ttTime); 
 834:     ShowWeek();
 835:   //  AlarmLED=AlarmOn;
 836:     if (AlarmOn==1) Segment4|=0b10000000;
 837:     keyStatus=0;
 838:     delay_ms(255);
 839:     if (KeyTime==1) SetTime();
 840:     if (KeyAlarm==1) SetAlarm();
 841:     if (KeyPlus==1)  ShowTemperature();
 842:     if (((Min==AlarmMin)&&(Hour==AlarmHour)&&(AlarmOn==1)&&(DisableCurAlarm==0))) Alarm();
 843:     
 844:     if (SavePower==0)  //Переходим в режим экономии энергии
 845:    { while(SavePower==0)
 846:    { restart_wdt();
 847:             sleep();
 848:      delay_us(3);
 849:             //спим, пока свет не включат
 850:    }
 851:    }
 852:    }
 853:   }
Прошивка от 15.01.2011, скачать .hex
1. Добавлена поддержка датчика температуры DS18B20. Сигнальный выход датчика следует подключить к ножке №2 микроконтроллера
и соеденить через резистор на 4,7 кОм с питанием МК. Температура отображается по нажатию кнопки "+".
Часы успешно эксплуатируются с 05.05.2009.
upd: 19.07.2017 . Часы продолжают работать в режиме 24/7
upd: 18.08.2017 . Ruslan Aktaliev , радиолюбитель из Молдавии, повторил конструкцию часов и предоставил свои материалы:
VIDEO
Чертеж платы в sLayout6
18.08.2017
2003-2022 (С) SergeyK HomePage
Кoнтaкти
Хостинг від FerR0zer
Повне копіювання матеріалів лише зі згоди автора.
Часткове копіювання обов'язково з посиланням на джерело.