51单片机——交通灯

2023-11-02

原理图

在这里插入图片描述

功能描述

  1、基本功能就是如同红绿灯一般,不做赘述。
  2、红灯时长和绿灯时长可通过按键设置,即按键列中的上面4个,当这4个按键有一个按下后便进入时长设置功能,设置完成后按最下面两个按键(紧急控制按钮)任意一个便可退出该功能。
  3、有紧急控制功能,按下紧急控制按钮后,便进入该功能,保持红灯或绿灯常亮,且关闭数码管,当按下时长控制按钮即最上面的4个按钮便可退出该功能。

效果展示

在这里插入图片描述

代码

#include <reg52.h>

//数码管选择位
sbit EW_1=P1^0;		   
sbit EW_2=P1^1;
sbit NS_1=P1^2;		   
sbit NS_2=P1^3;

sbit add_red_time=P1^4;		   		//加红灯时间按钮
sbit add_green_time=P1^5;	   		//加绿灯时间按钮
sbit reduce_red_time=P1^6;		   	//减红灯时间按钮
sbit reduce_green_time=P1^7;	   	//减绿灯时间按钮
sbit NS_led=P2^6;	   				//南北向灯紧急控制按钮
sbit EW_led=P2^7;	   				//东西向灯紧急控制按钮

sbit EW_red=P2^0;	   				//东西向红灯
sbit EW_green=P2^1;	   				//东西向绿灯
sbit EW_yellow=P2^2;	   		    //东西向黄灯
sbit NS_red=P2^3;	   				//南北向红灯
sbit NS_green=P2^4;	   				//南北向绿灯
sbit NS_yellow=P2^5;	   			//南北向黄灯


char count=0;						//计数,count=20表示1s
char red_time=30;					//红灯停留时间
char green_time=25;					//绿灯停留时间
char yellow_time=0;					//黄灯停留时间
char NS_second=0;					//南北红绿灯秒计时
char EW_second=0;		    		//东西红绿灯秒计时
char code smgduan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};		//共阳数码管段码表,仿真中用的是共阴数码管,所以使用时需对段码取反
char display_data[4]={0};			//show_data[0]显示南北计时十位,show_data[1]显示南北计时个位,show_data[2]显示东西计时十位,show_data[3]显示东西计时个位
char temp_data[4]={0};

char NS_R_G_mode=0;					//南北红绿灯亮模式  0  红灯  1  绿灯  2  黄灯
char EW_R_G_mode=1;					//东西红绿灯亮模式  0  红灯  1  绿灯  2  黄灯

bit NS_R_G_flag=0;					//南北红绿灯标识位  0  红灯  1  绿灯 
bit EW_R_G_flag=0;					//东西红绿灯标识位  0  红灯  1  绿灯 

void delay(unsigned int i)			//简单延时
{
	while(i--);
}

void Timer_init()					//定时器初始化
{
	//定时50ms
    TMOD = 0x01;					//定时器方式1
    TH0 = 0x3C;						//定时器赋初值
    TL0 = 0xB0;
    EA = 1;							//开启总中断
    ET0 = 1;						//开启定时器中断
    TR0 = 1;						//开启定时器
}

void Init()							//系统初始化
{
	P0=0x00;
	P2=0x00;
	EW_1=1;		   
	EW_2=1;
	NS_1=1;
	NS_2=1;
	NS_led=1;
	EW_led=1;
	NS_second=red_time;				//默认初始时南北向灯亮红灯,并赋红灯时长
	EW_second=green_time;			//默认初始时东西向灯亮绿灯,并赋绿灯时长
	yellow_time=red_time-green_time;//黄灯时间为红灯时间与绿灯时间差
	Timer_init();
}

void NS_SMG_drive(char *buff)		//南北向数码管驱动
{
	//显示十位
	NS_1=0;
	NS_2=1;
	P0=~smgduan[buff[0]];           //段码取反
	delay(5); 						//间隔一段时间扫描	
	P0=0x00;						//消隐

	//显示个位
	NS_1=1;
	NS_2=0;
	P0=~smgduan[buff[1]];
	delay(5); 
	P0=0x00;

	//关闭南北向数码管
	NS_1=1;
	NS_2=1;
}

