将PIN状态作为功能参数传递

问题描述 投票:1回答:3

我想为我的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;
    }
}
} 

我有一个预感我的问题是我使用的数据类型作为参数,我似乎在网上得到了不同的答案。

任何帮助,将不胜感激!

c embedded avr atmega
3个回答
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))

0
投票

各种问题:

  • 功能应该是void debounceSwitch(volatile uint8_t* port, uint8_t pin)。指向硬件寄存器的指针必须始终为volatile。返回任何东西都没有意义。
  • 在位移时,切勿使用1签名的int文字。当1u << n大于8时,应该是n或你的程序会出错。
  • 在繁忙的延迟中多次燃烧30ms是一种可怕的做法。它会将你的CPU锁定在100%,没有任何意义,永恒。

去抖按钮有很多种方法。最简单的专业形式可能是每隔10ms就有一个周期性的定时器运行中断(应该足够了,如果有疑问的话,用你的按钮测量按钮的去抖峰)。它看起来像下面的伪代码:

volatile bool button_pressed = false;

void timer_interrupt (void)
{
  uint8_t button = port & mask;
  button_pressed = button && prev;
  prev = button;
}

假设按钮使用高效逻辑。


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
 }
© www.soinside.com 2019 - 2024. All rights reserved.