[PIC programování] – 7. díl
Vítám vás po dlouhé době u dalšího dílu série PIC programování !!!
V minulém díle jsme se seznámili s moduly Timer2/4/6, pomocí kterých jsme si vytvořili časování programu. Slíbil jsem nějaké časování, ale nakonec jsem se rozhodl pro PWM. Za toto se omlouvám, ale myslím, že se máte na co těšit!
V dnešním díle použijeme vám již známé moduly Timer2 a Timer4 pro tzv. pulzně šířkovou modulaci – PWM (Pulse Width Modulation). Jedná se o modulaci signálu, kde výstupní signál může nabývat dvou úrovní: logická 0 a logická 1 (stejně jako u klasického digitálního výstupu), tyto dva stavy se ovšem střídají (s určitou frekvencí).
PWM je tedy určena dvěma parametry: frekvencí (frequency) a střídou (duty cycle).
Frekvence nám udává počet stříd za sekundu. Střída nám vypovídá něco o intenzitě výstupního signálu. Udává se obvykle v procentech (od 0% do 100%).
Následující obrázek znázorňuje pulzně šířkovou modulaci o nějaké frekvenci s určitými pracovními cykly:
První graf ukazuje PWM se střídou 25%. Tedy čtvrtina času periody je výstupní napětí logická 1 a tři čtvrtiny času periody logická 0. Druhý graf je PWM se střídou 50% – polovina času logická 1, polovina času logická 0. Na posledním grafu je znázorněna PWM se střídou 75% – tři čtvrtiny času logická 1, jedna čtvrtina času logická 0.
Nyní již máte představu o tom, jak asi PWM funguje.
Pokud na takový výstup připojíme LED a budeme mít frekvenci 1Hz, střídu 50%, bude LED půl sekundy svítit a půl sekundy bude zhasnutá. Pomocí PWM můžeme řídit jas LEDky. Pokud použijeme vyšší frekvenci (např. 1kHz), bude se nám díky persistenci vidění zdát, že LED svítí. Střídou pak jednoduše regulujeme jas.
Pojďme si popsat dostupné periferie mikrokontroléru PIC16F1705 pro realizaci PWM:
Tento mikrokontrolér disponuje dvěma CCP moduly (Capture/Compare/PWM). Tyto moduly jsou univerzální a mohou se nastavit i pro další funkce mimo PWM. Jako vstupní signál přijímají výstup z modulu Timer2. Tento signál se potom dělí podle střídy na logickou 1 a logickou 0. Následující obrázek zobrazuje schéma zapojení CCP modulu v PWM módu:
Dále budeme používat PPS modul (Peripheral Pin Select), který zajistí fyzické propojení periferie (v tomto případě PWM výstupu) s pinem mikrokontroléru.
A nyní přikročíme k psaní kódu. Použijeme kód z minulého dílu. Timer2 ovšem potřebujeme pro CCP modul. Proto pro časování programu použijeme Timer4. Dále pro lepší čitelnost kódu zavedeme značení předponou R_ pro adresu registru a předponou K_ pro konstanty.
Následující kód je úplný program.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include "p16f1705.inc" ; CONFIG1 ; __config 0xC9E4 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF ; CONFIG2 ; __config 0xDEFB __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_OFF & _ZCDDIS_ON & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_OFF #define K_CITAC .1 #define R_CITAC 0x20 ;dekrementující čítač, výchozí hodnota K_CITAC org 0 ;začínáme na adrese 0 ;nastavení vnitřního oscilátoru na frekvenci 4MHz movlw b'01101010' banksel OSCCON ;je třeba vybrat správnou banku movwf OSCCON ;nastavení dekrementujícího čítače movlw K_CITAC ;čítač začíná na hodnotě K_CITAC banksel R_CITAC movwf R_CITAC ;nastavení časové základny (timer2) banksel T2CON movlw b'0000100' ;postscaler se u PWM nepoužívá, timer on, 1:1 prescaler movwf T2CON ;strany 259 a 266 movlw .249 ;PWM perioda = [(PR2)+1]*4*(prescale)/Fosc movwf PR2 ;(Fosc = 4MHz) perioda = 250ms => frekvence = 4kHz ; ... (timer4) banksel T4CON movlw b'1001101' ;1:10 postscaler, tmr on, 1:4 prescaler movwf T4CON movlw .250 movwf PR4 ;nastavení portu RC3 pro PWM ; postupujeme podle instrukcí v datasheetu na str. 266 ; kroky, které už máme (timer2 apod.) vynecháme banksel RC3PPS ;propojíme CCP1 modul s výstupem RC3 movlw b'01100' ;viz strana 141 movwf RC3PPS banksel TRISC ;odpojíme RC3 od latche (tím, že jej bsf TRISC,3 ; dočasně nastavíme jako vstup) banksel CCP1CON ;nastavíme CCP1 modul do pwm módu movlw b'1100' ;str. 269 movwf CCP1CON ;pozn.: nezáleží na tom, co dosadíme za x banksel CCPR1L clrf CCPR1L ;počáteční střída = 0 banksel PIR1 ;nastavíme bit TMR2IF na 0 bcf PIR1,TMR2IF banksel TRISC bcf TRISC,3 ;nastavíme RC3 jako výstup HLAVNI_SMYCKA banksel PIR2 ;PIR2 obsahuje bit TMR4IF, který signalizuje btfss PIR2,TMR4IF ;platnost timeru; musí se ručně vynulovat goto HLAVNI_SMYCKA ;čekat, dokud není timer platný ;čítač je platný ;100Hz bcf PIR2,TMR4IF ;vynulování TMR4IF banksel R_CITAC decfsz R_CITAC ;je čítač na nule? goto HLAVNI_SMYCKA ;není, vracíme se zpět na začátek movlw K_CITAC ;je movwf R_CITAC ;čítač nastavíme na výchozí hodnotu ; postupně zvyšujeme střídu každých 10ms banksel CCPR1L incf CCPR1L ; konec naší rutiny goto HLAVNI_SMYCKA ;po provedení našeho kódu se vracíme na začátek a opět čekáme na to, až timer doběhne do konce end |
Pro zprovoznění PWM podnikáme dva následující kroky:
- propojení pinu s PWM výstupem (modulu CCP1) pomocí PPS
- nastavení časování (pomocí Timeru 2):
- PWM perioda (1 / frekvence) = [(PR2)+1] * 4 * (TMR2 prescale) / Fosc = [249 + 1] * 4 * 1 / 4000000 = 250ms
- PWM střída pomocí registru CCPR1L (horních 8 bitů)
Pozn.: Pokud to již z textu nevyplynulo, střída pro modul CCP1 se nastavuje pomocí 10-bitového čísla. My ovšem používáme pouze prvních 8 MSB (Most Significant Bits), tedy prvních 8 bitů zleva. Je to jako kdybyste počítali součástky v řádu 10^3 (třeba 6200, 8100, …), zde nás také netrápí nějaké jednotky. Dva spodní bity DC1B se nachází v registru CCP1CON a ponecháváme je nulové.
V hlavní smyčce následně každých 10 ms zvýšíme registr CCPR1L o 1. Vzhledem k tomu, že pracujeme s 8 bity, trvá nám přesně 256 * (10 / 1000) = 2.56 sekund, než naše LEDka na výstupu RC3 zhasne.
A to je pro tento díl vše. Rád bych tuto sérii obnovil a v následujících dílech doplnil informace o rozhraních UART, I2C a SPI, nepřímé adresování a další.
Do příště, nashledanou!