Kapcsolatok

Alapvető időzítők az STM32-ben. Munka egyszerű időzítőkkel STM32 F4 felfedezés Stm32 időzítő megszakítja

A cikk az STMicroelectronics STM32 sorozatú 32 bites ARM mikrovezérlőinek időzítőit írja le. Figyelembe veszi az alapvető időzítő regiszterek felépítését és összetételét, és gyakorlati példákat adunk a programokra.

Bármely mikrokontrollernél az időzítő az egyik legfontosabb komponens, amely lehetővé teszi az időintervallumok nagyon pontos számlálását, a bemenetekre érkező impulzusok számlálását, belső megszakítások generálását, impulzusszélesség-modulációval (PWM) jelek generálását és közvetlen memóriaelérés támogatását ( DMA) folyamatok.

Az STM32 mikrokontroller többféle időzítőt tartalmaz, amelyek funkcionalitásban különböznek egymástól. Az első típusú időzítő a legegyszerűbb, és az alapvető időzítők. Ebbe a típusba tartoznak a TIM6 és a TIM7 időzítők. Ezek az időzítők nagyon könnyen konfigurálhatók és vezérelhetők minimális regiszter használatával. Képesek időintervallumok számlálására és megszakítások generálására, amikor az időzítő elér egy meghatározott értéket.
A második típus az általános célú időzítők. Ez magában foglalja a TIM2 - TIM5 időzítőket és a TIM12 - TIM17 időzítőket. Képesek PWM-et generálni, számolni a mikrokontroller bizonyos tűire érkező impulzusokat, feldolgozni a kódolóból érkező jeleket stb.

A harmadik típus fejlett vezérlésű időzítőket határoz meg (Advanced-Control Timer). Ez a típus tartalmazza a TIM1 időzítőt, amely a fenti műveletek mindegyikét képes végrehajtani. Ezen túlmenően az időzítő alapján olyan eszközt építhet, amely képes háromfázisú elektromos hajtás vezérlésére.

Alapvető időzítő eszköz

Tekintsük egy alapidőzítő kialakítását és működését, melynek blokkvázlata az ábrán látható. Az alapidőzítő 16 bites regiszterek alapján épül fel. Ennek alapja a TIMx_CNT számláló regiszter. (A továbbiakban az „x” szimbólum a 6-os vagy a 7-es számot helyettesíti a TIM6 és TIM7 alapidőzítőknél.) A TIMx_PSC előskálázó lehetővé teszi a számlálóregiszter órafrekvenciájának beállítását, a TIMx_ARR autoload regiszter pedig lehetővé teszi a beállítást. az időzítő számlálási tartománya. A trigger- és szinkronvezérlő a vezérlő- és állapotregiszterekkel együtt az időzítő működési módjának megszervezésére és működésének szabályozására szolgál.

Szervezetének köszönhetően az időzítő számlálója előre és hátra, valamint egy adott tartomány közepéig előre, majd visszafelé tud számolni. Az alapidőzítő bemenet több forrásból táplálható, beleértve az APB1 busz órajelét, külső jelet vagy más rögzítő és összehasonlító érintkezőkre alkalmazott időzítők kimenetét. A TIM6 és a TIM7 időzítők az APB1 buszról szólnak. Ha 8 MHz-es kristályt és gyári alapértelmezett órabeállítást használ, az APB1 órabusz órajel frekvenciája 24 MHz lesz.

Alapvető időzítő regiszterek

A táblázat a TIM6 és TIM7 alapidőzítők regisztertérképét mutatja. Az alapvető időzítők a következő 8 regisztert tartalmazzák:

●● TIMx_CNT – Számláló (számláló regiszter);
●● TIMx_PSC – Előskálázó (előskálázó);
●● TIMx_ARR – Automatikus újratöltési regiszter;
●● TIMx_CR1 – 1. vezérlőregiszter (1. vezérlőregiszter);
●● TIMx_CR2 – 2. vezérlőregiszter (2. vezérlőregiszter);
●● TIMx_DIER – DMA megszakítás engedélyezési regiszter (DAP és megszakítás engedélyezési regiszter);
●● TIMx_SR – Állapotnyilvántartás;
●● TIMx_EGR – Eseménygenerációs nyilvántartás.

