Étape 4: Code de microcontrôleur
J’ai mis mon travail code place sur Github. Il comporte quelques pièces :Ces #defines et déclarations const effectuer des calculs de compilation afin que le code n’a besoin que de faire des comparaisons simples uint8_t plutôt que virgule flottante qui n’est pas réalisable dans un microcontrôleur. À l’aide de const encourage au compilateur d’effectuer le calcul au moment de la compilation et forces le type du résultat uint8_t.
#define PWM_FREQ 62500
#define PWM_RESOLUTION (F_CPU / PWM_FREQ)
#define MIN_DUTY_CYCLE 0,40
#define MAX_DUTY_CYCLE 0,80
const uint8_t MIN_PWM_LEVEL = PWM_RESOLUTION * MIN_DUTY_CYCLE ;
const uint8_t MAX_PWM_LEVEL = PWM_RESOLUTION * MAX_DUTY_CYCLE ;#define VREF 1.1
#define DESIRED_VOUT 20,0
#define DIVIDER_RATIO 30,0
#define DESIRED_ADC_IN_V (DESIRED_VOUT / DIVIDER_RATIO)const uint8_t DESIRED_ADC_RESULT = 255 * DESIRED_ADC_IN_V / VRÉF ;
Ceux-ci définissent certaines macros utilitaire utile afin que le code est plus facile à suivre :
#define DUTY_CYCLE_REG OCR0B
#define ADC_ENABLE() (ADCSRA | = _BV(ADEN))
#define ADC_START_CONVERSION() (ADCSRA | = _BV(ADSC))
La fonction principale a une phase initiale d’installation où il se trouve sur différents périphériques que nous aurons besoin :
int main (void) {}
/ * Valeur A7 en tant que sortie. (Nécessaire pour le PWM). */
DDRA | = _BV(DD7) ;
PORTA = 0 ;/ * Let alimentation stabiliser... * /
_delay_ms(500) ;/*
* Configurer le Timer0 comme un PWM rapide. Il sera
* - tourner sur la broche de sortie au début de chaque cycle
* - éteindre quand la valeur de frappe DUTY_CYCLE_REG
* - envelopper à 0 quand il frappe OCR0A
*/
TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00) ;
OCR0A = PWM_RESOLUTION ;
/ * Démarre avec le cycle d’utilisation de 40 % et d’une rampe éviter les surcharges. */
DUTY_CYCLE_REG = (uint8_t)(PWM_RESOLUTION * 0.40) ;
/ * Définir source d’horloge Timer0 être oscillateur principal. Cela permet à la minuterie. */
TCCR0B = _BV(CS00) | _BV(WGM02) ;/*
* Allumez l’ADC,
* - Utilisez ref de tension interne.
* - configurer ADC0 comme notre source
* - gauche-ajustez le résultat, 8-bits est suffisant pour nous
* - désactiver la mémoire tampon d’entrée numérique sur la broche
* - activez le service ADC.
*/
ADMUX = / * REF = * / _BV(REFS1) | / * ENTRÉE = * / 0 ;
ADCSRA | = / * PRÉDIVISEUR = 16 = 2 ^ * / 4 ;
ADCSRB | = / * RÉGLAGE GAUCHE * / _BV(ADLAR) ;
DDRA & = ~ _BV(DD0) ;
DIDR0 | = _BV(ADC0D) ;
ADC_ENABLE() ;
_delay_ms(1) ;
Ensuite, il boucle simplement, lecture de la valeur analogique du potentiomètre et en le comparant à sa cible :
tandis que (1) {}
/ * Attendez le Timer0 déborder... * /
loop_until_bit_is_set (TIFR0, TOV0) ;
/ * Fin de notre OFF période, devrait être tension crête... * /
TIFR0 | = _BV(TOV0) ; / * Effacer l’indicateur. *// * Vérifier la tension de sortie. */
ADC_START_CONVERSION() ;
loop_until_bit_is_clear (ADCSRA, ADSC) ;
uint8_t adc_result = ADCH ;Si (adc_result < DESIRED_ADC_RESULT & &
DUTY_CYCLE_REG < MAX_PWM_LEVEL) {}
DUTY_CYCLE_REG ++ ;
}
ElseIf (adc_result > DESIRED_ADC_RESULT & &
DUTY_CYCLE_REG > MIN_PWM_LEVEL) {}
DUTY_CYCLE_REG--;
}
}
}