基于51单片机的交通灯设计(含完整代码、Proteus仿真、原理图及芯片头文件等资料)

基于51单片机的交通灯设计(附有Proteus仿真和原理图)
该设计,难点在于程序编写时对于定时器中断,标志位的灵活使用,其次是对数码管的控制。
注:
1.单片机型号是“stc10f08xe”,Keil软件中不包含stc10.h这个头文件,与原理图和仿真文件一起附在附件中了。
2.此型号的单片机端口驱动能力不够,采用的推挽输出,增强对小灯的驱动能力,改善实际显示效果
3.按下plus button 可以增加此干道的通行时间,minus button可以减少通行时间,stop button对应紧急情况,所有路口红灯亮。
4.下载附件后若无法查看,建议修改文件格式为“zip”,然后解压查看。
资料链接:[基于51单片机的交通灯设计(含原理图,程序源码和Proteus仿真).zip
(17个子文件)]

//2024/04/20新增内容:
5.可以优化的部分有哪些呢:
(1)增加左转/右转功能
(2)提高部分,设置一个忙碌因子“车流量P”,可以根据这个因子来调节路口绿灯时间。做接口出来,就可以对接AI 图像识别,实现交通灯的自动化控制。

交通灯仿真界面图仿真启动显示通行时间,主干道绿灯亮,次干道红灯亮绿灯通行结束后,有3秒的等待时间,黄灯亮起紧急情况,所有路口红灯亮

/****************************************交通灯程序*********************************************/
/*
	作者:Eric 
	功能:以南北方向为主干道,东西方向为次干道。		
			1、实现主干道通行15秒转通行注意状态,黄灯亮3秒。这段时间内次干道保持红灯常亮  (由数码管显示时间)
			2、次干道通行10秒转通行注意状态,黄灯亮2秒。这段时间内主干道保持红灯常亮      (由数码管显示时间)
			3、紧急按键按下,所有路口红灯 
			
/************************************调用头文件、宏定义*****************************************/
#include<stc10.h>
#define D P1
#define uchar unsigned char
#define uint unsigned int
/*******************************************函数声明******************************************/
void south_north_green_light(void);	 // 南北通
void south_north_yellow_light(void); // 南北注意
void east_west_green_light(void);	 // 东西通
void east_west_yellow_light(void);	 // 东西注意
void close_all_light(void);			 // 全关
void open_all_red_light(void);		 // 紧急状态,红灯全亮
void scan_keys(void);				 // 键盘扫描
void south_north_plus_1_second();	 // 按键加一秒
void south_north_minus_1_second();	 // 按键减一秒
void east_west_plus_1_second();
void east_west_minus_1_second();
void timer(void);	// 定时器T1初始化
void time1(void);	// 定义定时器T1中断服务程序
void display(void); // 显示函数
void delay(uint a); // 10ms延时函数
/*************************************定义数组,全局变量***************************************/
// 0~9 数码管段选
uint duan[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};

// 定时器溢出计数,即时钟敲了多少下以后,产生一次计时器中断
uint count_50_ms_num;	//中断计数
uint second_count; 		//秒计数

// 数码管显示的数字
uint gw;  // 南北十位
uint sw;  // 南北个位
uint gw2; // 东西十位
uint sw2; // 东西个位

// 路口控制时间
int time_south_north_total; // south north green light time_south_north_total + yellow light time_south_north_total 
int time_south_north_green; // south north green light time_south_north_total
int time_east_west_total;   // east west green light time_south_north_total + yellow light time_south_north_total
int time_east_west_green;   // east west green light time_south_north_total

int time_yellow_light;

/*************************外界模块:定义12个小灯、数码管位、按键****************************/
/************* 12个 LED *******************/
sbit d1 = P2 ^ 0; //west 
sbit d2 = P2 ^ 1;
sbit d3 = P2 ^ 2;
sbit d4 = P2 ^ 3; //north
sbit d5 = P2 ^ 4;
sbit d6 = P2 ^ 5;
sbit d7 = P2 ^ 6; //east
sbit d8 = P2 ^ 7;
sbit d9 = P3 ^ 2;
sbit d10 = P3 ^ 3;//south
sbit d11 = P3 ^ 4;
sbit d12 = P3 ^ 5;

// 数码管位选//
sbit w1 = P0 ^ 0;
sbit w2 = P0 ^ 1;
sbit w3 = P0 ^ 2;
sbit w4 = P0 ^ 3;

/* 按键分布
  --LINE1----KEY1--KEY2--KEY3
  --LINE2----KEY4--KEY5--KEY6
*/
sbit LINE1 = P3 ^ 6;
sbit LINE2 = P3 ^ 7;
sbit key1 = P0 ^ 5; // if LINE2 ,key4
sbit key2 = P0 ^ 6; // if LINE2 ,key5
sbit key3 = P0 ^ 7; // if LINE2 ,key6

