[单片机类] 【一个小小的个人经验分享】【五】定时计数器初探

[复制链接]
 楼主| enderman1 发表于 2019-2-25 19:43 | 显示全部楼层 |阅读模式
本帖最后由 enderman1 于 2019-2-25 19:59 编辑

说在前面的话:真正开学了!从今天开始,楼主要一星期两更了,而且每次更新附带工程源代码,真的!
定时计数器作为51单片机的一个基础外设是必须掌握且熟练掌握的,它的功能不单单和它的名字一样简单,用定时器的功能可以有很多很多,之后会给大家一一列举,在这里就结合数码管和按键来操作吧!

【思路】
首先按键,在之前的经验分享中有提到过按键的使用,包括松手检测和软件消抖,但是都没有基于定时器中断,在松手检测的过程中我们都知道单片机是不干任何事情的,如果把数码管显示的部分写在while(1)循环里面甚至会导致按键按下的时候数码管无法正常显示,而今天的例程结合定时器中断数码管显示一定可以完美解决这个问题。
先放一下之前的代码:
  1. //改进方法
  2. sbit key1=P3^0;
  3. if(key1==0){
  4.     delay_ms(5);
  5. if(key1==0){
  6.     num++;
  7. }
  8. }while(!key1){display();}
这是之前的按键松手检测保持数码管显示的解决方法,但是这不是一个最好的方法,不妨想一想,将数码管显示函数放到定时器中断服务函数里面就可以解决这个问题,在此之前先配置一下定时计数器。
【定时计数器配置】
关于定时计数器的配置,个人认为,阅读芯片使用手册是一个最好的选择。下图:
定时器相关寄存器:
定时器.jpg
TCON各个位功能介绍:
具体1.jpg
TMOD各个位功能介绍:
具体2.jpg
中断允许寄存器:

中断.jpg
通过上面的芯片使用手册,就可以对定时计数器或者中断进行配置了,配置参数依据具体使用情况。以下是本节的配置参数:
  1. void timer0(){
  2.                 TMOD=0x01;
  3.                 TH0=0xdc;
  4.                 TL0=0x00;                //定时10ms请求一次中断
  5.                 EA=1;
  6.                 ET0=1;
  7.                 TR0=1;                        //开定时器
  8. }

定时器中断之所以配置10ms中断一次是因为经实验证明这个刷新频率可以维持数码管的稳定显示,那么我们基于这个配置参数完成一个简单的程序:KEY1=P30  负责加数据    KEY2=P31  负责减数据   数码管显示两位显示数据,数据范围是0~99。
以下是源代码:
  1. #include "stc15f2k60s2.h"
  2. #include "intrins.h"
  3. sbit key1=P3^0;
  4. sbit key2=P3^1;
  5. unsigned char disNum;
  6. unsigned char code leddata[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
  7. unsigned char disBuf[2];
  8. unsigned char wela=0x80;
  9. bit we=0;

  10. void switch_138(unsigned char dat){
  11.                 switch(dat){
  12.                         case 0:P27=0;P26=0;P25=0;break;
  13.                         case 1:P27=0;P26=0;P25=1;break;
  14.                         case 2:P27=0;P26=1;P25=0;break;
  15.                         case 3:P27=0;P26=1;P25=1;break;
  16.                         case 4:P27=1;P26=0;P25=0;break;
  17.                         case 5:P27=1;P26=0;P25=1;break;
  18.                         case 6:P27=1;P26=1;P25=0;break;
  19.       case 7:P27=1;P26=1;P25=1;break;
  20.       default:break;
  21.      }
  22. }

  23. void timer0(){
  24.                 TMOD=0x01;
  25.                 TH0=0xdc;
  26.                 TL0=0x00;                //定时10ms请求一次中断
  27.                 EA=1;
  28.                 ET0=1;
  29.                 TR0=1;                        //开定时器
  30. }
  31. void display(){
  32.                 wela=_cror_(wela,1);
  33.                 if(wela==0x20)wela=0x80;
  34.                 switch_138(6);
  35.                 P0=wela;
  36.                 switch_138(7);
  37.                 P0=leddata[disBuf[we=~we]];
  38.                
  39. }
  40. void main(){
  41.                 timer0();
  42.                 while(1){
  43.                                 disBuf[0]=disNum%10;
  44.                                 disBuf[1]=disNum/10;
  45.                                 if(key1==0){
  46.                                                 disNum++;
  47.                                                 if(disNum==99)disNum=0;
  48.                                 }while(key1==0);
  49.                                 if(key2==0){
  50.                                                 disNum--;
  51.                                                 if(disNum==0)disNum=99;
  52.                                 }while(key2==0);
  53.                 }
  54. }

  55. void timerIT() interrupt 1{
  56.                 TH0=0xdc;
  57.                 TL0=0x00;

  58.                                 display();

  59.                
  60. }
不难发现,在等待松手检测的时候仍然不影响定时器中断,也就是说仍然不影响数码管的显示,而且又能保证数码管的稳定显示。

我是演员 发表于 2019-2-25 21:48 | 显示全部楼层
能看出来,作者在尽量的使程序变得通俗,使得更多新手能理解,这一点很好,对我们这些婴儿玩家比较关照,但是在我看来还是有些败笔,比如说添加的那些烧写软件说明说,看起来比较生硬,有凑字数之嫌,不过大体看来还是比较不错,整体看来作者是很用心的,希望正在阅览的,或者是想要有所造诣的,能跟着作者的思路一起走,不要掉队,最后谢谢作者大大,辛苦了!!!!!!!!!
3524198427 发表于 2023-12-18 17:07 | 显示全部楼层
我可以问一下单片机怎么同时实现led和数码管互不干扰,各干各的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

71

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部

11

主题

71

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部