Aide spécifique et générale

binjch
dim, 01/06/2019 - 22:59
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
Walter
lun, 01/07/2019 - 09:14
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?
Walter
lun, 01/07/2019 - 10:22
Ha, Bien Maître!
Walter
lun, 01/07/2019 - 15:09
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.
binjch
lun, 01/07/2019 - 10:59
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
binjch
lun, 01/07/2019 - 15:22
Bon ben j'attends les explications du professeur...
binjch
lun, 01/07/2019 - 16:44
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
binjch
lun, 01/07/2019 - 17:13
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.
binjch
lun, 01/07/2019 - 17:32
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...).
binjch
lun, 01/07/2019 - 17:38
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
binjch
lun, 01/07/2019 - 17:39
...super bien locoduino
Walter
lun, 01/07/2019 - 17:41
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
binjch
lun, 01/07/2019 - 17:56
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).
Walter
mar, 01/08/2019 - 11:15
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.
Cela te parais t-il claire ?
Vois tu comment faire ?
binjch
mer, 01/09/2019 - 20:43
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).
binjch
mer, 01/09/2019 - 21:04
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]
binjch
mer, 01/09/2019 - 21:05
Je n'ai plus qu'à intégrer les timings correctes et connecter le buzzer
Walter
jeu, 01/10/2019 - 15:06
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 ?