当前位置:   article > 正文

【笔记】6位数码管显示定时器定时的时分秒,通过按键控制时间,自定义串口通信协议,根据单片机接收到的指令控制数码管显示_单片机实现时钟,数码管显示时分秒的代码

单片机实现时钟,数码管显示时分秒的代码

          目的:利用PROTUES仿真软件、串口调试助手、虚拟串口,搭建单片机与PC通信仿真平台,熟悉单片机串口的配置及与PC机的通信方法;尝试制定通信协议(含开始码、指令、数据、停止码),单片机根据通信协议解析接收到的内容,并根据接收的指令执行相应的操作。

1、proteus仿真实验电路:

2、基本功能

程序功能:1.时分秒的动态显示。2.用三个按键实现时分秒的修改,调节的数字闪烁提示。
3.串口控制时钟的暂停、开始、清零、读取、设置时间

串口协议格式:s+指令+数据+e
s:表示开始码
指令:
  p:计时暂停(无数据位)    
  r:计时重启(无数据位)    
  c:显示清零(无数据位)    
  q:查询当前时间(无数据位)         
  t:设置时间(数据位格式为6位数字)   

3、效果

 

4、源代码 

  1. /*******************************************************************************
  2. 程序功能:1.时分秒的动态显示。2.用三个按键实现时分秒的修改,调节的数字闪烁提示。
  3. 3.串口控制时钟的暂停、开始、清零、读取、设置时间
  4. 串口协议格式:s+指令+数据+e
  5. s:表示开始码
  6. 指令:
  7. | p:计时暂停(无数据位) |
  8. | r:计时重启(无数据位) |
  9. | c:显示清零(无数据位) |
  10. | q:查询当前时间(无数据位)
  11. | t:设置时间(数据位格式为6位数字)
  12. *******************************************************************************/
  13. #include <reg52.h> //包含需要的头文件
  14. #define u8 unsigned char
  15. #define u16 unsigned int
  16. u8 WeiMa[6]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};
  17. u8 DuanMa[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  18. //函数声明
  19. void Delay_ms(u16 xms);
  20. void ShuMaGuan(u8 wei,u8 duan);
  21. void Display_Timer(u8 hour,u8 min,u8 sec);
  22. u8 Key_Scan();
  23. void PutChar(u8 n);
  24. void UartInit();
  25. void PutString(u8 *p);
  26. void Key_Timer_Set();
  27. void Uart_Timer_Set();
  28. void Pintf_Uart();
  29. //引脚定义
  30. sbit SW1=P3^2;
  31. sbit SW2=P3^3;
  32. sbit SW3=P3^4;
  33. u8 Hour=0,Min=0,Sec=0;//全局变量,时分秒
  34. u8 mode=0;//全局变量:状态切换,0:时钟显示,1:调节时;2:调节分;3:调节秒
  35. bit flash_tip=1;//数码管闪烁标志,为0时数码管熄灭,为一时数码管显示
  36. #define Data_SIZE 15 //数据长度
  37. u8 USART_RX_BUF[Data_SIZE]; //接收缓冲,最大Data_SIZE个字节.末字节为换行符
  38. u8 Start_Receiving=0; //开始接收标志位
  39. u8 Receive_OK=0; //接收完毕接收位 1为接收完毕
  40. //函数功能:定时器初始化
  41. void Time0init()
  42. {
  43. TMOD|=0x01; //设置定时器模式
  44. TF0=0; //清除TF0标志
  45. TH0=(65536-50000)/256; //设置定时初值
  46. TL0=(65536-50000)%256; //设置定时初值
  47. TR0=1; //定时器0允许计时
  48. ET0=1; //中断允许
  49. EA=1; //CPU中断允许位打开
  50. }
  51. //串口初始化
  52. void UartInit() //9600bps@11.0592MHz
  53. {
  54. PCON &= 0x8F; //波特率倍速
  55. SCON = 0x50; //8位数据,可变波特率
  56. TMOD &= 0x0F; //清除定时器1模式位
  57. TMOD |= 0x20; //设定定时器18位自动重装方式
  58. TL1 = 0xFD; //设定定时初值
  59. TH1 = 0xFD; //设定定时器重装值
  60. TR1 = 1; //启动定时器1
  61. EA=1;
  62. ES=1; //打开接收中断
  63. }
  64. /*******************************************************************************
  65. * 函 数 名: void main()
  66. * 函数功能: 主函数
  67. *******************************************************************************/
  68. void main()
  69. {
  70. Time0init();//定时器
  71. UartInit(); //串口
  72. Pintf_Uart();//输入提示
  73. while(1)
  74. {
  75. Key_Timer_Set();//按键控制时钟
  76. Uart_Timer_Set();//按键调节时钟
  77. Display_Timer(Hour,Min,Sec);//数码管显示
  78. }
  79. }
  80. /*******************************************************************************
  81. * 函 数 名: void Pintf_Uart()
  82. * 函数功能: 串口助手输入指示
  83. *******************************************************************************/
  84. void Pintf_Uart()
  85. {
  86. /***************输入指示*******************/
  87. PutString("Please input:s+command(data)+e\r\n");
  88. PutString("Stop_Time:spe\r\n");
  89. PutString("Start_Time:sre\r\n");
  90. PutString("Zero_Time:sce\r\n");
  91. PutString("Read_Time:sqe\r\n");
  92. PutString("Set_Time:st******e\r\n");
  93. /*******************************************/
  94. }
  95. /*******************************************************************************
  96. * 函 数 名: void Key_Timer_Set()
  97. * 函数功能: //按键调节时钟
  98. *******************************************************************************/
  99. void Key_Timer_Set()
  100. {
  101. u8 keynum;
  102. keynum=Key_Scan();//按键返回值
  103. if(keynum) //0表示有按键按下
  104. {
  105. switch(keynum) //判断是哪个按键按下,按键一调节模式,按键2自加,按键3自减
  106. {
  107. case 1:if(++mode>=4) mode=0;break; //++mode为先自增再判断是否大于4
  108. case 2:
  109. if(mode==1) if(++Hour>=24) Hour=0;//++mode为先自增再判断是否大于4
  110. if(mode==2) if(++Min>=60) Min=0;//++Min先自增再判断是否大于60
  111. if(mode==3) if(++Sec>=60) Sec=0;//++Sec先自增再判断是否大于60
  112. break;
  113. case 3:
  114. if(mode==1) if(--Hour==255) Hour=23;//--Hour先自增再判断是否溢出
  115. if(mode==2) if(--Min==255) Min=59;//--Min先自增再判断是否大溢出
  116. if(mode==3) if(--Sec==255) Sec=59;//--Sec先自增再判断是否大溢出
  117. break;
  118. default:break;
  119. }
  120. }
  121. }
  122. /*******************************************************************************
  123. * 函 数 名: void Key_Timer_Set()
  124. * 函数功能: 串口调节时钟
  125. 串口协议格式:s+指令+数据+e
  126. s:表示开始码
  127. 指令:
  128. | p:计时暂停(无数据位) |
  129. | r:计时重启(无数据位) |
  130. | c:显示清零(无数据位) |
  131. | q:查询当前时间(无数据位)
  132. | t:设置时间(数据位格式为6位数字)
  133. *******************************************************************************/
  134. void Uart_Timer_Set()
  135. {
  136. static u8 Hour_1,Min_1,Sec_1;//时间暂存
  137. if(Receive_OK) //如果串口接收到数据
  138. {
  139. Receive_OK=0;
  140. switch(USART_RX_BUF[0])//存入数组的数据没有开始码,所以第一个数据是指令
  141. {
  142. case 'p': //时钟暂停
  143. if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
  144. PutString("Error!\r\n");
  145. else
  146. {
  147. TR0=0;
  148. PutString("Stop OK!\r\n");
  149. }
  150. break;
  151. case 'r': //开始计时
  152. if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
  153. PutString("Error!\r\n");
  154. else
  155. {
  156. TR0=1;
  157. PutString("Start OK!\r\n");
  158. }
  159. break;
  160. case 'c': //清零
  161. if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
  162. PutString("Error!\r\n");
  163. else
  164. {
  165. Hour=0;
  166. Min=0;
  167. Sec=0;
  168. PutString("Zero OK!\r\n");
  169. }
  170. break;
  171. case 'q': //查询当前时间
  172. if(USART_RX_BUF[1]!='e')//说明第2位数组的数据不是停止码
  173. PutString("Error!\r\n");
  174. else
  175. {
  176. PutString("The time is:");
  177. PutChar(Hour/10+48); //转化ASCII码字符,048148+1=49.....
  178. PutChar(Hour%10+48);
  179. PutChar(':');
  180. PutChar(Min/10+48);
  181. PutChar(Min%10+48);
  182. PutChar(':');
  183. PutChar(Sec/10+48);
  184. PutChar(Sec%10+48);
  185. PutString("\r\n");
  186. }
  187. break;
  188. case 't': //设置时间
  189. if(USART_RX_BUF[7]!='e')//如果接收到的数据不是6位数字,说明第7位数组的数据不是停止码
  190. PutString("Error!\r\n");
  191. else
  192. {
  193. Hour_1=(USART_RX_BUF[1]-48)*10+(USART_RX_BUF[2]-48); //转化成十进制
  194. Min_1=(USART_RX_BUF[3]-48)*10+(USART_RX_BUF[4]-48); //转化成十进制
  195. Sec_1=(USART_RX_BUF[5]-48)*10+(USART_RX_BUF[6]-48); //转化成十进制
  196. if(Hour_1>23 || Min_1>59 || Sec_1>59) //超出时间阈值
  197. PutString("Error!\r\n");
  198. else
  199. {
  200. Hour=Hour_1;
  201. Min=Min_1;
  202. Sec=Sec_1;
  203. PutString("Set OK!\r\n");
  204. }
  205. }
  206. break;
  207. default:PutString("Error!\r\n");break;
  208. }
  209. ES=1; //开启接收
  210. }
  211. }
  212. /*******************************************************************************
  213. * 函 数 名: void Delay_ms(u16 xms)
  214. * 函数功能: 软件延时函数,xms为延时多少毫秒
  215. *******************************************************************************/
  216. void Delay_ms(u16 xms)
  217. {
  218. unsigned char i, j;
  219. while(xms--)
  220. {
  221. i = 2;
  222. j = 135;
  223. do
  224. {
  225. while (--j);
  226. } while (--i);
  227. }
  228. }
  229. /*******************************************************************************
  230. * 函 数 名: void ShuMaGuan(u8 wei,u8 duan)
  231. * 函数功能: 静态显示一位,参数:wei控制位选duan控制段选,表示要显示的一个数字
  232. *******************************************************************************/
  233. void ShuMaGuan(u8 wei,u8 duan)
  234. {
  235. P1=WeiMa[wei]; //位选
  236. P2=DuanMa[duan]; //段选
  237. Delay_ms(1); //间隔一段时间扫描
  238. P1=0xFF;
  239. P2=0xFF; //消隐
  240. }
  241. /*******************************************************************************
  242. * 函 数 名: void Display_Timer(u8 hour,u8 min,u8 sec)
  243. * 函数功能:数码管动态显示
  244. flash_tip为数码管闪烁标志,为0时数码管熄灭,为一时数码管显示
  245. flash_tip每4.5秒进行取反
  246. *******************************************************************************/
  247. void Display_Timer(u8 hour,u8 min,u8 sec)
  248. {
  249. if(mode!=1 || flash_tip==1) //mode=1时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
  250. {
  251. ShuMaGuan(5,hour/10);
  252. ShuMaGuan(4,hour%10);
  253. }
  254. else P1=0xFF;
  255. if(mode!=2 || flash_tip==1)//mode=2时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
  256. {
  257. ShuMaGuan(3,min/10);
  258. ShuMaGuan(2,min%10);
  259. }
  260. else P1=0xFF;
  261. if(mode!=3 || flash_tip==1)//mode=3时,左边的条件一直为假,当flash_tip=1时,或运算为真,进入if,数码管显示
  262. {
  263. ShuMaGuan(1,sec/10);
  264. ShuMaGuan(0,sec%10);
  265. }
  266. else P1=0xFF;
  267. }
  268. /*******************************************************************************
  269. * 函 数 名: u8 Key_Scan()
  270. * 函数功能: 独立按键检测,按键按下分别返回1.2.3
  271. *******************************************************************************/
  272. u8 Key_Scan()
  273. {
  274. static u8 key_up=1; //按键按松开标志
  275. if(key_up && (SW1==0 || SW2==0 || SW3==0))
  276. {
  277. Delay_ms(10); //去抖动
  278. key_up=0; //松手标志为0,那么下次再检测,if结果为0,则不会进入这里的语句
  279. if(SW1==0) return 1;
  280. if(SW2==0) return 2;
  281. if(SW3==0) return 3;
  282. }
  283. else if(SW1 == 1 && SW2 == 1 && SW3 == 1) key_up=1; //松手标志
  284. return 0; // 无按键按下
  285. }
  286. /*******************************************************************************
  287. * 函 数 名: void PutChar(u8 n)
  288. * 函数功能: 发送一个字符
  289. *******************************************************************************/
  290. void PutChar(u8 n)
  291. {
  292. SBUF=n;
  293. while(!TI);
  294. TI=0;
  295. }
  296. /*******************************************************************************
  297. * 函 数 名: void PutString(u8 *p)
  298. * 函数功能: 发送字符串
  299. *******************************************************************************/
  300. void PutString(u8 *p)
  301. {
  302. while(*p!='\0')
  303. {
  304. PutChar(*p);
  305. p++;
  306. }
  307. }
  308. /*******************************************************************************
  309. * 函 数 名: void uart() interrupt 4
  310. * 函数功能: 串口中断服务函数,单片机接收数据并存入USART_RX_BUF[]数组中
  311. 开始码s不存入数组
  312. *******************************************************************************/
  313. void uart() interrupt 4
  314. {
  315. static u8 Data_count=0;
  316. u8 Data;
  317. if(RI==1)
  318. {
  319. RI=0;
  320. Data=SBUF;
  321. if(Data=='s')
  322. {
  323. Start_Receiving=1; //开始接收数据
  324. }
  325. else if(Start_Receiving)
  326. {
  327. USART_RX_BUF[Data_count++]=Data;//数据还没结束发送,就存到USART_RX_BUF[]数组中
  328. if(Data=='e')
  329. {
  330. Start_Receiving=0;
  331. Data_count=0;
  332. Receive_OK=1;
  333. ES=0;
  334. }
  335. }
  336. }
  337. }
  338. /*******************************************************************************
  339. * 函 数 名: void Time0() interrupt 1
  340. * 函数功能: 定时器0中断服务函数,时钟效果
  341. *******************************************************************************/
  342. void Time0() interrupt 1
  343. {
  344. static unsigned char flag_1,flag_2;
  345. TH0=(65536-50000)/256;
  346. TL0=(65536-50000)%256;//重新赋初值
  347. if(mode==0)flag_1++; //mode0时,数码管正常显示
  348. else flag_2++;
  349. if(flag_1==20 && mode==0) //每秒执行一次
  350. {
  351. flag_1=0;
  352. if(++Sec>=60) //++Sec先自增再判断是否大于60
  353. {
  354. Sec=0;
  355. if(++Min>=60)//++Min先自增再判断是否大于60
  356. {
  357. Min=0;
  358. if(++Hour>=24)//++Hour先自增再判断是否大于60
  359. {
  360. Hour=0;
  361. }
  362. }
  363. }
  364. }
  365. if(flag_2==9)
  366. {
  367. flash_tip=~flash_tip;//4.5秒进行取反
  368. flag_2=0;
  369. }
  370. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/848833
推荐阅读
相关标签
  

闽ICP备14008679号