[ATmega32] Mesure sur ADC synchonysé avec INT
Répondre à la discussion
Affichage des résultats 1 à 7 sur 7

[ATmega32] Mesure sur ADC synchonysé avec INT



  1. #1
    deuchix

    [ATmega32] Mesure sur ADC synchonysé avec INT


    ------

    Bonjour à tous,

    je tourne en rond sur un problème que je n'arrive pas à résoudre.

    le but du jeux est de déclencher une série de 14 mesures à une fréquence de 700Hz à la suite d'un "TOP Départ"

    matériellement, j'ai un ATmega32 et j'utilise AVR Studio 6 pour mon programme en C que j'envoie avec l'interface USBAsp dans mon composant.

    le signal de départ est le 50Hz du secteur remis en forme par transfo + AOP pour ne pas descendre sous les 0V ni dépasser les 5V et raccordé sur ADC0 (broche PA0). au signal original, j'ai mis un trigger de schmitt pour détecter le passage à 0 et donc débuter la série de mesure par interruption et raccordé sur INT0 (broche PD2)

    voilà donc ce que donne l'oscillo pour la synchro des deux signaux :
    Nom : qqqr.jpg
Affichages : 83
Taille : 66,2 Ko

    l'idée pour le programme était :

    une boucle d'attente du bon nombre de mesure
    une fois OK, je bloque toutes le IT, affiche toutes les mesures sur l'écran, je réactive INT0 tout en bloquant le compteur

    INT0 :
    je bloque les IT,
    je désactive INT0,
    charge le compteur,
    réactive les IT
    active le compteur

    Timer 1:
    je recharge le compteur
    je fais ma mesure que je met dans un tableau
    j'incrémente le nombre de mesure

    voilà donc le programme en C que j'ai fait :

    Code:
    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    #include <avr/io.h>
    #include "u8g.h"
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    u8g_t Ecran;
    
    #define FREQ_ECH 700UL			// fréquence à la quelle on veut mesurer
    #define NB_ECH 14				// nombre d'échantillons à mesurer
    
    
    uint16_t TC1_VAL = (65535UL - F_CPU / FREQ_ECH);		// valeur pour Timer 1 pour la mesure à la bonne fréquence
    
    volatile uint8_t nb_mesure = 0;	// nb de mesure prise **** en volatile pour eviter bug compilateur ****
    uint8_t data[NB_ECH];  // valeurs mesurées
    
    
    void adc_init()
    {
    	// AREF = AVcc
    	ADMUX = (1<<REFS0)|(1<<ADLAR);
    	
    	// ADC Enable and prescaler of 16
    	ADCSRA = (1<<ADEN)|(1<<ADPS2);
    }
    
    uint8_t adc_read(uint8_t ch) // mesure sur 8 bits
    {
    	// select the corresponding channel 0~7
    	// ANDing with ’7? will always keep the value
    	// of ‘ch’ between 0 and 7
    	ch &= 0b00000111;  // AND operation with 7
    	ADMUX = (ADMUX & 0xF8)|ch; 
    	
    	// start single convertion
    	// write ’1? to ADSC
    	ADCSRA |= (1<<ADSC);
    	
    	// wait for conversion to complete
    	// ADSC becomes ’0? again
    	// till then, run loop continuously
    	while(ADCSRA & (1<<ADSC));
    	
    	return (ADCH);
    }
    
    ISR(TIMER1_OVF_vect)
    {
    TCNT1 = TC1_VAL;					// recharge le compteur
    data[nb_mesure] = adc_read(0);		// enregistre la mesure	
    nb_mesure++;						// incrémente le compteur de mesure
    }
    
    ISR(INT0_vect)
    {
    cli();
    GICR = 0;				// désactive INT0
    TCNT1 = 0xFFFE;			// charge le compteur à une valeur proche pour la mesure
    sei();
    TCCR1B = _BV(CS10);		// active le comptage a une fréquence horloge = F_CPU
    }
    
    int main(void)
    {
    uint8_t i = 0;
    
    for (i = 0; i < NB_ECH; i++) data[i] = 0;
    
    DDRB = _BV(PB1); 
    PORTB |= _BV(PB1);			//allume l'écran
    
    PORTD = 0b00000000;			// config du port D
    DDRD = ~(1<<PD2);			// PORTD en sortie sauf PD2 où se trouve INT0
    	
    GICR = 1<<INT0;					// Active INT0
    MCUCR = 1<<ISC01 | 1<<ISC00;	// Trigger INT0 sur front montant
    
    TCCR1A = 0;
    TCCR1B = 0;				// bloque le comptage a une fréquence horloge = 0
    TIMSK = _BV(TOIE1);		// autorise l'interruption d'overflow
    TCNT1 = 0;				// met le competur à 0
    
    u8g_InitSPI(&Ecran, &u8g_dev_st7920_128x64_sw_spi,P  N(1,7),PN(1,5), PN(1,0), U8G_PIN_NONE, U8G_PIN_NONE);
    // init écran GLCD
    
    
    adc_init();			// init du convertisseur analogique / numérique
    
    
    sei();				// active les interruptions
    
    while(1)
    	{				// boucle d'attente
    	while (nb_mesure >= NB_ECH)  //si j'ai fait assez de mesure ...
    		{
    			cli();			// bloque les IT
    			PORTD = 0;		// eteint la LED indicatrice ce mesure
    			
    			u8g_FirstPage(&Ecran);
    			do {
    				for (i = 0; i < NB_ECH; i++)
    					{
    					u8g_DrawLine(&Ecran, 4*i, data[i]>>2,4*(i+1), data[i+1]>>2);
    					
    					}
    			} while( u8g_NextPage(&Ecran) );
    			
    			TCCR1B = 0;			// desactive le timer 1 : prescaler = 0
    			GICR = 1<<INT0;		// réactive l'interruption 0
    			nb_mesure = 0;		// réinitialise les mesures
    
    			PORTD |= 1<<PD3;
    
    			sei();				// activation des interruptions
    			
    		}
    		
    	}
    }

    le soucis c'est que les valeur affichées sont déphasées d'une série de mesure à l'autre ce qui, il me semble, ne devrait pas arriver avec ce programme. ça fait comme si INT0 comptais pour rien !!!!

    je vous ai fait une petite video pour voir le résultat, ça peu aider à comprendre :



    j'ai du faire une bourde quelque part mais où ???
    je vous vois déjà venir : les fusibles sont mal configurés.
    sans doute, voilà donc ma config :
    Low Fuse : 0xEE
    High Fuse : 0xCF

    donc si j'ai bien compris la doc : pas de Jtag, et horloge réglé sur quartz > 1MHz

    merci

    -----

  2. #2
    inoxxam

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    L'instant où tu remets nb_mesure à 0 (dans la boucle principale) est arbitraire, donc ça ne me parait pas étonnant. Il faudrait faire ça dans l'interruption INT0, en plus de quelques autres précautions pour que tout ça se passe bien.

  3. #3
    deuchix

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    re,

    en quoi est ce arbitraire la mise à 0 de nb_mesure ???

    la partie "affichage" ne se fait que lorsque que j'ai fait suffisamment de mesure et pas autrement
    une fois l'affichage fini, je remet tout à 0

    @ peluche

  4. #4
    inoxxam

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    Comme tu le dis, il est remis à 0 après un certain nombre de mesures. Et de la façon dont c'est codé c'est le seul critère de remise à zéro. Donc si tu nombre de mesures ne correspond pas à un nombre entier de périodes de ton signal, ça va défiler comme ça le fait, et c'est tout l'intérêt d'un trigger.

    Petite note au passage, on ne doit jamais désactiver les interruptions, on ne le fait que dans des cas très spéciaux, notamment dans les systèmes d'exploitations, et encore on se l'autorise uniquement le temps le plus court possibles, rarement plus de quelques instructions, voire dizaines d'instructions.

  5. A voir en vidéo sur Futura
  6. #5
    deuchix

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    re,

    merci, je comprend mieux maintenant !!! c'est la première fois que je me frotte à un µC et j'avoue que c'est à la fois très proche et très loin d'un PC. rare sont les fois sur PC où j'ai eu affaire aux IT.

    voilà donc la nouvelle fonction :

    Code:
    ISR(INT0_vect)
    {
    nb_mesure = 0;
    TCNT1 = 0xFFFE;			// charge le compteur à une valeur proche pour la mesure
    TCCR1B = _BV(CS10);		// active le comptage a une fréquence horloge = F_CPU
    }

    et en effet, ça fonctionne !!! merci.

    par contre une autre interrogation : si au lieu de mesurer 14 valeurs (donc une période) je veux en mesurer 28 (donc 2 période) ça s'écroule comme un château de carte

    encore merci pour ton aide

    @ peluche

  7. #6
    ftorama

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    Tout le problème est de séparer le buffer d'acquisition du buffer d'affichage.

    En gros, il vaut mieux faire 16 mesures stockées dans un tableau A (avec un index iA). Quand iA est à 16, on copie le tableau A dans un tableau B et on remet iA à 0. Le parcours du tableau B se fait avec un autre index.

    Un gros problème que je vois dans ce programme est que le programme reste bloqué dans l'interruption timer le temps que 16 mesures soient réalisées. Il aurait peut-être été mieux de déclencher la première conversion sur l'IT timer puis les suivantes sur l'IT fin de conversion ADC.

    Maintenant, je ne sais pas si l'Atmega32 est le plus adapté pour une telle tâche. Sur certains micros plus modernes (je pense en particulier aux STM32), on peut linker les timers sur les ADC et ne déclencher une IT qu'après les 16 acquisitions. Au lieu de traiter 17 IT (le timer + les 16 fins de conversion), on n'en gère qu'une....
    Quand un homme a faim, mieux vaut lui aprendre à pecher que de lui donner un poisson.

  8. #7
    inoxxam

    Re : [ATmega32] Mesure sur ADC synchonysé avec INT

    Probablement que la période de ton signal est supérieure à 14 mesures et inférieure a 28 mesures. Du coup, il peut y avoir plusieurs déclenchements en une période.
    Ne mets n_mesure à 0 que s'il est supérieur à 28, ça assurera un seul déclenchement par "salve" de mesures.

Discussions similaires

  1. Fréquencemetre avec un Atmega32
    Par invite6d67225b dans le forum Électronique
    Réponses: 15
    Dernier message: 01/06/2011, 21h53
  2. Programmation d'un ATMEGA32
    Par Noxa dans le forum Électronique
    Réponses: 2
    Dernier message: 17/02/2011, 07h34
  3. Module EZL, ATMEGA32 et PHP
    Par guicara dans le forum Électronique
    Réponses: 9
    Dernier message: 28/04/2010, 09h33
  4. Créer un Robot(Reversed Pendulum) Avec un ATmega32
    Par mehditlili dans le forum Électronique
    Réponses: 2
    Dernier message: 12/12/2009, 18h36
  5. ATmega32 HS ?
    Par Kilhian dans le forum Électronique
    Réponses: 0
    Dernier message: 18/07/2007, 08h01
Découvrez nos comparatifs produits sur l'informatique et les technologies.