IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Embarqué Discussion :

Attiny 5 en C [AVR]


Sujet :

Embarqué

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 27
    Points
    27
    Par défaut Attiny 5 en C
    Bonjour à tous

    Je me lance dans un projet perso avec un Attiny 5 et j'ai des difficultés pour détecter l'appui d'un bouton relié à une entrée. Je suis électronicien de base pas programmeur.


    Voici le code
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    // déclaration des variables locales
    int var1;
    int regport = 0;
     
    // setup
    void setup () {
     
    DDRB = 0b0100;                       // on configure PB3 en sortie
    PORTB = 0b0100;                      // PB3 à l'état haut
    regport =PINB;                       // regport enregistre l'état des entrées du portB
      }
    // création de la fonction delay por Attiny5  
    void delay (int millis) {
      for (volatile unsigned int i = 34*millis; i>0; i--);
    }
     
    // boucle principale 
    void loop () {
    var1 = PINB; // Var1 prend l'état des entrées du portB
     
    // test si Var1 est différent de regport pour savoir si l'entrée B0 à changé d'état
     
    if(var1!= regport){
     PORTB = 0b0000;                              // on mets la sortie PB3 à zéro
     delay(200);                                  // on attends 200 milisecondes
     PORTB = 0b0100;                              // on mets la sortie PB3 à un
     
      } 
     
     
    }

    le datasheet https://ww1.microchip.com/downloads/...S40002060A.pdf


    Je vous joint le schéma

    Ma difficulté et sur le test de l'entrée PB0 je ne suis pas sur que ce soit bon car le code tel qu'il est ecrit tourne en boucle en faisant clignoter la led alors que je voudrait simplement l'éteindre 200 millisecondes à chaque appui sur le bouton .
    Si vous avez des pistes soit coté hard ou coté soft je suis preneur

    Nom : schéma.png
Affichages : 635
Taille : 28,0 Ko

  2. #2
    Modérateur

    Homme Profil pro
    Ingénieur électricien
    Inscrit en
    Septembre 2008
    Messages
    1 267
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur électricien

    Informations forums :
    Inscription : Septembre 2008
    Messages : 1 267
    Points : 4 829
    Points
    4 829
    Par défaut
    Bonjour Greg

    Le problème c'est que PinB lit les 4 entrées/sorties (oui une I/O en sortie est également lue). Et donc la condition de test est beaucoup plus souvent vraie.

    Il faut faire du masquage: regport = PINB & 0x0001; et Var1 = PinB & 0x0001;.
    0x0001 peut être écrit 1<<0 ou encore _BV(0). Le zéro étant le numéro du Pin, c'est sans coût tant que la valeur est connue à la compilation.
    Pas besoin de passer par une variable intermédiaire Var1, la lecture de PinB peut se faire directement dans le IF. Avec les AVR on y gagne même en efficacité du code compilé.

    Quelques remarques pour faire plus pro:
    - Mettre le bouton poussoir à la masse et utiliser la pull-up interne de l'ATTiny.
    - Activer les pull-up internes des deux entrées inutilisées pour éviter leur oscillation.
    - Un transistor N fonctionnant mieux qu'un transistor P, Il est préférable que la Led et sa résistance soit reliée à VCC et tirée à la masse par l'ATTiny.
    - Utiliser la bibliothèque <util/delay.h> de l'AVR pour avoir un code optimisé pour la fonction _delay_ms().
    Les trois premiers points étaient déjà obligatoires avec les circuits logiques TTL et sont toujours pertinent avec les circuits modernes bien que plus obligatoires.

    Bonne suite

    Delias

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 27
    Points
    27
    Par défaut ça progresse
    Merci pour ces infos
    Pour les conseils concernant le BP et la LED en fait c'est pour visualiser le code car ensuite ce sera intégré à un montage avec du TTL en entrée et un NPN qui attaque un relais .
    Ce qui me pose PB c'est le masque avec la rotation << ça ça me fait tourner en bourrique ( DONKEY_LOOP ) .
    Je vais faire le bêta et copier direct le code sans le comprendre .

    Pour l'optimisation c'est pas grave le µcontroleur ne fais que ce code !!!

    Le poussoir ayant un contact repos je l'ai câblé avec repos au gnd travail au plus et commun sur l'entrée du µcontroleur.

    - Activer les pull-up internes des deux entrées inutilisées pour éviter leur oscillation.
    ça je vais appliquer direct !


    Nom : schéma.png
