找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2502|回复: 2
收起左侧

基于STC单片机的继电器1~9999秒定时断电器程序 2按键+4位共阴数码管+有源蜂鸣器

[复制链接]
ID:57657 发表于 2021-11-6 17:06 | 显示全部楼层 |阅读模式
上电后点亮数码管的所有段码,且蜂鸣器响,持续1秒。
设定定时时间,按S2加1(长按连加),按S1输入下一位(长按退回千位)。
时间设定完成后开始倒计时,按下S2暂停(长按3秒复位),再按恢复,按S1无动作。
倒计时结束后显示 End 蜂鸣器响6下,短按任意键返回,如有问题请跟帖回复。
单片机型号:STC任意 (STC89/90除外) 晶振频率:12Mhz

数码管扫描/按键消抖/长按连加/毫秒延时全部使用定时器中断实现。
更改不同STC系列的型号,只需更改头文件,不需要改动程序任何部分。

硬件连接:
按键S1                -> P3.0 (低电平按下)
按键S2                -> P3.1
有源蜂鸣器        -> P3.2 (低电平鸣叫)
继电器或MOS管        -> P3.3        (低电平吸合或导通)

0.28~0.56英寸4位共阴数码管:
段码        -> P2.0~P2.7
位码        -> P1.0~P1.3
单片机源程序如下:
  1. #include "STC15.h"
  2. #include "intrins.h"
  3. #define u8 unsigned char
  4. #define u16 unsigned int
  5. #define u32 unsigned long
  6. #define s8 signed char
  7. #define s16 signed int
  8. #define s32 signed long
  9. #define KEY_TIME 25                        //按键消抖时间 (毫秒)
  10. #define reset()        IAP_CONTR |= 0x20                //芯片复位
  11. #define feed_dog()  WDT_CONTR |= 0x10   //看门狗喂狗
  12. u8 code nbr[16] = {                //共阴数码管段码16进制
  13.     0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
  14. };
  15. u8 show[4];                //4位数码管当前显示的段码 更改数码管显示的段码 只需更改此数组
  16. u8 wink;                //闪烁的数码管段码        0x01: 第一位闪烁 0x02:第二位闪烁 0x04: 第三位闪烁 0x0F:全闪烁 0x00:全不闪烁

  17. sbit P3_0 = P3 ^ 0;                //按键S1 (I/O口定义的按键未经消抖,请勿在中断外直接使用)
  18. sbit P3_1 = P3 ^ 1;                //按键S2
  19. sbit P3_2 = P3 ^ 2;     //有源蜂鸣器 低电平鸣叫
  20. sbit P3_3 = P3 ^ 3;     //继电器或MOS管 低电平吸合(导通)
  21. u16 S1_ms, S2_ms;                //按键0、按键1连续按下的时间 定时器中断计数此变量 最长65535毫秒 松开清零

  22. u16 delay_ms;  //定时器中断延时 (毫秒)
  23. u16 time;      //定时时间 (秒)
  24. u16 beep_ms;   //蜂鸣器鸣叫时间 (毫秒)

  25. u16 bdata Bit16 = 0;    //定义16位可位寻址变量
  26. sbit delay = Bit16 ^ 0;      //定时器中断延时毫秒开关 中断外置1 延时完中断内清0
  27. sbit test = Bit16 ^ 1;       //此值为1数码管全亮 蜂鸣器响 所有按键无效 否则正常
  28. sbit S1 = Bit16 ^ 2;         //按键0 连续按下N毫秒清0, 松开置1(定时器0中断消抖)
  29. sbit S2 = Bit16 ^ 3;         //按键1 (处理方式与按键0相同)
  30. sbit hz10 = Bit16 ^ 4;      //10Hz信号源 (定时器0中断产生,用于控制数码管闪烁)
  31. sbit bak = Bit16 ^ 5;       //按键长按识别处理用
  32. sbit Beep = Bit16 ^ 6;      //有源蜂鸣器 低电平响
  33. sbit start = Bit16 ^ 7;     //倒计时开关 置1倒计时开始 清0则结束
  34. sbit pause = Bit16 ^ 8;     //1暂停倒计时 0正常
  35. sbit relay = Bit16 ^ 9;     //继电器或MOS管 低电平吸合(导通) 1秒只能吸合或释放1次

  36. void InitTimer0() {        //初始化定时器0中断
  37.     TMOD = 0x01;
  38.     TH0 = 0xFC;
  39.     TL0 = 0x18;
  40.     EA = 1;
  41.     ET0 = 1;
  42.     TR0 = 1;
  43. }

  44. void beep(u16 ms) {     //蜂鸣器鸣叫 参数:鸣叫毫秒
  45.     beep_ms = ms;
  46.     Beep = 0;
  47. }

  48. u16 set_time() {        //设定定时时间
  49.     u8 n = 0;       //0:编辑千位 1:百位 2:十位 3:个位
  50.     u8 o[4];
  51.     o[0] = 0; o[1] = 0; o[2] = 0; o[3] = 0;
  52.     while (1) {
  53.         feed_dog();
  54.         wink = 8 >> n;
  55.         show[0] = nbr[o[0]];
  56.         show[1] = nbr[o[1]];
  57.         show[2] = nbr[o[2]];
  58.         show[3] = nbr[o[3]];
  59.         if (S2 == 0) {                        //S2按下 短按加1
  60.             beep(50);
  61.             if (o[n]++ >= 9) o[n] = 0;
  62.             show[n] = nbr[o[n]];
  63.             delay_ms = 500; delay = 1;
  64.             while (delay && S2 == 0);        //长按延时等待
  65.             while (S2_ms >= 500) {                //按键长按,开始连加
  66.                 feed_dog();
  67.                 delay_ms = 125; delay = 1;                //0.125秒连加一次
  68.                 while (delay && S2 == 0);
  69.                 beep(50);
  70.                 if (o[n]++ >= 9) o[n] = 0;
  71.                 show[n] = nbr[o[n]];
  72.             }
  73.             delay = 0;
  74.             delay_ms = 0;
  75.         }

  76.         if (S1 == 0) {                //S1按下
  77.             beep(50);
  78.             n++;                //输入下一位
  79.             while (S1 == 0) {
  80.                 feed_dog();
  81.                 if (S1_ms >= 1000 && !bak) {                //长按退回编辑
  82.                     beep(50);
  83.                     n = 0;
  84.                     wink = 8 >> n;
  85.                     show[0] = nbr[o[0]];
  86.                     show[1] = nbr[o[1]];
  87.                     show[2] = nbr[o[2]];
  88.                     show[3] = nbr[o[3]];
  89.                     bak = 1;
  90.                 }
  91.             }

  92.             if (bak) {
  93.                 bak = 0;
  94.                 continue;
  95.             }

  96.             if (n >= 4) {                //个位输入完成
  97.                 wink = 0;
  98.                 return o[0] * 1000 + o[1] * 100 + o[2] * 10 + o[3];

  99.             }
  100.         }
  101.     }
  102.     return 0;
  103. }

  104. void main() {
  105.     u8 i = 0;
  106.     Beep = 1;
  107.     WDT_CONTR = 0x27;           //初始化看门狗
  108.     P1M0 = 0x0F; P1M1 = 0x00;   //P1.0~P1.3强推挽
  109.     P2M0 = 0xFF; P2M1 = 0x00;   //P2.0~P2.7强推挽
  110.     //上电1秒数码管全亮 蜂鸣器响
  111.     test = 1;
  112.     InitTimer0();
  113.     delay_ms = 1000; delay = 1;
  114.     while (delay);
  115.     test = 0;

  116.     show[0] = nbr[0];
  117.     show[1] = nbr[0];
  118.     show[2] = nbr[0];
  119.     show[3] = nbr[0];

  120.     while (1) {
  121.         relay = 1;
  122.         pause = 0;
  123.         do {        //时间设定
  124.             time = set_time();
  125.         } while (!time);
  126.         time -= 1;
  127.         start = 1;
  128.         relay = 0;
  129.         while (start) {
  130.             feed_dog();
  131.             if (S1 == 0) {      //S1按下蜂鸣器响1下
  132.                 beep(50);
  133.                 while (S1 == 0) {
  134.                     feed_dog();
  135.                 }
  136.             }

  137.             if (S2 == 0) {      //S2按下暂停倒计时
  138.                 beep(50);
  139.                 pause = !pause;
  140.                 relay = pause;
  141.                 while (S2 == 0) {
  142.                     feed_dog();
  143.                     if (pause && S2_ms >= 3000) {       //长按3秒复位
  144.                         _nop_(); _nop_(); _nop_(); _nop_();
  145.                         reset();
  146.                         _nop_(); _nop_(); _nop_(); _nop_();
  147.                     }
  148.                 }
  149.             }

  150.         }
  151.         //倒计时结束
  152.         show[0] = 0x79;     //E
  153.         show[1] = 0x54;     //n
  154.         show[2] = 0x5E;     //d
  155.         show[3] = 0x00;
  156.         for (i = 0; i < 6; i++) {       //蜂鸣器响6下
  157.             delay_ms = 500; delay = 1; while (delay);
  158.             beep(500);
  159.             while (!Beep);
  160.             feed_dog();
  161.         }

  162.         while (1) {
  163.             feed_dog();
  164.             if (S1 == 0 || S2 == 0) {
  165.                 beep(50);
  166.                 while (S1 == 0 || S2 == 0) {
  167.                     feed_dog();
  168.                 }
  169.                 break;
  170.             }
  171.         }
  172.     }
  173. }

  174. void Timer0Interrupt() interrupt 1{         //12Mhz 1mS定时器中断
  175.     static u8 seg = 0;  //当前正在扫描的数码管段码 4位数码管 范围:0~3
  176.     static u8 ms1 = 0;
  177.     static u16 ms = 0, ms2 = 0;
  178.     TH0 = 0xFC;
  179.     TL0 = 0x18;
  180.     if (delay && !--delay_ms) {    //延时任意毫秒
  181.         delay = 0;
  182.     }
  183.     //数码管动态扫描处理
  184.     P1 |= 0xF;          //消影
  185.     P2 = test ? 0xFF : (wink & (1 << (3 ^ seg)) && !hz10 ? 0 : show[seg]);      //段码
  186.     P1 &= ~(1 << seg);   //位码
  187.     if (++seg >= 4) seg = 0;

  188.     if (test) {     //测试模式
  189.         S1 = 1; S2 = 1;
  190.         P3_2 = 0;
  191.         return;
  192.     }

  193.     //蜂鸣器处理
  194.     P3_2 = Beep;
  195.     if (!Beep && !--beep_ms) {
  196.         Beep = 1;
  197.     }
  198.     if (++ms1 >= 50) {
  199.         ms1 = 0;
  200.         hz10 = !hz10;
  201.     }

  202.     //按键处理
  203.     if (P3_0 == 0) {
  204.         if (S1_ms != 0xFFFF) S1_ms++;
  205.     }
  206.     else {
  207.         S1_ms = 0;
  208.     }

  209.     if (P3_1 == 0) {
  210.         if (S2_ms != 0xFFFF) S2_ms++;
  211.     }
  212.     else {
  213.         S2_ms = 0;
  214.     }

  215.     S1 = !(S1_ms >= KEY_TIME);
  216.     S2 = !(S2_ms >= KEY_TIME);
  217.     //继电器处理
  218.     if (++ms2 >= 1000) {    //继电器1秒只能进行1次吸合或释放,防止频繁开关导致设备损坏
  219.         ms2 = 0;
  220.         P3_3 = relay;
  221.     }
  222.     //时间倒计时处理
  223.     if (start) {
  224.         if (pause) {
  225.             wink = 0xF;
  226.         }
  227.         else {
  228.             wink = 0;
  229.             if (++ms >= 1000) {
  230.                 ms = 0;
  231.                 show[0] = nbr[time / 1000 % 10];
  232.                 show[1] = nbr[time / 100 % 10];
  233.                 show[2] = nbr[time / 10 % 10];
  234.                 show[3] = nbr[time % 10];

  235.                 if (!time--) {      //倒计时结束
  236.                     start = 0;
  237.                     relay = 1;
  238.                 }
  239.             }
  240.         }

  241.     }


  242. }
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:849826 发表于 2021-11-6 20:10 | 显示全部楼层
在这基础上,有999天倒计时程序吗?
回复

使用道具 举报

ID:57657 发表于 2021-11-29 22:27 | 显示全部楼层
6313 发表于 2021-11-6 20:10
在这基础上,有999天倒计时程序吗?

999天用晶振误差太大,需要网络授时以及时间戳计算。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表