A TIMx_CNT, TIMx_PSC és TIMx_ARR regiszterek 16 információs bitet használnak, és lehetővé teszik 0 és 65535 közötti értékek írását. A TIMx_CNT számlálóregiszter órajel-impulzusainak frekvenciája, amely áthalad a TIMx_PSC osztón, a következő képlettel számítható ki: Fcnt = Fin /(PSC + 1), ahol Fcnt az időzítő számláló regiszterének impulzusfrekvenciája; Fin – órajel frekvencia; PSC – az osztási együtthatót meghatározó időzítő TIMx_PSC regiszter tartalma. Ha a TIMx_PSC regiszterbe a 23999 értéket írjuk, akkor a TIMx_CNT számlálóregiszter 24 MHz-es órajel frekvencián másodpercenként 1000-szer változtatja az értékét. Az automatikus betöltési regiszter tárolja a TIMx_CNT számlálóregiszter betöltéséhez szükséges értéket. A TIMx_CNT regiszter tartalma a túlcsordulás vagy alaphelyzetbe állítás után frissül, a hozzá meghatározott számlálási iránytól függően. A TIMх_CR1 vezérlőregiszternek több vezérlőbitje van. Az ARPE bit engedélyezi és letiltja a TIMx_ARR autoload regiszterbe történő írások pufferelését. Ha ez a bit nulla, akkor ha új értéket írunk a TIMx_ARR-be, az azonnal betöltődik bele. Ha az ARPE bit egyenlő eggyel, akkor a regiszterbe való betöltés a határérték elérése után történik meg. Az OPM kisütés lehetővé teszi az „egyimpulzusos” üzemmódot. Ha be van állítva, a számlálóregiszter túlcsordulása után a számlálás leáll, és a CEN bit visszaáll. Az UDIS bit engedélyezi vagy letiltja az időzítő esemény generálását. Ha törlődik, akkor az esemény akkor jön létre, amikor az esemény generálásának feltétele bekövetkezik, vagyis amikor az időzítő túlcsordul, vagy amikor az UG bit be van programozva a TIMx_ EGR regiszterbe. A CEN bit be- és kikapcsolja az időzítőt. Ha visszaállítja ezt a bitet, a számlálás leáll, és ha be van állítva, a számlálás folytatódik. A bemeneti osztó nullától kezdi a számolást. A TIMx_CR2 vezérlőregiszter három MMS2...MMS0 vezérlőbittel rendelkezik, amelyek meghatározzák az időzítő mester üzemmódját. A TIMx_DIER regiszter két bitet használ. Az UDE bit lehetővé teszi vagy letiltja a DMA kérés kiadását esemény bekövetkeztekor. Az UIE bit engedélyezi és letiltja az időzítő megszakításokat. A TIMx_SR regiszter csak egy UIF bitet használ megszakítási jelzőként. Hardver telepíti, amikor időzítő esemény történik. Programozottan vissza kell állítania. A TIMx_EGR regiszter tartalmaz egy UG bitet, amely lehetővé teszi a „számláló regiszter túlcsordulás” esemény programozását. Amikor ez a bit be van állítva, egy esemény generálódik, és a számláló regiszter és az előskálázó visszaáll. Ezt a bitet hardver alaphelyzetbe állítja. Ennek a bitnek köszönhetően programozottan generálhat eseményt egy időzítőből, és ezáltal erőteljesen meghívhatja az időzítő megszakításkezelő funkciót.

Nézzük meg a vezérlőregiszterek célját és az időzítő állapotát konkrét programpéldák segítségével.

Példa programok

Az időzítő elindításához több műveletet kell végrehajtani, mint például az időzítő órajelét és a regisztereinek inicializálását. Nézzük meg ezeket a műveleteket az időzítőkkel való munkavégzésre szolgáló példaprogramok alapján. A programozási folyamatban gyakran felmerül az időkésések megvalósításának feladata. A probléma megoldásához késleltetésgeneráló funkcióra van szükség. Az 1. listában egy példa látható egy ilyen funkcióra, amely az STM32 alap TIM7 időzítőjén alapul.

Lista 1

#define FAPB1 24000000 // APB1 busz órajel frekvencia // Késleltetési funkció ezredmásodpercben és mikroszekundumban void delay(előjel nélküli char t, előjel nélküli int n)( // A PSC előskálázó regiszter betöltése If(t = = 0) TIM7->PSC = FAPB1 /1000000-1 // a mikroszekundumok számlálására If(t = = 1) TIM7->PSC = FAPB1/1000-1 // ezredmásodpercek számlálására TIM7->ARR = n // A minták számának betöltése az automatikus betöltésbe; regiszter ARR TIM7 ->EGR |= TIM_EGR_UG // Frissítési esemény generálása a PSC és az ARR regiszterekbe való beírásához TIM7->CR1 |= TIM_CR1_CEN|TIM_CR1_OPM // Indítsa el az időzítőt // a számláló engedélyezése bit beírásával; A CEN // és a mód bit átadja az OPM-et a CR1 vezérlőregiszternek (TIM7->CR1&TIM_CR1_CEN != 0 // Várakozás a számlálás végére)

Ez a funkció mikroszekundumban vagy ezredmásodpercben késleltetést generálhat a "t" paramétertől függően. A késleltetés időtartamát az „n” paraméter állítja be. Ez a program a TIM7 időzítő egyszeri lépéses módját használja, amelyben a CNT számlálóregiszter az ARR regiszterben rögzített túlcsordulási értékig számol. Ha ezek az értékek megegyeznek, az időzítő leáll. Az időzítő leállása a while ciklusban várható a CR1 állapotregiszter CEN bitjének ellenőrzésével. Az időzítők időzítésének engedélyezése egyszer történik meg a program fő moduljában az inicializálás során. Az alapidőzítők az APB1 buszra csatlakoznak, így az óraellátás így néz ki:

RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Órajel bekapcsolása a TIM6-on RCC->APB1ENR |= RCC_APB1ENR_ TIM7EN; // Órajelzés engedélyezése a TIM7-en

A késleltetés generálására szolgáló, fentebb leírt szoftveres eljárásnak van egy jelentős hátránya, mivel a processzor a teljes késleltetési idő alatt kénytelen lekérdezni a zászlót, és ezért nem tud más feladatokat végrehajtani ezalatt az idő alatt. Ez a hátrány kiküszöbölhető az időzített megszakítási mód használatával. Az alapvető időzítők megszakításkezelési funkciói általában így néznek ki:

