定时器实验+51+主从机串口通信+模拟红绿灯

一、 实验目的

1、 熟练掌握Keil和Proteus软件的C51设计与仿真操作
2、 熟悉C51编程的变量、存储等概念及使用方法
3、 掌握74LS245或74LS373的扩展方法
4、 熟悉定时计数器、外部中断的编程设计,初步掌握串行通信编程方法

二、 实验要求

1、 D级别要求:
a) 机制1:南北:红5秒,红 3 秒,绿5秒,黄闪3秒,在南北向亮灯的同时,东西方向的状态:绿5秒,黄闪3秒,红5秒,红 3 秒
b) 或机制2:可以按照四个路口方向逐次亮起红灯24秒,绿灯5秒,黄灯3秒。
c) 有一个外部中断,下降沿触发,触发后,四个方向全红,再次触发后,恢复正常
注:a) 和 b) 是两种不同的红绿灯控制机制,选择实现其一即可
2、 C级别要求:
a) 实现D级别的功能
b) 有设置键,可设置绿灯时间为其他秒数(红灯对应)
c) 可切换D级别的两种红绿灯机制,用设置键切换
3、 B级别要求:
a) 用2个单片机分别作为南北方向和东西方向的灯的控制
b) 2个单片机之间通过串行通信发送数据,实现同步,功能现象如D级要求
4、 A级别要求:
a) 实现B级别的功能
b) 某一个单片机上有设置键,能实现绿灯时间的设置(红灯对应)。

三、 实验实现的功能说明

在Proteus仿真软件中实现了A级别要求,主要完成了两个单片机分别控制两个方向的状态如D级别中的机制1状态,通过串行通讯用定时器1的方式二设置相同的波特率完成数据的收发,实现了红绿灯的正常同步,同时加入了两个数码管分别显示红绿灯的时间,并且可以通过四个按钮完成对红绿灯时间的加减,可以任意调节红绿灯的时间,同时代码也保持两个方向的红绿灯时间的对应。

四、 实验实现的原理及仿真电路设计

实验原理

为了便于观察与更好的模拟红绿灯将南北和东西方向的LED灯按照上北下南左西右东的方式排列,使之共地后分方向接入到主机与从机,将主机的RXD连接到从机的TXD,主机的TXD连接到从机的RXD,将主机与从机通过定时1的方式二设置相同的波特率后从而进行数据的收发。通过定时器0对红灯绿灯的时间进行控制,定义一个标志位,并且设置重装载值为50000us,即50毫秒溢出产生中断,当中断十次时候即0.5s时进行判断是否进行黄灯亮,在进入20次时即为1s时进行计时并通过算法判断各种灯的状态,黄灯比较特殊,我们在20次时将黄灯IO口置0并且抛出标志位,即可完成黄灯每过半秒闪烁,即可省略Delay延时函数在定时器中延时带来的干扰。

实验原理电路图:

在这里插入图片描述
主机代码:

#include <reg51.h>
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
u8 x;
u8 value;
u8 count0;//定时器0中断次数
sbit greenIO1=P1^0;
sbit yellowIO1=P1^1; 
sbit redIO1=P1^2;
sbit k1=P3^4;
sbit k2=P3^5;
sbit k3=P3^6;
sbit k4=P3^7;
u8 red = 5;
u8 green = 5;
u8 Time1 = 7;
u8 Time_yello = 0;
u8 Time_green = 0;
u8 Time_yello1 = 0;
u8 change = 0;
u16 wei[4] = {0,0,0,0};
u16 wei2[4] = {0,0,0,0};
//共阴数码管编码表
u8 code numberList[] =
{0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};


void delay(u16 i)	 // delay延时函数	   i=1时,大约延时10us
{
	while(i--);	
}

void Time_arry(u16 count)
{
	wei[0] = (count%1000)%100/10;
	wei[1] = (count%1000)%100%10;
}
void Time_arry1(u16 count)
{
	wei[2] = (count%1000)%100/10;
	wei[3] = (count%1000)%100%10;
}


void Timer0Init()	   //定时器0初始化
{
	TMOD|=0X21;  //选择为定时器0模式,工作方式1,仅用TR0打开启动。
	TH0 = (65536 - 50000)/ 256; //50000us定时,即50毫秒溢出产生中断
	TL0 = (65536 - 50000)% 256; //50000us定时,即50毫秒溢出产生中断
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器			
}


void TimerChange()	   //按键
{
	if(k1==0)
	{
	  delay(10);  // 消抖
			if(k1==0){
				red += 1;
	      while(k1==0);
				Time1 = 7 + red + green;
				Time_yello = red+3;
				Time_green = green+3;
				Time_yello1 = Time_yello + 3;
			}
	}
	if(k2==0)
	{
	  delay(10);  // 消抖
			if(k2==0){
				if(red >= 4)
				{
				red -= 1;
				}
//				change = 1;
	      while(k2==0);
				Time1 = 7 + red + green;
				Time_yello = red+3;
				Time_green = green+3;
				Time_yello1 = Time_yello + 3;
			}
	}
	if(k3==0)
	{
	  delay(10);  // 消抖
			if(k3==0){
				green += 1;
//				change = 1;
	      while(k3==0);
				Time1 = 7 + red + green;
				Time_yello = red+3;
				Time_green = green+3;
				Time_yello1 = Time_yello + 3;
			}
	}
	if(k4==0)
	{
	  delay(10);  // 消抖
			if(k4==0){
				if(green>=4)
				{
				green -= 1;
				}
					//change = 1;
	      while(k4==0);
				Time1 = 7 + red + green;
				Time_yello = red+3;
				Time_green = green+3;
				Time_yello1 = Time_yello + 3;
			}
	}
}


