单片机——交通灯(定时器中断)
创始人
2024-06-02 06:06:18
0

1.基础知识
1.1、中断源

中断源符号名称中断引起原因中断号
/INT0外部中断0P3.2引脚低电平或下降沿信号0
T0定时器0中断定时,计数器0计数回0溢出1
/INT01外部中断1P3.3引脚低电平或下降沿信号2
T1定时器1中断定时/计数器1计数回0溢出3
TI/RI串行口中断串行通信完成一帧数据发送或接收引起中断4

1.2、定时器中断
设置模式:这里用的是定时器0中断,中断模式为1。

void zhongduan(){TMOD=0x01;TH0=(65536-45872)/256;TL0= (65536-45872)%256;EA=1;ET0=1;TR0=1;}

(1)TMOD=0x01 表示设置计时器 0 为工作方式 1,这种方式使用计数器模式,并且计数器的值被装入 TH0 和 TL0 寄存器中。
(2)TH0=(65536-45872)/256 和 TL0=(65536-45872)%256 是设置定时器计数初值的代码。65536是2的16次方,定时器是加1计数器16位。晶振为11.0592,故所记次数应为45872,计时器每隔50000(50ms)微秒发起一次中断。45872的来历,为(50000/(12*(1/11.0592M))
(3)EA=1,ET0=1,TR0=1 是开启中断的代码。EA 表示总中断使能开关,设置为 1 时表示打开所有中断。ET0 表示定时器 0 的中断使能开关,设置为 1 时表示打开定时器 0 中断。TR0 表示定时器 0 的运行控制开关,设置为 1 时表示启动定时器 0 的计数器开始计时。

void Time0() interrupt 1
{TH0=(65536-45872)/256 ;TL0=(65536-45872)%256 ;count++;}

在程序的结束,要重新设置定时器0的重载值,以便定时器可以继续计时并产生下一个中断。由于定时器的工作方式是在计数器减到0时产生中断,因此每次产生中断后都需要重新设置定时器的重载值,从而控制中断的时间间隔。这里的值根据定时器的时钟频率和所需的中断时间间隔计算而得。
2、代码
2.1、宏定义、头文件与延时
大多数程序都会用到,前面的博客有说,这里就不说了

#include
#define uchar unsigned char
#define uint unsigned intsbit duan=P2^6;
sbit wei =P2^7;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar shijian ,deng = 2;
uchar count;//延时
void delay(uint k)
{
uint i,j;for(i=0;ifor(j=0;j<113;j++){;}  }
}

解释一下这里的全局变量count,是计数用的,是整个程序定时的关键。
变量deng就是指灯的意思,将deng初始化为2是因为最开始需要亮绿灯,因此将deng设置为2,表示初始状态为绿灯。如果将deng初始值设置为其他数字,例如0或1或3,则初始状态为红灯、黄灯或黄灯(绿灯和黄灯之间的转换),这都不符合交通信号灯的正常工作流程,因此将deng初始值设置为2最合适。(不懂得话。可以看一下后面的红绿灯程序的switch,case)
2.2、数码管显示

 void display(uchar a,b){P0=0xfb;wei=1;wei=0;P0=table[a];duan=1;duan=0;delay(5);P0=0xf7;wei=1;wei=0;P0=table[b];duan=1;duan=0;delay(5);}

这段代码实现了数码管的显示功能。在这里,a和b分别是需要显示的十位数和个位数。具体的显示流程是:

选择第一个数码管(P0=0xfb),并将要显示的十位数写入P0口。打开第一个数码管的使能(wei=1),并在一段时间后关闭(wei=0)。选择第二个数码管(P0=0xf7),并将要显示的个位数写入P0口。打开第二个数码管的使能(wei=1),并在一段时间后关闭(wei=0)。

在每个数码管的使能开启后,相应的数字通过将数码管段选(duan)开启来实现。而在开启使能和关闭使能之间需要适当的延时,以确保数字能够正确显示。

段选根据端口连线
在这里插入图片描述

2.3、中断部分在本文第一部分讲过了,这里不在赘述

 void zhongduan(){TMOD=0x01;TH0=(65536-45872)/256;TL0= (65536-45872)%256;EA=1;ET0=1;TR0=1;}

2.4、红绿灯显示

void redgreenyellow()
{uchar shi,ge;if(shijian==0){switch(deng){case 0:shijian=10;deng=1;break;//红灯case 1:shijian=5;deng=2;break; //黄灯case 2:shijian=10;deng=3;break;//绿灯case 3:shijian=5;deng=0;break; //黄灯}switch(deng){case 1:P1=0xfc;break;//红灯case 2:P1=0xcf;break; //黄灯case 3:P1=0xf3;break;//绿灯case 0:P1=0xcf;break; //黄灯}}shi = shijian/10;ge  = shijian%10;display(shi,ge);if(count==20){count=0;shijian--;}}

这段代码实现了红绿灯的控制和倒计时显示的功能。具体来说,代码中定义了两个变量 shi 和 ge 分别表示时间的十位数和个位数。在 if (shijian==0) 语句块中,程序首先根据当前的红绿灯状态 deng 设置下一个状态,并更新相应的倒计时时间 shijian。然后根据新的红绿灯状态 deng 在数码管上显示相应的时间。最后,程序检测到 count 的值为 20 时,说明经过了 20 次中断周期,即 1 秒钟,此时将 shijian 减一,更新时间,并将 count 重置为 0,以便下一次计时。

需要注意的是,代码中对 deng 变量的值进行了多次判断和修改。这是因为程序需要根据当前的红绿灯状态来决定下一个状态,所以需要不断地对 deng 变量进行判断和修改。

同时,注意一个小细节case空格0!!
在这里插入图片描述
2.5、主程序
这里比较简单,是对其他程序的综合调用

//主函数
void main()
{
zhongduan();
while(1)
{redgreenyellow();
}}

2.6、小尾巴
最后一点,是中断程序服务程序非常重要,没有它,前面的不能实现定时功能

void Time0() interrupt 1
{TH0=(65536-45872)/256 ;TL0=(65536-45872)%256 ;count++;}

在这个程序中,中断服务程序是通过定时器中断触发的,每当定时器溢出时,中断服务程序会被执行一次。在这个中断服务程序中,count变量的作用是用来计时的。每次中断服务程序被执行时,count的值会加1,这样可以通过累加count的值来计算时间。在这个程序中,count的单位是50毫秒,所以count累加20次就代表1秒过去了。

3.完整代码

//红绿灯,需要用到的模块有数码管显示秒数,定时中断,以及相应的灯。
#include
#define uchar unsigned char
#define uint unsigned intsbit duan=P2^6;
sbit wei =P2^7;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar shijian ,deng = 2;
uchar count;//延时
void delay(uint k)
{
uint i,j;for(i=0;ifor(j=0;j<113;j++){;}  }
}//数码管显示部分void display(uchar a,b){P0=0xfb;wei=1;wei=0;P0=table[a];duan=1;duan=0;delay(5);P0=0xf7;wei=1;wei=0;P0=table[b];duan=1;duan=0;delay(5);}//中断部分,采用定时器中断0void zhongduan(){TMOD=0x01;TH0=(65536-45872)/256;TL0= (65536-45872)%256;EA=1;ET0=1;TR0=1;}//红绿灯显示模块
void redgreenyellow()
{uchar shi,ge;if(shijian==0){switch(deng){case 0:shijian=10;deng=1;break;//红灯case 1:shijian=5;deng=2;break; //黄灯case 2:shijian=10;deng=3;break;//绿灯case 3:shijian=5;deng=0;break; //黄灯}switch(deng){case 1:P1=0xfc;break;//红灯case 2:P1=0xcf;break; //黄灯case 3:P1=0xf3;break;//绿灯case 0:P1=0xcf;break; //黄灯}}shi = shijian/10;ge  = shijian%10;display(shi,ge);if(count==20){count=0;shijian--;}}//主函数
void main()
{
zhongduan();
while(1)
{redgreenyellow();
}}void Time0() interrupt 1
{TH0=(65536-45872)/256 ;TL0=(65536-45872)%256 ;count++;}

4.运行结果
动态的,截几个图演示一下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...