我想为我的AVR ATmega328编写一个函数,该函数使用状态空间来确认开关的按下来对开关进行反跳。完成它之后,我想对我的函数进行泛化,以便将来在不做任何工作的情况下就可以重用它,但这涉及将我想用作功能参数的引脚传递给我,而我只是无法使其正常工作。>
这就是我现在拥有的:
int debounceSwitch(unsigned char *port, uint8_t mask)
{
int n = 0;
while (1)
{
switch (n)
{
case 0: //NoPush State
_delay_ms(30);
if(!(*port & (1<<mask))){n = n + 1;}
else {return 0;}
break;
case 1: //MaybePush State
_delay_ms(30);
if(!(*port & (1<<mask))){n = n + 1;}
else {n = n - 1;}
break;
case 2: //YesPush State
_delay_ms(30);
if(!(*port & (1<<mask))){return 1;}
else {n = n - 1;}
break;
}
}
}
我有一个直觉,我的问题是我正在使用的数据类型作为参数,而且我似乎在网上得到了不同的答案。
任何帮助将不胜感激!
答案 0 :(得分:0)
AVR端口中的端口是特殊的IO寄存器,可使用IN和OUT指令对其进行访问。不像使用LDR等的内存。
从端口定义中可以看到,您需要使端口指针易变。当您试图将PORT传递给该函数时,编译器也会警告您。
#define PORTB _SFR_IO8(0x05)
映射到
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
答案 1 :(得分:0)
各种问题:
void debounceSwitch(volatile uint8_t* port, uint8_t pin)
。指向硬件寄存器的指针必须始终为volatile
。返回任何东西都没有意义。1
签名的int
文字。应该为1u << n
,否则当n
大于8时您的程序会出错。有许多种方法可以消除按钮的抖动。最简单的专业形式可能是让周期计时器每10ms运行一次中断(如果有疑问,请用示波器测量按钮的反跳尖峰就足够了)。它看起来像下面的伪代码:
volatile bool button_pressed = false;
void timer_interrupt (void)
{
uint8_t button = port & mask;
button_pressed = button && prev;
prev = button;
}
这假设按钮使用高电平有效逻辑。
答案 2 :(得分:0)
我对您的实现不满意的是对PORT / IO处理和实际的过滤器/反跳逻辑的纯粹依赖。然后,当开关输入通过信号例如来自CAN吗?
此外,如果您考虑使用可配置/可参数化的过滤器,则可以更轻松地进行处理。您只需实现一次逻辑,然后只需创建适当的配置并将单独的状态变量传递到过滤器即可。
// Structure to keep state
typedef struct {
boolean state;
uint8 cnt;
} deb_state_t;
// Structure to configure the filters debounce values
typedef struct {
uint8 cnt[2]; // [0] = H->L transition, [1] = L->H transition
} deb_config_t;
boolean debounce(boolean in, deb_state_t *state, const deb_config_t *cfg)
{
if (state->state != in) {
state->cnt++;
if (state->cnt >= cfg->cnt[in]) {
state->state = in;
state->cnt = 0;
}
} else {
state->cnt = 0;
}
return state->state;
}
static const deb_config_t debcfg_pin = { {3,4} };
static const deb_config_t debcfg_can = { {2,1} };
int main(void)
{
boolean in1, in2, out1, out2;
deb_state_t debstate_pin = {0, 0};
deb_state_t debstate_can = {0, 0};
while(1) {
// read pin and convert to 0/1
in1 = READ_PORT(PORTx, PINxy); // however this is defined on this architecture
out1 = debounce(in1, &debstate_pin, &debcfg_pin);
// same handling, but input from CAN
in2 = READ_CAN(MSGx, SIGxy); // however this is defined on this architecture
out2 = debounce(in2, &debstate_can, &debcfg_can);
// out1 & out2 are now debounced
}