Void TIM7_IRQHandler())( TIM7->SR = ~TIM_SR_UIF; // A jelző törlése //Műveletek végrehajtása ) void TIM6_DAC_IRQHandler())( //Ha az esemény a TIM6-ból származik if(TIM6->SR & TIM_SR_UIF)( TIM6- >SR =~ TIM_SR_UIF // A zászló törlése // Műveletek végrehajtása ) ;

Tekintsünk egy példát egy olyan programra, amely egy alap TIM6 időzítőn késleltetést szervez, amely egy időzítő megszakításait használja. A program végrehajtásának vezérléséhez a mikrokontroller egyik tűjét használjuk a LED-jelzők vezérlésére, amelyeknek a TIM6 időzítőn szervezett programkésleltetése által meghatározott időközönként kell kapcsolniuk. Egy ilyen program példája a 2. listában látható.

2. lista

// Beleértve a könyvtárakat #include #beleértve #beleértve #beleértve #beleértve // Tűk hozzárendelése a LED indikátorokhoz enum ( LED1 = GPIO_Pin_8, LED2 = GPIO_Pin_9 ); // Funkció a LED-vezérlőportok inicializálásához void init_leds() ( RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio; GPIO_StructInit(&gpio); gpio.GPIO_PPMode_init_GPIOut | Init(GPIOC, &gpio); /TIM6 időzítő inicializálási függvény void init_timer_TIM6() ( // Az időzítő órajelének engedélyezése RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef base_timer; TIM_TimeBase_2tti a base_9.9/9/StructInittimer TIM_Prescale r = 24000 - 1 // Állítsa be a periódus 500 ms-ig base_timer.TIM_Period = 500 TIM_TimeBaseInit (TIM6, &base_timer) / Időzítő megszakításkezelő funkció void TIM6_DAC_IRQHandler())( // Ha megszakítás történik a TIM6 időzítő számláló túlcsordulása miatt if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) ( //A feldolgozott megszakítás bitjének visszaállítása(TIMendingCletarIT(TIMendingCletar) , TIM_IT_Update); //A LED-jelzők állapotának megfordítása GPIO_Write(GPIOC, GPIO_ReadOutputData(GPIOC) ^ (LED1 | LED2)); ) ) // A program fő modulja int main() ( init_leds(); GPIO_SetBits(GPIOC, LED1); GPIO_ResetBits(GPIOC, LED2); init_timer_TIM6(); while (1) ( // Hely más parancsokhoz ) )

Ebben a programban a késleltetési függvényt egyszer hívják meg, ami után a processzor további műveleteket hajthat végre, és az időzítő rendszeresen generál megszakításokat a megadott késleltetési időközönként. Hasonló program írható a TIM7 időzítőhöz is. Az ilyen programok közötti különbség a regiszterek és a megszakításkezelő nevében lesz. A TIM6 időzítő megszakításkezelőnek van egy olyan tulajdonsága, hogy az időzítő megszakítás-feldolgozási vektora egy digitális-analóg konverter (DAC) megszakításával van kombinálva. Ezért a megszakításkezelő funkció ellenőrzi a megszakítás forrását. Az STM32 mikrokontroller időzítőiről a St.com weboldalon tudhat meg többet. Az időzítőnek számos, fentebb leírt feladata van, amelyeket sikeresen meg tud oldani. Ezért a programban való használata jelentősen csökkenti a processzor terhelését, és hatékonyabbá teszi a programot.

Bármely modern vezérlő rendelkezik időzítők. Ez a cikk arról fog szólni egyszerű (alap) időzítők stm32f4 felfedezése.
Ezek normál időzítők. 16 bitesek, automatikus újraindítással. Ezen kívül van egy 16 bites programozható frekvenciaosztó. Lehetőség van generálni számláló túlcsordulás megszakítjaés/vagy DMA kérés.

Kezdjük el. Mint korábban, az Eclipse + st-util-t használom ubuntu linuxban

Először is összekapcsoljuk a fejléceket:

#beleértve #beleértve #beleértve #beleértve #beleértve

Nincs ebben semmi új. Ha nem világos, honnan származnak, olvassa el a korábbi cikkeket, vagy nyissa meg a fájlt és olvassa el.

Definiáljunk két állandót. Az egyik a diódákat, a másik ugyanazon diódák tömbjét jelöli:

Const uint16_t LEDS = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; // minden dióda const uint16_t LED = (GPIO_Pin_12, GPIO_Pin_13, GPIO_Pin_14, GPIO_Pin_15); // tömb diódákkal

Valószínűleg már ismeri a perifériák (azaz a diódák) inicializálásának funkcióját:

Void init_leds())(RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // a GPIO_InitTypeDef gpio órajelének engedélyezése; // a GPIO_StructInit(&gpio) felépítése; // kitöltése szabványos értékekkel a gpio_Pio.pey pio .GPIO_Mode = GPIO_Mode_OUT; // kimenetként működik gpio.GPIO_Pin = LED-ek // minden dióda GPIO_Init(GPIOD, &gpio);

Időzítő inicializálási funkció:

Void init_timer())(RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // az időzítés engedélyezése /* A TIM_TimeBaseInitTypeDef * struktúra egyéb paraméterei nem értelmezhetők az alapidőzítők esetében mer); /* Az osztó az figyelembe véve: TIM_Pre scaler + 1, tehát vonja ki az 1-et */ base_timer.TIM_Prescaler = 24000 - 1; // osztó 24000 base_timer.TIM_Period = 1000 //period of 1000 impulzusok TIM_TimeBaseInit, &*TimeBaseInit; frissítés (ebben az esetben - * túlcsordulás esetén) */ TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE) // Az időzítő engedélyezése /* A TIM6 számláló túlcsordulási megszakításának engedélyezése az interrupt a DAC kiürítéséért is felelős.

Kommentáltam a kódot, úgyhogy szerintem minden világos.
A legfontosabb paraméterek itt az időzítő osztója (TIM_Prescaler) és periódusa (TIM_Period). Ezek azok a paraméterek, amelyek ténylegesen konfigurálják az időzítő működését.

Például, ha az STM32F4 DISCOVERY-n 48 MHz-re van beállítva az órajel, akkor az általános célú időzítők frekvenciája 24 MHz. Ha az osztót (TIM_Prescaler) 24000-re állítja (számlálási frekvencia = 24MHz/24000 = 1KHz), a periódust (TIM_Period) pedig 1000-re, akkor az időzítő 1 másodpercben számolja az intervallumot.

Kérjük, vegye figyelembe, hogy minden az órajeltől függ. Pontosan meg kell találnia.

Megjegyzem továbbá, hogy magas frekvenciákon a LED megszakítással történő kapcsolása jelentősen torzítja a frekvenciaértéket. 1 MHz értékkel a kimeneten kb 250 KHz-et kaptam, azaz. a különbség elfogadhatatlan. Ez az eredmény nyilvánvalóan a megszakítás végrehajtására fordított idő miatt érhető el.

Globális változó – világító dióda zászló:

U16 zászló = 0;

Az időzítőt előállító megszakításkezelő. Mert Ugyanez a megszakítás generálódik, amikor a DAC fut, először ellenőrizzük, hogy az időzítő váltotta-e ki:

Void TIM6_DAC_IRQHandler())( /* Mivel ezt a kezelőt a DAC is hívja, ellenőrizni kell, * hogy nem történt-e TIM6 időzítő számláló túlcsordulási megszakítása. */ if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) ( flag++; if (flag> 3) flag = 0 /* A folyamatban lévő megszakítás bitjének törlése */ TIM_ClearITPendingBit(GPIO_Write(GPIOD, LED);

fő funkció:

Int main())( init_leds(); init_timer(); do ( ) while(1); )

A ciklust üresen hagyjuk. A számláló aszinkron módon végzi munkáját, a megszakítás pedig megszakítás, hogy ne függjön az éppen végrehajtott művelettől.

Jó napot. Ma megírom az első cikket az STM32 időzítőiről. Általánosságban elmondható, hogy az STM32 időzítői annyira menők, hogy még Schwarzenegger is idegesen dohányzik a hideg miatt))) És több mint egy, kettő vagy három cikkben kell tanulmányoznia őket. De először ne zavarjuk magunkat túlságosan, hanem egyszerűen tanulmányozzuk az első egyszerű időzítőket, és dolgozzunk velük.

