avr单片机大作业|交通灯控制系统

引语

记录学习路程,抛砖引玉。如有更好的算法或者出现错误,欢迎指点。

题目

  1. 实现十字路口交通灯控制运行(包括白天模式、夜间模式、紧急模式三种情况)
  2. 红绿灯运行时间可通过按键实时修改,修改后的运行时间可通过两位数码管显示, 并实际保存下来(即断电后再上电,依然能保存最新修改的红绿灯运行时间)
  3. 创新地自行设计了光敏实现白天模式与夜间模式的自动切换

实现过程

步骤如下:

  1. 初步构思出功能实现的系统框图
  2. 根据构思画出流程图,进一步设计实现题目要求,根据需求拟出按键操作说明
  3. 探索电路原理图
  4. 把功能细化,有序进行设计以及代码编写
  5. 查漏补缺进一步完善项目

系统框图

在这里插入图片描述

流程图以及操作说明

在这里插入图片描述

一共设计了8个按键,序号代表按键序号

  1. 在时间调节时进行减一操作。
  2. 在时间调节时进行加一操作。
  3. 进入南北方向(上下两个模块)的时间调整状态,数码管显示需要调节的时间,调整的相应的灯亮(例如:调整黄灯为5s,数码管显示5,黄灯亮)
  4. 进入东西方向(左右两个模块)的时间调整状态,数码管显示需要调节的时间,调整的相应的灯亮(例如:调整红灯为15s,数码管显示15,红灯亮)
  5. 模式间的切换,按照(普通模式、夜间模式、紧急模式)顺序进行循环切换
  6. 在紧急模式情况下按照(禁止通行、东西通行、南北通行)顺序进行循环切换
  7. 待定(无功能)
  8. 储存设定的时间,切断电源后重启将会是设定后的时间

在使用过程中的调节环节,由于是同个按键根据顺序进行调节,为避免调节重复所以添加了笑脸^^确认项来确认已完成调整,然后再进一步进行其他操作。

电路原理图

在这里插入图片描述
选用的单片机是atmega128单片机,其中的PB端控制数码管显示,PC端控制灯的显示,PD端控制按键输入,PE1端口连接位移寄存器,PF0端口作为光敏控制端。74HC595是一款漏极开路输出的CMOS位移寄存器,输出端口为可控三态输出端,所以通过使用74HC595串行输出控制数码管显示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

元件清单:
7SEG-MPX2-CC、74HC595、7404、ATMEGA128、BUTTON、LED-GREEN
LED-RED、LED-YELLOW、RES、TORCH_LDR、[7404]

代码

#include  <avr/io.h>
#include  <util/delay.h>
#define   delay_ms(x)   _delay_ms(x)
#include  <avr/interrupt.h>

const unsigned char disp[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char ledbuf[]={0x00,0x00,0x00,0x00};// 显示缓冲区,分别存放的是南北和东西方向的十位、个位段码

int ms10=0,sec=0,x1,x2;


int a1=10,b1=6,c1=4,a2=10,b2=7,c2=3;
int nbred,nbgreen,nbyellow,dxred,dxgreen,dxyellow;  


int x=0,dx=-1,nb=-1,shanshuo=1,k=-1,turn=-1,save=0,STOP_music=0,T=-1,CLOCK=0,led=0,sos=-1;










/******定时器1的初始化,CTC模式,8分频,中断周期5ms******/
void  disp_init(void)
{
	OCR1A = 4999;		//100Hz=8MHz/(2*8*(1+OCR1A))
	TCCR1A = 0x00;
	TCCR1B = (1 << WGM12);        //CTC模式
	TCCR1B |= (1 << CS11);	//8分频
	TIMSK |= (1 << OCIE1A);	//开比较匹配中断A
}




/******数码管显示函数 ******/
void display(char num,char pos)
{ 	SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0);
	PORTB &= 0x0F; 		//关位选
	PORTB &=~(1<<0);
	SPDR=num;
	while(0==(SPSR&0X80)); 	//等待 SPIF中断结束置位
	PORTB|=(1<<0);
	PORTB |= 1<<(7-pos);
}






/********数码管控制IO初始化*******/
void io_init(void)

