Aide spécifique et générale

Portrait de binjch

Bonjour à toutes et à tous,

Je poste mon problème qui concerne le codage d'un exercice ultra débutant sur un atmega32a car il n'y a pas de forum dédié AVR.

Je suis des cours d'électronique et viens de commencer la programmation AVR. J'avoue que je suis complètement perdu. J'ai cherché des sites pour débuter mais tout est orienté arduino et en anglais que je maîtrise bien mais disons que lorsqu'il s'agit de décortiquer un truc aussi complexe que ce type de programmation cela ajoute une couche de difficulté. Le problème est que le prof n'a pas de cours il nous pousse à nous débrouiller avec le web et je trouve qu'il manque un tuto en français hyper clair pour aborder la mécanique de base des sytèmes AVR. Les explications sont toujours trop brouillonnes ou alors c'est que c'est vraiment difficile à expliquer (en tous cas le prof n'y arrive pas on est tous dans les choux).

Mon problème actuel est je pense hyper facile, c'est le stade suivant du blinking led mais je n'arrive pas à aboutir.

On doit réaliser un Quiz game sans faire appel à _delay_ms() : 4 push buttons / Quand un est enfoncé il interrompt les 3 autres  boutons et déclenche une led pendant 4 secondes et un buzzer pendant la moitié du temps de la led donc 2 secondes. Le cahier des charges ne précise pas que chaque bouton à sa propre led donc à priori on peut connecter les boutons en parallèle et utiliser une patte de requête externe (int0 ou int1).

J'ai réussi à ma manière à gérer les delays des leds mais je n'arrive pas à implémenter l'interruption des boutons non enfoncés. 

Voici mon code:

[code]#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/delay.h>    //pour gestion debouncing du bouton
#include <avr/interrupt.h>

// Variable de comptage des dépassements
volatile uint8_t count;

#define BUTTON_HIGH(byte,bit) (byte & (1 << bit))

/** Déclaration des fonctions **/

static void avr_init(void);

void timer1_init(void);

/** Gestion de l'interruption **/

ISR(INT0_vect)
{
    PORTA |= (1 << PA0);
    PORTA |= (1 << PA1);
    timer1_init();
}

ISR(TIMER1_OVF_vect)
{
    // keep a track of number of overflows
    count++;
}

//MAIN
int main(void)
{
    avr_init();

    while(1)
    {
        if (count >= 2)                    // 2 X count X 0,2500112 = 1,00045sec
        {
            PORTA &= ~(1 << PA0);
            if (count >= 4)                // 2 X count X 0,2500112 = 2,0009sec
            {
                PORTA &= ~(1 << PA0);
                PORTA |= (0 << PA0);
                PORTA &= ~(1 << PA1);
                PORTA |= (0 << PA1);
                TCNT1 = 0;                // reset counter
                TCCR1B = 0x00;            //stops the timer
            }
        }
        else
        {

        }
    }
    return 0;
}

static void avr_init(void)
{
    // Les sorties

    DDRA |= (1 << PA0);        //Les ports D sont conf. comme sorties
    DDRA |= (1 << PA1);

    // Les entrées

    DDRD &= ~(1 << PD2);
    PORTD |= (1 << PD2);        // configure PORTD bit 2 comme résistance de tirage

    // Active l'interruption externe "INT0" qui allume les leds et active le timer1
    GICR |= (1 << INT0);

    // Définit un déclenchement sur front descendant

    MCUCR |= (1 << ISC01);

    // Active les requètes d'interruptions
    sei();

    return;
}

void timer1_init()
{
    // set up timer with prescaler = 1024        // 1 cycle = 0,000977 sec
    TCCR1B |= (1 << CS11)|(1 << CS10);
    // initialize counter
    TCNT1 = 0;                                    // 1 cycle = 256    // 256 X 0,000977 = 0,250112sec
    // enable overflow interrupt
    TIMSK |= (1 << TOIE1);
    // initialize overflow counter variable
    count = 0;
}

