【C51学习总结】综合和应用:中断法控制倒计时红绿灯的编程实现以及仿真

       在经过了一段时间的C51课程学习后,使我更系统的认识了单片机的主要结构,本篇文章主要是将我所学习到的内容进行一个整理,并结合中断控制法这个综合性的任务尽量对每一个部分进行讲解,希望对大家的学习能够有一点帮助,文章内如有出错还请指正。


目录

一、前期准备工作

1、硬件选择

2、软件选择

二、仿真搭建

1、Proteus工程搭建及器件选择

2、复位电路及外部时钟电路

(1)复位电路:

(2)外部时钟电路:

2、LED灯部分

3、按键部分

4、数码管部分

5、完整仿真图

三、程序编写

1、工程搭建

2、定义所需变量 

3、中断源

(1)定时器设置

(2)按键中断控制开始与停止

 4、红绿灯控制部分

5、数码管控制部分 

四、最终效果

五、完整工程链接

一、前期准备工作

1、硬件选择

仿真软件中:单片机:AT89C51

                      数码管驱动:74ls47

                       数码管:7SEG-MPX2-CA

实体硬件:单片机:STC89C52RC

                   下载器:USB转TTL下载器

由于上课时所选择的单片机为宏晶科技的STC89C52RC,但仿真软件中只有AT系列单片机,故在仿真时选择AT89C51,编译仿真效果相同。

2、软件选择

编程软件:keil5

仿真软件:Proteus 8.9

下载器:STC-ISP(用于实物烧写程序,仅仿真则可不用)

二、仿真搭建

1、Proteus工程搭建及器件选择

打开安装好的Proteus ,点击新建工程

工程名称可以自行定义,并选择好工程文件存放路径,然后一直按下一步,设置均为默认即可

进入工程之后点击P选取所需元器件

左侧搜索栏搜索元器件(这里搜索的是AT89C51),中间可以选中器件,右侧有对应原理图以及封装图,选中后点击确定

依次添加好以下器件

右侧一栏选择终端模式,则可以选择调用电源以及接地,双击图标可以编辑字符

2、复位电路及外部时钟电路

(1)复位电路:

复位电路即初始化电路,其作用是将运行中的单片机恢复到初始状态,相当于重置运行状态

复位的触发要求,输入端RST至少保持两个机器周期为高电平(当晶振为12M时机器周期为1us)

 

(2)外部时钟电路:

该电路中,电容的选择由晶振决定,具体容量需参照技术手册选择,此处晶振的值为12MHz,单片机内部也有时钟电路,具体选择看个人需求

在仿真中可以不使用外部晶振,双击单片机在其设置中可以设置晶振的值

2、LED灯部分

这里设计红绿灯的引脚由P1组引脚控制,且为了方便,设计上选择南-北、东-西联动

对应关系为:

引脚方位led灯灯色方位led灯灯色
P1.0绿绿
P1.1
P1.2
P1.3绿西绿
P1.4西
P1.5西

3、按键部分

选用P3.3引脚连接按键

4、数码管部分

选用P2组引脚进行控制,由高四位(P2.4-P2.7)输出十六进制数,并通过74LS47译码器转换为二进制数据并通过QA-QG控制数码管进行显示,P2.0与P2.1控制数码管两位数的显示切换

十六进制数

P2对应二进制

数码管显示数字

十六进制数

P2对应二进制

数码管显示数字

0x0d

0000 1101

00

0x0e

0000 1110

00

0x1d

0001 1101

01

0x1e

0001 1110

10

0x2d

0010 1101

02

0x2e

0010 1110

20

0x3d

0011 1101

03

0x3e

0011 1110

30

0x4d

0100 1101

04

0x4e

0100 1110

40

0x5d

0101 1101

05

0x5e

0101 1110

50

0x6d

0110 1101

06

0x6e

0110 1110

60

0x7d

0111 1101

07

0x7e

0111 1110

70

0x8d

1000 1101

08

0x8e

1000 1110

80

0x9d

1001 1101

09

0x9e

1001 1110

90

5、完整仿真图

三、程序编写

1、工程搭建

打开KEIL5,选择Project→New uVision Project...新建工程

依次选择Legacy Device Database [no RTE]→Microchip→AT98C51 

新建文件,并引用头文件,点击保存,命名需要带上后缀.C

 随后双击Source Group 1 ,找到刚才保存的路径,双击选择添加main.c文件,添加完成后点击编译

编译完成后可以看到main文件下已经引用了reg51.h文件

2、定义所需变量 

数码管显示数据、控制数据及其他变量

