Il programma per il microcontrollore è scritto in assembler con MPLAB v8.4 e usa meno di 1K di flash (700word).
Questo è strutturato in più file:
Il file principale - pic16f883.asm
I file *.inc :
- bank.inc (le macro per cambiare i banchi di memoria);
- wait_i.inc (le macro per ritardo );
- timers.inc ( routine interrupt per i timer
);
- math.inc (routine per operazioni matematiche );
- Led_display.inc (routine per la gestione del display LED 7segmenti).
Il file main - pic16f883.asm
Il microcontrollore usa l'oscillatore interno settato a 8Mhz.
La sequenza di istruzioni per il settaggio del modulo pwm:
;init_PWM / out RB1 (P1C) |
|
movlw PR2 |
;set period timer 2 (1ms)-1Khz |
movwf FSR |
; |
movlw d'125' |
; |
movwf INDF |
;---- |
movlw 0x0C |
;pwm mode ,single output, P1C output High |
movwf CCP1CON |
; |
movlw PSTRCON |
;select PWM port pin - P1C(RB1) |
movwf FSR |
; |
movlw 0x04 |
; |
movwf INDF |
;---- |
movlw d'62' |
;duty cycle |
movwf CCPR1L |
; |
movlw b'01001110' |
;presc =16 Postsc=10 |
movwf T2CON |
;timer on 10 ms interrupt period |
btfss PIR1,TMR2IF |
;loop 1 PWM cycle |
goto $-1 |
; |
movlw TRISB |
; RB1 output |
movwf FSR |
; |
bsf INDF,TRISB1 |
;---- |
Il duty cycle si aggiusta cambiando il valore dei registri CCPR1L e CCP1CON<5:4>, tenendo conto che questo dipende anche dalla frequenza (periodo Timer 2).
Il duty cycle è aggiustabile con i tasti UP/DOWN tra 1 e 99% se in precedenza si preme il tasto S1 per selezionare il modo "Duty Cycle".
Dal valore scelto per la variabile duty_cycle (1..99) si calcola il valore per i registri CCPR1L e CCP1CON<5:4> con la formula "CCPR1L:CCP1CON<5.4> = duty_cycle * 4 (periodT2 + 1) / 100" .
La frequenza del generatore PWM si modifica cambiando il valore del registro PR2 (periodo Timer2 ) e il prescaler del Timer 2 (registro T2CON). Questa può essere variata tra 500Hz e 200Khz in oltre 500 passi incrementando/decrementando la variabile periodT2 con i tasti Up/Down .
La variabile "periodT2" prende valori in funzione del prescaler ottenendo cosi una gamma più ampia di frequenze disponibili.
I valori delle frequenze in funzione del prescaler e periodT2 |
prescaler |
periodT2 |
Frequenza |
1:1 |
9 .. 199 |
200,0KHz .. 10,00KHz |
1:8 |
50 .. 199 |
9,803KHz .. 2,500Khz |
1:16 |
50 .. 255 |
2,450KHz .. 0,488KHz |
Dopo la modifica della variabile periodT2, viene calcolata la frequenza e mandata al display con la funzione "print_freq".
Il file "timers.inc" contiene la routine per l'interrupt del Timer1 necessaria alla gestione dei segnali per il display LED 7 segmenti. Il Timer1 uno è settato per un periodo di 3.2ms.
La funzione "isr_tim1" viene chiamata ogni 3,2ms. Ogni volta "isr_tim1" spegne il digit acceso e accende il digit seguente in sequenza 1->2->3->4->1->2.., poi mette alla porta C (PORTC) il valore del digit attivo dal variabile "dig_x". Ogni digit è acceso per un periodo di 3,2 millisecondi e spento per il tempo in cui sono accesi i restanti 3, 3x3,2ms = 9,6ms.
Il file "Led_display.inc" contiene alcune routine per la conversione dei dati nei formati appropriati al "display 7 segmenti". Queste rutine sono:
- "bcd27seg" tabella per la conversione di un numero (0-9) in formato 7 segmenti;
- "BintoBCD" converte il valore (0.99) di una variabile 8 bit in formato BCD (Binary Coded Decimal) 2 digit ;
- "bin2bcd" (macro) converte il valore (0..65535) di una variabile 16 bit in formato BCD (Binary Coded Decimal) 6 digit;
- "bcd2led" - manda il valore della frequenza al display.
Il file "math.inc" contiene due routine:
-"MULT_16x8_FASTEST"(macro) per la moltiplicazione di due numeri positivi, uno di 16bit e altro di 8bit;
- "div32by16to16" per la divisione con resto di due numeri di 16bit. |