单片机定时器与数码管静态显示

描述

很多新手在单片机上走的第一步是点亮第一个LED灯,实际上因为开发板的不同,所编写的代码也不同,关键是你要去了解你用的开发板的电路布局。对于电路方面的知识我这里也不详讲,我要做的是无论你用哪一种开发板我的文章都能帮助你。

P0 = 0xFE;

这句代码大家不陌生。

void main(){

unsigned char count = 0;

while(1){

P0 = ~(0x01 << count);

Delay(); //单独实现一个延时函数

count++;

if(count > =8){

count = 0;

}

}

}

以上就是实现流水灯的基本代码,这里没有电路供你分析,但是无论什么开发板,核心代码可以用以上代码实现。

我相信你能看到这里也是有点基础的,这里的延时函数Delay,接下来要讲的是定时器,定时器就是可以替代延时函数的。

定时器

标准的51单片机内部有T0和T1两个定时器,实际上就是TCON特殊功能的寄存器来控制这两个定时器的。

数码管

除此之外,定时值存储寄存器有TH和TL,给TL赋值后,TL会自动加1,加到255后TH加1,有趣的TH也可以提前赋值,但这只是定时器工作的一种模式,定时器有四种模式,这里我不祥讲,而且我们几乎用的模式就是这种,后面涉及到会详细讲解。这里只需要知道TCON(地址0x88)位分配,以后会经常用到。

还有一个TMOC就是定时器作用的模式,位分配如下图:

数码管

代码:

void main()

{ TH0 = 0xB8;  //给TH0赋值,后面的0代表是给定时器T0的TH赋值

TL0 = 0x00;

TR0 = 1; //启动T0定时器

if(TF0 == 1)  //判断T0是否溢出,TF是个标志位

{   //重置

TH0 = 0xB8;

TL0 = 0x00; } }

以上就是定时器,时间多少呢?

我们以晶振位11.0592为例,时钟周期是1/11059200,机器周期(1ms)12/11059200,如果我们定时20ms,那个要执行20*(12/110592)次,算出来是18432次,换成十六进制是B800,所以对TH0赋值B8,对TL0赋值00;

数码管

#include

sbit ADDR0 = P1^0;

sbit ADDR1 = P1^1;

sbit ADDR2 = P1^2;

sbit ADDR3 = P1^3;

sbit ENLED = P1^4;

void main() {

ADDR2 = 1;

ADDR1 = 0;

ADDR0 = 1;

ADDR3 = 1;

ENLED = 0;

P0 = 0XF8;

while(1);}

上面代码是用位STC-51开发板写的,在最后一个数码管上显示数字7,数码管难度简单,只需要针对数码管等的排布编程即可。

下面我们用关键字code定义数码管所能够显示所有字符的数组,这里再结合定时器一起。

#include sbit ADDR0 = P1^0;sbit ADDR1 = P1^1;sbit ADDR2 = P1^2;sbit ADDR3 = P1^3;sbit ENLED = P1^4;

//数组

unsigned char code led[] = 

{ 0xC0, 0xF9, 0xA4,

0xB0, 0x99, 0x92,

0x82, 0xF8, 0x80,

0x90, 0x88, 0x83,

0xC6, 0xA1, 0x86,0x8E};

void main() {    unsigned char count = 0;

//记录T0中断次数

unsigned char secnt = 0;

//记录经过的秒数

ADDR2 = 1;

ADDR1 = 0;

ADDR0 = 0;

ADDR3 = 1;

ENLED = 0;

//设置T0模式

TMOD = 0x01;

//为T0的TH0,TL0初始化

TH0 = 0xB8;

TL0 = 0x00;

//启动T0 TR0 = 1;

while(1){   

if(TF0 ==1)

{ TH0 = 0xB8;

TL0 = 0x00;

count++;

TF0 = 0; }

if(count >=50)

{  count = 0;

P0 = led[secnt];

secnt++;

if(secnt>=16)

{ secnt = 0; }         }     }}

这里代码比较紧凑,不过不影响。上面的代码我相信你也能懂,但是你能发现定时器在这里起到了一个定时中断的作用。

这里讲一下中断。

中断

下面是中断IE寄存器位分配图:

数码管

直接上代码:

#include

//数码管显示字符真值数组

unsigned char code ledchar[]=

{0xC0, 0xF9, 0xA4, 0xB0, 0x99,

0x92, 0x82, 0xF8, 0x80, 0x90,

0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E };

//数码管显示区数组

unsigned char ledbuff[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

sbit ADDR0 = P1^0;sbit ADDR1 = P1^1;sbit ADDR2 = P1^2;sbit ADDR3 = P1^3;sbit ENLED = P1^4;

unsigned char i = 0;

//动态扫描索引

unsigned int c = 0;

//记录中断次数

void main() {

unsigned long s = 0;

//记录秒数

//使能U3

ADDR3 = 1;

ENLED = 0;

//设置T0模式

TMOD = 0x01;

//初始化TH0,TL0

TH0 = 0xFC; TL0 = 0x66;

//启动TR0

TR0 = 1;

//使能总中断

EA = 1;

//使能T0中断

ET0 = 1;

//主循环

while(1)     {          //1s中断          if(c>=1000)          {               s++;               c=0;               //为数码管显示区赋值               ledbuff[0] = ledchar[s%10];               ledbuff[1] = ledchar[s/10%10];               ledbuff[2] = ledchar[s/100%10];               ledbuff[3] = ledchar[s/1000%10];               ledbuff[4] = ledchar[s/10000%10];               ledbuff[5] = ledchar[s/100000%10];          }     }}

//定时器T0中断服务void InterruptTimer0() interrupt 1{     //重新赋值     TH0 = 0xFC;     TL0 = 0x66;     c++;     //显示消隐     P0 = 0xFE;     //完成数码管动态扫描     switch(i)     {          case 0:          ADDR2 = 1;ADDR1 = 0;          ADDR0 = 1; i++;          P0 = ledbuff[0];          break;

case 1:          ADDR2 = 1; ADDR1 = 0;          ADDR0 = 0; i++;          P0 = ledbuff[1];          break;

case 2:          ADDR2 = 0; ADDR1 = 1;          ADDR0 = 1; i++;          P0 = ledbuff[2];          break;

case 3:          ADDR2 = 0; ADDR1 = 1;          ADDR0 = 0; i++;          P0 = ledbuff[3];          break;

case 4:          ADDR2 = 0; ADDR1 = 0;          ADDR0 = 1; i++;          P0 = ledbuff[4];          break;

case 5:          ADDR2 = 0; ADDR1 = 0;          ADDR0 = 0; i=0;          P0 = ledbuff[5];          break;     default:break; 

}

}

这组代码能够按照我们计算好的时间为单位显示秒数。

我们能够提出中断核心代码

EA = 1//中断总开关

ET0 = 1//确认使用T0定时器中断开关

TR0 = 1//肯定要启动T0定时器

void InterruptTimer0() interrupt 1//定时器T0中断服务,中断代码写在这里面,至于interrupt 1是因为interrupt会去寻找地址' 1 ',而T0定时器中断的地址就是1,所以我们可以直接在此函数中写中断期间的代码。至于各种中断的地址我也不再这里多写了。值得一谈的是IP——中断优先级寄存器位分配

数码管

各级中断都差不多,中断发生的也很多,当同时有许多中断发生时,可以通过置上面的值为1升级成优先级中断。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分