void EW_SMG_drive(char *buff)		//东西向数码管驱动
{
	//显示十位
	EW_1=0;
	EW_2=1;
	P0=~smgduan[buff[2]];           //段码取反
	delay(5); 						//间隔一段时间扫描	
	P0=0x00;						//消隐

	//显示个位
	EW_1=1;
	EW_2=0;
	P0=~smgduan[buff[3]];
	delay(5); 	
	P0=0x00;

	//关闭东西向数码管
	EW_1=1;		   
	EW_2=1;
}

void data_del(char *buff,char data1,char data2)	//数据处理
{
	buff[0]=data1/10;							//取data1的十位
	buff[1]=data1%10;							//取data1的个位
	buff[2]=data2/10;							//取data2的十位
	buff[3]=data2%10;							//取data2的个位
}

void Time_del()									//计时处理
{
	if(count>=20)								//判断是否满1s
	{
		NS_second--;							//南北向灯计时自减
		EW_second--;							//东北向灯计时自减
		switch(NS_R_G_mode)						//南北向灯
		{
			case 0:								//红灯
			{
				if(NS_second<0)
				{
					NS_second=green_time;		//开始绿灯倒计时
					NS_R_G_mode=1;   			//红灯亮完绿灯亮
				}				
			}break;
			case 1:								//绿灯
			{
				if(NS_second<0)
				{
					NS_second=yellow_time;		//开始黄灯倒计时
					NS_R_G_mode=2;   			//绿灯亮完黄灯亮					
				}		
			}break;
			case 2:								//黄灯
			{
				if(NS_second<0)
				{
					NS_second=red_time;			//开始红灯到计时
					NS_R_G_mode=0;   			//黄灯亮完红灯亮					
				}		
			}break;
			default:break;
		}
		switch(EW_R_G_mode)						//东西向灯
		{
			case 0:								//红灯
			{
				if(EW_second<0)
				{
					EW_second=green_time;		//开始绿灯倒计时
					EW_R_G_mode=1;   			//红灯亮完绿灯亮
				}				
			}break;
			case 1:								//绿灯
			{
				if(EW_second<0)
				{
					EW_second=yellow_time;		//开始黄灯倒计时
					EW_R_G_mode=2;   			//绿灯亮完黄灯亮					
				}		
			}break;
			case 2:								//黄灯
			{
				if(EW_second<0)
				{
					EW_second=red_time;			//开始红灯倒计时
					EW_R_G_mode=0;   			//黄灯亮完红灯亮					
				}		
			}break;
			default:break;
		}
		count=0;								//计数值清零
	}
}

void R_G_Y_led()								//红绿灯驱动
{
	switch(NS_R_G_mode)							//南北向
	{
		case 0:									//红灯
		{
			NS_yellow=0;						//黄灯灭
			NS_red=1;							//红灯亮
		}break;
		case 1:									//绿灯
		{
			NS_red=0;							//红灯灭
			NS_green=1;							//绿灯亮
		}break;
		case 2:									//黄灯
		{
			NS_green=0;							//绿灯灭
			if(count<10)						//黄灯以1hz频率闪烁
				NS_yellow=1;
			else
				NS_yellow=0;			
		}break;
		default:break;		
	}
	switch(EW_R_G_mode)							//东西向
	{
		case 0:									//红灯
		{
			EW_yellow=0;						//黄灯灭
			EW_red=1;							//红灯亮
		}break;
		case 1:									//绿灯
		{
			EW_red=0;							//红灯灭
			EW_green=1;							//绿灯亮
		}break;
		case 2:									//黄灯
		{
			EW_green=0;							//绿灯灭
			if(count<10)						//黄灯以1hz频率闪烁
				EW_yellow=1;
			else
				EW_yellow=0;			
		}break;
		default:break;		
	}
}