Az STM32-ben általában háromféle időzítő létezik
1) alapvető időzítők
2) általános célú időzítők
3) fejlett (fejlett vezérlésű időzítők)

A fejlett időzítők a legmenőbbek, és egyesítik a két előző csoport képességeit, valamint számos további funkciót, mint például a háromfázisú motorokkal való munka stb. stb. Még nagyon messze vagyunk tőlük, ezért ebben a részben megfontoljuk az alapvető időzítők használatát.
Először is nézzük meg, milyen időzítők vannak az STM32F407VG processzorunkon (megnézed a processzorokat, amelyekkel dolgozik)). A processzoromban 14 időzítő van - 12-16 bit és 2 32 bit

Ahogy a képeken is látjuk, az ARV1 buszra TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM12 időzítők csatlakoznak.
És az ARV2 buszhoz - TIM1, TIM8, TIM9, TIM10, TIM11
Most nézzük meg a képet az órajel beállításáról a CubeMX programban. Az órajelrendszert külön is leírom, hiszen nem tudok nélküle élni, de egyelőre csak azt mutatom meg, hogyan tudjuk a belső HSI óraforrás segítségével órajelezni az időzítőinket.
Itt van a standard órabeállításunk frekvenciaszorzók stb. nélkül. Ezt fogjuk használni.

És itt van egy lehetőség a munka felgyorsítására)) De azt tanácsolom, hogy ne másszon túl sokat játékos kis kezeivel, különben a processzort a lapockáira helyezheti)) Mindezt később tanulmányozzuk és mérlegeljük.

Tehát megnyitjuk az F4 sorozatú mikrokontrollerek Referencia kézikönyvét, és elkezdjük füstölni a kézikönyvet. IGEN, az STM32-ben nem minden olyan egyszerű, szóval elvtársak, tanuljatok angolul és olvassátok el a kézikönyveket, mert e nélkül sokáig fogtok keresni, hogy mi az. Régebben nagyon nehezen olvastam a dokumentációt (nyilván azért, mert a feladatok egyszerűek voltak, és elegem volt a szokásos internetes példákból). Nos, most olvasunk... olvasunk... olvasunk...
Folytassuk...
Tehát a 6. és 7. időzítő alapvető időzítők. Az ARV1 buszon ülnek, ahogy a referencia kézikönyv képén látjuk.

A 6. és 7. alapidőzítők 16 bitesek, 0-tól 65535-ig állítható előskálázóval rendelkeznek. Ezekhez az időzítőkhöz ezek a regiszterek állnak rendelkezésre az olvasáshoz/íráshoz.
Counter Register (TIMx_CNT) - számláló
Prescaler Register (TIMx_PSC) - előskálázó
Regiszter automatikus újratöltése (TIMx_ARR) - regiszter újratöltése

A munka részleteiben nem fogunk túl mélyen elmélyülni, hiszen 10 oldalnyi regiszterleírás áll rendelkezésünkre, stb., nekünk elég lesz a fent leírt három
Tehát mik ezek a regiszterek, és miért van szükségünk rájuk? Igen, ezért. Úgy döntöttünk, hogy sürgősen villogunk egy LED-et, hogy meglepjük például AVR-társainkat, és azt mondjuk - aki gyorsan be tudja állítani az egyik LED-et fél másodperces, a másodikat pedig egy másodperces villogással, nyer. (egyébként hasonló kísérletet is végezhet))))
Ennek megvalósításához mindössze 5 lépésre van szükségünk - 1
1) Indítsa el a CubeMX-et, és hozzon létre egy projektet a vezérlőnknek.
2) CubeMX-ben állítsa be az időzítők működését
3) hozzon létre egy projektet, és nyissa meg a Keil uVisionban
4) inicializálja az időzítőket (időzítőnként egy sor)
5) írja be minden időzítő megszakításába annak a lábnak a kódját, amelyhez a LED csatlakoztatva van.
Tehát nézzük ezt részletesebben. Először is indítsuk el a CubeMX programunkat
és konfigurálja a 2 PD12 és PD13 érintkezőt a kimenetre (a LED-ek csatlakoztatására szolgáló lábak). Beállítjuk számukra a GPIO_Output módot, illetve az Output Push_Pull módot.
Ezután a bal oldalon aktiváljuk a 6-os és 7-es alapvető időzítőnket.