/******************不同状态函数、定时器初始化、定时器中断服务函数************************/
void south_north_green_light() // 南北通行,东西禁止
{
	while (second_count < time_south_north_total)
	{
		scan_keys();
		south_north_plus_1_second();
		south_north_minus_1_second();
		if (TR1 == 1)
		{
			// 蓝   /黄   /红
			d4 = 0;
			d5 = 1;
			d6 = 1; // 北
			d10 = 0;
			d11 = 1;
			d12 = 1; // 南
			d7 = 1;
			d8 = 1;
			d9 = 0; // 东
			d1 = 1;
			d2 = 1;
			d3 = 0; // 西
		}
		sw2 = (time_south_north_green - second_count) / 10; // 数码管十位(南北主干道)
		gw2 = (time_south_north_green - second_count) % 10; // 数码管个位
		sw = (time_south_north_total - second_count) / 10;
		gw = (time_south_north_total - second_count) % 10;
		display();		   // 显示
		close_all_light(); // 关闭
	}
	second_count = 0; // 对定时时间标志位清零重置
}
void south_north_yellow_light() // 南北注意,东西禁止
{
	time_yellow_light = 3;
	while (second_count < time_yellow_light)
	{
		scan_keys();
		if (TR1 == 1)
		{
			// 蓝   /黄   /红
			d4 = 1;
			d5 = 0;
			d6 = 1; // 北
			d10 = 1;
			d11 = 0;
			d12 = 1; // 南
			d7 = 1;
			d8 = 1;
			d9 = 0; // 东
			d1 = 1;
			d2 = 1;
			d3 = 0; // 西
		}
		sw2 = (time_yellow_light - second_count) / 10; // 数码管十位(南北主干道)
		gw2 = (time_yellow_light - second_count) % 10; // 数码管个位
		sw = sw2;						   // 东西次干道
		gw = gw2;
		display();					  // 显示
		close_all_light());			  //关闭
	}
	second_count = 0; // 对定时时间标志位清零重置
}
void east_west_green_light() // 东西通行,南北禁止
{

	while (second_count < time2)
	{
		scan_keys();
		east_west_plus_1_second();
		east_west_minus_1_second();
		// 蓝   /黄   /红
		d4 = 1;
		d5 = 1;
		d6 = 0; // 北
		d10 = 1;
		d11 = 1;
		d12 = 0; // 南
		d7 = 0;
		d8 = 1;
		d9 = 1; // 东
		d1 = 0;
		d2 = 1;
		d3 = 1; // 西
		sw2 = (time_east_west_total - second_count) / 10;// 南北主干道
		gw2 = (time_east_west_total - second_count) % 10;
		sw = (time_east_west_green - second_count) / 10; // 数码管十位(东西次干道)
		gw = (time_east_west_green - second_count) % 10; // 数码管个位
		display();						  // 显示
		close_all_light();				  // 关闭
	}
	second_count = 0; // 对定时时间标志位清零重置
}
void east_west_yellow_light() // 东西注意,南北禁止
{
	time_yellow_light = 2;
	while (second_count < time_yellow_light)
	{
		scan_keys();
		// 蓝   /黄   /红
		d4 = 1;
		d5 = 1;
		d6 = 0; // 北
		
		d10 = 1;
		d11 = 1;
		d12 = 0; // 南
		
		d7 = 1;
		d8 = 0;
		d9 = 1; // 东
		
		d1 = 1;
		d2 = 0;
		d3 = 1;							  // 西
		
		sw = (time_yellow_light - second_count) / 10; // 东西次干道_数码管十位
		gw = (time_yellow_light - second_count) % 10; // 东西次干道_数码管个位
		sw2 = sw;						  // 南北主干道
		gw2 = gw;
		display();		   // 显示
		close_all_light(); // 关闭
	}
	second_count = 0; // 对定时时间标志位清零重置
}
void open_all_red_light() // 红灯全亮,其余全灭,紧急状态
{
	// 蓝   /黄   /红
	d4 = 1;
	d5 = 1;
	d6 = 0; // 北

	d10 = 1;
	d11 = 1;
	d12 = 0; // 南
	
	d7 = 1;
	d8 = 1;
	d9 = 0; // 东
	
	d1 = 1;
	d2 = 1;
	d3 = 0; // 西
}
void close_all_light() // 全部关闭
{
	// 蓝   /黄   /红
	d4 = 1;
	d5 = 1;
	d6 = 1; // 北
	
	d10 = 1;
	d11 = 1;
	d12 = 1; // 南
	
	d7 = 1;
	d8 = 1;
	d9 = 1; // 东
	
	d1 = 1;
	d2 = 1;
	d3 = 1; // 西
}
void delay(uint a) //@11.0592MHz	10ms延时(使用烧录软件生成的延时代码)
{
	for (a; a > 0; a--)
	{
		unsigned char i, j;
		i = 18;
		j = 235;
		do
		{
			while (--j)
				;
		} while (--i);
	}
}
void display() // 数码管显示
{
	w1 = 0; // 十位
	LED_P1 = duan[sw];
	delay(1);
	w1 = 1;
	LED_P1 = 0X00;
	w2 = 0; // 个位
	LED_P1 = duan[gw];
	delay(1);
	w2 = 1;
	LED_P1 = 0x00;
	
	w3 = 0; // 十位
	LED_P1 = duan[sw2];
	delay(1);
	w3 = 1;
	LED_P1 = 0X00;
	w4 = 0; // 个位
	LED_P1 = duan[gw2];
	delay(1);
	w4 = 1;
	LED_P1 = 0x00;
}
void timer1(void)
{
	TMOD = 0X10;
	TH1 = (65536 - 50000) / 256; // 50ms定时
	TL1 = (65536 - 50000) % 256;
	EA = 1;
	ET1 = 1;
	TR1 = 1;
}
void time1_isr(void) interrupt 3 // 定时器T1中断服务程序
{
	TH1 = (65536 - 50000) / 256; // 50ms定时
	TL1 = (65536 - 50000) % 256;
	count_50_ms_num++;
	if (count_50_ms_num == 20) // 20 * 50ms = 1000ms , -> 1s
	{
		second_count++; // second++
		count_50_ms_num = 0;
	}
}

