gpt4 book ai didi

c - 旋转编码器防溢出

转载 作者:太空狗 更新时间:2023-10-29 16:13:13 26 4
gpt4 key购买 nike

我正在为 AVR Atmega328p 微 Controller 编写代码。微 Controller 应该读取编码器并根据编码器的旋转递增或递减 r23。不幸的是,此时,无论我转动编码器的方向如何,输出只会下降到 0,然后从 255 开始。

我的代码相当简单,它基于结合了编码器先前状态和当前状态的表查找值。如果之前的状态和当前状态没有结合起来创建一个有效的回合,则会返回一个错误并且代码不执行任何操作。如果发生有效的状态更改,则通过 r24 将 1 或 -1 添加到 r23。

让微 Controller 读取编码器没有问题,但我不知道如何防止 r23 溢出。我的问题是当我打到 255 并加 1 时,寄存器溢出并变为 0。我不希望寄存器变为零;我希望它保持在 255,直到我以相反的方向旋转编码器。我对 0 有同样的问题。如果寄存器为 0 并且我添加 -1,我不希望寄存器转到 255,我希望它保持在 0,直到我以相反的方向旋转它。

我对跳出框框思考没有问题。如果您有解决方案或想法,请随时发布。

;**** A P P L I C A T I O N   N O T E  *************************************
;*
;* Title:
;* Version:
;* Last updated:
;* Target: AVR Dragon
;*
;*
;* DESCRIPTION
;*
;*.device ATmega328P @ 1M clock speed
;*
;* This is a simple program to test an optical encoder
;***************************************************************************

.include "m328Pdef.inc"
.org 0x0000
jmp RESET ;Reset Handle

.org 0x0008
jmp Interrupt1 ; PCINT1 Handler

enc_states:
.db 0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0

RESET:

;Setup stack pointer
ldi temp, low(RAMEND)
out SPL, temp
ldi temp, high(RAMEND)
out SPH, temp

//Set Port B pins to output
ser temp ; Set Register Rd <-- 0xff (output)
out DDRB,temp ; set all PORTB bits as output

//Clear analog input pins and enable pull ups on Pin 0 and 1 (Port C)
clr temp
out DDRC, temp ;all pins input
ldi temp, (1<<PC1)|(1<<PC0)
out PORTC,temp ;Enable pullups on Pin 0 and 1

//Set Port D pins to output
ser temp ; Set Register Rd <-- 0xff
out DDRD,temp ; set all PORTD bits as output

//Enable encoder pins interrupt sources (Encoder 1)
ldi temp, (1<<PCINT9)|(1<<PCINT8)
sts PCMSK1, temp

//Enable encoder pins interrupt sources (Encoder 2)
// ldi temp, (1<<PCINT11)|(1<<PCINT10)
// sts PCMSK1, temp

//Enable pin change interrupts
ldi temp, (1<<PCIE1)
sts PCICR, temp

//Enable global interrupts
sei

//Lookup table initial value
ldi ZL, 0x00 ;lookup table index and initial state

.def temp = r16
clr r25
clr r24
clr r23

loop:
out PORTB, r23
jmp loop

Interrupt1:
// Push SREG, etc
in r25, PORTC ;encoder value from PORTC

ldi ZH, High(enc_states*2) ; setup Z pointer hi
ldi ZL, Low (enc_states*2) ; setup Z pointer lo
rol r22 ;remember previous state and shift left twice
rol r22
cbr r25, 0xFC ;clear encoder bits 7:2
mov r21,r25
or r25, r22 ;combine encoder bits with old bits
cbr r25, 0xF0 ;clear bits 7:4 for table lookup
mov r22, r25 ;save table lookup value
mov ZL, r25 ;load index value into table
lpm r24, z ;get result
add r23,r24

// Pop SREG, etc.
reti

最佳答案

“饱和度”可以通过利用进位标志非常简单地完成,例如:

  mov __tmp_reg__, r23
add __tmp_reg__, r24 ; do the addition

brcs saturated ; if the carry flag is set we have an overflow and should discard the result

mov r23, __tmp_reg__ ; there was no overflow so we store the result

saturated:

将 ISR 末尾的 add r23,r24 替换为上述代码,您应该没问题。 (显然,您可能需要将 __tmp_reg__ 更改为可以用作临时存储的寄存器。)

考虑到 r24 可能是正数、负数或零,所有情况都可以通过稍微扩展上述原则来正确处理:

  mov __tmp_reg__, r23

tst r24

breq doreturn ; if r24 == 0 we have nothing to do and may just return

brmi subtract ; if r24 is 'negative' we need to subtract

add __tmp_reg__, r24 ; if r24 is not negative we just add
rjmp store ; and go to where the result may be stored

subtract:

neg r24 ; r24 := -r24
sub __tmp_reg__, r24 ; do the subtraction

store:

brcs doreturn ; if the carry flag is set we have an overflow and should discard the result

mov r23, __tmp_reg__ ; there was no overflow so we store the result

doreturn:

仔细查看您的代码,在我看来,当 Z 指针的计算完成时,其中还有另一个“故障”:

ldi   ZH, High(enc_states*2)   ; setup Z pointer hi
ldi ZL, Low (enc_states*2) ; setup Z pointer lo

mov     ZL, r25    ;load index value into table

看起来有问题:Z 地址的较低部分只是被忽略并被索引值覆盖。如果 Low (enc_states*2) 恰好不是 0,这将导致麻烦;您可能需要执行 add ZL, r25adc ZH, __zero_reg__(16 位加法)而不是 mov ZL, r25

另一种可能降低日常工作复杂性的想法:

增量旋转编码器的输出可以解释为某种同步串行数据:一个输出(比如“A”)代表“时钟”信号,而另一个输出(“B”)代表“数据”信号。

您可以自由选择哪个输出用于哪个信号,以及您选择的“时钟”极性。算法就相当简单了:

  1. (去抖动和)检测“时钟”信号上的上升(或下降,由您选择)转换
  2. 一旦检测到“时钟”边沿,只需读取“数据”信号的电平 - 这里不需要去抖动
  3. 读取的单个“数据”位直接指示编码器刚刚迈出的方向:“0”或“1”,一个方向或另一个方向。

在伪代码中,这看起来像:

bit lastClockState;

void readEncoder() {

bit currentClockState = readClockPin();

if ( lastClockState == 1 && currentClockState == 0 ) {
// A (falling) edge was detected...

// Get the direction of the rotation:
bit direction = readDataPin();

if ( direction == 1 ) {
value++;
} else {
value--;
}
}

lastClockState = currentClockState; // Update the lastClockState for the next iteration

}

例如,让它每 10 毫秒执行一次,您就已经拥有了一些“免费”的极简去抖动。

(顺便说一句,总结之前许多其他人的教训:不要尝试使用一些外部/引脚变化中断来检测任何机械开关或机械编码器产生的(未去抖动的)信号转换这很重要。机械元件的弹跳特性将确保它永远不会按预期工作。)

关于c - 旋转编码器防溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15235060/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com