单片机P1口控制数码管段选,P2口控制数码管位选,P0口控制两边的灯光。
void SMG_shift()
{
P2=~(0x01<<shift);
switch(shift)
{
case 0:bits=second1/10; break;
case 1:bits=second1%10; break;
case 2:bits=second2/10; break;
case 3:bits=second2%10; break;
}
P1=smg[bits];
shift=(shift+1)%4;
}
首先是数码管控制函数,声明一个变量shift作为数码管位移量,首先进行位选,这里数码管使用的是共阴极数码管,所以位选脚为低时点亮,因为位移时除了置1的位保持1,其他的位都会变成0(例如0x01<<1是0x02,0xfe<<1是0x0xfc),为了避免位移时会点亮其他数码管,这里对0x01位移后进行取反,switch语句对变量bits赋值,结合数码管段码表达到第一位显示计时器一的十位,第二位显示计时器二并以此类推的效果。
void timer()
{
if(second<=60 && second>33) //左绿灯右红灯
{
status1=1;
status2=3;
second1=second-33; //左边倒计时为second-33
second2=second-30;
}
if(second<=33 && second>30) //左黄灯右红灯
{
status1=2;
status2=3; //此时左右倒计时相等
second2=second-30;
second1=second2;
}
if(second<=30 && second>3) //左红灯右绿灯
{
status1=3;
status2=1;
second1=second; //左倒计时等于second
second2=second-3; //右倒计时比左倒计时少3秒
}
if(second<=3 && second>=0) //左红灯右黄灯
{
status1=3;
status2=2;
second1=second;
second2=second;
}
second--;
if(second==0)
second=60;
}
倒计时的效果用变量second实现,将一个红绿灯周期设定为60秒,则在60秒中需要实现左绿右红,左黄右红,左红右绿,左红右黄的循环,黄灯占用3秒,绿灯27秒,红灯30秒,在倒计时函数中分别对计时器一二进行赋值,显示当前灯的剩余时间,对status赋值控制灯的变化。
void Light_Ctrl() //红绿灯控制
{
switch(status1)
{
case 1: P0 |= 0x07; P0 &= 0xfe; break;
case 2: P0 |= 0x07; P0 &= 0xfd; break;
case 3: P0 |= 0x07; P0 &= 0xfb; break;
}
switch(status2)
{
case 1: P0 |= 0x38; P0 &= 0xf7; break;
case 2: P0 |= 0x38; P0 &= 0xef; break;
case 3: P0 |= 0x38; P0 &= 0xdf; break;
}
}
灯光控制函数利用上一个函数对status的赋值控制P0口输出,在灯光变化之前先对之前的状态用|=置1,再用&=置0(这里的灯光是低电平点亮),否则在变灯的时候会出现三个灯同时亮的情况。
void main()
{
Timer0Init();
P1=0xff;
P0=0xff;
second1=27;
second2=30;
while(1);
}
主函数包含了定时器0、P0P1口和计时器变量的初始化,while(1)死循环避免main函数循环运行。
void timer0ISP () interrupt 1 //定时器0中断服务函数
{
TH0=(65536-1000)/256; //1ms一次脉冲
TL0=(65536-1000)%256;
Light_Ctrl();
i++;
SMG_shift();
if(i>=1000)
{
i=0;
timer();
}
}
定时器0中断服务程序包含灯光控制及数码管刷新函数,1秒运行一次倒计时函数。
全部代码
#include <REG51.H>
#define uint unsigned int
#define uchar unsigned char
uint second1,second2,i,bits,status1,status2,shift;
uint second=60;
uchar smg[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Timer0Init()
{
TMOD=0x01; //工作模式1 ,需赋初值
TH0=(65536-1000)/256; //定时1000,高八位
TL0=(65536-1000)%256;
EA=1; //打开中断允许总开关
ET0=1; //定时器0中断允许
TR0=1; //定时器0启动控制
}
void SMG_shift()
{
P2=~(0x01<<shift);
switch(shift)
{
case 0:bits=second1/10; break;
case 1:bits=second1%10; break;
case 2:bits=second2/10; break;
case 3:bits=second2%10; break;
}
P1=smg[bits];
shift=(shift+1)%4;
}
void timer()
{
if(second<=60 && second>33) //左绿灯右红灯
{
status1=1;
status2=3;
second1=second-33; //左边倒计时为second-33
second2=second-30;
}
if(second<=33 && second>30) //左黄灯右红灯
{
status1=2;
status2=3; //此时左右倒计时相等
second2=second-30;
second1=second2;
}
if(second<=30 && second>3) //左红灯右绿灯
{
status1=3;
status2=1;
second1=second; //左倒计时等于second
second2=second-3; //右倒计时比左倒计时少3秒
}
if(second<=3 && second>=0) //左红灯右黄灯
{
status1=3;
status2=2;
second1=second;
second2=second;
}
second--; //每运行一次该函数减一秒
if(second==0)
second=60;
}
void Light_Ctrl() //红绿灯控制
{
switch(status1)
{
case 1: P0 |= 0x07; P0 &= 0xfe; break;
case 2: P0 |= 0x07; P0 &= 0xfd; break;
case 3: P0 |= 0x07; P0 &= 0xfb; break;
}
switch(status2)
{
case 1: P0 |= 0x38; P0 &= 0xf7; break;
case 2: P0 |= 0x38; P0 &= 0xef; break;
case 3: P0 |= 0x38; P0 &= 0xdf; break;
}
}
void main()
{
Timer0Init();
P1=0xff;
P0=0xff;
second1=27;
second2=30;
while(1);
}
void timer0ISP () interrupt 1 //定时器0中断服务函数
{
TH0=(65536-1000)/256; //1ms一次脉冲
TL0=(65536-1000)%256;
Light_Ctrl();
i++;
SMG_shift();
if(i>=1000)
{
i=0;
timer();
}
}
仿真电路图
文章来源:https://www.toymoban.com/news/detail-502596.html
文章来源地址https://www.toymoban.com/news/detail-502596.html
到了这里,关于基于51单片机的简易红绿灯电路的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!