STM32: cronometre de bază. STM32F3

De fapt, prin urmare, să trecem imediat la programare. Luați oricare dintre cronometrele de bază ale microcontrolerului STM32F3, îi vom face setarea minimă și vom încerca să generăm întreruperi la intervale regulate. Cel mai simplu exemplu 😉

Deci de la Biblioteca periferică standard avem nevoie de câteva fișiere care implementează interacțiunea cu registrele cronometrului:

#include „stm32f30x_gpio.h” #include „stm32f30x_rcc.h” #include „stm32f30x_tim.h” #include „stm32f30x.h” /*******************************************************************/ temporizator TIM_TimeBaseInitTypeDef; /*******************************************************************/

Inițializarea minimă a temporizatorului arată astfel. Apropo, în același timp, vom seta unul dintre picioarele controlerului să funcționeze în modul de ieșire. Este necesar doar să clipești LED-ul 😉

/*******************************************************************/ void initAll() ( // Clocking - unde fără ea RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE) ; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE) ; // Avem un LED albastru pe acest pin (STM32F3Discovery) gpio.GPIO_Mode = GPIO_Mode_OUT; gpio.GPIO_Pin = GPIO_Pin_8; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_Speed ​​​​= GPIO_Speed_50MHz; GPIO_Init(GPIOE, & gpio) ; // Și iată setarea mult așteptată a temporizatorului TIM2 TIM_TimeBaseStructInit(&timer) ; timer.TIM_Prescaler = 7200 ; timer.TIM_Period = 20000 ; TIM_TimeBaseInit(TIM2, & timer) ; /*******************************************************************/

Aici merită să fiți atenți la două numere care vin de nicăieri - 7200 Și 20000 . Acum să ne dăm seama ce este 😉 Cronometrul meu este tactat cu o frecvență 72 MHz. Prescaler, cunoscut și ca prescaler, este necesar pentru a împărți această frecvență) Astfel, obținem 72 MHz / 7200 = 10 kHz. Deci o bifare a cronometrului îi corespunde (1/10000) secunde, care este egal 100 microsecunde. Perioada temporizatorului este valoarea, după numărare până la care programul va zbura către gestionarea întreruperilor la depășirea temporizatorului. În cazul nostru, cronometrul trece până la 20000 , care corespunde (100 * 20000) µs sau 2 secunde. Adică LED-ul (pe care îl aprindem și îl stingem în gestionarea întreruperilor) va clipi cu un punct 4 secunde (2 secunde pornit, 2 secunde nu arde =)). Acum, cu asta totul este clar, continuăm...

În funcțiune principal() numim funcția de inițializare și, de asemenea, activăm întreruperi și un cronometru. Într-un ciclu în timp ce (1) cu atât mai puțin cod - este pur și simplu gol 😉

/*******************************************************************/ int main() ( __enable_irq() ; initAll() ; TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE) ; TIM_Cmd(TIM2, ENABLE) ; NVIC_EnableIRQ(TIM2_IRQn) ; while (1 ) ( ) ) /*******************************************************************/

Totul, rămâne să scrieți câteva rânduri pentru manipulatorul de întreruperi și treaba este gata:

/*******************************************************************/ void TIM2_IRQHandler() ( TIM_ClearITPendingBit(TIM2, TIM_IT_Update) ; dacă (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_8) == 1 ) ( GPIO_ResetBits(GPIOE, GPIO_IT_Update); /*******************************************************************/

După ce a introdus programul în controler, observăm un LED albastru intermitent, prin urmare programul funcționează corect! În principiu, asta este totul pentru astăzi, s-a dovedit un articol atât de scurt)

Ne-am uitat deja la temporizatorul SysTick, care face parte din nucleul Cortex. Totuși, nu se termină aici. Există multe cronometre în stm32 și sunt diferite. În funcție de obiectiv, va trebui să alegeți unul sau altul cronometru:

  • SysTick;
  • temporizatoare de uz general - TIM2, TIM3, TIM4, TIM15, TIM16, TIM17;
  • advanced timer (cronometru avansat în engleză) - TIM1;
  • cronometru de supraveghere.

Singurul lucru care merită menționat despre acesta din urmă este că este conceput pentru a controla înghețarea sistemului și este un cronometru care trebuie resetat periodic. Dacă cronometrul nu este resetat într-un anumit interval de timp, temporizatorul watchdog va reseta sistemul (microcontroler).