[/code[

Merci

Portrait de Walter

Tu te trompe je ne suis pas professeur, même si le développement est mon métier!
Par contre je suis étonné d'un programme aussi documenté et non condescendant. peut être à force Maitre Spy commence à comprendre ce que l'on veut lui dire? 

Portrait de Walter

Ha, Bien Maître!

Portrait de Walter

Donc c'est la preuve que tout tes programmes sont documentés, ok, je ne connaissais pas cette nouvelle définition, je note Maître.

Portrait de binjch

C'est super, grand merci mais... Je dois le faire sous Armel studio en langage C avec syntaxe proche assembleur en utilisant seulement les timers et les interruptions. (DDR*, PORT*, TCNT*,...). En fait je bosse direct sur ma breadboard avec un atmega32a, pas le atmega328p. Mais je suis agréablement surpris de votre réactivité et je vais décortiquer le code pour voir si je n'y trouve pas des pistes :-D

Portrait de binjch

Bon ben j'attends les explications du professeur...

Portrait de binjch

Bon pas grave je continue à chercher un bon tuto ou un bon livre. Le but de l'exercice est de le faire en langage pseudo machine donc exit le langage arduino :-/ En arduino ce serait déjà fait :-D

Portrait de binjch

je suis pas dans la mouize... C'est pas que j'ai pas essayé. De plus je me suis déjà bien intéressé à ce genre de discipline et c'est la première fois que je cale, ce qui me fait penser que si il y'a bien une matière qui demande de l'aide claire au départ c'est celle-là. Le truc est que les profs de l'école pompent quasi tous leurs cours sur des trucs internet et au sujet de l'AVR il n'y a pas grand-chose qui n'est pas destiné à de "déjà ingénieurs qui s'y mettent". Pffff... Bon peut-être que j'ai mal compris. En gros l'exercice est à faire en C avec la config "manuelle" des timers.

Portrait de binjch

Tout cela est déjà opérationnel dans le code que j'ai posté, le prob est la gestion des interruptions Comme je l'explique à la fin de mon premier message. Mais merci pour les lignes "machines".(Comme si j'avais pas déjà assez mangé pendant les fêtes...).

Portrait de binjch

J'ai un peu regardé. Ca ressemble à ce qu'on trouve en anglais mais en français ce qui rend la chose un peu plus agréable. Merci ;-) Mais faire clignoter une led est une chose, gérer deux temps d'allumage sur interruption en est une autre :-D

Portrait de binjch

...super bien locoduino

Portrait de Walter

Oups trop tard :)

Je pense que tu confond Binjch, comme Spy, ca m'étonne beaucoup que ton prof te demande de faire ça en langage machine, sans vous avoir fait des cours dessus.
En règle général tu commence à faire de l'assembleur qui est la représentation humainement lisible du langage machine, après pourquoi pas tu fais du langage machine, histoire de bien comprendre ce que fait le processeur.

Je pense que tu doit "simplement" remplacer le delay, par des Timers + interruptions avec du C.
Ce que tu essayé de faire dans ton code à priori, j'ai pas testé ton programme.

Ton soucis est que tu n'a pas d'interruption au relâchement du bouton?
Que veux tu faire avec ton Timer1, tu ajout à counter +1 toutes les X µs et tu le test uniquement dans ta fonction d'interruption du bouton?

Qu'a tu compris des interruptions et des Timers?

Pour les Timers et interruptions je trouve cette documentation est très bien.

https://www.locoduino.org/spip.php?article84

Portrait de binjch

J'ai compris comment gérer les ports en entré ou sortie, j'ai compris que les interruptions servaient à mettre l'exécution du programme en pause lors d'événements spéciaux ce que j'ai réussi à réaliser sur le port int0 avec un bouton poussoir (problème de boucing mais bon). Ce que je ne comprends pas est comment programmer une instruction qui après interruption externe (physique boutton poussoir) fait s'allumer les leds pour un temps donné (AVEC TIMER SANS fonction delay) et exclut toutes autres exécution durant le temps d'allumage des leds. (en fait il y' aun led et un buzzer mais dans un premier temps j'utilise deux leds).

Portrait de Walter

Ok, le mieux reste de suivre les exemples de "locoduino" qui sont très didactiques.

Donc si on résumé on a deux choses:

Une interruption : l'interruption interrompt l'exécution du programme en cours, pour exécuter une routine d'interruption, puis rendre la main au programme principal, une fois la routine terminé.

Un Timer: c'est un compteur de cycle d'horloge,  qui  s'incrémente jusqu'a ce qu'il déborde et provoque une interruption.

En conclusion pour ton cas, on peut dire que l'on peut dans un premier temps faire clignoter une LED avec un corps principal(fct LOOP) vide. Le code qui fait clignoter la LED initialiement dans la fonction "Loop" ce retrouvera donc dans la fonction du Timer et appelée à intervalle régulier(ou non d'ailleurs).

