|
2 X; D) C8 h3 i; _
STM32学习笔记1——点亮第一盏LED灯 本文不特殊说明都以stc32F103C8为例,软件平台为KEIL5V5.15
* x) ~$ M) v1 @首先这次我们用寄存器直接点亮LED灯
3 [; j* ]5 Q; JLED电路图如下图:
3 ~9 z, M2 R9 o, N
8 \$ c# N0 e- h. n" B
可以看出如果需要点亮一盏LED灯只需要IO口输出高电平即可,本次以GPIOB为例子。0 r# m5 y/ L! P; @. }5 O3 x
6 _+ e( f2 z$ l7 U1 z g
7 T- d- E3 L: \1 [) p2 S" {' r+ _: O点亮LED灯
: ^, i' q7 H' h; h. o; t2 Q7 ~& |1 w
0 D& S S+ c# X5 G8 M. |5 J) ~# B% P% l% g
控制IO输出高电平通常需要三步:
5 H; J8 Z3 x1 o: ~1.开启时钟:因为STM32为了节约消耗,故上电时候外设时钟默认不开启。故我们需要开始GPIO的时钟。 $ M6 Z- Z* T4 {4 o5 T4 n# A& `0 M
2.设置GPIO输出模式:stm32F103提供了4种输出模式和3种输出速度:
4 X" y3 J) |- w; L) W% j |- 通用输出推挽 0 G z2 g) P- k4 T2 Y5 L9 `; A y
- 通用输出开漏
' @, \- ~5 }5 s' {- 复用输出推挽:串口输出 5 {4 r& \3 a. P* [( w) Y- m9 o0 e
- 复用输出开漏:IIC
: M- A& s! ~$ k1 O2 ~3 R/ N
( v% ?6 F3 T0 a$ Q; P2 q' G: Y: ^/ f8 |9 y, R' v% d
推挽输出电路如下图:
9 s2 I" S" ]1 H
" @' a% I* j7 I; r; b# i* ~两个三极管都是半个周期导通,轮流导通。从而减低了功耗,提高了每个管的承受能力。又由于不论走哪一路,管子导通电阻都很小,使RC常数很小,转变速度很快。因此,推拉式输出级既提高电路的负载能力,又提高开关速度。所以推挽输出可以输出高低电平,但输出幅度取决于输入,不可控。
+ U& F9 w* {2 P, o# h5 i1 a! Z
1 t% D; U$ y m/ B) v) O% i7 J+ k) O: a& l# K
开漏输出电路如下图: 7 D7 w' ^' M5 a- M
9 u$ z4 z3 E+ P从图中可以看出,当没有上拉电平和上拉电阻,当IN输出低电平时候,OUT输出低电平,当IN输出高电平时,OUT处于开漏状态,电平状态未知,当加上拉电阻时候,则上拉电平跟上拉电阻有关。
3 a+ J* n; h- \6 u开漏输出相当于三极管集电极,故它只能输出低电平,需要接上拉电阻才能得到高电平。开漏是用来连接不同电平的器件。很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的沿的速度 。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
" G0 Q- f. j* O0 j而且可以将多个开漏输出的管脚,连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系。这也是I2C,SMBus等总线判断总线占用状态的原理。6 X! m. X9 R/ W: f8 p! }% F
3.输出高电平
- r3 Q- V8 N4 W3 q' K. X
( g5 {( T6 _; N, m& V7 G# D9 J! ~- N2 n! e0 K
寄存器设置
2 k- F' M! e! y6 [/ f# p" g" \* \' h. T# g9 i" u" O: S- @$ I
1.设置时钟寄存器
J3 k' N/ j, K$ C. ]) h首先GPIO是挂载在APB2总线上的,APB2时钟使能寄存器为RCC_APB2ENR,如下图
6 n! |3 n/ B P- N- }
% ` N4 y3 \; y) ~2 F$ A- r1 _故只需开启GPIOB的时钟,即将RCC_APB2ENR第3位置1
- X. H5 c5 z* w
/ q% {" w, y5 X7 Q7 I+ ]6 {+ c1 g3 o2 _) |, F/ Q) c
2.设置IO口输出状态 % [& v- k6 I( T/ F* c0 ?! o
有关寄存器为GPIOB_CRL和GPIOB_CRH,如下图:
3 p V! d3 y4 H; [
+ a1 G& ~3 e% u5 R- R! [可以看出只需要设置MODEx[1:0]即可,我们可将他置01,设置成中速即可,则默认为推挽输出
% W" E: R x4 n0 g2 o1 C. T( W- @
5 W* S% O& [/ \; T! ]; N0 B+ j$ a% Q
3.设置IO口输出电平
" {0 W* d/ a5 F9 iIO电平有3个寄存器有关,分别是GPIOB_ODR,GOIOB_BSRR,和GPIOB_BRR;其中GOIOB_BSRR为置位/复位寄存器,GPIOB_BRR为复位寄存器,这两个寄存器都是间接控制GPIOB_ODR即端口数据输出寄存器,故为了初学方便,我们直接控制GPIOB_ODR寄存器。寄存器相关内容如下:6 ?; T. A9 j- q
0 m% n( Y9 @7 p. [9 q" j# u因为寄存器可以写和读,故可以直接置1即可。
+ D8 d: P& Q6 L' M; \5 B) U- a' f' ~2 p m1 ^, B
. _1 I: K7 A- W& E" ]注意事项:
1 s! v+ X- B* x- U1.需要提前设定相关总线和寄存器地址,如下表: % `, ]1 ^+ {- z/ a' w5 B
( n5 V! j- [* j4 ^6 N% r
2.初学者为了简单,通常都操作GPIOx_ODR寄存器,但实际上我还是推荐使用GPIOx_BSRR寄存器,因为BSRR只有写操作,和ODR要经历读——写操作,时间显然慢很多,而且使用BSRR不会被中断打断。! h& L8 Q& `8 L' h
5 O! r- ]/ l1 N
- f$ J" ]7 E/ o; q2 y1 C以下附代码(灯接GPIOB_8~15)
4 h: U# W- a; W6 _4 K- /*定义相关寄存器地址*/
# z/ r) S- n% P) ^- K% m - #define GPIOB_ODR *(unsigned int *)(0x40010C00+0x0c)
. i9 P7 F4 C* z: b b - #define GPIOB_CRH *(unsigned int *)(0x40010C00+0x04)
" O0 {' {- M: R E6 k - #define RCC_APB2ENR *(unsigned int *)(0x40021000+0x18). ^2 s3 Y9 o; F; \2 O* G4 I
- /*延时函数*/
. K, u' \8 N" B$ c {0 L* { - void delay(){& |# S( c( W9 u! w- X# q2 u2 X
- unsigned long n = 30000,j;' i% f2 [# g8 a* L
- while(n--){0 p: \; |. r* e5 ^, d
- j = 12;
) ~, h" N8 {& b; o - while(j--);
; x1 N0 Y) G. J- C5 O - }
. t' J B. S+ \& U8 d& T - }/ M5 i- `# ?4 |
- int main(){# R9 V4 m0 h o+ t W5 h$ y
- unsigned char i;' G5 A( z2 w* B& f1 n0 q$ x0 }. k c9 L: D
- % f* V2 E& l$ r2 }' q! n
- /*开启时钟*/) T" Z2 j7 r0 d0 f9 b
- RCC_APB2ENR |= 1<<3;! y: C" z; v, r/ D
- y! p! G0 K2 J+ N1 \
- /*配置PB8到PB15推挽输出,中速模式*/
" h. b6 y2 I9 N2 k- ~+ Q - GPIOB_CRH |= 0x33333333; 5 Y7 c9 q& [' J- v3 o, I
- 5 y" B) s$ I; ?: X q
- while(1){) \( A# Q9 T, l0 V$ g: n
- /*闪烁两次*/% w& X& P; D+ T3 G* P3 Y
- GPIOB_ODR |= 0XFF00;
8 \: p. x4 [4 B5 n+ L - delay();- M$ S( ~; O, w; N" e$ V9 ]% e; _
- GPIOB_ODR &= ~0XFF00;
* |$ [/ s, X8 W: p% D4 l - delay();
6 Q3 R& A0 L0 E9 \3 e - & R1 p( |. T9 Z6 }" n
- GPIOB_ODR |= 0XFF00;
5 q" f' I& x( B7 Y, f( s - delay();' `, h6 Z l! F) j( |6 G: I* z
- GPIOB_ODR &= ~0XFF00;* e2 w7 E' j1 T0 Y2 \; s: Z! Y
- delay();
: H* u5 y9 a6 V5 b; c - GPIOB_ODR = 0x0100;4 b/ n- l0 A& @% u; E! y
- /*流水灯*/( |8 e. I* Y; \4 V, Y- ?4 D
- for(i = 0;i<7;i++){
. H6 t' {6 C% J. j! U - GPIOB_ODR<<=1;
! S# q+ T- e" W. @ - delay();
0 p, N- [$ Y' {8 H% K - }
! i" f: {) E8 @7 m0 l# w - for(i = 0;i<7;i++){/ z, L: e+ l! N# r H! Q. e
- GPIOB_ODR>>=1;
2 Q+ `) u' `7 T3 N# ^3 p - delay();# S2 L9 F" ]$ ]6 j& J* S
- }) q' b* i" O4 F/ M0 p5 a
7 W/ u( H( U5 f! b3 p5 S9 H3 y I, z- }4 A( K0 i9 n+ R8 p4 p, m) R
- 7 j$ M6 `: q+ X" j. U
- }
复制代码
) z z% z, d9 m- b
! v8 A* o$ X7 W8 f$ M |