Temporizatoarele vin în diferite dimensiuni de biți: de exemplu, SysTick este pe 24 de biți și toate temporizatoarele pe care le avem în piatră sunt pe 16 biți (adică pot număra până la 2 16 = 65535), cu excepția WatchDog. În plus, fiecare cronometru are un anumit număr de canale, adică de fapt poate funcționa pentru două, trei, etc. Aceste cronometre pot funcționa cu encodere incrementale, senzori Hall, pot genera PWM (modulație pe lățime a impulsului, ing. Pulse Width Modulation - despre care vom vorbi mai târziu) și multe altele. În plus, pot genera întreruperi sau pot face o cerere către alte module (de exemplu, către DMA - Direct Memory Access) la diferite evenimente:

  • overflow (în engleză overflow);
  • captare semnal (ing. captare intrare);
  • comparație (compararea rezultatelor în engleză);
  • event-trigger (declanșare eveniment în engleză).

Dacă totul ne este clar odată cu depășirea temporizatorului (mai precis, ajungând la „0”) - am considerat SysTick - atunci nu suntem încă familiarizați cu alte moduri posibile de funcționare. Să le privim mai detaliat.

Captarea semnalului

Acest mod este potrivit pentru a măsura perioada impulsurilor (sau numărul acestora, de exemplu, pe secundă). Când un impuls ajunge la ieșirea MK, temporizatorul generează o întrerupere din care putem elimina valoarea curentă a contorului (din registrul TIM_CCRx, unde x este numărul canalului) și o putem salva într-o variabilă externă. Apoi va veni următorul puls, iar printr-o simplă scădere vom obține „timpul” dintre cele două impulsuri. Puteți prinde atât marginile inițiale, cât și cele de jos ale pulsului, sau chiar ambele simultan. De ce este nevoie de asta? Să presupunem că aveți un magnet pe care l-ați lipit de un disc pe o roată și un senzor cu efect Hall de o furcă de bicicletă. Apoi, pe măsură ce învârti roata, vei primi un impuls de fiecare dată când magnetul de pe roată se află în același plan cu senzorul Hall. Cunoscând distanța pe care o parcurge magnetul pe rotație și timpul, puteți calcula viteza de mișcare.

Există, de asemenea, un mod de captură PWM, dar acesta este mai mult o modalitate specială de a seta temporizatorul decât un mod separat de operare: un canal prinde marginile în creștere, iar al doilea prinde marginile în scădere. Apoi, primul canal detectează perioada, iar al doilea - umplerea.

Modul comparare

În acest mod, canalul de cronometru selectat este conectat la pinul corespunzător și, de îndată ce temporizatorul atinge o anumită valoare, starea de ieșire se va schimba în funcție de setarea modului (poate fi „1” sau „0”, sau starea de ieșire este pur și simplu inversată).

Modul de generare PWM

După cum sugerează și numele, temporizatorul în acest mod generează modulație pe lățimea impulsului. Vom vorbi mai multe despre acest mod, precum și despre unde poate/ar trebui să fie folosit, în următoarea lecție după ce ne gândim la captarea semnalului.

Cu ajutorul unui cronometru avansat, puteți forma un PWM trifazat, care este foarte util pentru controlul unui motor trifazat.

Modul timp mort

Unele cronometre au această caracteristică; este necesar să se creeze întârzieri la ieșiri, care sunt necesare, de exemplu, pentru a exclude curenții prin intermediul controlului întrerupătoarelor de alimentare.

În curs, vom folosi doar „captură semnal” și „generare pwm”.

Modul de captare este un mod special de funcționare al temporizatorului, a cărui esență este următoarea, când nivelul logic se schimbă la o anumită ieșire a microcontrolerului, valoarea registrului de numărare este scrisă într-un alt registru, care se numește registru de captare.

Pentru ce este?
Folosind acest mod, puteți măsura durata pulsului sau perioada semnalului.

Modul de captură STM32 are câteva caracteristici:

  • capacitatea de a alege ce front va fi activ
  • capacitatea de a schimba frecvența semnalului de intrare folosind un prescaler (1,2,4,8)
  • fiecare canal de captură are încorporat un filtru de intrare
  • sursa semnalului de captare poate fi un alt temporizator
  • sunt prevăzute două steaguri pentru fiecare canal, primul este setat dacă a avut loc o captură, al doilea dacă s-a produs o captură cu primul steag setat