void Set_time()									//设置红绿灯亮的时长
{
	if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//设置红绿灯时长时任一设置按钮都可触发
	{
		TR0 = 0;								//关闭定时器
		P2=0x00;								//清零P2寄存器
		EW_led=1;								//EW_led、NS_led引脚也在P2寄存器内,但是后面需要这两个按钮结束设置红绿灯时长任务,故而这两个引脚要拉高
		NS_led=1;
		while(1)
		{
			data_del(temp_data,red_time,green_time);//显示当前红绿灯时长
			NS_SMG_drive(temp_data);
			EW_SMG_drive(temp_data);
			if(add_red_time==0)					//判断加红灯时间按钮是否按下
			{
				delay(5);						//消抖
				if(add_red_time==0)
				{
					red_time++;					//红灯时间自加
					if(red_time>99)				//限制红灯时间最大值为99
						red_time=99;
					data_del(temp_data,red_time,red_time);//南北向数码管显示红灯时长
					NS_SMG_drive(temp_data);
				}while(!add_red_time);			//等待加红灯时间按钮弹起
			}
			if(add_green_time==0)				//判断加绿灯时间按钮是否按下
			{
				delay(5);
				if(add_green_time==0)
				{
					green_time++;				//绿灯时间自加
					if(green_time>95)			//限制绿灯时间最大值95
						green_time=95;
					data_del(temp_data,green_time,green_time);//东西向数码管显示绿灯时长
					EW_SMG_drive(temp_data);
				}while(!add_green_time);		//等待加绿灯时间按钮弹起
			}
			if(reduce_red_time==0)				//判断减红灯时间按钮是否按下
			{
				delay(5);
				if(reduce_red_time==0)
				{
					red_time--;					//红灯时间自减
					if(red_time<10)				//限制红灯时间最小值10
						red_time=10;
					data_del(temp_data,red_time,red_time);
					NS_SMG_drive(temp_data);
				}while(!reduce_red_time);		//等待减红灯时间按钮弹起
			}
			if(reduce_green_time==0)			//判断减绿灯时间按钮是否按下
			{
				delay(5);
				if(reduce_green_time==0)
				{
					green_time--;				//绿灯时间自减
					if(green_time<5)			//限制绿灯时间最小值5
						green_time=5;
					data_del(temp_data,green_time,green_time);
					EW_SMG_drive(temp_data);
				}while(!reduce_green_time);		//等待减绿灯时间按钮弹起
			}
			if((NS_led==0)||(EW_led==0))		//任一紧急控制按钮按下则结束设置红路灯时长任务
			{
				break;
			}
		}while((!NS_led)||(!EW_led));			//等待紧急控制按钮弹起
		TR0 = 1;								//开启定时器
		yellow_time=red_time-green_time;		//更新黄灯时间
	}
}

void Urgent()									//红绿灯紧急控制
{
	if((NS_led==0)||(EW_led==0))				//任一紧急控制按钮按下触发
	{
		TR0 = 0;								//关闭定时器
		P2=0x00;
		EW_led=1;
		NS_led=1;

		EW_1=1;									//关闭所有数码管
		EW_2=1;
		NS_1=1;
		NS_2=1;
		while((!NS_led)||(!EW_led));			//判断紧急控制按钮按是否弹起
		while(1)
		{
			if(NS_R_G_flag)						//根据NS_R_G_flag状态交替亮红灯或者绿灯
			{
				NS_green=1;	
				NS_red=0;					
			}	
			else
			{
				NS_red=1;	
				NS_green=0;				
			}
			if(EW_R_G_flag)						//根据EW_R_G_flag状态交替亮红灯或者绿灯
			{
				EW_green=1;	
				EW_red=0;									
			}
			else
			{
				EW_red=1;
				EW_green=0;						
			}	
			if(NS_led==0)						//判断南北向紧急控制按钮是否按下
			{
				delay(5);
				if(NS_led==0)
				{
					NS_R_G_flag=!NS_R_G_flag;	//NS_R_G_flag状态取反				
				}while(!NS_led);				//等待南北向紧急控制按钮弹起
			}
			if(EW_led==0)						//判断东西向紧急控制按钮是否按下
			{
				delay(5);
				if(EW_led==0)
				{
					EW_R_G_flag=!EW_R_G_flag;	//EW_R_G_flag状态取反						
				}while(!EW_led);				//等待东西向紧急控制按钮弹起
			}	
			if((add_red_time==0)||(add_green_time==0)||(reduce_red_time==0)||(reduce_green_time==0))//任一红绿灯设置时长按钮按下结束紧急控制人物
			{
				TR0 = 1;						//开启定时器
				break;
			}
		}while((!add_red_time)||(!add_green_time)||(!reduce_red_time)||(!reduce_green_time));//等待红绿灯时间设置按钮弹起	
		P2=0x00;
		EW_led=1;
		NS_led=1;
	}
}

