Taimer on väga populaarne mikrokontrollerite perifeeria, mis võimaldab lugeda aega, tekitada PWM signaale ja palju muud.
Oma olemuselt suurendavad taimerid loenduri väärtust ühe võrra iga kellasignaali tsükkliga. Tänu sellele saab taimeritega lugeda aega, täita mingit ülesannet iga teatud aja tagant ning PWM signaali genereerida.
Ekraanil olev juhend katab ainult PWM signaali genereerimist.
PWM ehk Pulse Width Modulation on väga kasulik digitaalsignaal, mida saab kasutada erinevate andurite ja seadmetega suhtmeliseks ning analoogsignaalide emuleerimiseks.
PWM kasutusalad
Oma olemuselt on PWM signaal hästi kiiresti 0V ja mingi loogikapinge vahel põrkav signaal.
PWM signaali üks tähtsamaid suuruseid on duty-cycle, mis näitab, mitu protsenti ajast on PWM signaal kõrge. Mida rohkem ajast on PWM signaal kõrge, seda suurem on duty-cycle ja vastupidi.
Duty-cycle on kasulik, et arvutada keskmine PWM signaali pinge. Kuna signaal põrkab pidevalt 0V ja loogikapinge (Nucleo F303K8 korral 3V3, Arduino-del 5V), siis on võimalik arvutada keskmine pinge. Selleks on valem Vavg = Vlogic * DT, kus DT on duty-cycle.
Näiteks, kui loogikgapinge on 3v3 ning duty-cycle on 25%, siis saame, et keskmine pinge on 3.3 * 0.25 = 0.825V.
Selle valemi abil ongi võimalik näha, kuidas saab emuleerida analogsignaale, näiteks LED-i põlema panemiseks või mootori kiiruse muutmiseks. Signaal on küll digitaalne, kuid muutes duty-cycle’t siis saame muuta keskmist pinget.
PWM signaali peamine tekitamisviis toimub taimerite abil. Taimeril on 3 väärtust, mis meid huvitavad. Nendeks on
Põhitöötsükkel käib nii:
Selleks, et teemat veidi paremini visualiseerida, on olemas Desmose graafik. (Kui see link on maas, pekske Kevinit) https://www.desmos.com/calculator/gwlvicnnpf
Sellel graafikul ülemine “saehamba signaal” näitab loenduri väärtust. See kasvab ajas lineaarselt, kuni jõuab maksimumi ning siis läheb tagasi nulli.
Alumine signaal on väljund PWM signaal, on näha, et kui loenduri väärtus jõuab compare väärtuseni, läheb PWM signaal madalaks. Kui loenduri väärtus ennast nullib, läheb PWM signaal kõrgeks.
Kui liigutada Desmos graafikul PWM Period Slider’i, siis on näha, kuidas PWM signaali duty-cycle muutub.
f_sys – Süsteemi põhikella sagedus
f_pwm – PWM signaali sagedus
DT - Duty cycle
f_pwm = f_sys / (prescaler * period)
DT = 100% * compare / period
Selleks, et saada sama signaal Nucleo mikrokontrolleritel, mis on Arduinodel, kasutada väärtuseid prescaler = 625 - 1 ning period = 256 - 1. Nende numbrite eelduseks on see, et Nucleo põhikell töötab tavakiirusel 8MHz. Need arvutavad tekitavad PWM signaali sagedusega 50Hz, mille vahemiku on 0 - 255.
Täpselt nagu kõikide teiste liidestega, saab taimereid konfigureerida CubeIDE-s. Selle eelis on see, et kõik sätted saab valida GUI-s ning programm genereerib selle koodi sinu eest.
Kõiki taimereid ja nende sätteid näeb .ioc failist
CubeIDE-st näeme, et Nucleo F303K8-l on kokku 8 taimerit, mida kasutadas saab. Kõik taimerid ei ole võrdsed, uurides näed lähemalt näeme, et esimesel taimeril on 6 väljundkanalit, teisel taimeril 4 väljundkanalit ning seitsmendal timeril polegi väljundeid.
Olenevalt taimerist, saab üks taimer tekitada mitu PWM signaali, kuid tuleb arvestada, et taimeri prescaler ja period väärtused kehtivad iga kanali kohta. See tähendab, et sa ei saa tekitada ühes taimeris kaks PWM signaali, millel on erinevad prescaler ja period.
Kasutame praeguses näites kõige võimsamat taimerit, milleks on taimer 1. Ütleme, et kasutame esimese taimeri esimest kanalit PWM signaali väljastamiseks.
Nüüd peaks tekkima uus jalg nimega TIM1_CH1. Seda jalga võib vabalt ümber nimetada, täpselt nagu GPIO jalgu. Pane tähele, et kui kanali valik on kollane või roosa, siis see tähendab, et selle kanali väljundjalg on juba kasutuses mingi teise asja jaoks. Näeme, et TIM1_CH1 väljundjalg on PA8.
Konfigureerime nüüd taimeri sätteid. Kõik olulised sätted on “Counter settings” kategooria all.
Kolm valikut, mis meid huvitavad on Prescaler – Siit saab valida prescaler väärtuse. Hoolikas tuleb olla sellega, et kui kui panna prescaler’i väärtuseks 0, siis jagatakse sisendkella väärtusega 1. Seega, kui tahetakse kella teha täpselt 16 korda aeglasemaks, peab prescaler olema tegelikult 15. Soovitav on kirjutada lahtrisse 16-1, et näidata teistele, sellega on arvestatud.
Counter Period – Siit saab valida period väärtuse. Kehtib täpselt sama reegel, et tegelik väärtus on ühe võrra väiksem, sest loendamine algab nullist.
Auto-reload – See valik tuleb panna “Enable”. Auto-reload tähendab seda, et kui loendur jõuab maksimum väärtuseni ning läheb nulli, jätkab kell lugemist. Ilma selle sätteda lõppeks PWM signaal pärast 1 tsükklit.
Koodi genereerimiseks tuleb kõigepealt .ioc fail salvestada ning siis vajutada üleval tööriista real kollast hammasratta pildiga nuppu.
Täpselt nagu GPIO HAL funktsioonid algavad kõik nimega “HAL_GPIO_”, algavad ka kõik taimeri funktsioonid liidesega “HAL_TIM_”.
Selleks, et PWM signaali tekitada, tuleb kõigepealt taimer käima panna. Selleks on olemas HAL funktsioon
See funktsioon võtab ühe argumendi, milleks on taimeri konfiguratsiooni struktuuri address. Selleks kirjutatakse argumendiks &htim ning taimeri number.
Näites kasutame taimer 1. Selleks, et taimer 1 käima panna, kirjutame. HAL_TIM_Base_Start(&htim1)
Eelmine funktsioon pani käima terve taimeri, kuid meil on vaja veel käima panna meie valitud kanal, et ta hakkaks PWM signaali tekitama.
See funktsioon võtab kaks argumenti.
Esimene neist argumentidest on jälle taimeri konfiguratsiooni struktuuri address, milleks antud näites on &htim1.
Teine argument ütleb, millist taimeri kanalit käivitatakse. Selleks genereerib CubeIDE automaatsed C macrod, mis näevad välja kujul “TIM_CHANNEL_x”, kus x on kanali number. Hetkel kasutame kanalit 1, seega kirjutame “TIM_CHANNEL_1”
Selleks, et taimer 1 esimene kanal käivitada, kirjutame HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
Nüüd meie PWM generatsioon käib, kuid väljundiks on ikka tühi, sest algolekus on compare väärtus 0, mis tähendab, et PWM signaal on alati madal.
Compare väärtuse muutmiseks on olemas C macro funktsioon, mis muudab compare muutmise kergemaks.
See funktsioon võtab kolm argumenti. Esimesed kaks argumenti on juba lahti seletatud, kui need on siin välja toodud teise nimega.
HANDLE all mõeldakse argumenti htim
CHANNEL all mõeldakse argumenti Channel
COMPARE all mõeldakse soovitud compare väärtust
Kuna kasutame taimer 1 esimest kanalit, saame, et HANDLE on &htim1 ning CHANNEL on TIM_CHANNEL_1. Tekitame 50% duty-cycle-ga PWM signaali. Kuna teame, et period väärtus on 256, paneme compare väärtuseks 256 / 2 = 128.
Kirjutame
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 128)
Nüüd on lõpuks näha väljundjalal 50% duty-cycle PWM signaali.
/* USER CODE BEGIN 2 */ HAL_TIM_Base_Start(&htim1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { for (int i = 0; i < 256; i++) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i); HAL_Delay(5); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
See kood paneb alguses käima esimese taimer ning seejärel esimese taimeri esimese kanali. Seejärel läheb kood while(1) tsükklisse, kus ta suurendab PWM compare väärtust iga tsükkel, kuni see jõuab maksimumi ja alustab uuesti.
Tulemusena tekib PWM signaal, mille duty-cycle läheb järjest suuremaks, kuni see jõuab 100%-ni ning siis läheb tagasi 0%-ni.