Registrele sunt folosite pentru a seta modul de captură. CCMR1(pentru 1 și 2 canale) și CCMR2(pentru 3 și 4), precum și registre CCER, DIER.

Să aruncăm o privire mai atentă la câmpurile de biți de registru CCMR2, care sunt responsabile pentru setarea celor 4 canale de cronometru, îl vom configura în exemplu. De asemenea, aș dori să remarc faptul că în același registru există câmpuri de biți care sunt folosite la setarea temporizatorului în modul de comparație.

CC4S- determină direcția celui de-al patrulea canal (intrare sau ieșire). Când configurați un canal ca intrare, mapează un semnal de captură către acesta

  • 00 - canalul funcționează ca ieșire
  • 01 - canalul funcționează ca intrare, semnal de captare - TI4
  • 10 - canalul funcționează ca intrare, semnal de captare - TI3
  • 11 - canalul funcționează ca intrare, semnal de captare - TRC
IC4PSC– determinați factorul de divizare, pentru semnalul de captare
  • 00 - divizorul nu este utilizat, semnalul de captare IC1PS este generat pentru fiecare eveniment
  • 01 - semnalul de captare este generat pentru fiecare al doilea eveniment
  • 10 - un semnal de captare este generat pentru fiecare al patrulea eveniment
  • 11 - un semnal de captare este generat pentru fiecare al optulea eveniment
IC4F- conceput pentru a regla filtrul de intrare, pe lângă numărul de mostre în timpul căruia microcontrolerul nu va răspunde la semnalele de intrare, puteți regla și rata de eșantionare. În esență, ajustăm timpul de întârziere din momentul în care marginea ajunge la eșantionul de „confirmare”.

Acum să ne uităm la registru CCER.

CC4E- activează/dezactivează modul de captură.
CC4P- determina fata de-a lungul caruia se va face captura, 0 - fata, 1 - spate.

Și înregistrează-te DIER.

CC4DE- permite formarea unei cereri către DMA.
CC4IE- Activează o întrerupere a capturii.

După ce a avut loc o captură, este generat un eveniment de captură care setează indicatorul corespunzător. Acest lucru poate determina generarea unei întreruperi și a unei cereri DMA dacă sunt permise în registru DIER. În plus, un eveniment de captură poate fi generat programatic prin setarea câmpului de biți în registrul de generare a evenimentelor EGR:

Câmpuri de biți CC1G, CC2G, CC3G și CC4G vă permit să generați un eveniment în canalul de captură/comparare corespunzător.

Apropo, CCR1, CCR2, CCR3 și CCR4- registre de captare, care stochează valoarea temporizatorului pe semnalul de captare.

Pentru a controla formarea semnalului de captare, in registru SR Fiecare canal are două steaguri.

CC4IF- setat atunci când este generat un semnal de captură, aceste steaguri sunt resetate prin software sau prin citirea registrului de captură/comparare corespunzător.
CC4OF- setați dacă steagul CC4IF nu a fost șters, dar a sosit un alt semnal de captură. Acest steag este șters programatic prin scrierea zero.

Acum sa aplicam cunostintele acumulate in practica, de la generatorul de semnal la intrarea TIM5_CH4 vom aplica o sinusoida cu frecventa de 50 Hz si vom incerca sa masuram perioada acesteia. Pentru a accelera procesul, vă sugerez să utilizați DMA. Ce ieșire a MK corespunde celui de-al 4-lea canal al TIM5 poate fi găsită în fișa tehnică a MK în secțiunea Pinouts și descriere pin.

Pentru DMA este necesară adresa de înregistrare CCR4, iată cum să-l găsești. Deschidem RM0008 iar în tabel Înregistrați adresele de limită găsiți adresa de pornire a lui TIM5.


înregistrează offset CCR4 pot fi găsite în același document sub inregistreaza harta.

