Projet

Général

Profil

Feature #14040 » PWM_TIMER1_Diviseur8_fast_pwm_14_pin_D9_20_05_2022_V3.ino

Code Arduino - Anonyme, 31/05/2022 13:41

 
//Le 20/05/2022//
//Mis à jour le 31/05/2022

// Programme pour générer une PWM de période 22ms avec un état haut varialble (de 1ms à 2ms) en changeant le diviseur du Timer 1 et en utilisant le mode Fast PWM 14 (c'est-à-dire TOP=ICR1)//
//===========================================================================================================================================================================================//
// 2ms à l'état haut c'est le mode marche avant;
//1.5 ms à l'état haut c'est le mode arrêt;
//1 ms à l'état haut c'est le mode marche arrière;

//===========
//Constantes:
//===========

//uint16_t diviseur[6] = {0,1,8,64,256,1024};
uint8_t flag;


//==========
//Variables:
//==========
// on compte jusqu'à 44000 (bin:1010 1011 1110 0000) pour avoir la période 22ms

byte VALEUR_DE_ICR1H=0b10101011; // limite "haute" de comptage pour le Timer 1 est de 65535,et la valeur de ICR1 doit être comprise entre 0 et 65535.
byte VALEUR_DE_ICR1L=0b11100000; //Le registre ICR1 est commun pour les pin D9 et D10;

//====================================================================================================================//
// pour avoir 2ms à l'état haut => OCR1B=OCR1A= 4000 en décimal; (bin: 0000 1111 1010 0000 ) : mode marche avant;
// pour avoir 1.5ms à l'état haut => OCR1B=OCR1A= 2990 en décimal; (bin: 0000 1011 1010 1110 ) : mode arrêt;
// pour avoir 1ms à l'état haut => OCR1B=OCR1A= 1980 en décimal; (bin: 0000 0111 1011 1100 ) : mode marche arrière;
//====================================================================================================================//
// La pin D9 est sur le port OC1A (PB1)

byte VALEUR_DE_OCR1AH=0b00001111; //Valeur de temps à l'état haut du signal PWM à générer sur la sortie OC1A,
byte VALEUR_DE_OCR1AL=0b10100000 ; // séparée en bits du poid fort et bits du poid faible

// La pin D10 est sur le port OC1B (PB2)

byte VALEUR_DE_OCR1BH=0b00001111; //Valeur du temps à l'état haut du signal PWM à générer sur la sortie OC1B;
byte VALEUR_DE_OCR1BL=0b10100000; // séparée en bits du poid fort et bits du poid faible;