Most lépjen a konfigurációs lapra. Emlékezetünk szerint a processzorunk frekvenciabeállításain semmit nem változtattunk, így minden buszunk -16 MHz-en van. Most ez alapján, és az alapján, amit meg kell szereznünk, konfiguráljuk az értékeinket az előskálázókhoz és az automatikus újratöltési regiszterhez.

Mint emlékszünk, szükségünk van egy LED-re, hogy 1 Hz-es frekvenciával villogjon (1000 ms-os periódus), a második pedig 2 Hz-es frekvenciával (500 ms-os periódus). Hogyan érjük el ezt nagyon egyszerű? Mivel az STM32-re bármilyen előskálázó felszerelhető, egyszerűen kiszámoljuk az értékét
A frekvenciánk tehát 16 000 000 kullancs másodpercenként, de másodpercenként 1000 kullancsra van szükségünk. Ez azt jelenti, hogy 16 000 000 \ 1 000 = 16 000 Ezt a számot mínusz 1-gyel írjuk be az előskálázó értékébe. Vagyis a kapott szám 15999.
Most az időzítőnk 1000-szer ketyeg másodpercenként. Ezután jeleznünk kell, mikor van szükség túlcsordulási megszakításra. Ehhez a Counter Period-ba (autoreload register) írjuk be a szükséges számot.
Vagyis másodpercenként egy megszakítást kell kapnunk, és mint emlékszünk, az időzítőnk 1-szer ketyeg ezredmásodpercenként. Egy másodpercben 1000 ms van, ezért ezt az értéket írjuk be az automatikus újraindítási regiszterbe.
Annak érdekében, hogy fél másodpercenként megszakítást kapjunk, ennek megfelelően írunk - 500.

Tehát beállítottuk, most már biztonságosan generálhatjuk projektünket. Generált, jó. Már csak egy kis idő van hátra a LED-ek villogásáig.
Megnyitottuk projektünket. Elvileg minden be van állítva és készen áll számunkra, csak el kell indítani az időzítőinket, hiszen bár a CubeMX mindent megtesz helyettünk, ezt már nem. Tehát inicializáljuk
időzítőink ezekkel a vonalakkal vannak

HAL_TIM_Base_Start_IT(&htim6);
HAL_TIM_Base_Start_IT(&htim7);

Itt találhatók az időzítőink megszakításkezelői.
Itt van a 7-es időzítő megszakításkezelője

void TIM7_IRQHandler(void)
{
/* FELHASZNÁLÓI KÓD BEGIN TIM7_IRQn 0 */

/* FELHASZNÁLÓI KÓD VÉGE TIM7_IRQn 0 */
HAL_TIM_IRQHandler(&htim7);
/* FELHASZNÁLÓI KÓD BEGIN TIM7_IRQn 1 */

/* FELHASZNÁLÓI KÓD VÉGE TIM7_IRQn 1 */
}

Beírjuk a megszakításkezelőbe, hogy mit akarunk csinálni - és minden megszakítással meg akarjuk változtatni azon lábaink állapotát, amelyekhez a LED-ek kapcsolódnak.
Ezt a konstrukciót használjuk - HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);

Ez minden. Megnyomjuk az F7 billentyűt, ellenőrizzük, hogy ne legyen hiba – és mindezt feltölthetjük a kísérleti processzorunkba.
Nos, máris élvezhetjük a LED-ek érdekes villogását.
Kicsit később teszek fel egy videót, de egyelőre szokás szerint a kép helyes. Nos, ne felejtsd el a hálát))

Az STM32 időzítői, mint elvileg minden periféria, nagyon kifinomultak. Az időzítők által végrehajtott különféle funkciók sokasága még a fejét is megpörgeti. Bár úgy tűnik, hogy az időzítő csak egy időzítő, csak számolni kell. De a valóságban minden sokkal menőbb)

Nemcsak az időzítők rendelkeznek ilyen széles lehetőségekkel, hanem minden vezérlőnek több is van belőlük. És nem is kettő vagy három, hanem több! Általában a végtelenségig lehet dicsérni mindezt. Nézzük meg, mi és hogyan működik. Tehát az STM32F103CB mikrokontroller rendelkezik:

  • 3 általános célú időzítő (TIM2, TIM3, TIM4)
  • 1 további fejlett időzítő fejlett képességekkel (TIM1)
  • 2 WDT (WatchDog Timer)
  • 1 SysTick időzítő

Valójában az általános célú időzítők és a TIM1 időzítő nem nagyon különböznek egymástól, ezért csak egy időzítőt veszünk figyelembe. Egyébként a TIM4-et választottam. Nincs különösebb oka, csak úgy éreztem =). Az időzítőknek 4 független csatornája van, amelyek a következőkre használhatók:

  • Signal Capture
  • Összehasonlítások
  • PWM generáció
  • Egyimpulzusgenerálás
  • Túlcsordulás
  • Jelfelvétel
  • Összehasonlítás
  • Kiváltó esemény

