Fréquence pwm

Bonjour,

Je viens d'acquérir un oscilloscope et en essayant cet oscilloscope, je me suis aperçu que la sortie pwm sur la pin 3 est à 490 Hz alors que sur la pin 5 elle est à 976 Hz.
Est ce quelqu'un a une explication ?

Ma carte est un clone arduino uno
Les 2 sorties sont programmées exactement de la même façon.

const int OUTPIN1=3;
const int OUTPIN2=5;

void setup() {
  // put your setup code here, to run once:
  pinMode(OUTPIN1,OUTPUT);
  pinMode(OUTPIN2,OUTPUT);

  analogWrite(OUTPIN1,50);
  analogWrite(OUTPIN2,50);
}

void loop() {
  // put your main code here, to run repeatedly:
  

}

là:

Merci, je n'avais même pas pensé à regarder la référence

Salut.

rien d'inquiétant. tes deux PWM sont sur des timers différents :

pin 3 : timer 2
pin 5 : timer 0

les deux timers sont configurés différemment,

  • TIMER0 est en fast PWM avec un prescaler de 64 pour pouvoir gérer correctement les fonction temporelles arduino.
  • TIMER2 est en phase correct PWM avec un prescaler de 64

On en déduit les fréquences de PWM :

  • F(TIMER0) = F_CPU / 64 / 256 = 976,5625 Hz
  • F(TIMER2) = F_CPU / 64 / 510 = 490,196 Hz

Tes mesures sont donc bonnes!

Mais tu peux modifier les fréquences (prescaler et mode PWM) dans ton setup(), en jouant sur les registres TCCRnA et TCCRnB. se référer a la datasheet de l'ATMEGA328, rubriques timers / compteurs.

Super_Cinci, merci de ces explications détaillées

kamill:
Merci, je n'avais même pas pensé à regarder la référence

bonjour
perso, je viens "aussi" de découvrir ce point particulier :grin:

Ben alors personne ne va voir ce que fait la fonction init() de l'IDE ?

void init()
{
	// this needs to be called before setup() or some functions won't
	// work there
	sei();
	
	// on the ATmega168, timer 0 is also used for fast hardware pwm
	// (using phase-correct PWM would mean that timer 0 overflowed half as often
	// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
	sbi(TCCR0A, WGM01);
	sbi(TCCR0A, WGM00);
#endif

	// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
	// CPU specific: different values for the ATmega128
	sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
	// this combination is for the standard atmega8
	sbi(TCCR0, CS01);
	sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
	// this combination is for the standard 168/328/1280/2560
	sbi(TCCR0B, CS01);
	sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
	// this combination is for the __AVR_ATmega645__ series
	sbi(TCCR0A, CS01);
	sbi(TCCR0A, CS00);
#else
	#error Timer 0 prescale factor 64 not set correctly
#endif

	// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
	sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
	sbi(TIMSK0, TOIE0);
#else
	#error	Timer 0 overflow interrupt not set correctly
#endif

	// timers 1 and 2 are used for phase-correct hardware pwm
	// this is better for motors as it ensures an even waveform
	// note, however, that fast pwm mode can achieve a frequency of up
	// 8 MHz (with a 16 MHz clock) at 50% duty cycle

#if defined(TCCR1B) && defined(CS11) && defined(CS10)
	TCCR1B = 0;

	// set timer 1 prescale factor to 64
	sbi(TCCR1B, CS11);
#if F_CPU >= 8000000L
	sbi(TCCR1B, CS10);
#endif
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
	sbi(TCCR1, CS11);
#if F_CPU >= 8000000L
	sbi(TCCR1, CS10);
#endif
#endif
	// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
	sbi(TCCR1A, WGM10);
#elif defined(TCCR1)
	#warning this needs to be finished
#endif

	// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
	sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
	sbi(TCCR2B, CS22);
#else
	#warning Timer 2 not finished (may not be present on this CPU)
#endif

	// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
	sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
	sbi(TCCR2A, WGM20);
#else
	#warning Timer 2 not finished (may not be present on this CPU)
#endif

#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
	sbi(TCCR3B, CS31);		// set timer 3 prescale factor to 64
	sbi(TCCR3B, CS30);
	sbi(TCCR3A, WGM30);		// put timer 3 in 8-bit phase correct pwm mode
#endif

#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */
	sbi(TCCR4B, CS42);		// set timer4 prescale factor to 64
	sbi(TCCR4B, CS41);
	sbi(TCCR4B, CS40);
	sbi(TCCR4D, WGM40);		// put timer 4 in phase- and frequency-correct PWM mode	
	sbi(TCCR4A, PWM4A);		// enable PWM mode for comparator OCR4A
	sbi(TCCR4C, PWM4D);		// enable PWM mode for comparator OCR4D
#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
	sbi(TCCR4B, CS41);		// set timer 4 prescale factor to 64
	sbi(TCCR4B, CS40);
	sbi(TCCR4A, WGM40);		// put timer 4 in 8-bit phase correct pwm mode
#endif
#endif /* end timer4 block for ATMEGA1280/2560 and similar */	

#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
	sbi(TCCR5B, CS51);		// set timer 5 prescale factor to 64
	sbi(TCCR5B, CS50);
	sbi(TCCR5A, WGM50);		// put timer 5 in 8-bit phase correct pwm mode
#endif

#if defined(ADCSRA)
	// set a2d prescaler so we are inside the desired 50-200 KHz range.
	#if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
		sbi(ADCSRA, ADPS2);
		sbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
		sbi(ADCSRA, ADPS2);
		sbi(ADCSRA, ADPS1);
		cbi(ADCSRA, ADPS0);
	#elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
		sbi(ADCSRA, ADPS2);
		cbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
		sbi(ADCSRA, ADPS2);
		cbi(ADCSRA, ADPS1);
		cbi(ADCSRA, ADPS0);
	#elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
		cbi(ADCSRA, ADPS2);
		sbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
		cbi(ADCSRA, ADPS2);
		cbi(ADCSRA, ADPS1);
		sbi(ADCSRA, ADPS0);
	#endif
	// enable a2d conversions
	sbi(ADCSRA, ADEN);
#endif

	// the bootloader connects pins 0 and 1 to the USART; disconnect them
	// here so they can be used as normal digital i/o; they will be
	// reconnected in Serial.begin()
#if defined(UCSRB)
	UCSRB = 0;
#elif defined(UCSR0B)
	UCSR0B = 0;
#endif
}

