单片机跑马灯左右移动

2015-11-19 11:02:48 snyanglq 阅读数 9660



一、跑马灯和流水灯的区别

好多人分不清跑马灯和流水灯,还以为是同一种状态,虽然难度等级是一样的,但是灯的亮灭显示方式是不一样的。请看下图


二、单片机控制LED灯的常用电路接法

弄清楚跑马灯的显示状态后可以开始进行设计了,   在日常的跑马灯设计电路中LED灯一般接为这两种形式,共电源或共地,也就是通常说的灌电流式和拉电流式

三、电路分析与编程

大家可以根据自己实际的电路需要选择其中一种接法,由于AT89S52单片机IO端口不操作时是高电平所以下面我选择的是共电源接法。


   电路分析:当电路输出高电平[端口为1]LED灯灭,当电路输出低电平[端口为0]LED灯亮

  大家可以按照自己的思路编程,方法不唯一,下面我将介绍3种方法
   
方法一:不利用算法,直接使用IO控制[可以说是最蠢的方法,但是一样能实现效果,并且容易理解]

#include <reg52.h>

//LED输出端口位定义
sbit led0=P0^0;
sbit led1=P0^1;
sbit led2=P0^2;
sbit led3=P0^3;
sbit led4=P0^4;
sbit led5=P0^5;
sbit led6=P0^6;
sbit led7=P0^7;

//延时函数
void delay(void)
{
 unsigned char a,b;
  for(a=0;a<200;a++)
  for(b=0;b<200;b++);
}


void main()
{
led0=1; //端口初始化
led1=1;
led2=1;
led3=1;
led4=1;
led5=1;
led6=1;
led7=1;


while(1)
 {
 led0=0; //点亮LED0
  delay(); //延时
  led0=1; //熄灭LED0
  delay(); //延时,为下一个灯准备

 led1=0;
 delay();
  led1=1;
  delay();
   
  led2=0;
  delay();
 led2=1;
  delay();

 led3=0;
 delay();
 led3=1;
 delay();

 led4=0;
 delay();
 led4=1;
  delay();

 led5=0;
 delay();
 led5=1;
 delay();

 led6=0;
 delay();
 led6=1;
 delay();

 led7=0;
 delay();
 led7=1;
 delay();
 }
}


方法二:借助数组对上面程序进行改进,使端口一次性赋值定义

#include <reg52.h>
#define uchar unsigned char       
#define uint unsigned int

//定义一个一维数组
unsigned char table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};


//延时函数
void delay(void)
{
  uchar a,b;
 for(a=0;a<200;a++)
 for(b=0;b<200;b++);
}


void main()
{
  uchar i;


  while(1)
 {
  for(i=0;i<8;i++)
 {
 P0=table[i];//11111110
  delay();
  }
}
}


方法三:利用函数封装库

#include <reg52.h>
#include <intrins.h>  //此为调用函数的头文件必须添加

#define uchar unsigned char 
#define uint unsigned int

//延时函数
void delay(void)
{
  uchar a,b;
  for(a=0;a<200;a++)
  for(b=0;b<200;b++);
}

void main()
{
  uchar k;


 k=0xfe;          //定义初值

  while(1)
  {
 P0=k;
  delay();
 k=_crol_(k,1);   //调用头文件封装库函数
  }
}

还有移位运算等其他的方法在这里就不一一列出,大家可以自己尝试!


2019-01-21 11:17:48 Zz0615 阅读数 1119

这里使用的是AT89S51,利用定时器方式1实现跑马灯可以以5种速度变换(速度可以增加,只需要修改一点点的代码),并实现4种花样(用K1-K4键进行控制),也使用到了点阵。

  1. 实现过程

    由于之前有做过按下按键使数码管显示的数字加一或减一的实验,本次的课程设计就使用此框架进行改造。
    首先是控制速度,我使用的方法是将速度储存在R0中,然后每次按下按键使R0加一,再调用数码管显示程序;接着控制花样,这个就让不同按键对应使不同的值存入R2中,最后在跑马灯花样控制时进行判断。

  2. 关于点阵
    点阵是我们一直想实现的内容,但是由于对74HC595的不熟悉,我们就利用P0口进行控制(还要向大佬学习),想要实现的是按下K4键点阵按照当前的速度进行移动,这里就遇到了一点点的挫折,因为忘记了延时程序还有使用到数码管显示程序,所以就造成了一些困惑,不管怎样,结果还是可以吧。

  3. 结果展示
    点阵按照一定的速度移动

  4. 代码

		ORG 	0000H
		LJMP 	MAIN
		ORG		000BH
		LJMP	TIMER0
		ORG 	1000H
		