#include "stm32f10x.h" #define TIM5_CCR4_Address ((u32)0x40000C00+0x40) #define DMA_BUFF_SIZE 2 uint16_t buff;//Buffer 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->AHBENR |= RCCMA_AHBENR | ; //Activați tactarea primului modul DMA DMA2_Channel1->CPAR = TIM5_CCR4_Address; //Specificați adresa periferică - registrul rezultat al conversiei ADC pentru canalele obișnuite DMA2_Channel1->CMAR = (uint32_t)buff; //Setați adresa de memorie - adresa de bază a matricei din RAM DMA2_Channel1 ->CCR &= ~DMA_CCR1_DIR; //Specificați direcția transferului de date, de la periferie în memorie DMA2_Channel1->CNDTR = DMA_BUFF_SIZE; //Numărul de valori transferate & ​​DMA2_Channel1->CCR = ~DMA_CCR1_PINC; //Nu incrementați adresa periferică după fiecare transfer DMA2_Channel1 ->CCR |= DMA_CCR1_MINC; //Măriți adresa de memorie după fiecare transfer DMA2_Channel1->CCR |= DMA_CCR1_PSIZE_0; //Dimensiunea datelor periferice --> 16 canale DMA2_6 CCR |= DMA_CCR1_MSIZE_0; //Dimensiunea datelor de memorie - 16 biți DMA2_Channel1->CCR |= DMA_CCR1_PL; //Prioritatea este foarte mare DMA2_Channel1->CCR |= DMA_CCR1_CIRC; //Activare DMA în modul ciclic DMA2_Channel1->CCR |= DMA_CCR1_TCIE;//Activare întrerupere la sfârșitul transferului DMA2_Channel1->CCR |= DMA_CCR1_EN; // Activați primul canal DMA ) int main(void) ( Init_DMA(); // activați sincronizarea portului A, funcții alternative și temporizator RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_TIAPB -1; >PSC = 56000-1;//frecvență nouă 1Khz TIM5->CCMR2 |= TIM_CCMR2_CC4S_0;//alegeți TI4 pentru TIM5_CH4 TIM5->CCMR2 &= ~(TIM_CCMR2_IC4F | TIM_CCMR2_IC4PSC);// nu filtrul divizor);// utilizați TIM5- >CCER &= ~TIM_CCER_CC4P;//selectați captura pe marginea ascendentă TIM5->CCER |= TIM_CCER_CC4E;//activați modul de captură pentru al 4-lea canal TIM5->DIER |= TIM_DIER_CC4DE;//permiteți formarea unei cereri la DMA //TIM5 ->DIER |= TIM_DIER_CC4IE; //activează întreruperea capturii TIM5->CR1 |= TIM_CR1_CEN; //activează contorul //NVIC->ISER |= NVIC_ISER_SETENA_18; //TIM5 Întrerupe NVIC->ISER |= NVIC_24ISER | ; //DMA Întreruperea în timp ce(1) ( ) )

STM32 are multe cronometre foarte convenabile și flexibile de configurat. Chiar și cel mai tânăr microcontroler (STM32F030F4P6) are 4 astfel de temporizatoare.

8. Configurați proiectul - adăugați fișierele necesare

Pentru a folosi temporizatorul, trebuie să includem fișierul bibliotecă periferică stm32f10x_tim.c. În același mod, faceți clic dreapta în Workspace (fereastra din stânga) pe grupul StdPeriphLib, Add –> Add files, fișierul LibrariesSTM32F10x_StdPeriph_Driversrcstm32f10x_tim.c.