Ha ezen események bármelyike ​​bekövetkezik, az időzítők kérést generálhatnak a DMA felé (a DMA közvetlen memóriaelérés, hamarosan foglalkozunk vele =)). Most egy kicsit többet az egyes időzítő üzemmódokról.

Jelrögzítési mód. Nagyon kényelmes az impulzusismétlési periódus mérése, amikor az időzítőt ebben az üzemmódban működteti. Győződjön meg Ön is: impulzus érkezik, az időzítő beírja az aktuális számláló értékét a regiszterbe TIM_CCR. Gyorsan felvesszük ezt az értéket, és elrejtjük valamilyen változóban. Ülünk és várjuk a következő impulzust. Hoppá! Megérkezett az impulzus, az időzítő ismét benyomja a számláló értéket TIM_CCR, és csak annyit kell tennünk, hogy ebből az értékből kivonjuk az előzőleg elmentett értéket. Valószínűleg ez a legegyszerűbb használata ennek az időzítő módnak, de nagyon hasznos. Az impulzus elülső élét és a lefutó élét is meg lehet fogni, így elég nagyok a lehetőségek.

Összehasonlító mód. Itt egyszerűen csatlakoztatunk egy időzítő csatornát a megfelelő kimenethez, és amint az időzítő egy bizonyos értékig számol (az TIM_CCR) a kimenet állapota az üzemmód beállításától függően változik (vagy egyre vagy nullára lesz állítva, vagy az ellenkezőjére változik).

PWM generálási mód. Nos, minden el van rejtve a névben) Ebben a módban az időzítő PWM-et generál! Valószínűleg most nincs értelme ide írni. Hamarosan lesz egy minta csak a PWM-hez, és részletesebben ássunk bele.

Holtidő mód. Az üzemmód lényege, hogy az időzítő fő és kiegészítő érintkezőinél bizonyos késleltetés jelenik meg a jelek között. Az interneten elég sok információ található arról, hol lehet és érdemes ezt alkalmazni.

Nos, elvileg nagyon röviden az időzítő fő működési módjairól. Ha kérdésed van más módokkal kapcsolatban, konkrétabbakkal kapcsolatban, írd meg a Megjegyzésekbe 😉

Lassan meg kell írnunk egy programot az időzítőkkel való munkavégzéshez. De először nézzük meg, mi van a Standard Peripheral Library-ban. Tehát a fájlok felelősek az időzítőkért - stm32f10x_tim.hÉs stm32f10x_tim.c. Megnyitjuk az elsőt, és látjuk, hogy a fájlszerkezet megismétli a GPIO-val való munkavégzéshez szükséges fájl szerkezetét, amelyet az előző cikkben tárgyaltunk. Ez leírja az időzítők konfigurálásához szükséges struktúrák struktúráit és mezőit. Igaz, nem csak egy, hanem több struktúra létezik (az időzítőknek több módjuk van, így beállításuk is, mint az I/O portoknak). Az összes szerkezeti mező megjegyzésekkel van ellátva, így itt nem lehet probléma. Nos például:

uint16_t TIM_OCMode; // Meghatározza a TIM módot.

Itt beállítjuk az időzítő működési módját. És itt van még egy:

uint16_t TIM_Channel; // Megadja a TIM csatornát.

Itt kiválasztjuk az időzítő csatornát, semmi váratlan) Általában minden elég átlátható, ha bármit kérdezel =) Az első fájl tiszta. És a fájlban stm32f10x_tim.c– kész funkciók az időzítőkkel való munkavégzéshez. Általában is minden világos. A könyvtárat eddig is használtuk GPIO-kkal, most időzítőkkel dolgozunk, és nyilvánvaló, hogy a különböző perifériák esetében minden nagyon hasonló. Tehát hozzunk létre egy projektet és írjunk egy programot.

Tehát hozzunk létre egy új projektet, adjunk hozzá minden szükséges fájlt:

Írjuk a kódot:

Megjegyzendő, hogy a TIM_Prescaler mezőbe egy olyan értéket kell beírni, amely eggyel kisebb, mint amit kapni szeretnénk.

/******************************** timers.c******************** *************/#include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_tim.h" //Ezzel az előskálázóval 10 µs-onként egy időzítő pipát kapok#define TIMER_PRESCALER 720 /*******************************************************************/ //Változó a PB0 láb előző állapotának tárolására uint16_t previousState; GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef időzítő; /*******************************************************************/ void initAll() ( //A GPIOB port és a TIM4 időzítő órajelének engedélyezése //A 4. időzítő lefagy az APB1 buszon RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE) ; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) ; //Itt a PB0 portot állítjuk be a kimenethez //Erről a GPIO-ról szóló cikkben olvashat bővebben GPIO_StructInit(& port) ; port.GPIO_Mode = GPIO_Mode_Out_PP; port.GPIO_Pin = GPIO_Pin_0; port.GPIO_Speed ​​= GPIO_Speed_2MHz; GPIO_Init(GPIOB, & port) ; //És itt az időzítő beállítása //Töltse ki a szerkezeti mezőket alapértelmezett értékekkel TIM_TimeBaseStructInit(& időzítő) ; //Az előskálázó beállítása timer.TIM_Prescaler = TIMER_PRESCALER - 1 ; //Itt az az érték, amelyre az időzítő megszakítást generál //Ezt az értéket egyébként magában a megszakításban fogjuk megváltoztatni timer.TIM_Period = 50 ; //A TIM4 inicializálása értékeinkkel TIM_TimeBaseInit(TIM4, & időzítő) ; ) /*******************************************************************/ int main() ( __enable_irq() ; initAll() ; //Időzítő beállítása frissítési (túlcsordulási) megszakítás generálásához TIM_ITConfig(TIM4, TIM_IT_Frissítés, ENGEDÉLYEZÉS) ; //Indítsa el az időzítőt TIM_Cmd(TIM4, ENGEDÉLYEZÉS) ; //Engedélyezze a megfelelő megszakítást NVIC_EnableIRQ(TIM4_IRQn) ; míg (1) ( //Végtelenül hülyék vagyunk) Minden hasznos munka a megszakításban van __NOP() ; ) ) /*******************************************************************/ //Ha a kimenet 0 volt... timer.TIM_Period = 50 ; TIM_TimeBaseInit(TIM4, & időzítő) ; //A megszakítási bit törlése TIM_ClearITPendingBit(TIM4, TIM_IT_Update) ; ) más ( //Állítson be nullát a kimeneten timer.TIM_Period = 250 ; TIM_TimeBaseInit(TIM4, & időzítő) ; TIM_ClearITPendingBit(TIM4, TIM_IT_Update) ; ) )

