设为首页收藏本站淘宝杂货铺

从F到0 - From F to 0

 找回密码
 注册已关闭
搜索
查看: 2131|回复: 10
收起左侧

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

[复制链接]
发表于 2021-11-6 09:33:47 | 显示全部楼层 |阅读模式
1.png
上电后点亮数码管的所有段码,且蜂鸣器响,持续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.         } else {
  206.             S1_ms = 0;
  207.         }

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

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

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

  238.         }


  239. }
复制代码

相关帖子

发表于 2021-11-8 19:35:45 | 显示全部楼层

坐吖 !
发表于 2021-11-10 17:43:00 | 显示全部楼层
发表于 2021-11-11 21:36:59 | 显示全部楼层

来晚了
发表于 2021-11-13 09:39:36 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册已关闭

本版积分规则

QQ|手机版|Archiver|从F到0 ( 蒙ICP备17002595号-1 )
蒙公网安备15010402000325号

腾讯云安全认证

GMT+8, 2024-4-28 13:50 , Processed in 1.471084 second(s), 22 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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