De asemenea, trebuie să activați utilizarea antetului pentru acest fișier. Deschideți stm32f10x_conf.h (dați clic dreapta pe numele acestui fișier din cod, „Deschideți stm32f10x_conf.h”. Decomentați linia #include „stm32f10x_tim.h”.

9. Adăugați un cronometru

Întârzierea cu un ciclu gol este un sacrilegiu, mai ales pe un cristal atât de puternic precum STM32, cu o grămadă de temporizatoare. Prin urmare, vom face această întârziere folosind un cronometru.

STM32 are cronometre diferite care diferă în setul de proprietăți. Cele mai simple sunt cronometrele de bază, cele mai dificile sunt cronometrele de uz general, iar cele mai dificile sunt cronometrele avansate. Temporizatoarele simple sunt limitate doar la numărarea ciclurilor. În temporizatoarele mai complexe, apare PWM. Cele mai sofisticate cronometre, de exemplu, pot genera PWM trifazat cu ieșiri înainte și inversă și timp mort. Un simplu cronometru, numărul 6, ne este suficient.

Un pic de teorie

Tot ce ne trebuie de la temporizator este să numărăm până la o anumită valoare și să generăm o întrerupere (da, vom învăța și cum să folosim întreruperile). Temporizatorul TIM6 este tactat din magistrala de sistem, dar nu direct, ci printr-un prescaler - un simplu contra-divizor programabil (doar gândiți-vă, microcircuite-contoare speciale au fost produse în URSS, iar cele programabile au fost un deficit special - și acum am vorbesc despre un astfel de contor doar întâmplător). Prescaler-ul poate fi setat la orice valoare de la 1 (adică, frecvența completă a magistralei, 24 MHz, va atinge contorul) la 65536 (adică, 366 Hz).

Semnalele ceasului, la rândul lor, măresc contorul cronometrului intern, începând de la zero. De îndată ce valoarea contorului atinge valoarea ARR, contorul depășește și are loc evenimentul corespunzător. La apariția acestui eveniment, cronometrul încarcă din nou 0 în contor și începe să numere de la zero. În același timp, poate declanșa o întrerupere (dacă este configurată).

De fapt, procesul este puțin mai complicat: există două registre ARR - externe și interne. În timpul calculului, valoarea curentă este comparată exact cu registrul intern, iar numai la depășire se actualizează cel intern față de cel extern. Astfel, este sigur să schimbați ARR în timp ce cronometrul funcționează - în orice moment.

Codul

Codul va fi foarte asemănător cu cel precedent, deoarece. inițializarea tuturor perifericelor are loc în același mod - cu singura excepție că temporizatorul TIM6 se blochează pe magistrala APB1. Prin urmare, activarea temporizatorului: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

Acum creăm o structură de tip TIM_TimeBaseInitTypeDef, o inițializam (TIM_TimeBaseStructInit), o setăm, o trecem la funcția de inițializare a temporizatorului (TIM_TimeBaseInit) și în final activăm cronometrul (TIM_Cmd).

TIM_TimeBaseInitTypeDef TIM_InitStructure; // Configurați structura TIM_TimeBaseStructInit(&TIM_InitStructure); // Inițializarea structurii TIM_InitStructure.TIM_Prescaler = 24000; // Prescaler TIM_InitStructure.TIM_Period = 1000; // Perioada de cronometru TIM_TimeBaseInit(TIM6, &TIM_InitStructure); // Funcția de setare a temporizatorului TIM_Cmd(TIM6, ENABLE); // Porniți cronometrul

Care sunt numerele magice? După cum ne amintim, există o frecvență de ceas de 24 MHz pe magistrală (cu setările proiectului nostru). Setând prescalerul cronometrului la 24000, împărțim această frecvență la 24 de mii și obținem 1 kHz. Această frecvență va merge la intrarea contorului cronometrului.

Valoarea din contor este 1000. Aceasta înseamnă că contorul se va depăși în 1000 de cicluri, adică. exact 1 secundă.

După aceea, avem cu adevărat un cronometru care funcționează. Dar asta nu este tot.

10. Faceți față întreruperilor

Bine, întreruperi. Pentru mine, odată (în zilele PIC) au fost o pădure întunecată și am încercat să nu le folosesc deloc - și nu știam cum, de fapt. Cu toate acestea, ele conțin o putere care este în general nedemn de ignorat. Adevărat, întreruperile în STM32 sunt un lucru și mai complicat, în special mecanismul de preempțiune; dar mai multe despre asta mai târziu.

După cum am observat mai devreme, temporizatorul generează o întrerupere în momentul în care contorul depășește - dacă procesarea întreruperii acestui dispozitiv este activată, această întrerupere particulară este activată și cea anterioară este resetată. Analizând această frază, înțelegem de ce avem nevoie:

  1. Activați deloc întreruperile temporizatorului TIM6;
  2. Activați întreruperea temporizatorului TIM6 pentru depășirea contorului;
  3. Scrieți o procedură de gestionare a întreruperilor;
  4. După procesarea întreruperii, resetați-o.

Activați întreruperile

Sincer să fiu, nu este nimic complicat. În primul rând, activați întreruperile TIM6: NVIC_EnableIRQ(TIM6_DAC_IRQn); De ce un astfel de nume? Pentru că în nucleul STM32, întreruperile de la TIM6 și de la DAC au același număr. Nu știu de ce s-a făcut așa - economii, lipsă de numere, sau doar un fel de chestie moștenită - în orice caz, asta nu va aduce probleme, deoarece acest proiect nu folosește un DAC. Chiar dacă în proiectul nostru a fost folosit un DAC, am putea afla cine l-a numit în mod special atunci când a intrat în întrerupere. Aproape toate celelalte temporizatoare au o singură întrerupere.

Configurarea evenimentului sursă de întrerupere: TIM_ITConfig(TIM6, TIM_DIER_UIE, ENABLE); - porniți întreruperea temporizatorului TIM6 la evenimentul TIM_DIER_UIE, adică. Eveniment de actualizare a valorii ARR. După cum ne amintim din imagine, acest lucru se întâmplă în același timp în care contorul se revarsă - deci acesta este exact evenimentul de care avem nevoie.

În acest moment, codul cazurilor de cronometru este următorul:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_TimeBaseStructInit(&TIM_InitStructure); TIM_InitStructure.TIM_Prescaler = 24000; TIM_InitStructure.TIM_Period = 1000; TIM_TimeBaseInit(TIM6, &TIM_InitStructure); TIM_Cmd(TIM6, ENABLE); NVIC_EnableIRQ(TIM6_DAC_IRQn); TIM_ITConfig(TIM6, TIM_DIER_UIE, ENABLE);

Manevrarea întreruperii

Acum nu puteți începe proiectul - prima întrerupere a temporizatorului nu își va găsi handlerul, iar controlerul se va bloca (mai precis, va cădea în handler-ul HARD_FAULT, care este în esență același lucru). Trebuie să-l scrii.

Un pic de teorie

Trebuie să aibă un nume foarte specific, void TIM6_DAC_IRQHandler(void). Acest nume, așa-numitul vector de întrerupere, este descris în fișierul de pornire (în proiectul nostru este startup_stm32f10x_md_vl.s - puteți vedea singur, linia 126). De fapt, vectorul este adresa operatorului de întrerupere, iar atunci când are loc o întrerupere, nucleul ARM se accesează cu crawlere în zona inițială (în care este tradus fișierul de pornire - adică locația sa este setată complet rigid, chiar la începutul memorie flash), caută vectorul acolo și merge la locul potrivit în cod.

Verificare eveniment

Primul lucru pe care trebuie să-l facem când intrăm într-un astfel de handler este să verificăm ce eveniment a cauzat întreruperea. Acum avem un singur eveniment, dar într-un proiect real pot exista mai multe evenimente pe un singur cronometru. Prin urmare, verificăm evenimentul și executăm codul corespunzător.

În programul nostru, această verificare va arăta astfel: dacă (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) - totul este clar, funcția TIM_GetITStatus verifică dacă cronometrul are evenimentul specificat și returnează 0 sau 1.

Ștergerea steagului UIF

Al doilea pas este să ștergeți semnalizarea de întrerupere. Înapoi la imagine: ultimul grafic UIF este indicatorul de întrerupere. Dacă nu este șters, următoarea întrerupere nu va putea fi apelată, iar controlerul va cădea din nou în HARD_FAULT (ce este!).

Efectuarea acțiunilor într-o întrerupere

Vom comuta pur și simplu starea LED-ului, ca în primul program. Diferența este că acum programul nostru o face mai dificilă! De fapt, este mult mai corect să scrii astfel.

Dacă (starea) GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET); else GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET); stare = 1 - stare;

