Передача статуса PIN в качестве функционального параметра - PullRequest
0 голосов
/ 27 февраля 2019

Я хочу написать функцию для моего 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 голосов
/ 27 февраля 2019

Различные проблемы:

  • Функция должна быть void debounceSwitch(volatile uint8_t* port, uint8_t pin).Указатели на аппаратные регистры всегда должны быть volatile.Не имеет смысла возвращать что-либо.
  • Никогда не используйте 1 подписанные int литералы при сдвиге битов.Должно быть 1u << n, иначе ваша программа будет выдавать ошибку, если n больше 8.
  • Сжигание 30 мс несколько раз за задержку занятости - ужасная практика.Он будет блокировать ваш процессор на 100%, ничего не делая бессмысленно, на вечность.

Есть много способов отменить кнопки.Простейшая профессиональная форма, вероятно, состоит в том, чтобы иметь периодический таймер, работающий с прерыванием каждые 10 мс (этого должно быть достаточно, если сомневаетесь, измерьте шипы отклонения вашей кнопки с областью действия).Это будет выглядеть примерно так: псевдокод:

volatile bool button_pressed = false;

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

При этом предполагается, что кнопки используют активную высокую логику.

0 голосов
/ 28 февраля 2019

Что мне не нравится в вашей реализации, так это чистая зависимость от обработки 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
 }
0 голосов
/ 27 февраля 2019

В портах AVR имеются специальные регистры ввода-вывода, доступ к которым осуществляется с помощью инструкций 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))
...