;=========进行初始化==========================
MAIN:   
		CLR A			;把A清零
		MOV R0,#0		;赋初值,用于记录当前的数值
		MOV R1,#0
		MOV R2,#0		;R2用于选择第几中变换方式
		MOV P2,#0FEH	;跑马灯的初值
		MOV 50H,#00H
		
LOOP:	LCALL DIS		;等待按键按下
		LCALL KEY1
		;LCALL TIME_S
		SJMP LOOP

KEY1:	
;=========判断按键是否按下====================
		;LCALL DIS		;用于显示当前的数值(即使按键没有按下)
		MOV P3,#0FFH	;将初值赋给P3,写入全一
		MOV A,P3		;P3的值赋给A
		CPL A			;累加器A中的内容取反
		ANL A,#0FH		;检查是否有按键按下(只有四个按键)
		JZ KEY1			;累加器为0,即如果没有按键按下就跳转回到KEY1
		
		LCALL DELAY		;延时程序去抖动
		
		MOV P3,#0FFH	;重新判断是否有按键按下
		MOV A,P3
		CPL A
		ANL A,#0FH	
		JZ KEY1			;若无按键按下,则继续循环
		
		JB ACC.0, PK1	;检查按键按下的情况
		JB ACC.1, PK2
		JB ACC.2, PK3
		JB ACC.3, PK4
		
		
PK1:	LCALL PKAY2		
		LJMP PK
PK2:  	LCALL PKAY1
		LJMP PK
PK3:	LCALL PKAY3
		LJMP PK
PK4:    LCALL PKAY4
		LJMP PK
PK:		RET		
		
;=========对按键按下进行处理====================		
;处理K1按下的情况
PKAY1:	CJNE R0,#5,ADD_OP	;判断是否等于5,即是否溢出,若无溢出,则跳转到加法运算
		MOV R0,#0			;如果等于5的话,就让R0回到0
ADD_OP:						;加法运算
		INC R0		        ;R0加一
		LCALL DIS			;调用数码管显示程序
LIGHT:
		MOV R2,#01H		    ;表示选择第一种花样
		SJMP DIS_2	
		RET
;处理K2按下的情况		
PKAY2:  CJNE R0,#5,ADD_OP_2	;和K1的处理方式相似
		MOV R0,#0	
ADD_OP_2:					;加法运算
		INC R0		        ;R0加一
		LCALL DIS			;调用数码管显示程序
LIGHT_2:
		MOV R2,#02H			;表示选择第二种花样
		SJMP DIS_2	
		RET
			
;处理K3按下的情况		
PKAY3:	CJNE R0,#5,ADD_OP_3	;和K1的处理方式相似
		MOV R0,#0
ADD_OP_3:					;加法运算
		INC R0		        ;R0加一
		LCALL DIS			;调用数码管显示程序
LIGHT_3:
		MOV R2,#03H			;表示选择第三种花样
		SJMP DIS_2	
		RET	
		
;处理K4按下的情况
PKAY4:  CJNE R0,#5,ADD_OP_4 ;和K1的处理方式相似
		MOV R0,#0
ADD_OP_4:					;加法运算
		INC R0				;R0加一
		LCALL TIME_S		;调用数码管显示程序
		LCALL TIME_S
		;LCALL DIS
LIGHT_4:				
		MOV R2,#04H			;表示选择第四种花样
		MOV P0,#00H
		SJMP DIS_2
		RET
		
DIS_2:
		MOV R6,#0
		MOV DPTR,#NUM_CLOCK	;这里根据R0表示取出跑马灯的不同速度,
		MOV A,R0			;不同速度储存在NUM_CLOCK中,进行片选
		MOVC A,@A+DPTR
		MOV R3,A 			;利用不同的初值可以选择不同的速度
		MOV 41H,A
		SJMP DIS_3			;跳转到跑马灯程序

