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

时间:2019-02-27 03:16:05

标签: c embedded avr atmega

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

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

任何帮助将不胜感激!

3 个答案:

答案 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时您的程序会出错。
  • 在忙碌的延迟中多次消耗30ms的时间是可怕的做法。它将永恒地将您的CPU锁定在100%无所作为。

有许多种方法可以消除按钮的抖动。最简单的专业形式可能是让周期计时器每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
 }