Ebben a programban azt nézzük, hogy mi volt a kimeneten a megszakítás generálása előtt - ha nulla, akkor 0,5 ms-ra egyet állítunk be. Ha volt ilyen, állítsa nullára 2,5 ms-ra. Fordítsa le és kezdje el a hibakeresést =)

Egy apró, de nagyon fontos kitérő... Példánk természetesen működni fog, és tesztelésre is bőven alkalmas lesz, de ennek ellenére a „harci” programokban figyelni kell a kód optimálisságát mind a mennyiségét, mind a mennyiségét tekintve. teljesítmény és fogyasztási memória tekintetében. Ebben az esetben nincs értelme az időzítő struktúrát használni, és a TIM_TimeBaseInit() függvényt minden alkalommal meghívni, amikor a periódus változik. Helyesebb, ha csak egy értéket módosítunk egy regiszterben, mégpedig a TIMx->ARR regiszterben (ahol x az időzítő száma). Ebben a példában a kód a következőképpen alakul:

/*******************************************************************/ void TIM4_IRQHandler() ( //Ha a kimenet 0 volt... if (previousState == 0 ) ( //Állítson be egyet a kimeneten előző Állapot = 1 ; GPIO_SetBits(GPIOB, GPIO_Pin_0) ; //A periódus 50 időzítő, azaz 0,5 ms TIM4->ARR = 50 ; ) más ( //Állítson be nullát a kimeneten előző Állapot = 0 ; GPIO_ResetBits(GPIOB, GPIO_Pin_0) ; //És az időszak most 250 tick lesz – 2,5 ms TIM4->ARR = 250 ; ) TIM_ClearITPendingBit(TIM4, TIM_IT_Update) ; ) /********************************Fájl vége******************** **********/

Szóval, folytassuk, van még egy rake útban) Mégpedig a hiba:

..\..\..\SPL\src\stm32f10x_tim.c(2870): hiba: #20: a „TIM_CCER_CC4NP” azonosító nem definiált

Nem olyan ijesztő, mint amilyennek tűnhet, nyissa meg az stm32f10x.h fájlt, keresse meg a sorokat

Most minden össze van szerelve, lehet hibakeresni. Kapcsolja be a logikai elemzőt. A parancssorba ezt írjuk: la portb&0x01és nézd meg a kimenetet:

Megkaptuk, amit akartunk) Más szóval, minden megfelelően működik. A következő cikkben a PWM generálási módba ásunk bele, maradj kapcsolatban 😉

Ne hagyjon ki egy jó cikket az időzítőkről általában -.

A rögzítési mód az időzítő egy speciális üzemmódja, melynek lényege a következő: amikor a mikrokontroller egy bizonyos tűjénél a logikai szint megváltozik, a számláló regiszter értéke egy másik regiszterbe kerül, amit rögzítési regiszternek nevezünk. .

Mire jó ez?
Ezzel az üzemmóddal megmérheti az impulzus időtartamát vagy a jel időtartamát.

Az STM32 rögzítési mód néhány funkcióval rendelkezik:

  • kiválaszthatja, hogy melyik front legyen aktív
  • a bemeneti jel frekvenciájának megváltoztatása előskálázó segítségével (1,2,4,8)
  • Minden rögzítési csatorna beépített bemeneti szűrővel van felszerelve
  • a rögzítési jel forrása egy másik időzítő is lehet
  • Minden csatornához két jelző tartozik, az első akkor van beállítva, ha rögzítés történt, a második, ha rögzítés történt, miközben az első jelző be van állítva.

A regiszterek a rögzítési mód konfigurálására szolgálnak CCMR1(1. és 2. csatornához) és CCMR2(3. és 4.-hez), valamint regisztereket CCER, DIER.

Nézzük meg közelebbről a regiszter bitmezőit CCMR2, amely az időzítő 4. csatornájának beállításáért felelős, ezt fogjuk beállítani a példában. Azt is szeretném megjegyezni, hogy ugyanaz a regiszter bitmezőket tartalmaz, amelyeket az időzítő összehasonlító módban történő beállításakor használunk.

CC4S- meghatározza a negyedik csatorna működési irányát (bemenet vagy kimenet). Ha bemenetként beállít egy csatornát, a rendszer egy rögzítési jelet rendel hozzá

  • 00 - csatorna kimenetként működik
  • 01 - csatorna bemenetként működik, rögzítő jel - TI4
  • 10 - csatorna bemenetként működik, rögzítő jel - TI3
  • 11 - csatorna bemenetként működik, rögzítő jel - TRC