{
	PORTC = 0x00;   //灯
	DDRC  = 0xFF;	//灯
	
	
	DDRD = 0X00;	//八位独立按键
	PORTD = 0XFF;	//PD口8个按键端口输入,上拉
	
	DDRE=0xFF;
	PORTE&=~(1<<1); //74HC595使能
	
	PORTB = 0xFF;	//PB4\5\6\7控制数码管位码
	DDRB |= 0xFF;   //(1<<PB7) | (1<<PB6) | (1<<PB5) | (1<<PB4);
}
	






//扫描键盘,获得键码
void key_read(void)
{
	unsigned char i,j; 	 	 	 	 	 	//键码记录
	unsigned char key_num;
	i=PIND; 	 	 	 					//按键表示的数字 并记录
	delay_ms(20);  	 	 					//去按键颤抖
	j = PIND; 								//j=除抖后的按键情况
	if(i == j) 	 	 	 	//二次对比确定按键操作,且有按键按下
	{
		switch (i) 							 //将按键码转换成键值
		{
			case  0x7F: 	save=(++save)%2;      break;    //8  灯时间调整完成后的存档 数据写入EEPROM 
			case  0xBF:   CLOCK=(++CLOCK)%3;
			STOP_music=0;  		break;    //7  
			case  0xDF:  sos=(++sos)%3; 	break;	  	  //6  紧急模式 0禁止通行    1南北通行      2东西通行 
		
			
								 
			case  0xEF: 	x=(++x)%3;		break;	  	  //5  模式切换 0为普通模式  1为夜间模式    2为紧急模式 
			
			
			
			case  0xF7: 	dx=(++dx)%5;	break;	   	  //4  时间调整,0东西红灯 1东西绿灯 2东西黄灯   3笑脸确认设置
			case  0xFB:   nb=(++nb)%5;      break;   	//3  时间调整,0南北红灯 1南北绿灯 2南北黄灯    3笑脸确认设置
		
		
			case  0xFE: 								//1
			if(nb==0) a1--;       	//南北的红黄绿灯  第一键对应减一      
			if(nb==1) b1--;
			if(nb==2) c1--;
			
			if(dx==0) a2--;       	//东西的红黄绿灯  第一键对应减一      
			if(dx==1) b2--;
			if(dx==2) c2--;
			
			break;
			
			
			
			
			case  0xFD: 			//2 
			if(nb==0) a1++;		  //南北的红黄绿灯  第二键对应加一
			if(nb==1) b1++;
			if(nb==2) c1++;
		
		
			if(dx==0) a2++;		  //东西的红黄绿灯  第二键对应加一
			if(dx==1) b2++;
			if(dx==2) c2++;
			break;
		
		
		
		
			default:      break;
		}
			while(PIND!=0xFF)  ; 				//等待按键松开
	}
}



/******中断服务程序的功能******/
ISR(TIMER1_COMPA_vect)

