Kysymys:
Ensimmäinen STM32-koodini - kritisoi minua
Ekci
2015-03-05 19:35:01 UTC
view on stackexchange narkive permalink

Kirjoitin juuri ensimmäisen koodini STM32: lle - vilkkuva LED. Se yhdistää fragmentteja eri lähteistä; arvostele minua, jotta voin oppia kirjoittamaan oikean koodin enkä opi typeriä tapoja.

  #include "stm32f30x.h" void SysTick_Handler (void); void TimingDelay_Decrement (void); void Viive (__ IO uint32_t nTime); staattinen __IO uint32_t TimingDelay; int main (mitätöity) {RCC->AHBENR | = ((1UL << 21)); // Ota GPIOE-kello käyttöön ?? GPIOE->MODER | = (1 << 2 * 8); // PIN 9 lähdönä // GPIOE->BSRR = 1 << 9; // LED palaa // GPIOE->BSRR = 1 << 9 << 16; // LED ei pala // GPIOE->BRR = 1 << 9; // LED OFF, jos (SysTick_Config (SystemCoreClock / 1000)) {/ * Sieppausvirhe * / while (1); } kun taas (1) {GPIOE->BSRR = 1 << 8; Viive (50); GPIOE->BRR = 1 << 8; Viive (50); }} void SysTick_Handler (void) {TimingDelay_Decrement ();} void Delay (__ IO uint32_t nTime) {TimingDelay = nTime; while (TimingDelay! = 0);} void TimingDelay_Decrement (void) {if (TimingDelay! = 0x00) {TimingDelay--; }}  

Miksi minun on otettava GPIOE-kello käyttöön? Ja mitä eroa on 1UL << 21 ja 1 << 21 välillä?