unsigned char seg[10]={0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90};//十六进制码,对应0-9,用于数码管显示,注意该处使用的数码管为共阳极数码管,并且有74ls47译码器作为驱动,此处传输的高位数据对应输出口为P2.4-P2.7,一位十六进制转四位二进制码,参考8421编码,如 0x80 等同于 1000 0000B(B代表二进制码) 从左往右位次依次降低,对应P2.7-p2.0共八个端口 
unsigned char con[2]={0x0d,0x0e};//对应数码管一二位码,低电平有效,即P2.1和P2.0
unsigned char time[3];//定义time[0]、time[1]、time[2],三个数组,前两个用于存放倒计时个位与十位的数值,第三个用于存放定义的倒计时时间,以便一个计时循环结束后重新装载数值
unsigned int j,i,come=0,ss=10;//i,j分别用于两个独立的循环自装载数值,come用于定时器中断,辅助以计时,ss为设置倒计时的计时时间
bit start=0;//定义一个一字节的变量,用于按键中断的判断储存

红绿灯控制引脚

sbit NB_G=P1^0;    //定义变量用于存放对应控制红绿灯的引脚,便于后面引用
sbit NB_Y=P1^1;    //分别为南北(NB)方向的绿灯(G)、黄灯(Y)、红灯(R)
sbit NB_R=P1^2;    //东西(DX)方向的绿灯(G)、黄灯(Y)、红灯(R)
sbit DX_G=P1^3;
sbit DX_Y=P1^4;
sbit DX_R=P1^5;

3、中断源

C51中共有5个中断源,中断源:INT0(外部中断0),INT1(外部中断1),T0(定时器0),T1(定时器1),RXD和TXD(同属串口中断)

关于中断可参考:(C51学习四)外部中断和定时器中断_用外部中断int0触发 关闭定时器-CSDN博客

此处使用的是  T1(定时器1)与  INT1(外部中断1) 

(1)定时器设置

此处使用的是定时器1进行中断(即T1)

TMOD=1;             //打开内部定时器1
TH0=-20000>>8;      //此处用于装载内部计时器的计数量,12M晶振时相当于计时20ms,及20ms触发一次内部中断,由于一次无法计时过长时间,故配合come进行多次计数以达到较长时间的计时
TL0=-20000;         //具体使用方法请参考51单片机计时器的使用一节内容
EA=1;TR0=1;ET0=1;	//开启计时器1中断功能以及设置,用于内部计时
EX1=1;IT1=1;		//开启外部中断1用于读取外部按键是否按下

void ist_time0(void) interrupt 1	//定时器触发内部中断后的操作
{
	TH0=-20000>>8;                  //重新装载内部计时器的数值
	TL0=-20000;
}

(2)按键中断控制开始与停止

此处的中断是由P3.3(即INT1-外部中断1)进行判断

void ist_key(void) interrupt 2	//外部中断(按键按下)触发后内部的操作
{
start=!start;	                //将start的状态反转,由于只有一个字节,故只有0和1两种状态,初始转状态为0,第一次按下后反转为1,以此类推
}

 4、红绿灯控制部分

if(ss==0)             //  5  内部倒计时为0秒,应输出数值为0,但此处不能让0出现,要直接跳过进入到下一个循环
	{
		DX_Y=!DX_Y;   //东西方向黄灯灭
		NB_R=!NB_R;   //南北方向红灯灭
		ss=time[2];   //将初始值重新赋给ss
	}
if(ss==3)             //  4  内部倒计时3秒,外部倒计时显3秒时
	{
		DX_G=!DX_G;   //东西方向绿灯灭
		DX_Y=!DX_Y;   //东西方向黄灯亮
	}
if(ss==time[2]/2)     //  3  部倒计时10秒,外部倒计时显10秒时,第一次倒计时结束,开始第二次倒计时
	{
		NB_Y=!NB_Y;   //南北方向黄灯灭
		NB_R=!NB_R;   //南北方向红灯亮
		DX_G=!DX_G;   //东西方向绿灯亮
		DX_R=!DX_R;   //东西方向红灯灭
	}
if(ss==time[2]/2+3)   //  2  内部倒计时13秒,外部倒计时显示3秒时
	{
		NB_G=!NB_G;   //控制南北方向绿灯的端口状态反转,及由0转变为1,此时灯灭
		NB_Y=!NB_Y;   //南北方向黄灯亮
	}
if(ss==time[2])       //  1  初始值为装载数值,故灯的变化规律从此处开始并往上 ↑
	{                 //此处以倒计时10秒做示例,内部倒计时数值为20,显示为10,显示时将数值砍半后输出,操作在后面
		NB_G=!NB_G;   //控制南北方向绿灯的端口状态反转,及由1转变为0,此时灯亮
		DX_R=!DX_R;   //东西方向红灯亮
	}

5、数码管控制部分 

if(ss>time[2]/2)                          //当ss数值大于10时(10-20间)
	{
		time[0]=(ss-(time[2]/2))/10;      //减去10,然后除以10取十位的数值并存放
		time[1]=(ss-(time[2]/2))%10;      //减去10,然后除以10取余,取个位的数值并存放
	}
