查表法,AVR 单片机
#define ROTARY_STOP 0
#define ROTARY_CW 1
#define ROTARY_CCW -1
#define ROTARY_MODE_HALF 0
#define ROTARY_MODE_FULL 1
#define ROTARY_MODE ROTARY_MODE_HALF
uint8_t _rotary_stats;
const char _rotary_value_table[16] PROGMEM = {
ROTARY_STOP, // 00: 00 -> 00
ROTARY_CW, // 01: 01 -> 00
ROTARY_CCW, // 02: 10 -> 00
ROTARY_STOP, // 03: 11 -> 00
#if ROTARY_MODE == ROTARY_MODE_HALF
ROTARY_STOP, // 04: 00 -> 01
ROTARY_STOP, // 05: 01 -> 01
ROTARY_STOP, // 06: 10 -> 01
ROTARY_STOP, // 07: 11 -> 01
ROTARY_STOP, // 08: 00 -> 10
ROTARY_STOP, // 09: 01 -> 10
ROTARY_STOP, // 10: 10 -> 10
ROTARY_STOP, // 11: 11 -> 10
#else
ROTARY_CCW, // 04: 00 -> 01
ROTARY_STOP, // 05: 01 -> 01
ROTARY_STOP, // 06: 10 -> 01
ROTARY_CW, // 07: 11 -> 01
ROTARY_CW, // 08: 00 -> 10
ROTARY_STOP, // 09: 01 -> 10
ROTARY_STOP, // 10: 10 -> 10
ROTARY_CCW, // 11: 11 -> 10
#endif
ROTARY_STOP, // 12: 00 -> 11#
ROTARY_CCW, // 13: 01 -> 11
ROTARY_CW, // 14: 10 -> 11
ROTARY_STOP // 15: 11 -> 11
};
char read_rotary() {
char rtnval;
// 0000aabb
// aa: current stats
// bb: last stats
if (_READ_PIN(ROTARY_HW_A)) _rotary_stats |= 0x04;
if (_READ_PIN(ROTARY_HW_B)) _rotary_stats |= 0x08;
rtnval = pgm_read_byte(_rotary_value_table + _rotary_stats);
_rotary_stats = _rotary_stats >> 2;
return rtnval;
}
解读:
read_rotary
函数中,_READ_PIN
宏用于读取 IO 状态,并将当前状态保存于_rotary_stats
变量的第 2、3 位- 此时
_rotary_stats
变量第 2、3 位为当前状态,第 1、0 位为上次检查状态,这 4 位共同作为索引进行查表 - 表的编制:上次状态与当前状态共有 16 种组合,分别对应 16 个索引,每个索引值对应一种状态变化过程,根据正交编码原理,可以得知对应的动作,据此打表
- 查表后,将当前
_rotary_stats
右移 2 位,待下次进入read_rotary
后,当前状态已变为上次状态。