Avec ces deux choses là, il suffit d'appliquer ce que tu décrit en algorithmique.
Sur interruption physique (bouton), tu veux allumer une LED un certain temps, puis au bout d'un temps donnée l'éteindre.

timer.png

Cela te parais t-il claire ?
Vois tu comment faire ?

Portrait de binjch

J'ai compris les principes. D'ailleurs mon code posté plus haut fonctionne plus ou moins suivant les principes de base mis en applications. Mais ce n'est pas parfait ou solide. Par exemple la séquence fonctionne correctement à la première exécution mais s'enlise dès la seconde ( les leds reproduisent plus la même séquence).

Portrait de binjch

Bon j'ai trouvé un code qui fonctionne:

[code]

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

// Variable de comptage des dépassements
volatile uint8_t count1;

/** Déclaration des fonctions **/
static void avr_init(void);
void timer1_init(void);

/** Gestion de l'interruption **/

ISR(INT0_vect)    //Ce qui se passe lors de l'interruption en PD2
{
    timer1_init();
    PORTA |= (1 << PA0) | (1 << PA1);

}

ISR(TIMER1_OVF_vect)    //Ce qui se passe lors des dépassements du timer1
{
    count1++;
    if (count1 >= 2)
    {
        PORTA &= ~(1 << PA0);
        PORTA |= (0 << PA0);
        count1 = 0;
    }
    PORTA &= ~(1 << PA1);
    PORTA |= (0 << PA1);
    cli();
}

//MAIN
int main(void)
{
    avr_init();
    //timer1_init();
    while(1)
    {
    }
    return 0;
}

static void avr_init(void)
{
    // Les sorties
    DDRA |= (1 << PA0);        //Les ports D sont conf. comme sorties
    DDRA |= (1 << PA1);

    // Les entrées
    DDRD &= ~(1 << PD2);        // Mise à zéro de PD2
    PORTD |= (1 << PD2);        // configure PORTD bit 2 comme résistance de tirage

    // Active l'interruption externe "INT0" qui allume les leds et active le timer1
    GICR |= (1 << INT0);

    // Définit un déclenchement sur front descendant
    MCUCR |= (1 << ISC01);

    // Active les requètes d'interruptions
    sei();
    return;
}

void timer1_init()
{
    // configure le timer1 avec un pré diviseur = 1024        // 1 cycle = 0,000977 sec
    TCCR1B |= (1 << CS11)|(1 << CS10);
    // initialise le comptage
    TCNT1 = 0;                                    // 1 cycle = 256    // 256 X 0,000977 = 0,250112sec
    // active les interruptions sur dépassements du timer1
    TIMSK |= (1 << TOIE1);
    // Initialise la variable de comptage des dépassements
    count1 = 0;
}

[/code]

Portrait de binjch

Je n'ai plus qu'à intégrer les timings correctes et connecter le buzzer

Portrait de Walter

J'ai du mal a voir ce que tu veux vraiment faire dans la fonction du Timer.
Tu désactives les interruptions à la fin du timer, c'est normal ? 

Erreur | Les Électroniciens.com

Message d'erreur

  • Warning : Error while sending QUERY packet. PID=27071 dans DatabaseStatementBase->execute() (ligne 2227 dans /home/leselectnn/www/includes/database/database.inc).
  • Warning : Cannot modify header information - headers already sent by (output started at /home/leselectnn/www/includes/bootstrap.inc:1640) dans drupal_send_headers() (ligne 1499 dans /home/leselectnn/www/includes/bootstrap.inc).
  • PDOException : SQLSTATE[HY000]: General error: 2006 MySQL server has gone away: SELECT 1 AS expression FROM {variable} variable WHERE ( (name = :db_condition_placeholder_0) ); Array ( [:db_condition_placeholder_0] => cron_last ) dans variable_set() (ligne 1258 dans /home/leselectnn/www/includes/bootstrap.inc).

Erreur

Le site Web a rencontré une erreur inattendue. Veuillez essayer de nouveau plus tard.

Uncaught exception thrown in shutdown function.

PDOException: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away: DELETE FROM {semaphore} WHERE (value = :db_condition_placeholder_0) ; Array ( [:db_condition_placeholder_0] =&gt; 109139658063d6f66703f724.64223753 ) in lock_release_all() (line 269 of /home/leselectnn/www/includes/lock.inc).