分享

用STC系列单片机制作四位可预置计时器

 共同成长888 2019-12-30
108_623247_5a21717862c094a.jpg



108_623247_c9769c93bfd1353.jpg 108_623247_588760cef8bdc75.jpg 108_623247_79eafbb7dab5f89.jpg
  用STC系列单片机制作四位可预置计时器_用UM5140X计时器电路改装
#:当使用的EEPROM起始地址不是C2~C7的IC时请到STC_EEPROM.h文件中注释#define EEPROM_C2_C7这行宏定义
功能: 具有二个按键,四位红色共阳极数码显示
  P3.6长按 = 模式键、短按 = 移位、保存
  P3.7长按 = 开始键、短按 = 加数、停止计时
  具有正、倒;计分或计秒预设选择
  具有预约、倒计时;开机功能分别输出一个1S低电平信号和一个长通低电平信号

使用说明:
A: 上电前若P1.0对地则为倒计秒//P1.1对地则为倒计分//其它状态组合未定义,建议不使用。
1: 长按P3.6口开关则先重新调出存在eeprom在的计时停止计时显示P***且第一个*以125ms闪烁
此时若依次短按P3.6口开关则移向下一位闪烁,在该位闪烁若短按P3.7口的开关则此位加1。
当第三个*闪烁时如果再短按一次P3.6口开关则保存此次设定值并退出设置状态,显示***。若
在闪烁10s内没有新键按下则自动退出设置状态并不保存此次设定值,显示***。
2: 长按P3.7口开关则开始计时显示***且最后一个dp点闪烁,在计时器运行中若短按P3.7口开关则
停止计时,10s内没有新键按下则自动重载预设值,显示***。
3: 当时间从预设值倒计到 000 时停止倒计时且P1^2口输出1S低电平信号(后自动变高)、P1.3口长通
低电平信号(短按P3.7口开关可关闭),10s后自动重载预设值。
程序设计:LBQ691477940  2018-03-10
升级记录:
增加上电自动选择设置正计时与倒计时的初步程序编写。  2018-3-11 23:08
P1.0 & P1.1 对地时为倒计秒
P1.0        对地时为倒计分
P1.1  对地时为正计秒
P1.0 & P1.1 不接时为正计分       2018-3-11 09:33
  1. /*********************************************************************/
  2. #include
  3. #include
  4. #include
  5. #define nop _nop_()
  6. #define uint unsigned int
  7. #define uchar unsigned char
  8. #define ulong unsigned long
  9. #define SBI(Y,X) Y |= (1 << X) //让Y的X位置1
  10. #define CBI(Y,X) Y &= ~(1 << X) //让Y的X位清0
  11. #define set_key  P1  //定义键盘口
  12. #define KEY  P3   //定义键盘口
  13. #define set_djm  0x00 //P1.0 & P1.1 对地时为倒计秒
  14. #define set_zjm  0x01 //P1.0        对地时为倒计分
  15. #define set_djf  0x02 //P1.1    对地时为正计秒
  16. //#define set_zjf  0x03 //P1.0 & P1.1 不接时为正计分
  17. sbit    P1_4 = P1^4; //位驱动
  18. sbit    P1_5 = P1^5; //位驱动
  19. sbit P1_6 = P1^6; //位驱动
  20. sbit P1_7 = P1^7; //位驱动
  21. sbit OUT1S = P1^2; //到时间后输出约1S低电平
  22. sbit OUTL = P1^3; //到时间后输出低电平,直到短按P3^7口开关键后才变高
  23. sbit DP   = P2^2;
  24. sbit sw_mode = P3^6;  //长按为模式键、短按移位
  25. sbit sw_strat = P3^7; //长按为开始键、短按加数
  26. bit  DPP = 0, g_shi = 0,up_dn; //闪烁标志位、千位是否显示标志位、正计时与倒计时标志位为1时倒计。
  27. static uchar yiwei = 4;   //用于设置时间值时移位
  28. static uint count = 0;    //定时器0内的计数器
  29. uint  set_count,set_time,time1 = 0; //倒计数次数、设置的时间值(倒计时计数器)、正计时计数器
  30. uchar  shi,ge,sf,bf,xflash,flash1;  //千位、百位、十位、个位、10s后自动退出设置、到时间后输出1s
  31. uchar  Ttotal[4];  //前面三个字节为设置好的时间,最后一个字节用来判断eeprom是否写过
  32. /*********************  函数声明  *****************************************/
  33. uchar key_function(void);   //独立按键检测函数声明
  34. void delay_ms(uint n);  //12MHZ晶振时毫秒级CPU延时函数
  35. void write_time(void);  //转换时间值并写入
  36. void abc_cba(unsigned int time);   //转换时间值供显示
  37. void Read_time(void);  //读出存在eeprom内的时间值
  38. /*********************** 共阳极数字编码  ********************************/
  39. uchar code table[]={
  40. //P2.0=E / P2.1=D / P2.2=DP / P2.3=C / P2.4=G / P2.5=B / P2.6=F / P2.7=A
  41. //   0   1  2 3  4   5    6 7  8   9
  42. 0x14,0xd7,0x4c,0x45,0x87,0x25,0x24,0x17,0x04,0x05,0x0e,0xff};//0~9 P共阳极数字编码
  43. /***************************************************************************/

  44. /*********************************************************************
  45. 功能:12MHZ晶振时毫秒级CPU延时函数
  46. 参数: 1~65535(不可以为0)
  47. 结果:占用CPU方式延时与参数值相同的毫秒时间
  48. 备注:应用于1T单片机时i<600 ;12T单片机时i<125
  49. XX: LBQ691477940   2011-02-19
  50. /**************************************************************************/
  51. void delay_ms(uint n)
  52. {
  53. uint i;
  54. while(--n !=0)
  55. {
  56. #ifdef EEPROM_C2_C7
  57.   for(i = 0;i < 600;i++);
  58. #else
  59.   for(i = 0;i < 125;i++);
  60. #endif
  61. }
  62. }
  63. /****************************************************************************
  64. /*********************************************************************
  65. 函数名:独立按键检测函数(带参数返回)
  66. 全局变量:无
  67. 参数说明:无
  68. 返回说明:返回按键值
  69. 说明:延时消抖,返回值为0xff表示无按键按下或按键不正常
  70. /**********************************************************************************/
  71. uchar key_function(void)
  72. {
  73. uchar data keytemp = 0;  //按键值局部变量
  74. if ((set_key & 0x03) != 0x03) //如果有按键按下 0000 0011 03h
  75.          //        0000 0001 01h
  76. {        //        0000 0010 02h
  77.   keytemp = set_key & 0x03; //取键值
  78.   delay_ms(50);    //延时消抖
  79.   if ((set_key & 0x03) == keytemp)
  80.   {
  81.    return (keytemp); //返回按键值
  82.   }
  83.   else
  84.   {
  85.    return (0xff);  //无正常按键
  86.   }
  87. }
  88. return (0xff);      //无按键按下
  89. }
  90. /************************************************************************/
  91. /*********************  转换时间值并写入 ***************************/
  92. void write_time(void)
  93. {
  94. Ttotal[0] = time1 / 100;
  95. Ttotal[1] = time1 % 100 / 10;
  96. Ttotal[2] = time1 % 10;
  97. Ttotal[3] = 0x00;
  98. Sector_Erase(EEPROM_ADD);   //擦除扇区
  99. String_write(EEPROM_ADD,4,Ttotal);  //重新写入数据
  100. String_Read(EEPROM_ADD,4); //重新设置后读出来备用,目的是更新Read_buf[]数组方便定时器0
  101. }       //中断后time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];的取值
  102. /*************************************************************************************/
  103. /***************************** 转换时间值供显示 *************************************/
  104. void abc_cba(unsigned int time)
  105. {
  106. ge = time / 100;
  107. sf = time % 100 / 10;
  108. bf = time % 10;
  109. }
  110. /**********************************************************************************/
  111. /************************** 读出存在eeprom内的时间值 *********************/
  112. void Read_time(void)
  113. {   
  114. String_Read(EEPROM_ADD,4);  //读出来备用
  115.          //EEPROM_ADD 要写读内部EEPROM的始起地扯
  116.          //  4    共要读出4个数据
  117. if(Read_buf[3] != 0)//不为0表示eeprom内容未写过
  118. {
  119.   time1 = 138;//给一个为138的初值
  120.   write_time();//写入eeprom
  121. }
  122. set_time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];
  123. if(up_dn)time1 = set_time;  //如果为倒计送设置的值
  124. else time1 = 0;     //如果为正计送0
  125. }
  126. /******************************************************************************/

  127. //*******************************主程序******************************************
  128. void main()
  129. {
  130. uint keynum;  //长按计数缓存区
  131. bit key = 0 ;  //sw_mode键长按标志位/正计、倒计
  132. SP = 0x60; //堆栈指针

  133. /******** 注意STC89系列没有此时钟频率分频功能故只能有 12M晶振  ******************/

  134. //CLK_DIV = 0x00; //系统时钟
  135. CLK_DIV = 0x01;  //系统时钟/2
  136. //CLK_DIV = 0x02; //系统时钟/4
  137. //CLK_DIV = 0x03; //系统时钟/8
  138. //CLK_DIV = 0x04; //系统时钟/16
  139. //CLK_DIV = 0x06; //系统时钟/32
  140. //CLK_DIV = 0x06; //系统时钟/64
  141. //CLK_DIV = 0x07; //系统时钟/128

  142. /*********************************************************************************/
  143. set_key = 0xff;
  144. switch (key_function())
  145. {
  146.   case set_djm:
  147.   {
  148.    up_dn = 1;  //正计时与倒计时标志位、为1时倒计。
  149.    set_count = 20;  //P1.6对地倒计秒
  150.    break;
  151.   }  
  152.   case set_djf:
  153.   {
  154.    up_dn = 1;  //正计时与倒计时标志位、为1时倒计。
  155.    set_count = 1200; //P1.7对地倒计分
  156.    break;
  157.   }
  158.   case set_zjm:
  159.   {
  160.    up_dn = 0;  //正计时与倒计时标志位、为1时倒计。
  161.    set_count = 20;  //P1.6对地倒计秒
  162.    break;
  163.   }  
  164.   /* case set_zjf:
  165.   {  
  166.    break;
  167.   } */
  168.   default:
  169.   {
  170.    up_dn = 0;  //正计时与倒计时标志位、为1时倒计。
  171.    set_count = 1200; //P1.7对地倒计分
  172.    break;
  173.   }
  174. }
  175. /***************************************************************************/
  176. TMOD = 0x11;   //设置定时器0/1为工作方式1(0001 0001)
  177. //write_time();//写入eeprom
  178. TH0 = (65536 - 50000) / 256;
  179. TL0 = (65536 - 50000) % 256;
  180. TH1 = (65536 - 2500) / 256;
  181. TL1 = (65536 - 2500) % 256;
  182. ET1 = 1;
  183. TR1 = 1;
  184. ET0 = 1;
  185. EA = 1;   //开定时器0中断、启动定时器0、开总中断
  186. OUT1S = 1; //到时间后输出约1S低电平,上电后置1
  187. OUTL = 1; //到时间后输出约低电平,上电后置1
  188. Read_time(); //读出存在eeprom内的时间值
  189. if(up_dn) time1 = set_time;
  190. abc_cba(time1);  //转换时间值供显示

  191. /*********************  长按为模式键、短按移位  **************************************/
  192. while(1)
  193. {  
  194.   if ((KEY & 0xc0) == 0x80) //如果有按键按下 1100 0000 C0h
  195.          //        1011 1111 80h
  196.   {
  197.    delay_ms(20); //延时消抖
  198.    while ((KEY & 0xc0) == 0x80) //长按为模式键、短按移位
  199.    {
  200.     keynum++;
  201.     delay_ms(10);  //防止干扰
  202.     if (keynum > 200) //如果是长按sw_mode模式键则
  203.     {
  204.      TR0 = 0;  //停止计时器0
  205.      DPP = 0;  //关闭小数点闪烁标志位
  206.      key = 1;  //置sw_mode键有长按标志位
  207.      g_shi = 1;  //千位是否显示标志位置位
  208.      yiwei = 0;
  209.      xflash = 0;   //每按一次清0一次让其永远达不到10s的退出值
  210.      time1 = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//重调回之前值
  211.      if(up_dn) abc_cba(set_time);//如果为倒计时转换set_time时间值供显示
  212.      else abc_cba(time1); //如果为正计时转换time1时间值供显示
  213.     }
  214.    }
  215.    if (keynum > 200)
  216.    {
  217.     keynum = 0;
  218.    }  
  219.    else if(keynum >= 10) //防止干扰
  220.    {
  221.     keynum = 0;   
  222.     if(key)  //如果sw_mode键有长按标志位
  223.     {
  224.      TR0 = 0;
  225.      DPP = 0;   //关闭小数点闪烁标志位
  226.      xflash = 0;   //每按一次清0一次让其永远达不到10s的退出值
  227.      yiwei++;
  228.      if(yiwei >= 3)
  229.      {
  230.       yiwei = 4;  //让移位功能失效
  231.       key = 0;  //关闪sw_mode键有长按标志位
  232.       g_shi = 0;  //关闭千位是否显示标志位
  233.       write_time(); //转换时间值并写入
  234.       if(!up_dn)time1 = 0; //如果为正计时则保存完后恢复time1为 000
  235.      }
  236.     }
  237.    }
  238.   }
  239. /**************** 长按为开始键、短按加数、停止计时  ************************************/
  240.   if ((KEY & 0xc0) == 0x40) //如果有按键按下 1100 0000 C0h
  241.   {       //        0111 1111 40h
  242.    delay_ms(20); //延时消抖
  243.    while ((KEY & 0xc0) == 0x40) //长按为开始键、短按加数、停止计时
  244.    {         
  245.     keynum++;
  246.     delay_ms(10);  //防止干扰
  247.     if (keynum > 200) //如果长按sw_strat开始键则
  248.     {
  249.      if((set_time !=0)||(up_dn == 0))//set_time=0未重置数时不能启动倒计时或为正计时模式时启动计时器
  250.      {
  251.       Read_time(); //启动前先更新set_time的值供定时器0中断程序参考
  252.       count = 0;  //定时器0内的计数器清0保持每次时间一样
  253.       TR0 = 1;  //开启计时器0
  254.      }  
  255.     }
  256.    }
  257.    if (keynum > 200)
  258.    {
  259.     keynum = 0;
  260.    }  
  261.    else if(keynum >= 10) //防止干扰
  262.    {
  263.     keynum = 0;
  264.     TR0 = 0; //关闪计时器0
  265.     DPP = 0; //关闭小数点闪烁标志位
  266.     xflash = 0; //每按一次清0一次让其永远达不到10s的退出值
  267.     OUTL = 1; //短按P3^7口开关键后才变高   
  268.     switch(yiwei)
  269.     {
  270.      case 0:
  271.      {
  272.       ge++;
  273.       if(ge >= 10) //如果大于10清0
  274.       ge = 0;
  275.       break;
  276.      }
  277.     case 1:
  278.      {
  279.       sf++;
  280.       if(sf >= 10) //如果大于10清0
  281.       sf = 0;
  282.       break;
  283.      }
  284.     case 2:
  285.      {
  286.       bf++;
  287.       if(bf >= 10) //如果大于10清0
  288.       bf = 0;
  289.       break;
  290.      }
  291.      default:
  292.      {      
  293.       break;
  294.      }      
  295.     }
  296.     set_time = time1 = ge * 100 + sf * 10 + bf; //将调节后的值转换为time值
  297.    }
  298.   }
  299.   if(up_dn) abc_cba(set_time);//如果为倒计时转换set_time时间值供显示
  300.   else abc_cba(time1); //如果为正计时转换time1时间值供显示   
  301. }
  302. }
  303. /**************************************************************************/
  304. /*****************************************************************************
  305. 函数功能:定时器中断
  306. 入口参数:
  307. 出口参数:
  308. /****************************************************************************/
  309. void timer0(void) interrupt 1
  310. {  
  311. CY = 0;
  312. TL0 +=(65536 - 50007) % 256;//中断响应时间同步修正/重装初值(低8位修正值)
  313. TH0 = (65536 - 50000) / 256 +(unsigned char)CY;//高8位初值修正/重装初值(高8位修正值)
  314. count++;
  315. if (count == set_count) //50ms x 20 = 1秒钟
  316. {      //50ms x 1200 = 1分钟
  317.   count = 0x00;
  318.   time1++;
  319.   set_time--;
  320.   if(!set_time)   //如果已倒计为0则重读eeprom内的值
  321.   {
  322.    TR0 = 0;
  323.    flash1 = 0;   //到时间后先将其清0保证1s输出的时间
  324.    DPP = 1;   //这里置1经下面取反后则为0关闭小数点闪烁标志位
  325.    OUT1S = OUTL = 0; //输出低电平直到短按P3^7口开关键后才变高
  326.   }      //到时间后输出约1S低电平
  327. }
  328. DPP = ~DPP;  //烁标志位取反一次
  329. xflash = 0;  //让其永远达不到10s的退出值
  330. }  
  331. /******************************************************************/
  332. /******************************************************************/
  333. void timer1(void) interrupt 3
  334. {
  335. static uchar led;
  336. uchar flash;
  337. bit flas;
  338. TH1 = (65536 - 2500) / 256;
  339. TL1 = (65536 - 2500) % 256;
  340. flash++;
  341. if(flash == 50)  //2.5ms x 50 = 125ms
  342. {
  343.   flash = 0;
  344.   flas = !flas; //跟据移位值来使某位闪焕
  345.   xflash++;
  346.   if(!OUT1S)  //从OUT1S输出为低时才++
  347.   flash1++;
  348. }
  349. if(flash1 == 8)  //125ms x 8 = 1s 后自动变为高电平
  350. {
  351.   OUT1S = 1;  //到时间后输出约1S低电平
  352. }
  353. if(xflash == 80) //125ms x 80 = 10s 后自动退出设置状态
  354. {
  355.   xflash = 0;  //清0
  356.   yiwei = 4;  //让跟据移位值来使某位闪焕功能失效
  357.   if(up_dn)
  358.   set_time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//如果为倒计时重调回之前值
  359.   else
  360.   time1 = 0;  //如果为倒计时则清0
  361.   DPP = 0;  //关闭小数点闪烁标志位
  362.   g_shi = 0;  //关闭千位是否显示标志位
  363. }
  364. switch(led)
  365. {
  366.   case 0:
  367.   {
  368.    P1_7 = 0;
  369.    if(g_shi)
  370.    P2 = table[10]; //不显示千位
  371.    else
  372.    P2 = table[11]; //显示千位
  373.    P1_4 = 1;
  374.    led = 1;
  375.    break;
  376.   }
  377.   case 1:
  378.   {
  379.    if((flas)&&(yiwei == 0))//跟据移位值来使某位闪焕
  380.    P2 = table[11]; //不显示
  381.    else
  382.    P2 = table[ge]; //显示个位
  383.    P1_4 = 0;
  384.    P1_5 = 1;
  385.    led = 2;
  386.    break;
  387.   }
  388.   case 2:
  389.   {
  390.    if((flas)&&(yiwei == 1))//跟据移位值来使某位闪焕
  391.    P2 = table[11]; //不显示
  392.    else
  393.    P2 = table[sf]; //显示十分位
  394.    P1_5 = 0;
  395.    P1_6 = 1;
  396.    led = 3;
  397.    break;
  398.   }
  399.   case 3:
  400.   {
  401.    if((flas)&&(yiwei == 2))//跟据移位值来使某位闪焕
  402.    P2 = table[11]; //不显示
  403.    else
  404.    P2 = table[bf]; //显示百分位
  405.    if(DPP)
  406.     DP = 0;  //直接打开小数点
  407.    else
  408.     DP = 1;  //直接关闭小数点
  409.    P1_6 = 0;
  410.    P1_7 = 1;
  411.    led = 0;
  412.    break;
  413.   }
  414.   default:break;
  415. }
  416. }
  417. /******************************************** END  ********************************/
复制代码



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多