Atmega2560 中的圆形 LED 回路使用组装

Posted

技术标签:

【中文标题】Atmega2560 中的圆形 LED 回路使用组装【英文标题】:Circular led loop in Atmega2560 using Assembly 【发布时间】:2017-11-21 14:04:17 【问题描述】:

我正在使用Atmega2560 微控制器开发一个简单的 LED 项目。 LED 应分别以圆形模式旋转。

DEF 常量:

LED_AMNT : 多少个 LED 会亮

LED_DATA:哪些 LED 可以工作

LED 布局设计:

LED_AMNT = 1 动画

LED_AMNT = 2 动画

我写的代码有点错误。

1) L7 和 L0 不能一起工作。最后第一个位移为 0。

步骤 0:L0 和 L1 -> 0000 0011

...

第 6 步:L6 和 L7 -> 1100 0000

第 7 步:L7 和 L0 -> 1000 0001(必须如此)

Step 7 : L7 and L0 -> //跳到Step 0

2) 当我点击LED_AMNT_INCREASE 按钮时,LED 的数量正在增加,但当游览结束时。它不会立即增加。我正在等待当前的巡演结束。 (当0x80变为0x01时)

我写了一个简单的程序,如下所示:

.def LEDS = R16

.def LED_DIRECTION = R17
.def LED_AMOUNT = R19
.def LED_DATA = R21

.org 0
    rjmp MAIN

MAIN:
    ldi LEDS, 0xFF          ; 0xFF = 1111 1111 

    ldi LED_DATA, 0x01      ; PORTC load register
    ldi LED_DIRECTION, 0x01 ; 0x01 ==> Right, 0x00 ==> Left
    ldi LED_AMOUNT, 0x01    ; total active led count

    out DDRC, LEDS          ; make PORTC's all pins to output
    sbi PORTB, 0
    sbi PORTB, 1
    sbi PORTB, 2

LOOP_MAIN:
    out PORTC, LED_DATA
    call DELAY
    call DELAY
    call DELAY
    call DELAY
    call DELAY

    sbis PINB, 0        
    rjmp BUTTON_CLICK_DIRECTION

    sbis PINB, 1        
    rjmp BUTTON_CLICK_AMOUNT

    cpi LED_DIRECTION, 0x01
    brne LOOP_RIGHT

    LOOP_LEFT:
    lsl LED_DATA
    cpi LED_DATA, 0x80
    brne LOOP_MAIN
    LEFT_RESET:
    lsl LED_DATA
    out PORTC, LED_DATA
    call DELAY
    mov LED_DATA, LED_AMOUNT
    ;mov LED_DATA, LED_AMOUNT
    ;brne LEFT_RESET
    rjmp LOOP_MAIN

    LOOP_RIGHT:


    LOOP_MAIN_END:
    rjmp LOOP_MAIN

BUTTON_CLICK_DIRECTION: 
    cpi LED_DIRECTION, 0x00
    brne it_is
    it_isnt:
    ldi LED_DIRECTION, 0x01
    rjmp yon_end
    it_is:
    ldi LED_DIRECTION, 0x00
    yon_end:
    rjmp LOOP_MAIN

BUTTON_CLICK_AMOUNT:
    rol LED_AMOUNT  
    cpi LED_AMOUNT, 0x1F
    breq amount_reset
    rjmp amount_end
    amount_reset:
    ldi LED_AMOUNT, 0x01
    amount_end:
    mov LED_DATA, LED_AMOUNT
    rjmp LOOP_MAIN

DELAY:          
   push r16     
   push r17     

   mov r16,0x40
   ldi r17,0x00     
   ldi r18,0x00     
_w0:
   dec r18          
   brne _w0     
   dec r17          
   brne _w0         
   dec r16          
   brne _w0         
   pop r17          
   pop r16          
   ret  

【问题讨论】:

对于 1) 你应该实现一个适当的旋转,总是把顶部的位带回底部。您的仅适用于单个 LED 外壳。对于 2) 你当然需要更新当前模式。完全不清楚你在用rol LED_AMOUNT; cpi LED_AMOUNT, 0x1f 做什么......为什么不是增量? 这意味着,我不想旋转最小 1 个 LED,最大 4 个 LED。我知道,它的设计很糟糕。我该怎么做? 【参考方案1】:

你基本上想要旋转字节的值。您可以通过以下伪代码执行此操作:

// Check if most significant bit is set:
if ( (LED_DATA & 0x80) != 0 ) 
  LED_DATA = LED_DATA << 1 | 1; // Copy msb to lsb after shift.
 else 
  LED_DATA = LED_DATA << 1;

在汇编程序中,您也可以将移位后的进位位复制到 LSB:

lsl LED_DATA
adc LED_DATA, ZERO_REG ; add 0 + carry (either 0 or 1) to LED_DATA

或者,更详细地说:

lsl LED_DATA
brcc SHIFT_0_IN ; if carry not set, the MSB was not set, so skip setting the LSB
ori LED_DATA, 1 ; set LSB to 1

SHIFT_0_IN:
  ; keep LSB as 0 -> do nothing, just continue

...

同样适用于其他方向的旋转: 只需右移 (LSR),将 ori LED_DATA, 1 替换为 ori LED_DATA, 0x80,设置 MSB 而不是 LSB。

要更新运行模式,您必须查看当前状态以找到要设置的位。

这可以通过“智能”方式完成:在移动 LED_DATA 之前,检查是否应该添加另一个 LED 位。如果不是,则按上述方式进行转换。如果是,请记住LED_DATA的旧值,如上移位LED_DATA,然后设置LED_DATA = LED_DATA | prevLedData

一种“简单”的方法是使用四种不同的模式,例如LED_DATA_1 = 0x00000001LED_DATA_2 = 0b00000011LED_DATA_3 = 0b00000111LED_DATA_4 = 0b00001111。在每一步中,您旋转所有四个值,并根据实际需要打开的 LED 数量,从四个寄存器之一输出相应的值。您需要另一个寄存器来存储每次按下按钮时应点亮多少个 LED,从 1 到 4(或 0 到 3)再回到 1(或 0)。

【讨论】:

谢谢你,你是救命稻草 :) 但我没看懂最后一段。当我点击“BUTTON_CLICK_AMOUNT”时我应该改变什么我不想旋转min-1 led,max-4 led。 对不起,我不是很清楚,错过了从4到1溢出的情况。我补充一些想法。 谢谢,我用 xor 和门解决了这个问题,将 LED 计数 4 更改为 1。我的重置功能:mov LED_DATA_PREV, LED_DATA lsl LED_DATA_PREV EOR LED_VERI, LED_DATA_PREV AND LED_DATA, LED_DATA_PREV 但是,如果 LED_DATA 为 1000 0111,则它不起作用。因为我向左移动。

以上是关于Atmega2560 中的圆形 LED 回路使用组装的主要内容,如果未能解决你的问题,请参考以下文章

Arduino使用所有端口ATMega2560

在 Atmel AVR studio 中使用 ATMega2560 读取 RC PWM 信号

PB7 上的 Atmega2560 PWM

使用定时器中断闪烁 LED(atmega 128)

ATmega8仿真——LED 数码管的学习

贴片LED灯工作电压?