{
		static unsigned char j=0,c=0; //显示刷新标志
	j++;c++;
	k=(++k)%4; 				     	//k 实现轮流刷新数码管


    


	if(j>99)  {shanshuo ^= 1;j=0;}  //小数点闪烁周期设置   1s=0.05*100*2
	
	
	
	
	
	/*************交通灯时间写操作**************/
	if(c>199)
	{
		c=0;
		if(save==1)      //将交通灯时间数据写入EEPROM
		{
			
			
			
			
		    EEPROM_write(100,a1);
		    EEPROM_write(101,b1);
		    EEPROM_write(102,c1);
		    EEPROM_write(103,a2);
		    EEPROM_write(104,b2);
		    EEPROM_write(105,c2);
		}	
		
	}
	
	
	
		/*******时间调整范围及数字变换*******/
	if(ms10>99)   
	{
	    ms10=0;
	    
		  
		
		x1=nbred;nbred--;
		x2=dxgreen;dxgreen--;  //100 * 10 =1s
		PORTC = 0x0A;
	   
	
	    if(nbred<0)     
		{
		    x1=nbgreen;nbgreen--;//南北红绿黄变换 
		    PORTC = PORTC + 0x08;
		    
     	    if(nbgreen<0)      
			{
			    x1=nbyellow;nbyellow--;
			    PORTC = PORTC + 0x10;
			    
	            if(nbyellow<0)      
			    {nbred=a1;nbgreen=b1;nbyellow=c1;x1=nbred;PORTC = PORTC - 0x18;}
			}
	    }
	
	 
	    if(dxgreen<0)      
		{
		    x2=dxyellow;dxyellow--;//东西绿黄红变换 
		    PORTC = PORTC + 0x02;
		    
	        if(dxyellow<0)      
			{
			    x2=dxred;dxred--;
			    PORTC = PORTC - 0x03;
			    
	            if(dxred<0)          
			    {dxgreen=b2;dxred=a2;dxyellow=c2;x2=dxgreen;PORTC = PORTC + 0x01;}
			}
	    }
	    
	    
	}	
	
	
	
	
	
	
	
	
	
	
		/******时间调整显示*******/
	if(nb==0)     //南北红灯调整
	{
        

	    dx=-1;x=-1;
		PORTC = 0x08;
		if(shanshuo==1)
		ledbuf[1] = disp[a1%10];
		else
		ledbuf[1] = 0x00;
		
		ledbuf[0] = disp[a1/10];
		ledbuf[2] = 0x00;
		ledbuf[3] = 0x00;
		display(ledbuf[k],k);
	}

	if(nb==1)   //南北绿灯调整
	{

	    dx=-1;x=-1;
		PORTC = 0x10;
		if(shanshuo==1)
		ledbuf[1] = disp[b1%10];
		else
		ledbuf[1] = 0x00;

		ledbuf[0] = disp[b1/10];
		ledbuf[2] = 0x00;
		ledbuf[3] = 0x00;
		display(ledbuf[k],k);
		
	}

	if(nb==2)		//南北黄灯调整
	{
	    dx=-1;x=-1;
		PORTC = 0x20;
		if(shanshuo==1)
		ledbuf[1] = disp[c1%10];
		else
		ledbuf[1] = 0x00;
		
		ledbuf[0] = disp[c1/10];
	    ledbuf[2] = 0x00;
	    ledbuf[3] = 0x00;
		display(ledbuf[k],k);
	}
	
	if(nb==3)		//设置确认 
	{
	    dx=-1;x=-1;
		PORTC = 0x00;
		ledbuf[1] = 0x23;
		
		ledbuf[0] = 0x23;
	    ledbuf[2] = 0x23;
	    ledbuf[3] = 0x23;
		display(ledbuf[k],k);
	}
	
	
	
	
	
	
	
	if(dx==0)     //东西红灯调整
	{
	    nb=-1;x=-1;
		PORTC = 0x01;
		if(shanshuo==1)
		ledbuf[3] = disp[a2%10];
		else
		ledbuf[3] = 0x00;
		
		ledbuf[2] = disp[a2/10];
		ledbuf[1] = 0x00;
		ledbuf[0] = 0x00;
		display(ledbuf[k],k);
	}

	if(dx==1)   //东西绿灯调整
	{
	    nb=-1;x=-1;
		PORTC = 0x02;
		if(shanshuo==1)
		ledbuf[3] = disp[b2%10];
		else
		ledbuf[3] = 0x00;

		ledbuf[2] = disp[b2/10];
		ledbuf[1] = 0x00;
		ledbuf[0] = 0x00;
		display(ledbuf[k],k);
		
	}

	if(dx==2)		//东西黄灯调整
	{
	    nb=-1;x=-1;
		PORTC = 0x04;
		if(shanshuo==1)
		ledbuf[3] = disp[c2%10];
		else
		ledbuf[3] = 0x00;
		
		ledbuf[2] = disp[c2/10];
	    ledbuf[1] = 0x00;
	    ledbuf[0] = 0x00;
		display(ledbuf[k],k);
	}

	if(dx==3)		//设置确认 
	{
	    nb=-1;x=-1;
		PORTC = 0x00;
		ledbuf[1] = 0x23;
		
		ledbuf[0] = 0x23;
	    ledbuf[2] = 0x23;
	    ledbuf[3] = 0x23;
		display(ledbuf[k],k);
	}
	
	
       if(save==1)
	      {  
			nb=-1;dx=-1;sos=-1;
		    PORTC = 0x00;
		    ledbuf[1] = 0x23;
		    ledbuf[0] = 0x23;
	        ledbuf[2] = 0x23;
	        ledbuf[3] = 0x23;
		    display(ledbuf[k],k);
	      }
	
	
	
	
	
	
	display(ledbuf[k],k);      //数码管显示函数
}