KRET:
		RET
		
		
;=========将结果展示在数码管上=================
DIS:	PUSH ACC
		MOV A,R0
		MOV R1,A			;A的值用R1暂存
		MOV DPTR ,#NUM		;取表值
		
		MOV A,R1
		MOVC A,@A+DPTR		;选择不同的字形码
		MOV P0,A 			;输送到P0口
		LCALL TIME_S		;延时程序
		
		POP ACC 
		RET

;=========跑马灯程序==========================		
DIS_3:	MOV R3,41H	
		MOV TMOD, #01H		  ;令T0为定时器方式1
		MOV TH0, #0D8H		  ;装入定时初值
		MOV TL0, #0F0H		  
		
		SETB EA			   	  ;开定时器中断总开关
		SETB ET0			  ;启动T0计数
		SETB TR0			  
		CLR	A				  ;把A清零	
		;MOV A,#0FEH
		LJMP	KRET
HERE:	AJMP HERE		
TIMER0:	
		MOV TH0, #0D8H		  ;重装定时初值
		MOV TL0, #0F0H		
		DJNZ R3,GOON
		MOV R3,41H
		CJNE R2,#01,A1
		AJMP MOD1
		AJMP A4
A1:		CJNE R2,#02,A2
		AJMP MOD2
		AJMP A4
A2:		CJNE R2,#03,A3
		AJMP MOD3
		AJMP A4
A3:		CJNE R2,#04,A4
		AJMP MOD4
A4:		RETI
GOON:	RETI

MOD1:	MOV A,P2				;方式一:跑马灯从当前位置向后移动一位
		RL A
		MOV P2,A 
		RETI
		
MOD2:	MOV A, P2				;方式二:跑马灯从当前位置向前移动一位  
		RR A				   
		MOV P2, A	
		
		RETI
		
MOD3:	MOV A, P2				;方式三:跑马灯从当前位置向前移动两位	
		RL A
		RL A
		MOV P2, A
		RETI
MOD4:							;方式四:实现LED点阵的花样控制	
		
		MOV DPTR,#TABA
		MOV A,R6
		MOVC A,@A+DPTR
		MOV P0,A
		INC R6
		CJNE R6,#5,RE_0
RE_0:	RETI
		MOV R6,#0
		RETI
;=========延时程序============================		
DELAY:  MOV R4,#200			;延时程序,其中调用DIS是为了防止按键按下时会闪烁			
D:		DJNZ R4,D
		RET

TIME_S:
		MOV R5,#250			;延时程序
D2:		MOV R7,#250
D3:		DJNZ R7,D3
		DJNZ R5,D2
		RET


NUM_CLOCK:					;定时器以每次0.01s的节奏循环的次数
		DB	00H, ,96H,064H,032H,14H  ;200 150 100 50 20
		
NUM:
		DB 3FH,06H,5BH,4FH,66H
		DB 6DH,7DH,07H,7FH,6FH

TABA: 	DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH
		DB 01H,02H,04H,08H,10H,20H,40H,80H
		DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH
		DB 01H,02H,04H,08H,10H,20H,40H,80H
		
		DB 0FEH,0FBH,0EFH,0BFH
		DB 0FDH,0F7H,0DFH,07FH
		DB 01H,04H,10H,40H
		DB 02H,08H,20H,80H
		
		DB 0FEH,0F7H,0BFH
		DB 0FDH,0EFH,07FH
		DB 0FBH,0DFH
		DB 01H,08H,40H
		DB 02H,10H,80H
		DB 04H,20H
		
		DB 0FEH,0EFH
		DB 0FDH,0DFH
		DB 0FBH,0BFH
		DB 0F7H,07FH
		DB 01H,10H
		DB 02H,20H
		DB 04H,40H
		DB 08H,80H
		
;TABB: 	DB 01H,02H,04H,08H,10H,20H,40H,80H

		END

2016-01-25 11:30:00 baidu_33836580 阅读数 3308

求单片机程序,实现灯左右移动和闪烁

   悬赏分:100 - 解决时间:2009-12-3 23:22

