你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

NUCLEO_L552ZE_Q 『人生中的首块STM32L552开发板』 ┅ GPIO

[复制链接]
三界狗 发布时间:2020-3-13 17:21
这两天家里有些事情需要忙,家里人刚去上班了,因此得接管家里的一些事情,也抽不出空来发帖子,让大家久等了。
" U1 r- J$ c& @( n) V$ T0 }这次是针对NUCLEO_L552ZE_Q开发板的第三次评测贴,上次的帖子介绍了如何在Windows平台上搭建开发环境,不知道大家有没有不明白的地方,如果有,欢迎在评论区向我提出;既然环境已经准备好了,接下来我们就要开始动手写程序测试了(写程序是不会写的,这辈子都不会写程序的,因为有STM32CubeMX),是的,STM32CubeMX把基本的程序框架都写好了,对于基本的测试,只需敲几行字母就行了,真是懒人的必备,哈哈哈。1 K* J. ^; b$ _4 `  a+ e& ^
废话不多说,相信许多玩过单片机的朋友都知道,拿到一款单片机,写程序的第一步无非就是GPIO口的输出输入功能,输出功能就是点亮一盏LED,输入功能就是按键扫描,那接下来我们就遵守这一不成文的规定,先从GPIO口的输出输入功能入手。
9 t. R! B) A8 J# |, [/ `* T2 R/ \! {% L) h3 s& K
评测内容:
, a% g+ \) Z3 {2 f4 Z1、新建MDK-ARM工程,使用STM32CubeMX新建一个工程;  W; ]% T: x/ T2 S' J+ _
2、GPIO口电平输出功能,控制NUCLEO_L552ZE_Q开发板上的红色LED灯闪烁;
! z( G$ s2 u! c2 n; z( s2 }3、GPIO口电平输入功能,使用NUCLEO_L552ZE_Q开发板上的USER BUTTON按键控制红色LED灯闪烁的频率大小。
5 ?7 \' i4 b% c0 N8 Y  }
. ~) K' q+ L3 ~/ |& u5 R# q% S0 ^& ^% p新建MDK-ARM工程:
0 }6 j) ^, _: |. k) I% h$ t在开始之前,我们还需要了解一些如何使用STM32CubeMX新建一个工程的知识。0 @4 p/ u5 L3 S: S* Z( H$ {
第一步:新建目录
0 u0 _" V, ]+ ]5 X: d0 l5 x3 d' s在电脑的磁盘上新建一个文件夹,这个文件夹并不是工程目录,至于工程目录是哪个,稍后会说。注意,文件件的名称,上级名称,上上级名称等,就是整个路径,一定不能含有中文!半个中文都不能有!不信你可以试试。为了演示,我就随便建个名为“Demo”的文件夹,如下图。
( Z- l% Y' I5 U% W8 H1 U
新建目录.png

$ L1 k2 Q- p; j6 f0 t7 Q8 i第二步:新建STM32CubeMX工程! d0 @) j$ |( y* w5 U+ P
1、打开STM32CubeMX,鼠标左键单击“New Project”中的“ACCESS TO MCU SELECTOR”,
: P/ S8 a( ~9 f+ n1 [6 i& n3 ?
2-1.png

4 f  A  A% D0 y2、在弹出的“New Project from a MCU/MPU”窗口中的左侧的搜索框中输入你需要的单片机型号,我这里输入“STM32L552ZE”,1 E. d! @. h8 c* H4 l8 [0 M7 J/ o% S
3、然后在左下角的“MCUs/MPUs List”中选择所需要的单片机型号,我这里选择STM32L552ZET6Q,双击单片机型号,, ^9 i  z6 @7 ?! T
2-2.png

: D, [' ^; R4 \4 ^) k4、弹出窗口问你是否使用TrustZone,我选择No,然后就创建了一个STM32CubeMX工程9 P3 V& t& M7 e, d# O" R
2-3.png

+ A* ?0 L) }# u4 d" }
- f. ^  o# z0 g$ e第三步:配置STM32CubeMX工程+ R  w4 N1 a- }  m6 l; b
1、设置工程属性,点击STM32CubeMX工程窗口上方的“Project Manager”选项,在最左边选项切换到“Project”,
* ~" S& H: g  [0 o! t2、在“Project Location”中选择在第一步的时候创建的文件夹,
3 f+ f$ A. C( u3、在“Project Name”中填入工程名(不能是中文),填入的工程名就是这个工程的根目录,路径如蓝色框所示,
( s9 P/ J" a! f8 w; ?5 V4、在“Toolchain / IDE”中选择“MDK-ARM”,其他保持默认即可,具体如下图所示,
  T) Z2 M9 ]4 J& h
3-1.png
8 R4 n; e" B1 t$ A
5、最左边选项切换到“Code Generator”,在右边的“STM32Cube MCU packages an embedded software packs”中有三个选项,意思分别为拷贝全部的库文件到工程目录中、仅拷贝需要的库文件到工程目录中、仅在工程文件中引用需要的库文件(库文件放在STM32CubeMX的安装目录中),我选择第二项,

) d' T5 B# R4 v. R0 [
3-2.png

6 P- }0 z4 c* X! w( y$ p. j7 w& a6、设置时钟属性,点击STM32CubeMX工程窗口上方的“Project Manager”选项,在“HCLK(MHz)”中输入需要的时钟频率,按回车键,在弹出的提示中选择Ok便可,我输入STM32L552ZET6Q的最大时钟频率:110MHz,其他的保持默认:内部高速时钟16MHz和内部低速时钟32KHz,
, d* _; o( }1 B
3-3.png

9 f3 ^% r  Q/ M! F: b3 K% J7、配置点亮LED灯的GPIO,NUCLEO_L552ZE_Q开发板上共有三盏LED灯,分别为绿三色,根据原理图提供的信息,绿三盏等分别接在了单片机的PA9PC7PB7引脚,我选择了最经典的红色LED,在“Pinout & Configuration”中使用鼠标左键点击单片机模型上的PA9引脚(右侧从上往下数第8个引脚),在小窗口中选择“GPIO_Output”,至此,STM32CubeMX工程就配置好了。
7 r: L0 q) W7 J! i! C5 X
3-4.png 3-5.png
1 B: c% e8 m2 w, v2 _1 p3 F4 P
第四步:保存STM32CubeMX工程。
点击上方菜单中的“File”,选择“Save Project”即可。
第五步:生成MDK-ARM工程。
鼠标左键单击右上方的“GENERATE CODE”,软件便可根据之前的配置自动生成一个代码工程,如果在第一步中创建的目录中有中文,在这一部生成代码工程的时候就会出现错误提示,导致工程创建失败,因此需要特别注意。
" Z: b, [' Z0 ~  r
5-1.png
" p* c% A4 T6 e0 {* e
5-2.png
GPIO口电平输出功能:点亮一盏LED灯
第一步:了解一下工程的目录结构。

" u+ y5 y9 M2 o. p& a3 _
6-1.png
Dirvers:存放STM32的固件库以及ARM公司提供的CMSIS库,通常情况下不需要修改里面的文件内容;
inc:存放用户编写的.h文件,文件内容可修改;
MDK-ARM:存放MDK的工程文件,以及STM32的启动文件,文件内容通常情况下不需要修改;
src:存放用户编写的.c文件,文件内容可修改。

3 K4 H: T' ]$ g  h4 e; a
第二步:在MDK-ARM文件夹内,双击打开.uvprojx后缀的工程文件,不需要改动,直接链接一遍,看是否有问题,结果0错误、0警告。

( P4 ^& }8 S4 v7 _! Q% }% B
7-1.png
) r! I- X$ `& B5 S6 ~2 ?6 ^
第三步:打开main.c文件,找到主函数main(),在主函数的while循环内添加如下代码,意思为每隔500ms对PA9引脚进行电平取反操作,让红色LED灯闪烁。
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_9);
HAL_Delay(500);
7 J- i7 z5 X1 s5 E+ e
第四步:配置目标属性。
1、电机窗口上方的魔术棒,弹出配置窗口;
2、切换到“Debug”选项;
3、选择调试器,我使用ST-Link Debugger;
4、电机左侧的“Settings”
( K' x" A6 K/ S3 t' ~
7-3.png

% h- z! ?! [9 \7 o% N) L, v
5、在弹出的窗口中切换到“Flash Download”选项,勾选“Reset and Run”,使得将程序烧录到单片机后就会自动复位并运行程序。
0 J# v& C2 w# q) m# c$ s
7-4.png
; z9 ?# x0 D0 x  `
6、点击“确定”、“OK”确认修改后,再次编译链接工程,0错误0警告。
第五步:烧录程序。
1、使用一根Micro USB数据线链接电脑与开发板上的ST-Link USB-A口,如果还没安装驱动,可查看我上一期的帖子,末尾有附件,如果开发板上的LD4亮红色,LD6亮绿色,说明连接正常。

' t: O0 x& I: U1 q, C; ~  U- R
8-1.jpg

( j4 T4 Y/ M" b7 ~( X; A
2、电机MDK软件左上角的下载按钮 LOAD.png ,开始将程序下载到单片机上运行。
3、观察运行情况,红色LED灯开始闪烁,说明GPIO口能够正常输出高低电平。
; m: D5 I/ Q9 {8 Z. n5 Q+ h
LED测试结果.gif
GPIO口电平输入功能:按键扫描
第一步:重新生成MDK-ARM工程。将MDK-ARM工程关闭,根据原理图知道开发板上的USER按键连接在单片机的PC13引脚,回到STM32CubeMX工程,在“Pinout & Configuration”中使用鼠标左键点击单片机模型上的PC13引脚(芯片模型的左侧从上往下数第7个引脚),在小窗口中选择“GPIO_Input”,保存STM32CubeMX工程并且点击“GENERATE CODE”重新生成代码。

2 K- _) ]/ ?' D* e7 p* i! f5 a; V
9-1.png

7 ~: P' H- K1 t7 q2 ]! I' g/ D" s
9-2.png

) U: @* x. S: o0 r, W4 H8 P
第二步:实现按键扫描代码