void main()
{
	Init();
	while(1)
	{
		Time_del();								//时间处理
		data_del(display_data,NS_second,EW_second);//数据处理
		NS_SMG_drive(display_data);				//南北向数码管驱动
		EW_SMG_drive(display_data);				//东西向数码管驱动
		R_G_Y_led();							//红绿灯驱动
		Set_time();								//红绿灯时长设置
		Urgent();								//紧急控制
	}
}

void Timer0(void) interrupt 1					//定时器中断
{
    TH0 = 0x3C;
    TL0 = 0xB0;
	count++;									//触发中断后计数值自加,定时器中断每50ms触发一次
}


工程下载

链接:https://pan.baidu.com/s/1P0Gj6PmNfffJdsEe5j6JGA
提取码:0yzj

由于后续发现了些小问题,程序有所修改,网盘中的代码由于一些原因暂时不能更新,以本篇博客为准。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

51单片机——交通灯 的相关文章

  • SNIP算法详解(极端尺寸目标检测)

    SNIP算法详解 极端尺寸检测 论文背景 算法背景 算法详情 主要问题 已有解决方案 研究现状 思考问题 SNIP算法 多尺寸图片分类器对比实验 Deformable RFCN 实例尺寸与数据对检测器的影响实验 SNIP算法细节 实验 结论
  • 【解决】解决联想小新pro14不能通过VMware打开虚拟机(打开虚拟机之后蓝屏)的问题

    步骤 1 打开控制面板 2 选择 系统与安全 gt 程序 gt 启用或关闭Windows功能 3 勾选虚拟机平台 4 问题完美解决 总结 还未尝试过小新系列的其他电脑是否也可以解决 下次可以尝试一下
  • Python时间序列预测——SARIMA季节性自回归综合移动平均

    简介 季节性自回归综合移动平均 SARIMA 或季节性ARIMA是ARIMA的一个扩展 它明确支持具有季节性分量的单变量时间序列数据 它增加了三个新的超参数来指定序列季节性成分的自回归 AR 差分 I 和移动平均 MA 以及季节性周期的附加
  • Rsync了解

    Rsync Rsync 实现全量及增量的本地或远程数据镜像同步备份的优秀工具 https www samba org ftp rsync rsync html 传统的cp scp 工具拷贝每次均为完整的拷贝 而rsync除了可以完整拷贝外

