Ich habe gerade meinen ersten Code auf STM32 geschrieben - blinkende LED. Es kombiniert Fragmente aus verschiedenen Quellen; Bitte kritisieren Sie mich, damit ich lernen kann, wie man richtigen Code schreibt und keine dummen Gewohnheiten lernt.
#include "stm32f30x.h"
void SysTick_Handler(void);
void TimingDelay_Decrement(void);
void Delay(__IO uint32_t nTime);
static __IO uint32_t TimingDelay;
int main(void)
{
RCC->AHBENR |= ((1UL << 21) ); // Enable GPIOE clock??
GPIOE->MODER |= (1 << 2*8); // PIN 9 as output
//GPIOE->BSRR = 1 << 9; // LED ON
//GPIOE->BSRR = 1 << 9 << 16; // LED OFF
//GPIOE->BRR = 1 << 9; // LED OFF
if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}
while(1)
{
GPIOE->BSRR = 1 << 8;
Delay(50);
GPIOE->BRR = 1 << 8;
Delay(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--;
}
}
Warum muss ich die GPIOE-Uhr aktivieren? Und was ist der Unterschied zwischen 1UL << 21
und 1 << 21
?
c
stm32
cortex-m
code
transistors
cmos
inverter
adc
i2c
addressing
serial-bus
mosfet
analog
dc
analysis
nmos
frequency
signal-processing
ultrasound
range-detector
voltage
stepper-motor
components
detection
schematics
symbol
communication
power
dc
fuses
regulations
voltage
led
circuit-analysis
resistors
pcb
pcb-fabrication
integrated-circuit
analog
decoder
connector
hardware
digital-logic
boolean-algebra
microcontroller
sensor
Ekci
quelle
quelle
Antworten:
Bei den STM32 sind standardmäßig alle Peripheriegeräte deaktiviert und erhalten keine Taktsignale. Dies spart eine Menge Energie (und zwingt Sie, beim Codieren über Wechselwirkungen zwischen Pins nachzudenken). Wenn Sie GPIOE verwenden möchten, müssen Sie den STM32 anweisen, seine Uhr zu aktivieren.
1UL << 21
verschiebt einenunsigned long
Wert von 1 21 Bit nach links.1 << 21
Verschiebt eine Zahl mit dem Wert 1, aber es handelt sich um einen Standardtyp, der möglicherweise nicht vorhanden istunsigned long
, und Sie wissen nicht unbedingt, wie breit Ihre Systemstandards sind. Es wird je nach Plattform und Compiler variieren. Tatsächlich kann UL auch je nach Plattform und Compiler variieren. Es ist am besten, die Bibliothekstypedefs zu verwenden, die sicher sind.(uint32_t)1 << 21
und(uint64_t)1 << 21
sind eindeutig.quelle
Insgesamt sieht es ganz gut aus. Könnte noch ein paar Kommentare gebrauchen.
Ist SysTick_Handler ein Interrupt-Handler? Wenn ja, sagen Sie es. Ich bin überrascht, dass es keine Attribute gibt, die dies deklarieren (die meisten eingebetteten Cs für andere Prozessoren haben das Wort Interrupt irgendwo in der Definition des Handlernamens). Ich gehe davon aus, dass das in einer #DEFINE in einer System .h Datei irgendwo eingerichtet sein muss. Schade, dass sie es so verstecken.
Wie oft wird der SysTick_Handler aufgerufen? Ich weiß, dass dies im SysTick_Config-Aufruf eingerichtet wurde, aber Sie sagen nichts darüber.
Was sind die Einheiten für den Verzögerungsaufruf? Millisekunden? Sag es.
Welche LED auf der Platine manipulieren Sie mit GPIOE-> BSRR = 1 << 8?
Ist die Funktion TimingDelay_Decrement wirklich notwendig? Warum nicht einfach den Code in SysTick_Handler einfügen? Normalerweise versucht man, unnötige Aufrufe innerhalb eines Interrupt-Handlers zu vermeiden. Macht hier keinen Unterschied, könnte aber in einiger Zeit kritische Handler sein.
quelle
Verwenden Sie zur besseren Lesbarkeit und zur Verringerung der Fehlerwahrscheinlichkeit Makros anstelle von magischen Zahlen.
stm32f30x.h enthält Makros für (hoffentlich) alle Registerwerte. Damit:
kann geschrieben werden als:
(In der Tat - der ursprüngliche Kommentar war hier falsch; die Verwendung eines Makros macht dies offensichtlicher!)
In ähnlicher Weise könnte der Pin-Umschaltcode wie folgt geschrieben werden:
Weiter zu gehen
GPIO_MODER_MODER8_0
ist nicht ganz klar, also könnte ich ein eigenes Makro hinzufügen:Das könnte etwas lästig werden, wenn Sie viele Stifte einrichten, also könnten Sie Folgendes tun:
Außerdem wird in der obigen Zeile davon
MODER
ausgegangen, dass diese Bits bereits 0x0 oder 0x1 waren. Wenn wir das nicht annehmen können, müssen wir sie zuerst löschen:Ebenfalls:
Wenn die oben in der Datei deklarierten Funktionen nirgendwo anders verwendet werden, deklarieren Sie sie
static
. Dies verhindert, dass sie versehentlich in einer anderen Datei verwendet werden.Wenn der Compiler dies zulässt,
main
sollte deklariert werden alsvoid
, ohne ein zurückzugebenint
, da es niemals zurückgibt.Dies ist ein echter Trottel:
TimingDelay
ist nur eine reguläre Zahl; Es wird nicht verwendet, wenn eine hexadezimale Darstellung angemessen ist. AlsoTimingDelay_Decrement
, wo es mit Null verglichen wird, verwenden Sie0
nicht0x00
. Dies macht es auch konsistent mit dem Vergleich inDelay
.Wenn ich richtig verstanden habe,
__IO
markiert eine Variable alsvolatile
und wird, wie ich vermute, verwendet, um Register zu markieren, die lesbar und beschreibbar sind.TimingDelay
muss in der Tat seinvolatile
, da es in einem Interrupt aktualisiert wird - aber ich würdevolatile
eher verwenden als__IO
, um anzuzeigen, dass es kein Register ist.nTime
muss nichtvolatile
(oder__IO
) sein, da es sich nur um einen normalen Funktionsparameter handelt, der als Wert übergeben wird und einmal gelesen wird.quelle
Diese technisch sollte gehören Code - Review .
Meine einzige Empfehlung ist, dass Sie Bitmaskierung / Verschiebung entweder Makros oder Funktionen sein sollten, die beschreiben, was los ist. Kommentare sind in Ordnung, funktionieren aber nicht und was auch immer die Kommentare sagen, bedeutet letztendlich nichts. Es ist der Code, der zählt (und sie werden nicht mehr synchron sein). Machen Sie den Code zu den Kommentaren mit funktionaler Zerlegung:
wird
und das
wird
wann
und
sind Aufzählungen. Zumindest können Sie sie MACROS machen. Dadurch müssen Sie sich nicht mehr an die richtige Bitmaskierung erinnern, um die Aufgabe auszuführen.
quelle