Tämä wikiartikkeli on yleisesti hyödyllinen: http://fi.wikipedia.org/wiki/Best_coding_practices
Siellä on erillinen [StackExchange-sivusto koodin tarkistusta varten] (http://codereview.stackexchange.com/), mutta he yleensä haluavat tarkempia kysymyksiä kuin "kritiikki minun koodi, kiitos".
@Dave Uskon, että tämä on parempi paikka tarkistaa koodi, joka on kirjoitettu erityisesti mikro-ohjainta varten.
@m.Alin: Minun (mahdollisesti liian hienovarainen) huomautukseni oli, että Mekin tarvitsemme tarkemmin kohdennettuja kysymyksiä.Lopullinen kysymys GPIOE-kellosta on ainoa asia, joka tuo koko aiheen.
@Dave Joo, olit hieman liian hienovarainen.Henkilökohtaisesti haluan nähdä koodin tarkistuskysymyksiä täällä, kun OP osoittaa, että hän on ponnistellut koodin kirjoittamisessa.
_ "Ole hyvä ja kritisoi minua" _ Koodisi sisennys on epäjohdonmukainen.
Miksi et käytä tavallista oheiskirjastoa?Se parantaa huomattavasti luettavuutta ja vähentää virheiden mahdollisuutta, joita voi esiintyä suoran rekisterin käytön yhteydessä.
Neljä vastused:
Scott Seidman
2015-03-05 19:44:42 UTC
view on stackexchange narkive permalink

STM32-laitteissa kaikki oheislaitteet ovat oletusarvoisesti pois käytöstä, eivätkä ne saa kellosignaaleja. Tämä säästää joukon voimaa (ja pakottaa sinut ajattelemaan nastojen välistä vuorovaikutusta koodaamisen aikana). Jos haluat käyttää GPIOE: tä, sinun on kerrottava STM32: lle sen kellon ottaminen käyttöön.

1UL << 21 siirtää allekirjoittamaton pitkä -arvon 1 21 bittiä vasemmalle. 1 << 21 siirtää jotakin arvoa, jonka arvo on 1, mutta se on jokin oletustyyppi, joka voi olla tai ei välttämättä ole allekirjoittamaton pitkä , etkä välttämättä tiedä kuinka leveä järjestelmäsi on oletukset ovat. Se vaihtelee alustan ja kääntäjän mukaan. Itse asiassa UL voi vaihdella alustan ja kääntäjän mukaan. On parasta käyttää kirjastotyyppiä, jotka ovat varmoja asioita.

(uint32_t) 1 << 21 ja (uint64_t) 1 << 21 ovat yksiselitteisiä. .

tcrosley
2015-03-05 20:36:39 UTC
view on stackexchange narkive permalink

Kaiken kaikkiaan näyttää aika hyvältä. Voisi käyttää vielä joitain kommentteja.

Onko SysTick_Handler keskeytyskäsittelijä? Jos on, sano niin. Olen yllättynyt siitä, ettei ole mitään attribuutteja, jotka ilmoittavat tämän (useimmissa muissa prosessoreissa upotetuissa C: ssä on sana keskeytä jossain i käsittelijän nimen määritelmä). Oletan, että se on määritettävä #DEFINE järjestelmään .h-tiedostoon jonnekin. Harmi, että he piilottavat sen näin.

Kuinka usein SysTick_Handler soitetaan? Tiedän, että se on määritetty SysTick_Config-puhelussa, mutta et sano siitä mitään.

Mitkä ovat Viive-puhelun yksiköt? Millisekuntia? Sano niin.

Mitä taulun LEDiä muokkaat GPIOE-> BSRR = 1 << 8 kanssa?

Onko toiminto TimingDelay_Decrement todella tarpeen? Miksei vain laittaa koodinsa SysTick_Handleriin? Tavallisesti yritetään välttää tarpeettomia puheluita keskeytyskäsittelijässä. Ei ole merkitystä tässä, mutta voi joskus kriittisiä käsittelijöitä.

Utelias: jos olisin huolissani TimingDelay_Decrement -kutsusta, voinko tehdä siitä sisäisen toiminnon?Auttaako se?
Se on hieman erilainen, mutta näin Cortex-M -jutut asennetaan.SysTick_Handler on vakio keskeytyskäsittelijä Cortex-M -prosessoreille, joka asennetaan käynnistystiedostoon, joka linkitetään käännettäessä.On oletuskäsittelijää, jota käytetään, jos käyttäjä ei kirjoita omaa, mikä ohittaa defaut-käsittelijän.(Toivon, että sanoin kaiken oikein. Olen pääasiassa laitteistoinsinööri).Puhelu: SysTick_Config (SystemCoreClock / 1000) asettaa SysTick_Handlerin keskeyttämään jokaisen millisekunnin.Jos se olisi kirjoitettu SysTick_Config (SystemCoreClock / 100), se rastisi joka 10 ms.
... tavalliset Cortex-M -tuotteet, mutta olen samaa mieltä siitä, että kommentit auttavat.
@Tut Miksi SysTick_Config (SystemCoreClock / 1000) keskeyttäisi 1 ms: n välein?Mikä on `SystemCoreClock`-oletusarvo?
@m.Alin Hyvä kysymys, enkä ole edes varma, onko se määritelty yllä olevassa esimerkissä vai ei.STM32F4: ää käyttävissä järjestelmissäni on alustustiedosto system_stm32f4xx.c, joka asettaa järjestelmän kellot ja määrittelee globaalin muuttujan SystemCoreClock, joka asetetaan ydinkellonopeuteen (sovellukselleni 168000000 eli 168 MHz) vastaavaan arvoon.SysTick_Config-kutsu asettaa kellonjakajan määrittelemään rastihinnan.Jos soitit SysTick_Config (SystemCoreClock), se rastisi kerran sekunnissa.Minun on sanottava, että osa Cortex-M -tuotteista on asetettu hämmentävällä tavalla (mielestäni).
@Kynit kyllä, TimingDelay_Decrementin tekeminen olisi sama kuin koodin sisällyttäminen käsittelijään, kuten ehdotin.
Steve Melnikoff
2015-03-05 23:23:30 UTC
view on stackexchange narkive permalink

Luettavuuden vuoksi ja virheiden todennäköisyyden vähentämiseksi käytä makroja maagisten numeroiden sijaan.

stm32f30x.h sisältää makrot (toivottavasti) koko rekisterille arvot. Joten:

  RCC->AHBENR | = ((1UL << 21)); // Ota GPIOE-kello käyttöön GPIOE->MODER | = (1 << 2 * 8); // PIN 9 lähdönä  

voidaan kirjoittaa seuraavasti:

  RCC->AHBENR | = RCC_AHBENR_GPIOEEN; // Ota GPIOE-kello käyttöön. GPIOE->MODER | = GPIO_MODER_MODER8_0; // PIN 8 - ei 9! - tuotoksena.  

(Todellakin - alkuperäinen kommentti oli väärä tässä; makron käyttäminen tekee siitä selvemmän!)

Vastaavasti pin-vaihtokoodi voidaan kirjoittaa kuten:

  GPIOE->BSRR = GPIO_BSRR_BS_8; Viive (50); GPIOE->BRR = GPIO_BRR_BR_8; Viive (50);  

Menee pidemmälle, GPIO_MODER_MODER8_0 ei ole aivan selvää, joten minä saattaa lisätä oman makron:

  #define GPIO_MODER_MODER8_OUT GPIO_MODER_MODER8_0  

Se voi olla hieman väsyttävää, jos määrität paljon nastoja, joten voit tehdä:

  #define GPIO_MODER_OUT (pin) ((((uint32_t) 1) << (2 * (pin)))  

Lisäksi Yläpuolella olevalla rivillä oletetaan, että nämä MODER -bittien bitit olivat jo 0x0 tai 0x1. Jos emme voi olettaa sitä, meidän on ensin tyhjennettävä ne:

  GPIOE->MODER & = ~ GPIO_MODER_MODER8; GPIOE->MODER | = GPIO_MODER_OUT (8);  

Myös:

Jos tiedoston yläosassa ilmoitettuja toimintoja ei käytetä missään muualla, ilmoita ne staattisiksi . Tämä estää niitä käyttämästä vahingossa missään muussa tiedostossa.

Jos kääntäjä sallii, main tulisi ilmoittaa void -tekstinä, ei palauttaa int , koska se ei koskaan palaa.

Tämä on todellinen nitpick: TimingDelay on vain tavallinen numero; sitä ei käytetä, jos heksadesimaalinen esitys on sopiva. Joten kohdassa TimingDelay_Decrement , jossa sitä verrataan nollaan, käytä 0 , ei 0x00 . Tämä tekee siitä myös johdonmukaisen vertailun kanssa Delay.

Jos olen ymmärtänyt oikein, __IO merkitsee muuttujan volatile , ja epäilen, että sitä käytetään merkitsemään luettavia ja kirjoitettavia rekistereitä. TimingDelay : n on todellakin oltava volatile , koska se päivitetään keskeytyksessä - mutta olisin halukas käyttämään volatile -tunnusta sijaan __IO osoittaa, että se ei ole rekisteri.

nTime ei tarvitse olla haihtuva (tai __IO koodi>), koska se on vain normaali toimintoparametri, joka välitetään arvolla, joka luetaan kerran.

Christian Bongiorno
2015-03-06 06:04:46 UTC
view on stackexchange narkive permalink

Tämän pitäisi teknisesti kuulua koodin tarkistukseen.

Ainoa suositukseni on, että bittimuodostuksen / siirtämisen tulisi olla joko makroja tai toimintoja, jotka kuvaavat mitä tapahtuu. Kommentit ovat hyviä, mutta ne eivät toimi ja viime kädessä mitä kommentit sanovat, ei tarkoita mitään; se on koodi, joka laskee (ja ne eivät synkronoidu). Tee koodista BE kommentit toiminnallisella hajotuksella:

  RCC->AHBENR | = ((1UL << 21)); 

tulee

  enableGpioe () {RCC->AHBENR | = (1UL << 21); }  

ja tämä

  GPIOE->BSRR = 1 << 9; 

tulee

  void setLEDStatus (LED led, Status status) {led = 1 <<-tila; // En tiedä sinun jäseniäsi.}  

kun

Led

ja

Status

ovat enumeja. Voit tehdä niistä vähintään makroja. Tämä helpottaa sinua siitä, että sinun ei tarvitse muistaa oikeaa bitin peittämistä tehtävän suorittamiseksi.

Vaikka se voisi todella kuulua CodeReview.SE-sivustoon, siellä olevat ihmiset ovat vähemmän todennäköisesti hyödyllisiä upotetun koodin ja käytäntöjen suhteen.Jotkut ihmiset saattavat pystyä auttamaan, mutta todennäköisesti vähemmän kuin täällä.
Koodi on koodi :) - Saatat olla oikeassa asenteessa siellä, mutta saat paljon todennäköisemmin vastauksen sinäkin.


Tämä Q & A käännettiin automaattisesti englanniksi.Alkuperäinen sisältö on saatavilla stackexchange-palvelussa, jota kiitämme cc by-sa 3.0-lisenssistä, jolla sitä jaetaan.
Loading...