随机推荐

  • maven配置settings.xml(腾讯云)

    jdk默认版本 1 8
  • vue鼠标停留变成小手

    在style里加 cursor pointer 鼠标悬停变小手
  • 基于ISO13209(OTX)实现EOL下线序列

    一 OTX是什么 OTX 全称Open Test Sequence Exchange Format 即开放式测试序列交换格式 国际标准 ISO13209 是专为汽车行业制定的序列开发标准 在车辆诊断 自动化标定和ECU测试等领域有广泛应用
  • 牛客网刷题第三天

    HJ32 密码截取 首先确定回文串 就是找中心然后向两边扩散看是不是对称的就可以了 在遍历中心点的时候 要注意中心点有两种情况 一个元素可以作为中心点 两个元素也可以作为中心点 import java util 注意类名必须为 Main 不
  • Java 时间格式之间的相互转换(Date、Calendar、timestamp时间戳)

    存在以下6种情况 目录 1 Date gt Calendar 2 Date gt 时间戳 3 Calendar gt 时间戳 4 Calendar gt Date 5 时间戳 gt Date 6 时间戳 gt Calendar 1 Date
  • 8. F5负载均衡配置一例 (型号:BIG-LTM-1600-4G-R)

    F5 提供的解决方案保证每个用户的应用实现安全 高速和高可用 帮助企业获得最大投资回报 通过在网络中增加智能和可管理性而降低应用的负荷 F5使应用得以优化 从而提高运行速度 并降低资源消耗 此次实施的F5型号为BIG LTM 1600 4G
  • hkpic forum.php,www.bi-si2.xyz

    Domain Name BI SI2 XYZ Registry Domain ID D74084834 CNIC Registrar WHOIS Server whois godaddy com Registrar URL https ww
  • rabbitmq简单示例

    1 pom文件引入rabbitmq
  • Java Collections unmodifiableSet()方法具有什么功能呢?

    转自 Java Collections unmodifiableSet 方法具有什么功能呢 下文讲述unmodifiableSet 方法的功能简介说明 如下所示 unmodifiableSet 方法的功能 返回一个不可修改的Set视图 un
  • 灰灰快醒醒的第一篇博客

    自我介绍 哈喽哈喽大家好哇 我是来自西安邮电大学的软件工程的大一学生哦 因为对编程的喜爱 打开了CSDN的大门 很高兴与大家在此见面 我是个阳光开朗的大学生 非常愿意与各位分享编程学习的知识和经验 然后近期正在重学C语言 非常愿意在平台上分
  • JS Object.assign()方法

    作用 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象 它将返回目标对象 实例 const one a 1 b 2 const two c 3 d 4 var three Object assign e 5 one two 打印结果
  • openwrt编译x86固件 VMware安装镜像

    x86 看到这里相信你们已经把镜像编译完成了 如下图所示 两个镜像 对应两个不同的文件系统 想办法把他拷贝到windows物理机上面去 你可以用U盘拷贝 还可以用ftp方式拷贝 具体方法就百度去啦 新建虚拟机 操作系统类型选择其他 一直下一
  • 如何看懂UDS诊断报文

    UDS介绍 UDS Unified Diagnostic Services 统一的诊断服务 诊断协议是ISO 15765 和ISO 14229 定义的一种汽车通用诊断协议 位于OSI模型中的应用层 它可在不同的汽车总线 例如CAN LIN
  • 未能找到服务器主机名,未能找到主机名服务器

    未能找到主机名服务器 内容精选 换一换 用户使用hostname命令查看不同镜像的裸金属服务器主机名 发现部分镜像的裸金属服务器主机名带后缀 novalocal 如示例所示 假设创建裸金属服务器时 用户自定义的主机名是abc 使用hostn
  • html的单选框和复选框

    div 性别 div
  • 安装nvidia-tensorflow时出现Preparing metadata (setup.py) ... error

    问题描述 安装nvidia tensorflow时执行语句 pip install nvidia tensorflow horovod 出现如下错误 这里的错误非常令人头疼 GitHub上nvidia官方论坛里的讨论贴也无法解决 问题原因
  • 微信小程序Invalid attempt to spread non-iterable instance解决办法

    微信小程序Invalid attempt to spread non iterable instance解决办法 原因 在js中给列表元素赋初值空 并且从缓存中取值赋给该列表元素 如 data daily 同时存在另一个数据 每次进入该页面
  • 前端vue elementUI upload上传组件封装&多文件上传&进度条,后端servlet request.getPart()接收文件信息

    vue upload组件 选中多个文件上传 通过axios请求 onUploadProgress方法监听 on progress on success用这两个钩子函数实现进度条 下面有对应的函数 本文是每个文件一个请求上传 也可以用一个请求
  • C程序的运行

    程序的翻译环境和执行环境 翻译环境 在这个环境中 源代码被转化为可执行的机器指令 执行环境 在这个环境中 执行代码 程序的运行过程 1 编译和链接 翻译环境 我们写出的代码文件叫做源代码 这样的源代码要经过编译和链接生成可执行文件才能真正执
  • 51单片机——交通灯

    原理图 功能描述 1 基本功能就是如同红绿灯一般 不做赘述 2 红灯时长和绿灯时长可通过按键设置 即按键列中的上面4个 当这4个按键有一个按下后便进入时长设置功能 设置完成后按最下面两个按键 紧急控制按钮 任意一个便可退出该功能 3 有紧急