void setup(){
// put your setup code here, to run once:

// Déclaration des pin D9 et D10 en Sortie (pins PWM):

pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
Serial.begin(19200);
//===============================================
//Configuration_PWM => Timer 1 (Sortie D9 et D10)
//===============================================
//Paramétrage du Timer 1 en mode de fonctionnement "FAST PWM 14" c'est à dire TOP=ICR1 :

bitSet(TCCR1B,WGM13); //Mise de WGM13 à 1
bitSet(TCCR1B,WGM12); //Mise de WGM12 à 1
bitSet(TCCR1A,WGM11); //Mise de WGM11 à 1
bitClear(TCCR1A,WGM10); //Mise de WGM10 à 0

//Paramétrage du prédiviseur du Timer 1 à 8
//NOTE: le prédiviseur du Timer 1 est configuré par défaut sur 64
bitClear(TCCR1B,CS12); // Mise de CS12 à 0
bitSet(TCCR1B,CS11); // Mise de CS11 à 1
bitClear(TCCR1B,CS10); // Mise de CS11 à 0
//Acquisition du signal capteur( Sortie de la génératrice)//
//=================================================================================================================//
//ici pour récupérer le signal du capteur qui est analogique on doit agir sur les registres de l'ADC du
//mirocontroleur pour avoir la précision etl'échontillonnage voulus. La fonction analogRead est beaucoup trop
//lente pour effectuer des numérisations échantillonnées à plusieurs kHz;On utilisera donc l'API Atmel, et l'accès
//direct aux registres pour certaines opérations.
//=================================================================================================================//



// Configuration de l'échantillonage:
//===================================
noInterrupts(); // On désactive les interruptions pour commencer

// Paramétrage du Timer 0 en mode de fonctionnement "CTC" (Clear Timer on Compare Match);
//pour qu'il déclenche une interruption à chaque fois que sa valeur sera égale à celle qu'on aura indéqué dans le registre OCR0A

bitClear(TCCR0B,WGM02); //Mise de WGM02 à 0
bitSet(TCCR0A,WGM01); //Mise de WGM01 à 1
bitClear(TCCR0A,WGM00); //Mise de WGM00 à 0

// Paramétrage du prédiviseur du Timer 0 à 1 //
//==============================================================================================================================================================//
//le prédiviseur du Timer 0 est configuré par défaut sur 64//
bitClear(TCCR0B,CS02); // Mise de CS02 à 0
bitClear(TCCR0B,CS01); // Mise de CS01 à 0
bitSet(TCCR0B,CS00); // Mise de CS01 à 1

//==============================================================================================================================================================//

//Activer l'interruption du Timer 0, qui est en permanence s'il y a égalité entre la valeur courante du Timer et la valeur
//stockée dans un registre de comparaison.En pratique, pour ce faire, on va mettre à 1 le bit OCIE0A dans le registre TIMSK0;
// afin qu'une interruption soit générée, à chaque fois que la valeur du Timer 0 sera égale à la valeur qu'on aura renseigné dans le registre OCR0A;


bitSet(TIMSK0,OCIE0A); // on metle bit OCIE0A à 1 ( contenu dans le registre TIMSK0)
//==============================================================================================================================================================//

//On met le compteur à zéro, on entre la valeur déclenchant l'interruption, et on réactive les interruption

TCNT0=0; //// Mise à zéro du Timer 0
OCR0A=120; // valeur correspond à 0,0075ms (120*0,062µs =0,0075ms) et 0.062µs provient du calcul(1/16MHz*1),
//avec 16MHz la fréquence du quartz de l'ATmega328P, "1" le réglage de prédiviseur du Timer 0 fait précedement;

interrupts(); //réactiver les interruptions


//Configuration de L'ADC de l'ATmega328P:
//======================================

// Désactivons l'ADC pour l'instant
bitClear(ADCSRA, ADEN); //Mise à 0 de ADEN
// le bit ADEN de ADCSRA permet d'activer ou désactiver la convertion analogique/numérique


//Activer le mode de fontionnement de l'ADC
//L'ADC configuré en mode "Timer/Counter0 compare match A",
// pour que je puisse introduire le timer 0 pour gérer l'échantillonnage
bitClear( ADCSRB,ADTS2); //Mise de ADTS2 à 0
bitSet( ADCSRB,ADTS1); //Mise de ADTS1 à 1
bitSet( ADCSRB,ADTS0); //Mise de ADTS0 à 1
// On sélectionne notre pin (A0)
bitClear(ADMUX,MUX3); //Mise de MUX3 à 0
bitClear(ADMUX,MUX2); //Mise de MUX2 à 0
bitClear(ADMUX,MUX1); //Mise de MUX1 à 0
bitClear(ADMUX,MUX0); //Mise de MUX0 à 0
//Définition de la référence de tension (ici, équivalent de DEFAULT: 5V pour Arduino UNO)

bitClear(ADMUX,REFS1); // Mise de REFS1 à 0
bitSet(ADMUX,REFS0); // Mise de REFS0 à 1


// échantillonnage rapide!
//l'ADC de l'Arduino travaille avec une fréquence plus basse que celle de l’Arduino, afin d’améliorer sa précision.
//Donc il faut trouver un compromis entre la vitesse d’exécution et la précision
// Choix de la division du prescaler de l'ADC (ici, facteur 2)
bitClear(ADCSRA,ADPS2); //Mise de ADPS2 à 0
bitClear(ADCSRA,ADPS1); //Mise de ADPS1 à 0
bitSet(ADCSRA,ADPS0); //Mise de ADPS0 à 1


// Ce bit doit être passé à 1 pour prendre en compte le mode "Timer/Counter0 compare match A" ou les autres modes
bitSet(ADCSRA, ADATE);

// Demande d'une interruption à la fin de la conversion (activer les interruptions)
bitSet(ADCSRA, ADIE);

// Réactivons l'ADC
bitSet(ADCSRA, ADEN);
// On lance la première conversion
bitSet(ADCSRA, ADSC);

// Ne pas oublier d'activer les interruptions matérielles
sei();

// end of setup
}

