基于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秒
	}
}

有问题可以私信我。

以下是基于51单片机的红绿灯仿真的步骤和代码: 1. 确定硬件电路,包括LED灯、数码管、按键等元件的连接方式和电路图。 2. 在Keil中新建一个工程,编写C语言程序。 3. 在程序中定义各个元件的引脚,例如LED灯的引脚为P1.0,数码管的引脚为P2。 4. 编写程序实现红绿灯的交替显示,可以使用定时器和外部中断来控制灯的状态转换。 5. 编写程序实现数码管的倒计时显示,可以使用定时器和计数器来实现。 6. 编写程序实现按键的检测和响应,例如按下按键可以切换灯的状态或者停止倒计时。 以下是示例代码: ```c #include <reg52.h> sbit LED_RED = P1^0; sbit LED_YELLOW = P1^1; sbit LED_GREEN = P1^2; sbit KEY = P3^2; sbit DIGIT_A = P2^0; sbit DIGIT_B = P2^1; sbit DIGIT_C = P2^2; sbit DIGIT_D = P2^3; sbit DIGIT_E = P2^4; sbit DIGIT_F = P2^5; sbit DIGIT_G = P2^6; sbit DIGIT_DP = P2^7; unsigned char code DIGIT_TABLE[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; unsigned char code TIME_TABLE[] = { 60, 50, 40, 30, 20, 10 }; unsigned char current_time = 0; unsigned char current_state = 0; void delay(unsigned int ms) { unsigned int i, j; for (i = 0; i < ms; i++) { for (j = 0; j < 110; j++); } } void display_digit(unsigned char digit, unsigned char dp) { DIGIT_A = (digit & 0x01) ? 0 : 1; DIGIT_B = (digit & 0x02) ? 0 : 1; DIGIT_C = (digit & 0x04) ? 0 : 1; DIGIT_D = (digit & 0x08) ? 0 : 1; DIGIT_E = (digit & 0x10) ? 0 : 1; DIGIT_F = (digit & 0x20) ? 0 : 1; DIGIT_G = (digit & 0x40) ? 0 : 1; DIGIT_DP = dp ? 0 : 1; } void display_time(unsigned char time) { unsigned char digit1, digit2; digit1 = time / 10; digit2 = time % 10; display_digit(DIGIT_TABLE[digit1], 0); delay(5); display_digit(DIGIT_TABLE[digit2], 1); delay(5); } void timer0_isr() interrupt 1 { TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; current_time--; if (current_time == 0) { current_state++; if (current_state > 2) { current_state = 0; } switch (current_state) { case 0: LED_RED = 1; LED_YELLOW = 0; LED_GREEN = 0; current_time = TIME_TABLE[0]; break; case 1: LED_RED = 1; LED_YELLOW = 1; LED_GREEN = 0; current_time = TIME_TABLE[1]; break; case 2: LED_RED = 0; LED_YELLOW = 0; LED_GREEN = 1; current_time = TIME_TABLE[2]; break; } } } void main() { TMOD = 0x01; TH0 = (65536 - 50000) / 256; TL0 = (65536 - 50000) % 256; ET0 = 1; EA = 1; TR0 = 1; while (1) { display_time(current_time); if (KEY == 0) { delay(10); if (KEY == 0) { current_state = 0; LED_RED = 1; LED_YELLOW = 0; LED_GREEN = 0; current_time = TIME_TABLE[0]; while (KEY == 0); } } } } ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值