4 F: W  v3 k5 Q$ p+ }: M
1、打开MDK-ARM工程,在main.c源文件的主函数实现代码的开头添加如下代码,声明两个局部变量。
uint8_t u_cnt=0, u_cycle=10; //计数值:u_cnt ; 闪烁周期:2 * u_cycle * 10ms
- V4 {1 A) D4 o/ n  n
2、在主函数的while循环内添加如下代码,实现按键扫描和LED闪烁功能。
/*GPIO口输入功能*/
//按键检测程序
if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
{
        HAL_Delay(20);//消抖
        if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
        {
                u_cycle += 10;
                if(u_cycle>=50)
                {
                        u_cycle = 10;
                }

& [$ P% y, {" o! s" e8 w
                while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET);
        }
}
//LED灯闪烁程序
u_cnt++;
if(u_cnt >= u_cycle)
{
        u_cnt = 0;
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_9);
}
HAL_Delay(10);
4 \5 h$ b4 y5 u% G1 L' R; i

, ^5 _% Q4 i0 ]  t0 `0 p
3、修改完之后,编译链接一遍代码,将代码烧录到开发板上,用手按开发板左下方的USER按键,观察红色LED的闪烁频率变化情况,实际情况如下:

8 }+ M3 l+ r0 ~2 E3 E. g 按键测试结果.gif

( p( @: g/ V( b& o6 Y
仿位带操作:实现与51单片机一样的IO口操作方法
使用过正点原子Cortex_M3或者Cortex_M4系列单片机开发板的朋友都应该接触过位带操作功能,在Cortex_M3权威指南(中文)中的第5.5节有如下介绍
在CM3中,有两个区中实现了位带。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。这两个位带中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。
% [, Q- Q' ?- \1 R  c, p
文中所述的位带区与位带别名区有如下对应关系
位带区与位带别名区的膨胀对应关系.png
- h! w6 L+ u+ ?% O+ J6 m4 u% L
STM32单片机的GPIO口地址就在片内外设区的最低1MB范围内,意思就是能够通过位带别名区中的每一个地址,操作到对应的片内外设区的外设寄存器中的一个bit,往位带别名区中的地址写1,则对应的片内外设区的外设寄存器中的相应位就会置1,读取位带别名区中的地址的值,就会返回对应的片内外设区的外设寄存器中的相应位的值,GPIO口的每一个Pin的电平就是由ODR寄存器中的每一个位来控制,以及通过IDR寄存器中的一个位来获取一个Pin的电平。但是,我查找过Cortex_M33的手册,并没有发现这个位带别名区,也就是Cortex_M33没有位带操作功能,但我可以通过自定义一个位域结构体来实现类似的操作,实现代码如下:
typedef struct
# s* d. }4 F" o5 k3 N& d{/ w( U6 @# P; \3 Z$ ?
    uint16_t OD0 : 1;2 q/ K0 H: M0 R$ ?0 _- y; y
    uint16_t OD1 : 1;, Y; b) D4 f  y- W) G6 `
    uint16_t OD2 : 1;6 W8 O; U7 J$ x
    uint16_t OD3 : 1;( d1 I# c% |* m* C& f# j# y5 S
    uint16_t OD4 : 1;
  x1 O' L& J. I' s; J    uint16_t OD5 : 1;
3 b/ V/ p9 M- _! f  k/ }  h    uint16_t OD6 : 1;6 R5 D4 Q0 m- {- i& w" q5 ?; p
    uint16_t OD7 : 1;
. f! s9 e" r) o0 q: C& M    uint16_t OD8 : 1;
$ X  p. o9 w+ N8 P) ]/ C6 I    uint16_t OD9 : 1;
# V6 p$ n1 F6 |    uint16_t OD10 : 1;6 c. W# P$ E) ^9 l) \
    uint16_t OD11 : 1;, v2 E4 x6 W, @! {* Q. X: y
    uint16_t OD12 : 1;4 n- s& [) `, p7 |
    uint16_t OD13 : 1;! L" v. o4 |1 G! v
    uint16_t OD14 : 1;
( m  s0 A5 v, C* M. n8 B& C  n    uint16_t OD15 : 1;
! k$ L4 O' ~/ a} ODR_TypeDef;3 v" r% t9 l4 W; n$ X

# n8 z( K) a2 s+ Y#define PAin(n) ( ( GPIOA->IDR&(1 << (n)) )>>n )
3 y3 z' f& x% S' Q9 J#define PBin(n) ( ( GPIOB->IDR&(1 << (n)) )>>n )& U: A  D1 \4 q# C# N9 t3 `
#define PCin(n) ( ( GPIOC->IDR&(1 << (n)) )>>n ); _. O# M9 n3 v
#define PDin(n) ( ( GPIOD->IDR&(1 << (n)) )>>n )* v( T, G+ o* n: {/ z  N/ u
#define PEin(n) ( ( GPIOE->IDR&(1 << (n)) )>>n )
% q* n( W2 B0 D2 @2 w# }) ]#define PFin(n) ( ( GPIOF->IDR&(1 << (n)) )>>n ), u  d' ?+ R7 B
#define PGin(n) ( ( GPIOG->IDR&(1 << (n)) )>>n )
* G8 M0 [, E3 o3 p( O- u" z
; \! R% r) q5 P; m#define PAout(n)  ( ((ODR_TypeDef *)(&(GPIOA->ODR)))->OD##n )4 e. ~, O2 d2 P- Y" i
#define PBout(n)  ( ((ODR_TypeDef *)(&(GPIOB->ODR)))->OD##n ). K  Q: J5 |: ~# [4 c! D  q% I9 h
#define PCout(n)  ( ((ODR_TypeDef *)(&(GPIOC->ODR)))->OD##n )# N  M8 F5 C- M/ V7 D+ _7 j5 S
#define PDout(n)  ( ((ODR_TypeDef *)(&(GPIOD->ODR)))->OD##n )# M' N* Y) ]1 t1 Q( t
#define PEout(n)  ( ((ODR_TypeDef *)(&(GPIOE->ODR)))->OD##n )7 J  X! c/ v7 ?. }
#define PFout(n)  ( ((ODR_TypeDef *)(&(GPIOF->ODR)))->OD##n )& U& B3 z* G9 Z3 b. X
#define PGout(n)  ( ((ODR_TypeDef *)(&(GPIOG->ODR)))->OD##n )

% D5 x$ W7 b% a* Q2 E可将此代码封装到一个头文件内供调用,使用方法同正点原子的源码一样。
#define LED_R PAout(9)
5 H/ F! X8 [7 X% G- K: K" S0 b: h- A#define USER_BUTTON PCin(13)
/*仿位带操作*/
# \; Q; A6 V$ M$ s//按键检测程序
/ X" g) {. u3 [7 J5 M+ dif(USER_BUTTON == 1)7 @. o* u  h! f, o
{
+ X# d0 W$ A8 y+ G! D2 O3 f! M* @        HAL_Delay(20);//消抖
) _8 ?, F& A/ E1 P/ ^& p        if(USER_BUTTON == 1)  M; e( H% w# W* e
        {3 @. _( a" A! O( e7 D: x
                u_cycle += 10;
/ d; M! y: M: ]* T6 W# }3 i                if(u_cycle>=50)
% X8 M6 N4 \8 |! ]/ c7 _) b0 n                {
, y$ B" m& S  ~* R                        u_cycle = 10;
* q3 e$ f( o) \! H4 U! T                }
/ l; G- r! J: }               
; \* S. @5 h7 U3 {! l                while(USER_BUTTON == 1);: S* L2 I2 P5 d/ ^2 a  P- V: z% l. q& k
        }0 P; ~1 H! ^; X3 N$ l0 w
}7 D" `( u6 C* \8 u" Z
//LED灯闪烁程序1 `6 `9 |( N# x6 C9 T1 [8 `  t2 g
u_cnt++;
  a/ A3 a9 K8 i4 ~1 qif(u_cnt >= u_cycle)
. J- [$ i( X3 d* b- Z{; i$ |$ t# T: {' k6 X: l2 s' s
        u_cnt = 0;
+ h4 T" ?3 c+ N! f1 [6 g  R$ r        LED_R = !LED_R;5 E3 G* x& }7 a$ X
}, s. n0 c. Z8 {3 B9 G3 b
HAL_Delay(10);

7 @% j% O7 r5 s3 T" V% r总结:2 |8 g( K* H- I
可见,在STM32CubeMX的帮助下,实现一些基础的功能代码还是比较方便的,加之有HAL固件库的支持,无论单片机的底层寄存器如何变化,HAL固件库都已经统一封装成一致的函数名,使用起来也非常方便。本次测试的GPIO口操作,主要使用到了两个函数:HAL_GPIO_TogglePin和HAL_GPIO_ReadPin,两个函数的实现也比较简单,都是直接操作寄存器:3 O0 n" w. [! |6 f( h
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)8 h4 ~0 l" M+ B
{
2 F8 O. l& F% \) r$ e  /* Check the parameters */
4 F. \5 o/ I: W0 y. U$ w  assert_param(IS_GPIO_PIN(GPIO_Pin));
: u. V% ~& l1 B8 l) T* ]* x4 N& R; L0 V0 V& p  B' p
  if ((GPIOx->ODR & GPIO_Pin) != 0U)( c7 N" J  N/ J6 |; y1 ^" r
  {
: k0 T7 ^, d( v: V    GPIOx->BRR = (uint32_t)GPIO_Pin;
% Y7 a, X! A7 z* T  }, h3 ^: L7 S1 I" X5 _) I
  else9 A( T  F( L; B% }# a3 h0 u
  {2 c  B: y: S' A$ q
    GPIOx->BSRR = (uint32_t)GPIO_Pin;, i1 l2 ^( s5 ?) l% N+ f' Y
  }
9 L. y5 K: {# L/ @/ \- R' {6 u}
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)3 J; m9 i9 }; T* o$ n: @3 \+ s$ Z
{2 v- a+ \# @; _- x9 {
  GPIO_PinState bitstatus;/ [) e, [) n$ T0 p+ }

9 _" }7 Y2 B" p" |" i& d( Z) n  /* Check the parameters */4 d/ X: ?0 U- \; K, T+ v
  assert_param(IS_GPIO_PIN(GPIO_Pin));$ p9 Y/ ]* Y3 r- Q

9 h9 k! B# |3 t  if((GPIOx->IDR & GPIO_Pin) != 0U)
- q6 a3 P$ [  B$ L# ?; e  {9 |' |% a, j0 p) n( K  J% V
    bitstatus = GPIO_PIN_SET;4 |2 E0 T1 A) r7 ^' q; D
  }& Q' u- H, g* C  ?- f* t" H
  else
% `7 v6 y& L# t' |! F# p8 d$ D. M  {+ w7 e: B5 ^4 j$ [9 X4 R
    bitstatus = GPIO_PIN_RESET;
! N; A% X6 C# A7 N2 }, K  ?  }
" H% Y0 z( \; D  return bitstatus;* z2 J# m, R' y4 R' _- S
}

) U9 r" K% O* v* |+ g) A; `- e; r. ^本次我们介绍了GPIO口的使用,由于篇幅已经太多了,花了一天时间才写完,等下次有空再介绍其他一些基本的功能。还是那句话,如果朋友们觉得有任何疑问,欢迎在评论区向我提出。感谢您的关注,谢谢。8 ~1 K1 o, s* ]* m- \  L; M
  V9 d9 j7 b& f- M% M1 F7 O, o0 u
GPIO_Demo.zip (990.25 KB, 下载次数: 8)
7-2.png
收藏 2 评论0 发布时间:2020-3-13 17:21

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版