標(biāo)題: 用STC系列單片機制作四位可預(yù)置計時器 [打印本頁]

作者: 51黑科技    時間: 2016-2-2 04:18
標(biāo)題: 用STC系列單片機制作四位可預(yù)置計時器





  用STC系列單片機制作四位可預(yù)置計時器_用UM5140X計時器電路改裝
#:當(dāng)使用的EEPROM起始地址不是C2~C7的IC時請到STC_EEPROM.h文件中注釋#define EEPROM_C2_C7這行宏定義
功能: 具有二個按鍵,四位紅色共陽極數(shù)碼顯示
  P3.6長按 = 模式鍵、短按 = 移位、保存
  P3.7長按 = 開始鍵、短按 = 加數(shù)、停止計時
  具有正、倒;計分或計秒預(yù)設(shè)選擇
  具有預(yù)約、倒計時;開機功能分別輸出一個1S低電平信號和一個長通低電平信號

使用說明:
A: 上電前若P1.0對地則為倒計秒//P1.1對地則為倒計分//其它狀態(tài)組合未定義,建議不使用。
1: 長按P3.6口開關(guān)則先重新調(diào)出存在eeprom在的計時停止計時顯示P***且第一個*以125ms閃爍
此時若依次短按P3.6口開關(guān)則移向下一位閃爍,在該位閃爍若短按P3.7口的開關(guān)則此位加1。
當(dāng)?shù)谌齻*閃爍時如果再短按一次P3.6口開關(guān)則保存此次設(shè)定值并退出設(shè)置狀態(tài),顯示***。若
在閃爍10s內(nèi)沒有新鍵按下則自動退出設(shè)置狀態(tài)并不保存此次設(shè)定值,顯示***。
2: 長按P3.7口開關(guān)則開始計時顯示***且最后一個dp點閃爍,在計時器運行中若短按P3.7口開關(guān)則
停止計時,10s內(nèi)沒有新鍵按下則自動重載預(yù)設(shè)值,顯示***。
3: 當(dāng)時間從預(yù)設(shè)值倒計到 000 時停止倒計時且P1^2口輸出1S低電平信號(后自動變高)、P1.3口長通
低電平信號(短按P3.7口開關(guān)可關(guān)閉),10s后自動重載預(yù)設(shè)值。
程序設(shè)計:LBQ691477940  2018-03-10
升級記錄:
增加上電自動選擇設(shè)置正計時與倒計時的初步程序編寫。  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; //位驅(qū)動
  18. sbit    P1_5 = P1^5; //位驅(qū)動
  19. sbit P1_6 = P1^6; //位驅(qū)動
  20. sbit P1_7 = P1^7; //位驅(qū)動
  21. sbit OUT1S = P1^2; //到時間后輸出約1S低電平
  22. sbit OUTL = P1^3; //到時間后輸出低電平,直到短按P3^7口開關(guān)鍵后才變高
  23. sbit DP   = P2^2;
  24. sbit sw_mode = P3^6;  //長按為模式鍵、短按移位
  25. sbit sw_strat = P3^7; //長按為開始鍵、短按加數(shù)
  26. bit  DPP = 0, g_shi = 0,up_dn; //閃爍標(biāo)志位、千位是否顯示標(biāo)志位、正計時與倒計時標(biāo)志位為1時倒計。
  27. static uchar yiwei = 4;   //用于設(shè)置時間值時移位
  28. static uint count = 0;    //定時器0內(nèi)的計數(shù)器
  29. uint  set_count,set_time,time1 = 0; //倒計數(shù)次數(shù)、設(shè)置的時間值(倒計時計數(shù)器)、正計時計數(shù)器
  30. uchar  shi,ge,sf,bf,xflash,flash1;  //千位、百位、十位、個位、10s后自動退出設(shè)置、到時間后輸出1s
  31. uchar  Ttotal[4];  //前面三個字節(jié)為設(shè)置好的時間,最后一個字節(jié)用來判斷eeprom是否寫過
  32. /*********************  函數(shù)聲明  *****************************************/
  33. uchar key_function(void);   //獨立按鍵檢測函數(shù)聲明
  34. void delay_ms(uint n);  //12MHZ晶振時毫秒級CPU延時函數(shù)
  35. void write_time(void);  //轉(zhuǎn)換時間值并寫入
  36. void abc_cba(unsigned int time);   //轉(zhuǎn)換時間值供顯示
  37. void Read_time(void);  //讀出存在eeprom內(nèi)的時間值
  38. /*********************** 共陽極數(shù)字編碼  ********************************/
  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共陽極數(shù)字編碼
  43. /***************************************************************************/

  44. /*********************************************************************
  45. 功能:12MHZ晶振時毫秒級CPU延時函數(shù)
  46. 參數(shù): 1~65535(不可以為0)
  47. 結(jié)果:占用CPU方式延時與參數(shù)值相同的毫秒時間
  48. 備注:應(yīng)用于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. 函數(shù)名:獨立按鍵檢測函數(shù)(帶參數(shù)返回)
  66. 全局變量:無
  67. 參數(shù)說明:無
  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. /*********************  轉(zhuǎn)換時間值并寫入 ***************************/
  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);   //擦除扇區(qū)
  99. String_write(EEPROM_ADD,4,Ttotal);  //重新寫入數(shù)據(jù)
  100. String_Read(EEPROM_ADD,4); //重新設(shè)置后讀出來備用,目的是更新Read_buf[]數(shù)組方便定時器0
  101. }       //中斷后time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];的取值
  102. /*************************************************************************************/
  103. /***************************** 轉(zhuǎn)換時間值供顯示 *************************************/
  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內(nèi)的時間值 *********************/
  112. void Read_time(void)
  113. {   
  114. String_Read(EEPROM_ADD,4);  //讀出來備用
  115.          //EEPROM_ADD 要寫讀內(nèi)部EEPROM的始起地扯
  116.          //  4    共要讀出4個數(shù)據(jù)
  117. if(Read_buf[3] != 0)//不為0表示eeprom內(nèi)容未寫過
  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;  //如果為倒計送設(shè)置的值
  124. else time1 = 0;     //如果為正計送0
  125. }
  126. /******************************************************************************/

  127. //*******************************主程序******************************************
  128. void main()
  129. {
  130. uint keynum;  //長按計數(shù)緩存區(qū)
  131. bit key = 0 ;  //sw_mode鍵長按標(biāo)志位/正計、倒計
  132. SP = 0x60; //堆棧指針

  133. /******** 注意STC89系列沒有此時鐘頻率分頻功能故只能有 12M晶振  ******************/

  134. //CLK_DIV = 0x00; //系統(tǒng)時鐘
  135. CLK_DIV = 0x01;  //系統(tǒng)時鐘/2
  136. //CLK_DIV = 0x02; //系統(tǒng)時鐘/4
  137. //CLK_DIV = 0x03; //系統(tǒng)時鐘/8
  138. //CLK_DIV = 0x04; //系統(tǒng)時鐘/16
  139. //CLK_DIV = 0x06; //系統(tǒng)時鐘/32
  140. //CLK_DIV = 0x06; //系統(tǒng)時鐘/64
  141. //CLK_DIV = 0x07; //系統(tǒng)時鐘/128

  142. /*********************************************************************************/
  143. set_key = 0xff;
  144. switch (key_function())
  145. {
  146.   case set_djm:
  147.   {
  148.    up_dn = 1;  //正計時與倒計時標(biāo)志位、為1時倒計。
  149.    set_count = 20;  //P1.6對地倒計秒
  150.    break;
  151.   }  
  152.   case set_djf:
  153.   {
  154.    up_dn = 1;  //正計時與倒計時標(biāo)志位、為1時倒計。
  155.    set_count = 1200; //P1.7對地倒計分
  156.    break;
  157.   }
  158.   case set_zjm:
  159.   {
  160.    up_dn = 0;  //正計時與倒計時標(biāo)志位、為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;  //正計時與倒計時標(biāo)志位、為1時倒計。
  171.    set_count = 1200; //P1.7對地倒計分
  172.    break;
  173.   }
  174. }
  175. /***************************************************************************/
  176. TMOD = 0x11;   //設(shè)置定時器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內(nèi)的時間值
  189. if(up_dn) time1 = set_time;
  190. abc_cba(time1);  //轉(zhuǎn)換時間值供顯示

  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;  //關(guān)閉小數(shù)點閃爍標(biāo)志位
  206.      key = 1;  //置sw_mode鍵有長按標(biāo)志位
  207.      g_shi = 1;  //千位是否顯示標(biāo)志位置位
  208.      yiwei = 0;
  209.      xflash = 0;   //每按一次清0一次讓其永遠(yuǎn)達(dá)不到10s的退出值
  210.      time1 = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//重調(diào)回之前值
  211.      if(up_dn) abc_cba(set_time);//如果為倒計時轉(zhuǎn)換set_time時間值供顯示
  212.      else abc_cba(time1); //如果為正計時轉(zhuǎn)換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鍵有長按標(biāo)志位
  223.     {
  224.      TR0 = 0;
  225.      DPP = 0;   //關(guān)閉小數(shù)點閃爍標(biāo)志位
  226.      xflash = 0;   //每按一次清0一次讓其永遠(yuǎn)達(dá)不到10s的退出值
  227.      yiwei++;
  228.      if(yiwei >= 3)
  229.      {
  230.       yiwei = 4;  //讓移位功能失效
  231.       key = 0;  //關(guān)閃sw_mode鍵有長按標(biāo)志位
  232.       g_shi = 0;  //關(guān)閉千位是否顯示標(biāo)志位
  233.       write_time(); //轉(zhuǎn)換時間值并寫入
  234.       if(!up_dn)time1 = 0; //如果為正計時則保存完后恢復(fù)time1為 000
  235.      }
  236.     }
  237.    }
  238.   }
  239. /**************** 長按為開始鍵、短按加數(shù)、停止計時  ************************************/
  240.   if ((KEY & 0xc0) == 0x40) //如果有按鍵按下 1100 0000 C0h
  241.   {       //        0111 1111 40h
  242.    delay_ms(20); //延時消抖
  243.    while ((KEY & 0xc0) == 0x40) //長按為開始鍵、短按加數(shù)、停止計時
  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未重置數(shù)時不能啟動倒計時或為正計時模式時啟動計時器
  250.      {
  251.       Read_time(); //啟動前先更新set_time的值供定時器0中斷程序參考
  252.       count = 0;  //定時器0內(nèi)的計數(shù)器清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; //關(guān)閃計時器0
  265.     DPP = 0; //關(guān)閉小數(shù)點閃爍標(biāo)志位
  266.     xflash = 0; //每按一次清0一次讓其永遠(yuǎn)達(dá)不到10s的退出值
  267.     OUTL = 1; //短按P3^7口開關(guān)鍵后才變高   
  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; //將調(diào)節(jié)后的值轉(zhuǎn)換為time值
  297.    }
  298.   }
  299.   if(up_dn) abc_cba(set_time);//如果為倒計時轉(zhuǎn)換set_time時間值供顯示
  300.   else abc_cba(time1); //如果為正計時轉(zhuǎn)換time1時間值供顯示   
  301. }
  302. }
  303. /**************************************************************************/
  304. /*****************************************************************************
  305. 函數(shù)功能:定時器中斷
  306. 入口參數(shù):
  307. 出口參數(shù):
  308. /****************************************************************************/
  309. void timer0(void) interrupt 1
  310. {  
  311. CY = 0;
  312. TL0 +=(65536 - 50007) % 256;//中斷響應(yīng)時間同步修正/重裝初值(低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內(nèi)的值
  321.   {
  322.    TR0 = 0;
  323.    flash1 = 0;   //到時間后先將其清0保證1s輸出的時間
  324.    DPP = 1;   //這里置1經(jīng)下面取反后則為0關(guān)閉小數(shù)點閃爍標(biāo)志位
  325.    OUT1S = OUTL = 0; //輸出低電平直到短按P3^7口開關(guān)鍵后才變高
  326.   }      //到時間后輸出約1S低電平
  327. }
  328. DPP = ~DPP;  //爍標(biāo)志位取反一次
  329. xflash = 0;  //讓其永遠(yuǎn)達(dá)不到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; //跟據(jù)移位值來使某位閃煥
  345.   xflash++;
  346.   if(!OUT1S)  //從OUT1S輸出為低時才++
  347.   flash1++;
  348. }
  349. if(flash1 == 8)  //125ms x 8 = 1s 后自動變?yōu)楦唠娖?br />
  350. {
  351.   OUT1S = 1;  //到時間后輸出約1S低電平
  352. }
  353. if(xflash == 80) //125ms x 80 = 10s 后自動退出設(shè)置狀態(tài)
  354. {
  355.   xflash = 0;  //清0
  356.   yiwei = 4;  //讓跟據(jù)移位值來使某位閃煥功能失效
  357.   if(up_dn)
  358.   set_time = Read_buf[0] * 100 + Read_buf[1] * 10 + Read_buf[2];//如果為倒計時重調(diào)回之前值
  359.   else
  360.   time1 = 0;  //如果為倒計時則清0
  361.   DPP = 0;  //關(guān)閉小數(shù)點閃爍標(biāo)志位
  362.   g_shi = 0;  //關(guān)閉千位是否顯示標(biāo)志位
  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))//跟據(jù)移位值來使某位閃煥
  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))//跟據(jù)移位值來使某位閃煥
  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))//跟據(jù)移位值來使某位閃煥
  402.    P2 = table[11]; //不顯示
  403.    else
  404.    P2 = table[bf]; //顯示百分位
  405.    if(DPP)
  406.     DP = 0;  //直接打開小數(shù)點
  407.    else
  408.     DP = 1;  //直接關(guān)閉小數(shù)點
  409.    P1_6 = 0;
  410.    P1_7 = 1;
  411.    led = 0;
  412.    break;
  413.   }
  414.   default:break;
  415. }
  416. }
  417. /******************************************** END  ********************************/
復(fù)制代碼








歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1