C'est la bible !

Fichier wiring.c
Tien donc "wiring" comme c'est bizarre :grin:

68tjs:
Ben alors personne ne va voir ce que fait la fonction init() de l'IDE ?

void init()

{
}




C'est la bible !

Fichier wiring.c
Tien donc "wiring" comme c'est bizarre :grin:

C'est de là que j'ai sorti mes explications :wink: Cette sale fonction qui préconfigure des trucs alors que ça sert à rien et parfois nous embête bien : tout n'est plus à 0 après un reset!

Il y a des tas de trucs qu'on ne peut pas deviner, j'ai même cramé un 328 une fois en collant une ref externe sur Aref : la datasheet dit que par défaut, l'ADC utilise la ref externe, alors que le core arduino la configure sur Avcc, il n'a pas beaucoup aimé le court-jus que ça a fait... Maintenant, je le sais...

la fonction int main(void) est instructive aussi :confused:

Intéressante explication...

J'ai trouvé cette fonction WIRING.C dans HARDWARE/ARDUINO/AVR/CORES, et elle est bien compliquée!!! mais où est-elle appelée?

Ou alors c'est implicite au démarrage?

Gérard.

L'IDE travaille par étape :

  1. elle transforme les fonctions de ton fichier ino en fonction dans un fichier cpp provisoire
    Elle y ajoute les déclaration de ces fonctions
  2. Elle construit le fichier main.cpp dont parle Infobarquee, elle y intègre le fichier cpp provisoire.
    Ce fichier main.cpp est le VRAI fichier, c'est celui là que le compilateur traite.
    C'est dans ce fichier que la fonction init () est appelée, plus d'autres choses.
    C'est dans ce fichier que la boucle infinie est créée.
    Ce fichier est 100% conforme a un fichier cpp classique.

Merci pour les explications.

Y a-t-il un fichier "temp" où on peut voir tout ça?

Sans doute mais je ne connais que Linux.

Sinon tout ce je sais je l'ai appris quand j'ai voulu utiliser Eclipse à la place de l'IDE Arduino.
Le meilleur lien que j'ai trouvé est celui là :

Il y a plusieurs pages à consulter. C'est là que j'ai compris ce qu'était une "librairie statique" qui en fait me paraît plutôt dynamique dans son fonctionnement (je suis un homme du matériel, je n'ai pas les même repères :slight_smile: )