很多新手在单片机上走的第一步是点亮第一个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
//数组
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升级成优先级中断。
-
数码管
+关注
关注
32文章
1874浏览量
90933 -
定时器
+关注
关注
23文章
3237浏览量
114448
原文标题:单片机定时器与数码管静态显示
文章出处:【微信号:mcugeek,微信公众号:MCU开发加油站】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论