1
votes

Passer l'état du code PIN en tant que paramètre de fonction

Je veux écrire une fonction pour mon AVR ATmega328 qui supprime les commutateurs en utilisant l'espace d'états pour confirmer une pression de commutateur. Après l'avoir terminé, je voulais généraliser ma fonction afin que je puisse la réutiliser à l'avenir avec peu de travail, mais cela implique de passer la broche que je veux utiliser comme paramètre de fonction, et je ne peux tout simplement pas faire fonctionner cela.

Voici ce que j'ai maintenant:

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;
    }
}
} 

J'ai l'impression que mon problème concerne le type de données que j'utilise comme paramètre, et il semble que j'ai obtenu des réponses différentes en ligne.

Toute aide serait appréciée!


0 commentaires

3 Réponses :


0
votes

Eh bien, dans les ports AVR, il y a des registres IO spéciaux et ils sont accessibles en utilisant les instructions IN et OUT. Pas comme la mémoire utilisant LDR etc.

À partir de la définition du port, vous pouvez voir que vous devez rendre le pointeur de port volatil. que le compilateur vous aurait également indiqué en guise d'avertissement lorsque vous auriez essayé de passer PORT à la fonction.

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

qui correspond à

#define PORTB _SFR_IO8(0x05)


0 commentaires

0
votes

Divers problèmes:

  • La fonction doit être void debounceSwitch (port uint8_t * volatile, pin uint8_t) . Les pointeurs vers les registres matériels doivent toujours être volatils . Cela n'a aucun sens de renvoyer quoi que ce soit.
  • N'utilisez jamais de littéraux 1 signés int lors du transfert de bits. Doit être 1u ou votre programme se déréglera lorsque n est supérieur à 8.
  • Brûler 30 ms plusieurs fois dans un délai chargé est une pratique horrible. Il verrouillera votre CPU à 100% sans rien faire de significatif, pour une éternité.

Il existe de nombreuses façons de supprimer les boutons. La forme professionnelle la plus simple est probablement d'avoir une minuterie périodique exécutée avec interruption toutes les 10 ms (devrait suffire, en cas de doute, mesurer les pointes anti-rebond de votre bouton avec une portée). Cela ressemblera au pseudo-code suivant:

volatile bool button_pressed = false;

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

Ceci en supposant que les boutons utilisent une logique haute active.


1 commentaires

Je vais essayer de nouveau dans cet esprit, merci. Malheureusement, ma première tentative de debouncing était exactement comme vous l'avez dit, attendez juste 10 ms (ce que j'ai trouvé était le temps d'attente recommandé pour le debouncing SW) et revérifiez. Je prends un cours en ce moment et le professeur a décidé d'introduire la conception d'espace d'état en utilisant le debouncing et a dicté à la fois la technique utilisée et les retards, donc je n'ai pas mon mot à dire sur le sujet en utilisant cette méthode).



0
votes

Ce que je n'aime pas dans votre implémentation, c'est la pure dépendance sur la gestion PORT / IO et la logique de filtrage / anti-rebond. Que faites-vous alors, lorsque l'entrée du commutateur reçoit un signal, par exemple de CAN?

En outre, cela peut être géré beaucoup plus facilement, si vous pensez aux filtres configurables / paramétrables. Vous implémentez la logique une fois, puis créez simplement les configurations appropriées et passez des variables d'état séparées dans le filtre.

// 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 commentaires