功能说明:单片机P1口接八只LED,要求端口做单一灯的变化:从P1.0开始先向左移3次,然后向右移2次,再闪烁4次,不断循环。

最佳答案:

用汇编语言编写程序如下。

    ORG   0000H

    MOV   A,   #0FEH

SSS:

    MOV   P1, A           ;P1.0外接LED发光

    LCALL DL1S

    RL    A                ;左移一位

    MOV P1, A           ;P1.1外接LED发光

    LCALL DL1S

    RL    A

    MOV   P1, A

    LCALL DL1S

    RL    A

    MOV   P1, A           ;左移3次完成

    LCALL DL1S

    RR    A                ;右移

    MOV   P1, A

    LCALL DL1S

    RR    A                ;右移

    MOV   P1, A

    LCALL DL1S

    MOV   P1, #0FF       ;灭

    LCALL DL1S

    MOV   P1, A           ;亮

    LCALL DL1S

    MOV   P1, #0FF       ;灭

    LCALL DL1S

    MOV   P1, A           ;亮

    LCALL DL1S

    MOV   P1, #0FF       ;灭

    LCALL DL1S

  MOV   P1, A           ;亮

    LCALL DL1S

    MOV   P1, #0FF       ;灭

    LCALL DL1S

  MOV   P1, A           ;亮

    LCALL DL1S

LJMP SSS                  ;循环

DL1S:                      ;亮灯时间,由下面的数字进行控制

    MOV   R5, #20

DL2:MOV   R6, #100

DL3:MOV   R7, #250

    DJNZ R7, $

    DJNZ R6, DL3

    DJNZ R5, DL2

    RET

回答者: 做而论道 - 十一级   2009-12-2 11:36

提问者对于答案的评价:谢谢

2014-04-12 08:49:45 greatwall_sdut 阅读数 3871
/*
* 跑马灯程序,做单片机的第一个小程序,相当于软件开发中的hello world
* 可实现led灯循环移动
* 通过P1口的8个引脚控制8个led灯的亮灭。
* 滨州学院信息技术研发中心 孙继磊  2014-4-11
*/
#include <reg52.h>
unsigned char  rotate(unsigned char n);
void main(void)
{    
	unsigned int j;
	unsigned char i=0xf0,k=0xf0;
	while(1)
	{ 
	  P1 = i;             //为p1口赋值(即相当于给8个引脚赋值)
	  for(j=0;j<40000;j++);//延时,保持当前灯亮状态一段时间,使人眼能够观察得到
	  i=rotate(i);         //循环右移
    }
}
//循环右移一位
unsigned char  rotate(unsigned char n)
{
    unsigned char t ;
    t = n & 1;		//取最低位
    n = n>>1;
    if(t) n = n | 0x80;
    return n;
}



2017-07-25 17:45:19 hemeinvyiqiluoben 阅读数 2671

转自: http://blog.csdn.net/Code_star_one/article/details/52999079


通过一位 F 的16进制 转换为 2进制的 1111 然后移动一位 有三极管开关所改变。0的时候发光,1的时候变暗。所以一开始0FFH表示高8位为0; 
低8位为1111 1111,表示全暗,然后右移变为1111 1110亮第一个等。 
之后类推。实现了跑马灯。

    ORG     0000H
    AJMP    MAIN
    ORG     0030H        //因为 0003H是外部中断0入口地址... 0002B 是定时器中断 T2入口地址 ,故一般都是从0030H开始写
MAIN:
    MOV     A,#0FFH 
    CLR     C       
    MOV     R2,#08H 

LOOP1:  
    RLC     A       /*左移一位*/
    MOV     P0,A    
    ACALL   DEL     
    DJNZ    R2,LOOP1    
    MOV     R2,#08H 

LOOP2:  
    RRC     A       /*右移一位*/
    MOV     P0,A    
    ACALL   DEL 
    DJNZ    R2,LOOP2    
    JMP     MAIN    


DEL:    MOV R5,#05H    /*这是一个延时函数*/
DEL1:   MOV R6,#0F0H
DEL2:   MOV R7,#0F0H
DEL3:   DJNZ R7, DEL3
    DJNZ R6, DEL2
    DJNZ R5, DEL1
    RET
END


跑马灯来回跑

阅读数 669