/************AD测电压值实现光控开启夜间模式************/
unsigned int get_ad(void) 
{ 
   long int i;  
   ADMUX = (1 << REFS0);  //参考电压AVCC
   ADCSRA = (1<< ADEN) | (1 << ADSC) | (1 << ADPS1) | (1 << ADPS0); //ADC使能,开始转换,8分频 
   while(!(ADCSRA & (1 << ADIF))); //等待转换结束中断标志置位 
   i = ADC; //取转换结果
   ADCSRA &= ~(1 << ADIF); //清除中断标志 
   ADCSRA &= ~(1 << ADEN); //关闭ADC 
   return i; 
}
 



	
	
	
	
	
	
/************EEPROM写操作************/

void EEPROM_write(unsigned int Address,unsigned char Data)
{
	while(EECR&(1<<EEWE));			//等待上一次写操作结束
	EEAR = Address;  				//地址
	EEDR = Data;  					//数据
	EECR |= (1<<EEMWE);  			//置位EEMWE
	EECR |= (1<<EEWE);				//置位EEWE启动写操作
}





/************EEPROM读操作************/
int EEPROM_read(unsigned int Address)
{
	while(EECR&(1<<EEWE));			//等待上一次写操作结束
	EEAR = Address;  				//地址
	EECR |= (1<<EERE); 				//置位EEMWE
	return EEDR;  					//返回读取结果
}





//主 函 数 
int main()
{
	ledbuf[3] = 0x00;
	ledbuf[2] = 0x00;
	ledbuf[1] = 0x00;
	ledbuf[0] = 0x00; 


    long int i;
    
    
	io_init();
	disp_init();
	sei();
	
	
	

   
	
	
		
	





	
	
	
    	/********读设置交通灯时间*********/

	if(save==0)
	{
	    T=-1;nb=-1;dx=-1;sos=-1;
		a1=EEPROM_read(100);
		b1=EEPROM_read(101);
		c1=EEPROM_read(102);
		a2=EEPROM_read(103);
		b2=EEPROM_read(104);
		c2=EEPROM_read(105);
	}
	



    nbred=a1,nbgreen=b1,nbyellow=c1;
	dxred=a2,dxgreen=b2,dxyellow=c2;
	


	
	
	while (1)
	{
        
		key_read(); 	 	//键盘扫描
		delay_ms(50); 		//键盘扫描间隔
		
		
        i = get_ad()/204.8;


		
		if(x==0)//普通模式 
		{
			T=-1;sos=-1;			//消除其他功能时间显示干扰
	
	      if(i>2)                //光控处检查的电压值作为是否为夜间模式标准
		  {
		    ms10++;
			ledbuf[3] = disp[x2%10];
			ledbuf[2] = disp[x2/10];
			ledbuf[1] = disp[x1%10];
			ledbuf[0] = disp[x1/10];
	      }
	      
	      else
	      {
	        ledbuf[3] = 0x00;
	        ledbuf[2] = 0x00;
        	ledbuf[1] = 0x00;
	        ledbuf[0] = 0x00;

			if(shanshuo==1)
			PORTC = 0x24;
			else
			PORTC = 0x00;
		  }
		  
		  
       
	
			
		}
		
		
		if(x==1)//夜间模式 
		{

            T=-1;sos=-1;			//消除其他功能时间显示干扰
            ledbuf[3] = 0x00;
	        ledbuf[2] = 0x00;
        	ledbuf[1] = 0x00;
	        ledbuf[0] = 0x00;

			if(shanshuo==1)
			PORTC = 0x24;
			else
			PORTC = 0x00;
			
		} 
		
		
		
		if(x==2)//紧急模式 
		{
			nb=-1;dx=-1;T=-1;;		//消除其他功能时间显示干扰
			ledbuf[3] = 0x00;
	        ledbuf[2] = 0x00;
        	ledbuf[1] = 0x00;
	        ledbuf[0] = 0x00;
			PORTC = 0x09;
			if(sos==0) PORTC = 0x09;
			if(sos==1) PORTC = 0x0A;
			if(sos==2) PORTC = 0x11;
			
			
		} 
			
	 
	    

    

	      
	
	
	    
			
	
		delay_ms(10); //键盘扫描间隔
	}
	
	
	
} 
	
	
	
	
	
	

	
	
	
	
	
	

  • 9
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值