
/* stdperiph_gpio.h */ ( x/ Y* T, y% c2 K2 E# l /* Includes ------------------------------------------------------------------*/4 a9 r/ p- S3 V" X #include "stm32f4xx.h" % U {/ ?; x! x! k. | I /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STDPERIPH_GPIO_H #define __STDPERIPH_GPIO_H' n/ g5 T7 r1 A2 [) [ ' r9 F- ^! Z9 m- U# K' w extern void StdPeriph_GPIO_Config(void);! D* N: ?! L l extern void StdPeriph_GPIO_Driver(void); union OutPort { uint8_t all;5 |. W9 H8 P4 m( l5 l struct {& J0 H& R0 ~. Y8 x; W uint8_t b0:1; // 0 bit0) P7 P0 W+ u9 I uint8_t b1:1; // 1 bit17 H4 t+ o0 m' j+ y$ h* s uint8_t b2:1; // 2 bit2 uint8_t b3:1; // 3 bit3' y- j, U9 K; j7 b uint8_t b4:1; // 4 bit4 uint8_t b5:1; // 5 bit53 H( j' z% J4 C, d# L6 N5 e' L uint8_t b6:1; // 6 bit6 uint8_t b7:1; // 7 bit7 ! n$ e, V! `0 L: V* I }bit; }; , G, m2 x/ K" m' R# {% @, @ extern __IO union OutPort Q1; #endif/ z4 s3 l% F& o) F, n 4 Z A* y& p( e /* stdperiph_gpio.c */ /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx.h"' a* t7 I" I W @0 x #include "stm32f4xx_gpio.h"$ p4 j! Q4 L: e. n9 h/ e3 o #include "stm32f4xx_rcc.h" struct BITS { uint16_t GPIO0:1; // 0 GPIO0 uint16_t GPIO1:1; // 1 GPIO18 P+ R7 \4 ^. O' K Q3 G uint16_t GPIO2:1; // 2 GPIO2 uint16_t GPIO3:1; // 3 GPIO3 uint16_t GPIO4:1; // 4 GPIO49 |7 S, L/ [% _' W9 _- V uint16_t GPIO5:1; // 5 GPIO5 uint16_t GPIO6:1; // 6 GPIO6 S! m6 O6 F! z! i uint16_t GPIO7:1; // 7 GPIO70 i5 ?9 b# @* }! c uint16_t GPIO8:1; // 8 GPIO8 uint16_t GPIO9:1; // 9 GPIO9& I1 O8 T" z9 @5 U1 @, t1 g( X uint16_t GPIO10:1; // 10 GPIO10 uint16_t GPIO11:1; // 11 GPIO11 uint16_t GPIO12:1; // 12 GPIO12 uint16_t GPIO13:1; // 13 GPIO13 uint16_t GPIO14:1; // 14 GPIO14 uint16_t GPIO15:1; // 15 GPIO15 }; 7 b0 q% S' R2 }( ]6 M, m3 X union BSRL_REG { uint16_t all;! J6 z$ A. G L; k+ v; u9 x struct BITS bit;7 [. |$ x4 `$ S+ x4 S! ~1 y/ J };9 g9 z$ g9 Q8 { union BSRH_REG {7 f0 w4 ?# w [ h- y- p; v: S uint16_t all; struct BITS bit; }; __IO union BSRL_REG GPIOE_BSRL_Shadow; m C& N7 D9 h- }- \. m; V __IO union BSRH_REG GPIOE_BSRH_Shadow; 5 [ T$ y, m& Z2 T- w union OutPort { uint8_t all;: d3 N1 n; ]2 `/ b# u! q" r8 M- G struct {7 N7 D. N' [/ N2 O uint8_t b0:1; // 0 bit09 V- K+ _. g; L Z9 B& M uint8_t b1:1; // 1 bit1 uint8_t b2:1; // 2 bit2 uint8_t b3:1; // 3 bit3 uint8_t b4:1; // 4 bit4 uint8_t b5:1; // 5 bit50 }+ {9 s' `/ }% Y% R0 C* Q uint8_t b6:1; // 6 bit6+ e, `5 P6 M/ x9 v+ B uint8_t b7:1; // 7 bit7 5 Y+ X" b1 Y$ s5 P }bit; }; __IO union OutPort Q1; void StdPeriph_GPIO_Driver(void)1 g) U3 v; Z: u T" m) }' y { /* 1: 打开MOSFET 0: 关闭MOSFET */" s/ P# U8 c _/ w$ a GPIOE_BSRL_Shadow.all = 0;0 O& K1 {# X/ g- I: r0 F, D GPIOE_BSRH_Shadow.all = 0;* U1 P4 k. a. l7 e" e. e if(Q1.bit.b0 == 0){2 O7 T- i) w7 B4 Q0 N- M GPIOE_BSRH_Shadow.bit.GPIO0 = 1; } else { GPIOE_BSRL_Shadow.bit.GPIO0 = 1; } if(Q1.bit.b1 == 0){+ a, Q' m# x J/ u2 | GPIOE_BSRH_Shadow.bit.GPIO1 = 1; } else {6 r5 V2 U& X; h8 i GPIOE_BSRL_Shadow.bit.GPIO1 = 1;& ?- `: m3 }& r# c } if(Q1.bit.b2 == 0){ GPIOE_BSRH_Shadow.bit.GPIO2 = 1; } else { GPIOE_BSRL_Shadow.bit.GPIO2 = 1;4 s# {1 Q8 k' W2 J* I( ] }7 {0 j' R2 `9 O: m; p if(Q1.bit.b3 == 0){6 {7 v- ]- C4 ]% B" J. ] Z1 N( Q GPIOE_BSRH_Shadow.bit.GPIO3 = 1; } else {1 \0 U5 W, H% t4 A GPIOE_BSRL_Shadow.bit.GPIO3 = 1; } if(Q1.bit.b4 == 0){ GPIOE_BSRH_Shadow.bit.GPIO4 = 1;5 j8 H& C3 ~2 E+ e; m } else {* m5 a9 V0 t2 p, P v1 v' _* [# v6 b GPIOE_BSRL_Shadow.bit.GPIO4 = 1; }" B# V+ k2 [* k, ^ if(Q1.bit.b5 == 0){ GPIOE_BSRH_Shadow.bit.GPIO5 = 1; } else { GPIOE_BSRL_Shadow.bit.GPIO5 = 1; } if(Q1.bit.b6 == 0){ GPIOE_BSRH_Shadow.bit.GPIO6 = 1;2 C$ `- a4 G/ G2 R) W$ D. K/ q } else { GPIOE_BSRL_Shadow.bit.GPIO6 = 1; } if(Q1.bit.b7 == 0){ GPIOE_BSRH_Shadow.bit.GPIO7 = 1; } else {6 ~; B8 D3 n" ~' B GPIOE_BSRL_Shadow.bit.GPIO7 = 1;( M$ Z; |; T0 x5 U! o1 b }3 X7 C% l" S6 X/ [) c& ? GPIOE->BSRRL = GPIOE_BSRL_Shadow.all;) X) P; Y. K( }) E; W$ t GPIOE->BSRRH = GPIOE_BSRH_Shadow.all; } R2 A6 Q! {. h. ? |
' W( o8 T* H4 Y+ _& p2 T' U5 C/ d; w
注意事项:+ c% V3 C. J0 F1 C6 F
1. 可以在主程序或定时程序中调用StdPeriph_GPIO_Driver函数,刷新GPIOE.0~GPIOE.7的状态。
2. 在应用程序中,只需访问Q1的位即可。例如下一句0 ~1 G+ H% k/ y5 H/ `
"Q1.bit.b0 = 1;"就可以修改GPIOE.0的状态为高电平;同样地,"Q1.bit.b0 = 0;"可以修改GPIOE.0的状态为低电平。+ N$ V4 ~3 T2 i: X
StdPeriph_GPIO_Driver函数调用的频率,建议在1~10ms,满足要求的即可。) S2 F: |6 p! d1 C, v& ?" f4 c
在MDK-ARM V5.15开发环境,键入"Q1."则会出现自动提示,Q1.all 是访问所有的位, Q1.bit.b7是访问最高位。
2 q+ d( D9 V& l( i) G1 S
补充说明:. m: u8 X! K. g8 T
1. 驱动编程的目的和出发点在于,仅在一个地方调用StdPeriph_GPIO_Driver函数,7 Q3 I; X$ D; N" q% s$ i/ G
用户层只操作Q1输出端口的8个位,8位变量Q1是函数对应用层提供的接口。" _# |7 z; m& y( n* K8 m T
2.宏定义的作用
宏定义直接操作GPIO,可以立即刷新GPIO的输出状态。* Q9 Y/ C& b: `! V5 U
例如在SPI通信中函数中,代码开头使CS片选脚变低,代码结尾使CS片选变高。
但宏定义不能给用户提供一个统一的中间变量。% a4 W$ m: o# x, z/ w* R0 t
假设有二个输出端口Q1、Q2,每个端口均是8路输出,分别安排在任意的GPIOA-GPIOE,* H4 ]+ V# X, ^# O. S' Z
可以设置16个宏定义,将这16路输出端口设置为高,另外再设置16个宏定义,
分别将这16个输出端口设置为低。显然,这种写法将对GPIO的操作复杂化了。
宏定义保证了效率,但对于应用层而言,不利于用户的使用和记忆。9 |+ q/ K- ^1 B; M- Q4 x4 g( a
/ U( X* Y! Z2 t0 E3 Z2 R+ a7 R
z# _" Y0 [( f+ w5 j8 r3 i; a