//Il y a aussi une interruption COMPA générée par le Timer 0 (curieusement, il faut exécuter cette interruption pour que l'ADC fonctionne).
//Dans la fonction d'interruption, on fait alterner la sortie PD3???, ce qui permettra de contrôler le fonctionnement de l'échantillonneur à;
//l'oscilloscope. Cette sortie est reliée à la borne 3 sur l'Arduino UNO, à la borne 18 sur l'arduino MEGA.

ISR(TIMER0_COMPA_vect){
// Faire quelques chose!
if (flag==0) {
flag = 1;
PORTD &= ~(1<<PORTD3); // sortie 3 sur Arduino UNO
}
else {
flag = 0;
PORTD |= (1<<PORTD3);
}
}
//Interruption: pour détecter une nouvelle mesure de l’entrée analogique

ISR(ADC_vect) {
// Code à exécuter lors d'une mesure analogique
int Resultat_CAN = (ADCH << 8) | ADCL ;

}


//=======================
//Boucle Principale//
//=======================

void loop() {

//Boucle infinie
//Si on utilise les interruptions,on quitte cette boucle
//pour aller exécuter le code en haut avant de revenir ici
// put your main code here, to run repeatedly:


//==============================
// Génération des signaux PWM//
//==============================

// Générer le signal PWM sur la sortie D9( connectée à OC1A du microcontrolleur):
// PWM en mode "non inversé":
//sortie D9 mise à 0 lorsque la valeur de timer 1 atteint la valeur de OCR1A;
//sortie D9 mise à 1 à chaque remise à zéro du timer 1 c'est à dire TOP=ICR1;
bitSet(TCCR1A,COM1A1); // Mise de COM1A1 à 1
bitClear(TCCR1A,COM1A0); // Mise de COM1A0 à 0
ICR1H=VALEUR_DE_ICR1H; //ICR1 va compter de 0 jusqu'à atteindre la valeur "VALEUR_DE_ICR1"
ICR1L=VALEUR_DE_ICR1L;
OCR1AH=VALEUR_DE_OCR1AH; // OCR1A va compter de 0 jusqu'à atteindre la valeur "VALEUR_DE_OCR1A"
OCR1AL=VALEUR_DE_OCR1AL;
// Générer le signal PWM sur la sortie D10( connectée à OC1B du microcontrolleur):
// PWM en mode "non inversé":
//sortie D10 mise à 0 lorsque la valeur de timer 1 atteint la valeur de OCR1B;
//sortie D10 mise à 1 à chaque remise à zéro du timer 1 c'est à dire TOP=ICR1;
bitSet(TCCR1A,COM1B1); // Mise de COM1B1 à 1
bitClear(TCCR1A,COM1B0); // Mise de COM1B0 à 0
ICR1H=VALEUR_DE_ICR1H; //ICR1 va compter de 0 jusqu'à atteindre la valeur "VALEUR_DE_ICR1"
ICR1L=VALEUR_DE_ICR1L;
OCR1BH=VALEUR_DE_OCR1BH; // OCR1B va compter de 0 jusqu'à atteindre la valeur "VALEUR_DE_OCR1B"
OCR1BL=VALEUR_DE_OCR1BL;



//Récupérer le résultat de la conversion analogique numérique:
int Resultat_CAN = (ADCH << 8) | ADCL; //opération bit à bit (décalage à gauche de 8 bits de ADCH et un masque pour les bits de ADCL)
//car "Resultat_CAN" est un entier stocké sur 16 bits
float tension_volt= Resultat_CAN *(5.0/1024.0);
//Serial.print("Vitesse\n");
Serial.print("Vitesse,consigne\n");
Serial.print(tension_volt);
Serial.print(",");
Serial.print(5);
Serial.print("\n");
}


//remarque:
// dans le graphe visualisé par le traceur série j'ai remarqué la présence d'une tension minimale (tension de seuil peut être!) de 1.7 volts malgré que le moteur n'ai pas alimenté!!
//
//
//
    (1-1/1)