else                                      //否则,即当ss数值小于10时(1-10间)
	{
		time[0]=ss/10;                    //直接除以10取十位的数值并存放             
		time[1]=ss%10;                    //直接除以10取余,取个位的数值并存放
	}
		
		ss--;                             //通过以上判断及取值赋值以后,ss数值减1,实现每秒减1
	}//操作结束

for(i=0;i<2;i++)                  //此处在计数范围外,故是每20ms中断一次的时候都执行一次
	{                             //由于本程序使用的是数码管的动态显示,需要考虑刷新率问题,20ms正好为每秒50Hz刷新率,高于25HZ有效避免了闪烁问题
		P2=seg[time[i]]|con[i];   //通过i的倒计时同时控制二数码管输出个位与十位的效果,本处通过或操作,将P2的高位和地位的有效数值相合并(1为有效,或操作保留1,与操作保留0),随后输出给74ls47驱动芯片和数码管,以控制数码管显示数字
		for(j=500;j>0;j--);       //软件延时,不同于计时器中断延时,此处通过j的自减使整个程序在此处执行j的减法运算,以稍微拉长数码管的显示时间,与上面的操作一起达到视觉暂留效果,但此处数值要合适,过长会拉低显示频率造成闪烁,过短亮度无法被人眼看到,造成无法显示
	}

四、最终效果

五、完整工程链接 

GitCode仓库:码路的小丘 / 【C51单片机应用】中断法倒计时红绿灯 · GitCode

  • 48
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
观察十字路口红绿灯工作流程,设计交通。 1、初始时:南北向、东西向直行左转均为红 2、南北向直行: ①南北向直行绿亮,延时若干秒 ②启动南北向左转数码管显示:倒计时6秒;同时南北向直行绿闪烁3下,灭亮灭亮灭亮共3秒,然后南北向直行绿灭,南北向直行黄亮,延时3秒 ③南北向左转数码管倒计时显示结束,关闭;同时南北向直行黄灭,南北向直行红亮 3、南北向左转: ①南北向左转绿亮,延时若干秒 ②启动东西向直行数码管显示:倒计时6秒;同时南北向左转绿闪烁3下,灭亮灭亮灭亮共3秒,然后南北向左转绿灭,南北向左转黄亮,延时3秒 ③东西向直行数码管倒计时显示结束,关闭;同时南北向左转黄灭,南北向左转红亮 4、东西向直行: ①东西向直行绿亮,延时若干秒 ②启动东西向左转数码管显示:倒计时6秒;同时东西向直行绿闪烁3下,灭亮灭亮灭亮共3秒,然后东西向直行绿灭,东西向直行黄亮,延时3秒 ③东西向左转数码管倒计时显示结束,关闭;同时东西向直行黄灭,东西向直行红亮 5、东西向左转: ①东西向左转绿亮,延时若干秒 ②启动南北向直行数码管显示:倒计时6秒;同时东西向左转绿闪烁3下,灭亮灭亮灭亮共3秒,然后东西向左转绿灭,东西向左转黄亮,延时3秒 ③南北向直行数码管倒计时显示结束,关闭;同时东西向左转黄灭,东西向左转红
以下是基于C51单片机的0-9红绿灯倒计时程序,同时利用定时计数器实现精确秒的功能: ```c #include <reg52.h> sbit red = P1^0; // 红 sbit green = P1^1; // 绿 unsigned char sec = 0; // 秒数 unsigned int count = 0; // 计数器 void timer0_init() // 定时器0初始化 { TMOD = 0x01; // 定时器0工作在模式1,16位定时器模式 TH0 = 0xFC; // 定时器初值为0xFC67,即65536-50000,每50ms中断一次 TL0 = 0x67; ET0 = 1; // 开启定时器0中断 TR0 = 1; // 启动定时器0 EA = 1; // 开启总中断 } void timer0_isr() interrupt 1 // 定时器0中断服务程序 { TH0 = 0xFC; TL0 = 0x67; count++; // 计数器加1 if (count == 20) // 1秒钟 { count = 0; sec++; // 秒数加1 } } void main() { timer0_init(); // 定时器0初始化 while (1) { if (sec >= 10) // 倒计时结束 { red = 1; // 红亮 green = 0; // 绿灭 } else if (sec >= 5) // 剩余5秒 { red = 0; // 红灭 green = 1; // 绿亮 } else // 剩余5秒以内 { red = 1; // 红亮 green = 0; // 绿灭 } } } ``` 程序中利用定时器0中断每隔50ms计数器加1,当计数器累加到20时,即1秒钟,秒数加1。根据秒数的不同,控制红绿灯的状态,当秒数大于等于10时,倒计时结束,红亮,绿灭;当秒数大于等于5时,剩余5秒,红灭,绿亮;当秒数小于5时,剩余5秒以内,红亮,绿灭。通过这种方式实现了0-9的红绿灯倒计时,并且能够精确计时,保证了倒计时的准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码路的小丘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值