基于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 图像识别,实现交通灯的自动化控制。
/****************************************交通灯程序*********************************************/
/*
作者: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秒
}
}
有问题可以私信我。