/************************************ keys operation *************************************************/ 
void scan_keys(void) // 键盘扫描函数
{
	LINE1 = 0;	   // 按键另一端置0,当按键按下相当于接地,由原理图,没有按下时,通过上拉电阻拉高了
	if (key1 == 0) // 判断按键是否按下
	{
		delay(2);		  // 消抖
		while (!key1)	  // 松手检测
			TR1 = !TR1;	  // 关闭定时器
		while (key1 == 1) // 四个方向全为红灯,进入紧急状态
		{
			close_all_light();
			open_all_red_light(); // 打开紧急状态
			gw = gw2 = sw = sw2 = 8;
			display();
		}
		while (key1 == 0) // 松手检测
			display();
		TR1 = 1; // 打开定时器,跳出
	}
}
void south_north_plus_1_second()
{
	LINE1 = 0;	   // 按键另一端置0,当按键按下相当于接地,由原理图,没有按下时,通过上拉电阻拉高了
	if (key2 == 0) // 判断按键是否按下
		delay(2);  // 消抖
	if (key2 == 0)
	{
		time_south_north_total += 1;
		time_south_north_green += 1;
	}
	while (!key2); // 松手检测
}
void south_north_minus_1_second()
{
	LINE1 = 0;	   // 按键另一端置0,当按键按下相当于接地,由原理图,没有按下时,通过上拉电阻拉高了
	if (key3 == 0) // 判断按键是否按下
		delay(2);  // 消抖
	if (key3 == 0)
	{
		time_south_north_total -= 1;
		time_south_north_green -= 1;
	}
	while (!key3); // 松手检测
}
void void east_west_plus_1_second()
{
	LINE2 = 0;	   // 按键另一端置0,当按键按下相当于接地,由原理图,没有按下时,通过上拉电阻拉高了
	if (key2 == 0) // 判断按键是否按下,在这里相当于key5
		delay(2);  // 消抖
	if (key2 == 0)
	{
		time_east_west_total += 1;
		time_east_west_green += 1;
	}
	while (!key2); // 松手检测
}
void east_west_minus_1_second()
{
	LINE2 = 0;	   // 按键另一端置0,当按键按下相当于接地,由原理图,没有按下时,通过上拉电阻拉高了
	if (key3 == 0) // 判断按键是否按下,这里相当于key6
		delay(2);  // 消抖
	if (key3 == 0)
	{
		time_east_west_total -= 1;
		time_east_west_green -= 1;
	}
	while (!key3); // 松手检测
}

/*********************************************主函数***********************************************/
void main(void)
{
	// default cross time_south_north_total
	time_south_north_total 	= 18; 	
	time_south_north_green 	= 15; 	
	time_east_west_total 	= 12;	
	time_east_west_green 	= 10;	

	count_50_ms_num = 0;	// 定时器溢出计数初始化
	second_count = 0; 		

	// 设置推挽输出,增加数码管亮度
	P1M1 = 0X00;			
	P1M0 = 0XFF;
	timer(); 	// 启动定时器T1
	while (1)
	{
		south_north_green_light();	// 主干道(南北)通行,绿灯15秒
		south_north_yellow_light(); // 主干道(南北)注意,黄灯 3秒
		east_west_green_light();	// 次干道(东西)通行,绿灯10秒
		east_west_yellow_light();	// 次干道(东西)注意,黄灯 2秒
	}
}

有问题可以私信我。

  • 44
    点赞
  • 389
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值