前言
随着各种陆路交通运输工具的飞速发展,交通灯也在我们的日常生活中,发挥了越来越大的作用。本试验通过单片机控制LED以及数码管,来模拟现实生活中的交通灯工作情形。
模拟试验中,南北方向的红绿灯分别用LED1和LED2表示,东西方向的红绿灯用LED5
和LED6表示,用数码管显示倒计时时间。交通灯的控制可以分为自动控制方式和人工控制方式:正常情况下,交通灯处于自动控制方式,此时东西方向和南北方向的交通灯轮流导通;特殊情况下,可以通过人工控制方式延长南北方向或东西方向交通灯的导通时间。
设计要求如下:
设计三个按键K1、K2、K3;K1为“自动”方式,K2位“南北”方向交通导通,K3为“东西”方向交通导通
用四个LED模拟交通灯:LED1为南北方向“红”灯;LED2为南北方向“绿”灯;LED5为东西方向“红”灯;LED6为东西方向“绿”灯
系统开始上电后,系统处于自动控制方式:
A.系统上电后,首先是南北方向交通导通,LED1灭、LED2亮、LED5亮、LED6灭,数码管从60秒开始倒计时,每隔1秒减1
B.倒计时到10秒时,南北方向绿灯(LED2)开始闪烁,闪烁间隔为0.5秒(亮、灭各0.5秒)
C.60秒倒计时结束之后,东西方向交通导通:LED1亮、LED2灭、LED5灭、LED6亮;数码管重新开始从60秒倒计时,每隔1秒减1
D.倒计时到10秒时,东西方向绿灯(LED6)开始闪烁,闪烁间隔为0.5秒(亮、灭各0.5秒)
E.60秒倒计时结束之后,操作同步骤A
在自动控制方式过程中,若按键K2或K3按下,则系统进入人工控制方式:
A.若K2键按下,则强制南北方向交通导通。此时若系统处于东西方向交通导通状态,则数码管从10秒开始倒计时,操作同步骤3 D,倒计时完成后进入南北交通导通状态,数码管显示“9999”,不递减
B.若K3键按下,则强制东西方向交通导通。此时若系统处于南北方向交通导通状态,则数码管从10秒开始倒计时,操作同步骤3 B,倒计时完成后进入东西交通导通状态,数码管显示“9999” ,不递减
在人工控制状态下,按下K1键进入自动控制状态:
A.若系统处于东西方向交通导通状态,则数码管从10秒开始倒计时,操作同步骤3 D,倒计时完成后进入南北交通导通状态,从步骤3 A进入自动控制状态。
B.若系统处于南北方向交通导通状态,则数码管从10秒开始倒计时,操作同步骤3 B,倒计时完成后进入东西交通导通状态,从步骤3 C进入自动控制状态。
一、如何在Proteus中快速找到目标元件
这就需要熟悉元件的英文名称,可以看下下面链接的博客,对找元件有很用处。
然后就是绘制原理图了
二、编写51代码
(部分)代码如下:
Delay.c 和Delay.h
//Delay.c
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
//Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
二、数码管的代码
//Nixie.c
#include <REGX52.H>
#include "Delay.h"
//共阴0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
//共阳数码管段码表 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
unsigned char NixieTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/**
* @brief 数码管扫描显示
* @param Location 要显示的位置,范围:1~8
* @param Number 要显示的数字,范围:段码表索引范围
* @retval 无
*/
void Nixie_Show(unsigned char Location,Number)
{
switch(Location) //位码输出
{
case 1:P2_4=0;P2_5=1;P2_6=1;P2_7=1;break;
case 2:P2_4=1;P2_5=0;P2_6=1;P2_7=1;break;
case 3:P2_4=1;P2_5=1;P2_6=0;P2_7=1;break;
case 4:P2_4=1;P2_5=1;P2_6=1;P2_7=0;break;
}
P0=NixieTable[Number]; //段码输出
Delay(10);
P0=0x00; //段码清0,消影
}
//Nixie.h
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie_Show(unsigned char Location,Number);
#endif
三、定时器的代码
//Timer0.c
#include <REGX52.H>
/**
* @brief 定时器0初始化,1毫秒@12.000MHz
* @param 无
* @retval 无
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 =(65536-50000)%256; //设置定时初值
TH0 = (65536-50000)/256; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
//Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
#endif
四、按键KEY的代码
//Key.c
#include <REGX52.H>
#include "Delay.h"
unsigned char Key_KeyNumber;
/**
* @brief 获取按键键码
* @param 无
* @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
*/
unsigned char Key(void)
{
unsigned char Temp=0;
Temp=Key_KeyNumber;
Key_KeyNumber=0;
return Temp;
}
/**
* @brief 获取当前按键的状态,无消抖及松手检测
* @param 无
* @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
*/
unsigned char Key_GetState()
{
unsigned char KeyNumber=0;
if(P3_0==0){KeyNumber=1;}
if(P3_1==0){KeyNumber=2;}
if(P3_2==0){KeyNumber=3;}
return KeyNumber;
}
/**
* @brief 按键驱动函数,在中断中调用
* @param 无
* @retval 无
*/
void Key_Loop(void)
{
static unsigned char NowState,LastState;
LastState=NowState; //按键状态更新
NowState=Key_GetState(); //获取当前按键状态
//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
if(LastState==1 && NowState==0)
{
Key_KeyNumber=1;
}
if(LastState==2 && NowState==0)
{
Key_KeyNumber=2;
}
if(LastState==3 && NowState==0)
{
Key_KeyNumber=3;
}
}
//Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key(void);
void Key_Loop(void);
#endif
三、 效果视频
交通灯仿真视频
总结
一次51单片机的实训,重新学习了Proteus如何查找对应的元件,并学习51单片机定时器的初始化、数码管的位选、段选、消影、按键的检测和消抖。尤其是数码管,得知道是共阳的还是共阴的
我选的数码管是共阴数码管。(想要代码和Proteus工程可以去工房购买 )