void serial_initial(void)	//串口初始化 //T1作为波特率发生器,使用工作模式1
{
	TMOD=0x21;		  //T1工作方式2八位定时器自动重装
	TH1=0xF3;         //计数器初始值设置,注意波特率是4800
	TL1=0xF3;
	TR1=1;		  //启动定时器1
	SM0=0;//设置串口工作方式
  SM1=1;
	EA=1;//打开总中断
  ES=1;//打开串口中断
}

void ledShow()
{
	u8 i;
    for(i=0;i<=3;i++)
    {
        switch(i)     //位选,选择点亮的数码管,
        {
            case(0):
                P2 = 0xfe; break;//显示第0位
            case(1):
                P2 = 0Xfd; break;//显示第1位	
						case(2):
                P2 = 0Xfb; break;//显示第0位
            case(3):
                P2 = 0Xf7; break;//显示第1位							
        }
     P0=numberList[wei[i]];//发送段码
     delay(200); //间隔一段时间扫描    
     P0=0x00;//消隐
		}
}
void send_byte(u8 x)	  //串口发送一个字节
{		
	SBUF=x;		  //启动串口发送
	while(TI==0);
	TI=0;		  //发送完毕,置位TI=0
}
void main()				 //主函数
{	
	Time1 = Time1 + red + green;
	Time_yello = red + 3;
	Time_green = green+3;
	Time_yello1 = Time_yello + 3;
	serial_initial();		 //串口初始化
	Timer0Init();			 //定时器0初始化
	
	while(1)
	{
		Time_arry(Time_yello);
		Time_arry1(Time_green);
		ledShow();
		TimerChange();
	}

}
void runLight() interrupt 1   //定时中断程序
{

	count0++;       //软件计数加1
	if(count0==10)      //加到10也就是半秒
	{       
		if(Time1<=4)    //东西黄灯闪                                
		{  
			greenIO1=0;
			yellowIO1=0;
			redIO1=0;
		}
	if((Time1<=Time_yello1)&&(Time1>Time_yello))  //南北黄闪
		{
			send_byte(2);
		}		
	}
	if(count0==20)                    // 定时器中断次数=20时(即1秒时)
	{ 
		serial_initial();	
		count0=0;      //清零计数器
		Time1--;      //东西时间减1
		if(Time1>Time_yello1)  //东西红灯
		{
			redIO1=1;
			yellowIO1=0;
			greenIO1=0;
			send_byte(1);
		}
		if((Time1<=Time_yello1)&&(Time1>Time_yello))  //东西红灯3s
		{
			redIO1=1;
			yellowIO1=0;
			greenIO1=0;
			send_byte(2);
		}
		
		if((Time1<=Time_yello)&&(Time1>=3))  //东西绿灯
		{
			redIO1=0;
			yellowIO1=0;
			greenIO1=1;
			send_byte(3);
		}	
		if(Time1<=4)    //东西黄灯闪  
		{
			greenIO1=0;
			redIO1=0;
			yellowIO1=1;
			send_byte(4);
		} 
		if(Time1==0)    //东西黄灯闪  
		{
			yellowIO1=1;
			delay(100);
			P1=0X00;     //重置状态
			Time1=16;	
			redIO1=1;
			send_byte(1);
		} 
	}
	TH0 = (65536 - 50000)/ 256; //50000us定时,即50毫秒溢出产生中断
	TL0 = (65536 - 50000)% 256; //50000us定时,即50毫秒溢出产生中断
}

从机代码:

#include <reg51.h>
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
u8 x;
u8 value;
char count0;//定时器0中断次数
sbit greenIO2=P1^5;
sbit yellowIO2=P1^6; 
sbit redIO2=P1^7;
char Time1=16;  		
int shan=0;			//闪烁标志位

void delay(u16 i)	 // delay延时函数	   i=1时,大约延时10us
{
	while(i--);	
}

void serial_initial(void)	//串口初始化 //T1作为波特率发生器,使用工作模式1
{
	TMOD=0X20;//定时器1方式2
	TH1=0xF3;         //计数器初始值设置,注意波特率是4800
	TL1=0xF3;
	TR1=1;//打开定时器
	SM0=0;//设置串口工作方式
	SM1=1;
	REN=1;
	EA=1;//打开总中断
	ES=1;//打开串口中断
}
void send_byte(u8 x)	  //串口发送一个字节
{		
	SBUF=x;		  //启动串口发送
	while(TI==0);
	TI=0;		  //发送完毕,置位TI=0
	delay(1);
}
void main()				 //主函数
{	
	serial_initial();
	while(1);

}
//串口中断服务函数
void uart() interrupt 4
{
	u8 Val;
	value=SBUF;
	switch(value)
	{
		case(1):
			greenIO2=1;
			yellowIO2=0;
			redIO2=0;
			break;
		case(2):
			greenIO2=0;
			yellowIO2=!yellowIO2;
			redIO2=0;
			break;
		case(3):
			greenIO2=0;
			yellowIO2=0;
			redIO2=1;
			break;
		case(4):
			greenIO2=0;
			yellowIO2=0;
			redIO2=1;
			break;
	}
	Val = SBUF;
	RI=0;                    //清除接收中断标志位
}

这是去年实验时的代码了,可能有些许不足,但是完成本次实验是完全没问题的,如果你发现了bug,请及时留言反应。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值