Affichages : 593
Taille : 16,6 Ko

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 27
    Points
    27
    Par défaut encore un petit coup de main
    Le test fonctionne que si l'entrée passe de high à low alors qu'il faudrait qu'il fonctionne sur un passage de low à high.
    autre petit plus qui n'était pas dans l'énoncé initial je voudrais que l'action sur la sortie ne se fasse qu'une seule fois sur le passage de 0 à 1 de l'entrée et que cela ne recommence que si l'entrée est repassée à zéro .

    si ce n'est pas trop demandé
    le code modifié avec tes indications
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // déclaration des variables locales
    int var1;
    int regport = 0;
    // setup
    void setup () {
     
    DDRB = 0b0100;                       // on configure PB3 en sortie
    PORTB = 0b0100;                      // PB3 à l'état haut
    PUEB=6 ;                              // active les pull-up des broches inutilisées
    //asm volatile (" nop \n"::);          // délai d'un cycle machine
     
     
    regport = PINB & 0x0001;                       // regport enregistre l'état des entrées du portB
      }
    // création de la fonction delay por Attiny5  
    void delay (int millis) {
      for (volatile unsigned int i = 34*millis; i>0; i--);
    }
     
    // boucle principale 
    void loop () {
    var1 = PINB& 0x0001; // Var1 prend l'état des entrées du portB
     
    // test si Var1 est différent de regport pour savoir si l'entrée B0 à changé d'état
     
     
     
     if (var1!= regport ){
     
     PORTB = 0b0000;                              // on mets la sortie PB3 à zéro
     delay(200);                                  // on attends 200 milisecondes
     PORTB = 0b0100;                              // on mets la sortie PB3 à un
     delay(200);                                 //on attends 200 milisecondes
     PORTB = 0b0000;                            // on mets la sortie PB3 à zéro
     delay(200);                               //on attends 200 milisecondes
      PORTB = 0b0100;                         // on mets la sortie PB3 à un
     
     
     
      } 
     
     
    }

  5. #5
    Modérateur

    Homme Profil pro
    Ingénieur électricien
    Inscrit en
    Septembre 2008
    Messages
    1 267
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur électricien

    Informations forums :
    Inscription : Septembre 2008
    Messages : 1 267
    Points : 4 829
    Points
    4 829
    Par défaut
    Bonsoir Greg

    La rotation (qui est plutôt un décalage) c'est juste une façon de mieux lire le code, une fois compilé c'est pareil.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    PB0 -> _BV(0) -> 1<<0 -> 0b0001
    PB1 -> _BV(1) -> 1<<1 -> 0b0010
    PB2 -> _BV(2) -> 1<<2 -> 0b0100
    PB3 -> _BV(3) -> 1<<3 -> 0b1000
    Ensuite cela permet une définition en début de fichier.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #define entree 0
    ...
    var1 = PinB & _BV(entree);
    De cette manière on ne doit changer qu'une ligne si ce n'est plus la même Pin qui est utilisée (cela implique qu'il faut bien faire les choses, notamment pour l’initialisation des registres en début de programme).
    C'est utilisé de manière intensive dans les exemples de code des docs AVR. C'est juste une manière d'écrire qui permet de mieux relire le code, il n'y a pas de différence sur le code compilé.

    Sur ton code, dans un soucis de relecture plus facile il faudrait utiliser la même façon d'écrire la valeur passée aux trois registres des I/O
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DDRB =  0b0100;                       // on configure PB3 en sortie
    PORTB = 0b0100;                       // PB3 à l'état haut
    PUEB =  0b1010;                       // active les pull-up des broches inutilisées
    Comme cela on a une vision directe que les trois valeurs sont bien coordonnées.

    Ton code actuel vérifie si l'entrée à changé d'état depuis la première lecture. Cela ne s'active que sur un état (à priori variable car dépendant de l'état de l'entrée lors du démarrage du micro) et en continu puisque la comparaison est vraie à chaque test tant que l'entrée ne revient pas dans son état initial. Je l'ai laissé selon ton premier code car il y avait qqch de plus gros qui posait problème.

    Pour tester un état d'une entrée on peut utiliser les expressions suivantes:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (PinB & 0b0001)
    //code si entrée à 1
    if (~(PinB & 0b0001))
    //code si entrée à 0
    Dans ton cas c'est préférable vu que tu ne cherche que la transition low vers high. Et lors d'un changement il faut mettre à jour regport qui sert d’enregistrement de l'état précédent de l'entrée, c'est nécessaire pour ne faire qu'une seul fois un cycle de clignotement.

    On peut écrire le code de la boucle de différentes manières, la mienne c'est celle-ci:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if (PinB & 0b0001)
        if (~regport){
            PORTB = 0b0000;                              // on mets la sortie PB3 à zéro
            delay(200);                                  // on attends 200 milisecondes
            PORTB = 0b0100;                              // on mets la sortie PB3 à un
            regport = 0b0001;                            // enregistrement état précédant
    }
    else
        if (regport){
            delay(10);                       //délai de 10ms pour l'anti-rebond
            regport = 0;
    }
    Ce code à l'avantage d'offrir un traitement rapide car il permet l'usage d'instructions en assembleur spécifique à ces cas que le compilateur reconnait. On ne lit et ne teste qu'une seule fois l'entrée, sinon en cas de tests multiples il faut effectivement utiliser une variable additionnelle (var1 de ton code). Et on ne s’intéresse qu'aux transitions. le délai de 10ms c'est pour contrer les rebonds au relâchement du bouton poussoir. Si c'est un signal provenant d'un circuit numérique (donc sans rebond) c'est possible de réduire le code dans la partie else à l'unique ligne regport = 0;. Il n'est pas nécessaire de tester, c'est bien plus court de juste écrire la valeur.

    Les 0.2s de led éteinte seront éventuellement difficile à voir. Pour les tests il serait bien d'augmenter un peu la valeur à 0.4 - 0.5s

    Un dernier point: regport devrait être déclaré d'un type de variable à 8 bits uniquement pour l'optimisation du code (byte, char, int_8 ou uint_8)

    Bonne suite

    Delias

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 27
    Points
    27
    Par défaut Très intéressant
    Merci pour toutes ces explications.
    J'ai plus programmé en basic qu'en C ou je ne suis qu'un débutant .
    La programmation ne représente moins de 1 pour mille de mon activité intellectuelle malgré que j'ai appris à programmer en 1980 en assembleur et en octal ...
    et encore c'était anecdotique .
    Je me pencherais que demain sur toutes ces informations intéressantes car j'ai mon boulot qui m'attends.

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 27
    Points
    27
    Par défaut C'est fini !!!!
    Ca y est cela fonctionne impeccable je vous publie le code final

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    // déclaration des variables locales
    byte flagloop;
    // setup
    void setup ()
    {
        DDRB =  0b0100;                       // on configure PB3 en sortie
        PORTB = 0b0100;                       // PB3 à l'état haut
        PUEB =  0b1010;                       // active les pull-up des broches inutilisées
        flagloop = 0;
    }
     
    // création de la fonction delay por Attiny5  
    void delay (int millis)
    {
        for (volatile unsigned int i = 34*millis; i>0; i--);
    }
     
     // création de la fonction blink
     
    void blink ()
    {
        PORTB = 0b0000;                              // on mets la sortie PB3 à zéro
        delay(200);                                  // on attends 200 milisecondes
        PORTB = 0b0100;                              // on mets la sortie PB3 à un
        delay(400);                                  // on attends 400 milisecondes
        PORTB = 0b0000;                              // on mets la sortie PB3 à zéro
        delay(400);                                  // on attends 400 milisecondes
        PORTB = 0b0100;                              // on mets la sortie PB3 à un
        delay(400);                                  // on attends 400 milisecondes
    }
     
    // boucle principale
    void loop ()
    {
     
        if (PINB & 0b0001)
        {
            if (flagloop == 0)
            {
                flagloop = 1;                     // enregistrement état précédant
                blink();
            }
        }
        else
        {
            flagloop = 0;                         // enregistrement état précédant
        }
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Platine de programmation ATtiny 85
    Par xillibit dans le forum Arduino
    Réponses: 7
    Dernier message: 25/09/2018, 21h41
  2. [AVR] Attiny 13 / 45 output pb5 impossible
    Par GOBANTEK dans le forum Embarqué
    Réponses: 6
    Dernier message: 10/06/2016, 11h08
  3. [AVR] Atmel Attiny 104
    Par neophite etudiant dans le forum Embarqué
    Réponses: 10
    Dernier message: 24/04/2016, 13h07
  4. Programmation d'un atmel attiny 2313
    Par Guillaume51 dans le forum Basic
    Réponses: 1
    Dernier message: 02/04/2008, 22h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo