2440汇编跑马灯优化方案

led驱动电路:led1 --> GPF4          led2 --> GPF5                led4 --> GPF6

 


方案一:蛮力破解法。直接安排多个子程序,在各个子程序中点亮一个led,轮转调用子程序点灯。

.text
.global _start

_start:
    /* 关闭看门狗 */
    ldr r0, =0x53000000
    ldr r1, =0
    str r1, [r0]

    /*led1 --> GPF4
    **led2 --> GPF5
    **led4 --> GPF6
    **gpfcon 0x56000050
    **gpfdat 0x56000054    
    */
    ldr r0,=0x56000050    //配置gpfcon寄存器让对应引脚为输出模式
    ldr r1,=0x00001500
    str r1,[r0]

    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000070    //全灭
    str r1,[r0]

led3:
    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000030    //亮led4
    str r1,[r0]
    bl delay

led2:
    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000050    //亮led2
    str r1,[r0]
    bl delay

led1:
    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000060    //亮led1
    str r1,[r0]
    bl delay             //在跳转前,将pc保存在R14寄存器中(lr)
    b led3               //直接跳转

delay:
    mov     r0, #0x20000
1:  subs    r0, r0, #1
    bne     1b
    mov pc,lr         //修改pc返回
    
halt:
    b halt


方案二:利用IO口连续的优势。对某特殊值逻辑右移,在每次右移之后,对应的二进制0/1位刚好吻合跑马灯gpio的高低电平要求。因为逻辑右移空出的高位自动补0。所以,当在临界值时候,应该重新赋值,让其继续移位输出。

.text
.global _start

_start:

    /* 关闭看门狗 */
    ldr r0, =0x53000000
    ldr r1, =0
    str r1, [r0]

    /*led1 --> GPF4
    **led2 --> GPF5
    **led4 --> GPF6
    **gpfcon 0x56000050
    **gpfdat 0x56000054    
    */
    ldr r0,=0x56000050    //配置gpfcon寄存器让对应引脚为输出模式
    ldr r1,=0x00001500
    str r1,[r0]

    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000070    //全灭
    str r1,[r0]

//灯从左往右跑
loop:
    ldr r1,=0xb6db6db6         //1011 0110  1101 1011  0110 1101  1011 0110
run:
    bl delay
    str r1,[r0]
    mov r1,r1,lsr#1        //逻辑右移1
    cmp  r1,#182           //临界值 0000 0000  0000 0000  0000 0000 1011 0110B
    bne run                    //当r1右移到某一值时返回重新赋值 
    b loop

delay:
    mov     r2, #0x20000
1:  subs    r2, r2, #1
    bne     1b
    mov pc,lr


halt:
    b halt
其中,cmp将r1和182作比较,就是两者相减,仅影响cpsr状态寄存器中的标志位,不保存运算结果。如果运算结果不为零,则通过ben run指令跳转到run,从run开始执行。


方案三:和方案二有点类似。利用IO口连续的优势。对某特殊值 循环右移,在每次右移之后,对应的二进制0/1位刚好吻合跑马灯gpio的高低电平要求。但是需要考虑cpsr状态寄存器中的C进位标志的处理与保护。

.text
.global _start

_start:

    /* 关闭看门狗 */
    ldr r0, =0x53000000
    ldr r1, =0
    str r1, [r0]

    /*led1 --> GPF4
    **led2 --> GPF5
    **led4 --> GPF6
    **gpfcon 0x56000050
    **gpfdat 0x56000054    
    */
    ldr r0,=0x56000050    //gpfcon
    ldr r1,=0x00001500
    str r1,[r0]

    ldr r0,=0x56000054    //gpfdat
    ldr r1,=0x00000070    //全灭
    str r1,[r0]

    mrs r3,cpsr                      //读出cpsr的值保存在r3
    orr r3,r3,#0x20000000    //进位标志置1
    msr cpsr_f,r3                  //仅修改条件标志位域中的C进位标志

    ldr r1,=0xb6db6db6
    
//灯从左往右跑
loop:
    str r1,[r0]
    movs r1,r1,rrx        //循环右移1,并且影响cpsr寄存器
    bl delay
    b loop

delay:
    mrs r3,cpsr           //保存当前的状态寄存器
    mov r2, #0x20000
1:  subs r2, r2, #1
    bne  1b
    msr cpsr_f,r3       
    mov pc,lr


halt:
    b halt
在延时子程序中,对状态寄存器的处理,主要是为了保护C进位标志的值,因为延时的过程中C的值已经被指令 subs r2, r2, #1 修改了。若放任不管,这会破坏数值的逻辑,使得led全灭或全亮。

以上代码,在韦东山的jz2440的开发板上都能正常运行,个人比较喜欢第二种方法。

需要注意:如果没有关闭看门狗,则过一段时间会自动复位,导致流水灯失败。


 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值