Göra en mikrokontroller-baserade uppsving omvandlare (4 / 5 steg)
Steg 4: Microcontroller kod
Jag har satt min arbetande koden upp på Github. Den har några delar:Dessa #defines och const förklaringar gör kompilering beräkningar så att koden endast behöver göra enkla uint8_t jämförelser snarare än flyttal som inte är genomförbara i en mikrokontroller. Med hjälp av const uppmuntrar kompilatorn att göra beräkningen vid kompileringen och tvingar typ av resultatet till 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 / VREF;
Detta definierar vissa nyttig nytta makron så att koden är lättare att följa:
#define DUTY_CYCLE_REG OCR0B
#define ADC_ENABLE() (ADCSRA | = _BV(ADEN))
#define ADC_START_CONVERSION() (ADCSRA | = _BV(ADSC))
Den huvudsakliga funktionen har en inledande installationsfasen där det visar på de olika kringutrustning som vi behöver:
int main(void) {
/ * Ange A7 som en utgång. (Behövs för PWM.) */
DDRA | = _BV(DD7);
PORTA = 0;/ * Låt ineffekt stabilisera... * /
_delay_ms(500);/*
* Konfigurera Timer0 som en snabb PWM. Det kommer att
* - Aktivera utgångsstiftet i början av varje cykel
* - stänga av när värdet träffar DUTY_CYCLE_REG
* - wrap till 0 när den träffar OCR0A
*/
TCCR0A = _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
OCR0A = PWM_RESOLUTION;
/ * Börja med 40% intermittens och ramp för att undvika översvämning. */
DUTY_CYCLE_REG = (uint8_t)(PWM_RESOLUTION * 0.40);
/ * Ange Timer0 klocka källa vara huvudsakliga oscillator. Detta gör att timern. */
TCCR0B = _BV(CS00) | _BV(WGM02);/*
* Slå på ADC,
* - använda inre spänning ref.
* - Konfigurera ADC0 som vår källa
* - vänster-justera resultatet, 8 bitar är nog för oss
* - Inaktivera digital indatabufferten på stift
* - aktiverar ADC.
*/
ADMUX = / * REF = * / _BV(REFS1) | / * INPUT = * / 0;
ADCSRA | = / * PRESCALER = 16 = 2 ^ * / 4;
ADCSRB | = / * VÄNSTER-JUSTERA * / _BV(ADLAR);
DDRA & = ~ _BV(DD0);
DIDR0 | = _BV(ADC0D);
ADC_ENABLE();
_delay_ms(1);
Då loopar det helt enkelt, läsning av värdet för analoga från potentiometer och jämföra den med sitt mål:
samtidigt (1) {
/ * Vänta Timer0 att svämma över... * /
loop_until_bit_is_set (TIFR0, TOV0);
/ * Slutet av våra OFF period, bör vara toppspänning... * /
TIFR0 | = _BV(TOV0); / * Avmarkera flaggan. *// * Kontrollera utspänningen. */
ADC_START_CONVERSION();
loop_until_bit_is_clear (ADCSRA, ADSC);
uint8_t adc_result = ADCH;om (adc_result < DESIRED_ADC_RESULT & &
DUTY_CYCLE_REG < MAX_PWM_LEVEL) {
DUTY_CYCLE_REG ++;
}
annars om (adc_result > DESIRED_ADC_RESULT & &
DUTY_CYCLE_REG > MIN_PWM_LEVEL) {
DUTY_CYCLE_REG--;
}
}
}