Folosim variabila globala int state=0;

11. Toate codurile de proiect cu un cronometru

#include "stm32f10x_conf.h" int state=0; void TIM6_DAC_IRQHandler(void) ( dacă (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) ( TIM_ClearITPendingBit(TIM6, TIM_IT_Update); dacă (starea) GPIO_WriteBit(GPIOC, TIM_IT_Update) ; = 1 - stare;)) void main () (RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_StructInit (& GPIO_InitStructure); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_Init (GPIOC, & GPIO_InitStructure); GPIO_WriteBit (GPIOC, GPIO_Pin_8, Bit_SET); RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_TimeBaseStructInit (& TIM_InitStructure); TIM_InitStructure.TIM_Prescaler = 24000; TIM_InitStructure.TIM_Period = 1000; TIM_TimeBaseInit (TIM6, & TIM_InitStructure); TIM_Cmd (TIM6, ENABLE); NVIC_EnableIRQ(TIM6_DAC_IRQn); TIM_ITConfig(TIM6, TIM_DIER_UIE, ENABLE); while(1) ( ) )

Arhivați cu proiectul de cronometru.

Ei bine, apropo, cronometrul poate comuta piciorul în sine, fără întreruperi și procesare manuală. Acesta va fi al treilea proiect al nostru.

Întregul ciclu:

1. Porturi I/O

2. Timer și întreruperi

3. Ieșiri timer

4. Întreruperi externe și NVIC

5. Instalați FreeRTOS

Vizualizări postare: 235