IC4PSC– határozza meg a rögzítési jel osztási együtthatóját
  • 00 - az osztó nincs használatban, az IC1PS rögzítési jel minden eseményhez generálódik
  • 01 - minden második eseményhez rögzítési jel generálódik
  • 10 - minden negyedik eseményhez rögzítési jel generálódik
  • 11 - minden nyolcadik eseményhez rögzítési jel generálódik
IC4F- a bemeneti szűrő beállítására szolgál, amellett, hogy hány minta alatt nem reagál a mikrokontroller a bemeneti jelekre, beállítható a mintavételi frekvencia is. Lényegében az él megérkezésének pillanatától a „megerősítő” mintáig állítjuk be a késleltetési időt.

Most pedig nézzük a regisztert CCER.

CC4E- be-/kikapcsolja a rögzítési módot.
CC4P- meghatározza azt az elejét, amely mentén a rögzítést végrehajtják, 0 - elöl, 1 - hátul.

És regisztrálj DIER.

CC4DE- lehetővé teszi kérés generálását a DMA felé.
CC4IE- lehetővé teszi a rögzítés megszakítását.

A rögzítés megtörténte után egy rögzítési esemény jön létre, amely beállítja a megfelelő jelzőt. Ez megszakítást és kérést eredményezhet DMA, ha engedélyezve vannak a nyilvántartásban DIER. Ezenkívül egy rögzítési esemény programozottan generálható az eseménygeneráló regiszterben egy bitmező beállításával EGR:

Bit mezők CC1G, CC2G, CC3G és CC4G lehetővé teszi, hogy eseményt generáljon a megfelelő rögzítési/összehasonlítási csatornában.

Apropó, CCR1, CCR2, CCR3 és CCR4- rögzítési regiszterek, amelyekben a rögzítési jel alapján az időzítő értéket tárolják.

A rögzítési jel generálásának szabályozása érdekében a regiszterben S.R. Minden csatornához két zászló van hozzárendelve.

CC4IF- beállítva a rögzítési jel generálásakor, ezeket a jelzőket szoftverrel vagy a megfelelő rögzítési/összehasonlítási regiszter kiolvasásával alaphelyzetbe állítjuk.
CC4OF- állítsa be, ha a CC4IF jelző nem törlődött, de újabb rögzítési jel érkezett. Ez a jelző programozottan nulla beírásával törlődik.

Most ültessük át ezt a tudást a jelgenerátorból a jelgenerátorból egy 50 Hz frekvenciájú szinuszoidot vezetünk a TIM5_CH4 bemenetére, és megpróbáljuk megmérni a periódusát. A folyamat felgyorsítása érdekében a DMA használatát javaslom. Hogy melyik MK tű felel meg a 4-es TIM5 csatornának, az megtalálható az MK adatlapján a részben. Pinouts és pin leírás.

Mert DMA regisztrációs cím szükséges CCR4, itt találja meg. Nyítás RM0008és a táblázatban Regisztrálja a határcímeket keresse meg a TIM5 kezdőcímét.


beszámítás a nyilvántartásba CCR4 részben ugyanabban a dokumentumban találhatók regisztrálni térképet.

#include "stm32f10x.h" #define TIM5_CCR4_Address ((u32)0x40000C00+0x40) #define DMA_BUFF_SIZE 2 uint16_t buff;//Puffer uint16_t volatile T; void DMA2_Channel1_IRQHandler (void) ( T = (buff > buff) ? (buff - buff) : (65535+ buff - buff); DMA2->IFCR |= DMA_IFCR_CGIF1; ) void Init_DMA(void) ( RCC->RCCD_MANRBENR_RCCD_MANR2 | ; //Az első DMA modul órajelének engedélyezése a tömb alapcíme a RAM-ban DMA2_Channel1 ->CCR &= ~DMA_CCR1_DIR //Jelölje meg az adatátvitel irányát a perifériáról a memóriába DMA2_Channel1->CNDTR = DMA_BUFF_SIZE //Az átvitt értékek számaDMA2_Channel1->; CCR &= ~DMA_CCR1_PINC //A periféria címe nem növekszik minden átvitel után DMA2_Channel1 -> CCR = DMCR1_MINC //Prioritás - nagyon magas DMA2_Channel1->CCR |= DMA_CCR1_CIRC; //DMA működés engedélyezése ciklikus módban DMA2_Channel1->CCR |= DMA_CCR1_TCIE;//Megszakítás engedélyezése az átvitel végén DMA2_Channel1->CCR |= DMA_CCR1_EN; //Az 1. DMA csatorna működésének engedélyezése) int main(void) ( Init_DMA(); //az A port órajelének engedélyezése, az alternatív funkciók és az időzítő RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR_TIAPM5 |=ENR ; TIM5 ->PSC = 56000-1;//új frekvencia 1Khz TIM5->CCMR2 |= TIM_CCMR2_CC4S_0;//Válassza ki a TI4-et a TIM5_CH4-hez TIM5->CCMR2 &= ~(TIM_CCMR2_IC4F | TIM_CCMR2_/IC4 ne tegyen szűrőt) használj elválasztót TIM5- >CCER &= ~TIM_CCER_CC4P;//rögzítés kiválasztása a vezető élen TIM5->CCER |= TIM_CCER_CC4E;//a rögzítési mód bekapcsolása a 4. csatornához TIM5->DIER |= TIM_DIER_CC4DE;//engedélyezés kérés létrehozása a DMA-hoz //TIM5 ->DIER |= TIM_DIER_CC4IE // TIM5->CR1 rögzítési megszakítás engedélyezése //számláló engedélyezése //NVIC->ISER |= NVIC_ISER_SETENA_18; >ISER |= NVIC_ISER_SETENA_24 Megszakítás while(1) ( ) )



Tetszett a cikk? Oszd meg