天天看点

51单片机实现流水灯左移、右移、先左移后右移程序

知识点回顾

<<:左移符号

.>>:右移符号

~:取反符号

思路:

a = 0x01<<1;就是a的结果等于0x01左移一位。需要注意的是,左移是指二进制移位,移位后低位(或高位)是要补0的。举个左移流水灯的例子,要使流水灯向左依次流动,则有代码:

下面展示一些

内联代码片

// 左移时流水灯P0口设置,cnt为从0开始逐渐递增的左移的位数,
//等下会贴一整段代码

P0 = ~(0x01 << cnt);
           

我们来解析一下这个代码的意思,先从括号里面看,0x01是十六位进制的数,化成二进制为:0000 0001,。当cnt = 1时,即左移一位后,变为000 0 0010,然后取反符号后其变为111 1 1101。根据低电平有效,等于0那个小灯亮了,及第二个小灯亮了。同理可得第三个小灯为:11 11 1011,后面以此类推。

左移代码:

//左移
 	while(1){
		P0 = ~(0x01 << cnt);		  //0000 0001 左移后:000 0 0010 取反:111 1 1101 低电平亮
		for(i= 0; i<30000; i++);
		cnt++;
		if(cnt >=8){
	 		cnt = 0;
		}
	}
           

右移代码:

//右移
	while(1){

	 	P0 = ~(0x80 >> cnt);       // 1000 0000 右移后: 01000 000 取反: 10111 111
		for(i=0; i<30000; i++);
		cnt++;
		if(cnt >=8){
			cnt = 0;
		}
	}
           

不精确时间的先左移后右移代码:

注:首先要先在前面定义flag: unsigned int flag = 0;

用除余的方法来先左后右。第一遍时flag = 0,除以2余等于0则进入左移的条件。第二遍时flag自加后等于1,除以2余不等于0,则进入右移条件。

while(1){
	
	
			if(flag %2 == 0){
	
				P0 = ~(0x01 << cnt);   //流水灯左移
	
			}
			else{
	
				P0 = ~(0x80 >> cnt);	//流水灯右移
	
			}
	
			for(i=0; i<30000;i++);		//闪烁
			cnt++;						//灯进行左(右)移
			if(cnt >= 8){
	
				cnt = 0;
				flag++;			//第二遍后flag+1, 取余不是零,则变成右移方向;
			}		
	}
           

用定时器精确时间的先左移后右移代码:

首先要先在前面打开定时器:

TMOD = 0;
	TH0 = 0xB8;
	TL0 = 0x00;
	TR0 = 1;
           

运行的程序代码为:

//用定时器来实现左右流水灯循环
   while(1){
		
		if(TF0 == 1){		//判断T0是否溢出,溢出一次换算得0.02秒

			TF0 = 0;		 //定时器控制0.02秒
			TH0 = 0xB8;
			TL0 = 0x00;
			count++;				//溢出次数
			if(count >= 50){	   //0.02乘以50等于1秒,每隔一秒点亮一个流水灯

				count = 0;
				if(flag %2 == 0){
	
					P0 = ~(0x01 << cnt);		//进行左移
	
				}else{
	
					P0 = ~(0x80 >> cnt);		//进行右移
				}
				cnt++;							//左(右)移几个单位数
				if(cnt >= 8){
		
					cnt = 0;
					flag++;			//第二遍后flag+1, 取余不是零,则变成右移方向;
				}
			} 				
   		}
	}
}
           

全部代码:

注:因上面只能看到某部分代码,某些定义没有给出,故放出整体代码,方便易于理解:

#include<reg52.h>

 sbit ENLED = P1^4;    //使能74HC138
 sbit ADDR3 = P1^3;

 sbit ADDR2 = P1^2;
 sbit ADDR1 = P1^1;
 sbit ADDR0 = P1^0;

void main(){

	unsigned int i = 0;			  
	unsigned int cnt = 0;
	unsigned int flag = 0;
	unsigned int count = 0;


	ENLED = 0;    //使能
	ADDR3 = 1;

	ADDR2 = 1;    //110 ,打开控制流水灯的三极管LEDS6,使其导通
	ADDR1 = 1;
	ADDR0 = 0;

	TMOD = 0;
	TH0 = 0xB8;
	TL0 = 0x00;
	TR0 = 1;


	//左移流水灯
 	while(1){
		P0 = ~(0x01 << cnt);		  //0000 0001 左移后:000 0 0010 取反:111 1 1101 低电平亮
		for(i= 0; i<30000; i++);
		cnt++;
		if(cnt >=8){

	 		cnt = 0;

		}
	}


	//右移流水灯
	while(1){

	 	P0 = ~(0x80 >> cnt);       // 1000 0000 右移后: 01000 000 取反: 10111 111
		for(i=0; i<30000; i++);
		cnt++;
		if(cnt >=8){

			cnt = 0;

		}
	}

	//先左移,后右移。左移时第一遍为0,除余后为0,则执行左移,第二遍时为1,除余后不是零则执行右移。同理可以继续下去
	while(1){
	
	
			if(flag %2 == 0){
	
				P0 = ~(0x01 << cnt);   //流水灯左移
	
			}
			else{
	
				P0 = ~(0x80 >> cnt);	//流水灯右移
	
			}
	
			for(i=0; i<30000;i++);		//闪烁
			cnt++;						//左(右)移
			if(cnt >= 8){
	
				cnt = 0;
				flag++;			//第二遍后flag+1, 取余不是零,则变成右移方向;
			}

		
	}

   //用定时器来实现左右流水灯循环
   while(1){
		
		if(TF0 == 1){

			TF0 = 0;		 		//定时器控制0.02秒
			TH0 = 0xB8;
			TL0 = 0x00;
			count++;
			if(count >= 50){	   //0.02乘以50等于1秒

				count = 0;
				if(flag %2 == 0){
	
					P0 = ~(0x01 << cnt);
	
				}else{
	
					P0 = ~(0x80 >> cnt);
				}
				cnt++;
				if(cnt >= 8){
		
					cnt = 0;
					flag++;			//第二遍后flag+1, 取余不是零,则变成右移方向;
				}
			} 				
   		}
	}
}