51单片机:利用单片机的定时器定时,实现十字路口的红黄绿灯交替点亮和熄灭,proteus+keil5

记一次实践

题目要求:
在这里插入图片描述
电路图:
在这里插入图片描述

代码:
头文件

#ifndef traffic_h
#define traffic_h

#include <reg52.h>

#define LedD P0                                              //段选
#define LedC P2                                              //位选

sbit red=P1^2;
sbit yellow=P1^1;
sbit green=P1^0;

unsigned char t=0;													//当前秒数,数码管显示时间的初值

unsigned char	j=0;														//闪烁位的延时参数
	
unsigned char	key1=0,key2=0;								//两个中断按键

unsigned int i=0;														//计数器计数参数

																																
																		//显示采用的是共阴极数码管
																																	
unsigned char num[] = {0,0};         	 						/* 时钟待显示字符对应key值*/  

code unsigned char wx[] = {0xfe,0xfd};   										//数码管地址(位选)

code unsigned char dx[] = {0x3f,0x06,0x5b,0x4f,0x66,      			 /* 0-9数字的编码 (段选)*/
                               0x6d,0x7d,0x07,0x7f,0x6f};

void init();																				//初始化
void delay(unsigned char);													//延时函数
void display();																			//数码管显示
void count();																				//计数(计时)
void transform();																		//将秒的个位十位分离并转换
void twinkle();																		  	//数码管某一位闪烁 
void clear();																				//重置led状态
void int0();																				//外部中断0
void int1();																				//外部中断1
												
#endif

c文件

#include "traffic.h"

void main(void)
{
	init();
	while(1)
	{
		if(key1)						//紧急通行
		{	
			twinkle();										//数码管00闪烁
			red=~red;											//数值取反 red=-red
		}
		else if(key2)					//夜间通行
		{
			twinkle();
			yellow=~yellow;
		}
		else
			display();
	}
}

void init(void)                /*初始化*/
{
	red=0;
	yellow=0;	
	green=0;									//灭掉红绿黄灯
	
	EA=1;													//总中断
	
	ET1=1;										//开启定时器1中断
	TR1=1;										//开启定时器1
	TMOD=0x20;								//定时器1,工作方式2,八位自动重装载
	TH1=156;
	TL1=156;									//一次中断需 0.1ms

	EX0=1;										//打开外部中断0、1
	EX1=1;
	IT0=1;										//下降沿(按键按下时高电平到低电平的一瞬间)触发中断   
	IT1=1;
}
void clear()							//重置函数
{
	red=0;
	yellow=0;	
	green=0;									//灭掉红绿黄灯
	t=0;											//计时清零
}

void display()												//字符显示
{
	unsigned char i;
	for(i=0; i<2; i++)								//i<2 是因为数码管只有两位,即i取值0,1足够
	{
		LedC = wx[i];            			 /* 选通某一位数码管,例如i=0,即选通第0位 */
		LedD = dx[num[i]];          	 /* 通过码表数组将第i位要显示的数字转换成数码管能识别的编码 */
		delay(10);                     /* 微量延时,用于显示保持 */
		LedD=0x00;										 //消隐
	}
}

void transform()														//数位转换
{
	if(t>0&&t<11)    				  //红灯时的倒计时
	{
		num[0]=(11-t)/10;				//十位
		num[1]=(11-t)%10;				//个位
	}
	else if(t>10&&t<14)				//黄灯时的倒计时
	{
		num[0]=(14-t)/10;				//十位
		num[1]=(14-t)%10;				//个位
	}
	else if(t>13)						//绿灯时的倒计时
	{
		num[0]=(24-t)/10;				//十位
		num[1]=(24-t)%10;				//个位
	}
}

void twinkle()				//数码管00闪烁		
{	
	j%=100;															//j<50
	if(j<50)								//j<25时,数码管亮
	{
		delay(20);
		LedC=0xfc;						//两位数码管一起选中   1111 1100
		LedD=dx[0];						//显示0
	}
	else															//j>=25,数码管不亮
	{
		delay(20);
		LedC=0xff;											//数码管都不选通
	}
	j++;
}


void int0() interrupt 0							//紧急通行 红灯 00闪烁  外部中断0服务函数
{
	key1++;					
	key1%=2;													//key1取值0、1
	clear();													//排除干扰
}

void int1() interrupt 2							//夜间 黄灯 00闪烁	外部中断1服务函数
{
	key2++;
	key2%=2;													//key2取值0、1
	clear();
}

void count() interrupt 3								//计时  定时器1中断服务函数
{
	if(key1||key2)
		return;														//若正在紧急状态,则直接回到主函数,不执行下列语句
	
	i++;
	if(i==10000)												//0.1ms*10000=1s
	{
		t++;															//秒数+1
		transform();
		i%=10000;													//i每次余10000,确保i的值处于0-100之间,避免溢出
		if(t==1)
		{
			red=1;
			yellow=0;
			green=0;
		}
		else if(t==11)
		{
			red=0;
			yellow=1;
			green=0;
		}
		else if(t==14)
		{
			red=0;
			yellow=0;
			green=1;
		}														//t记录当前秒数
		t%=23;
	}
}

void delay(unsigned char t)							//延时
{
	unsigned char i,j;
	for(i=0; i<20; i++)
		for(j=0; j<t; j++);
}

运行结果:
在这里插入图片描述

懒人一键下载链接

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值