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

STM32经验分享 第6章 单片机开发模式的发展

[复制链接]
STMCU小助手 发布时间:2022-8-30 13:39
6.1 STM32结构
从“2.2 ARM与STM32的关系”可知,ARM公司负责设计内核,半导体芯片厂商拿到内核授权后,根据产品需求,添加各类组件,生产芯片售卖。如图 6.1.1 所示,为STM32的组成示意图,其中Cortex-M3内核、调试系统都是ARM公司设计,内部总线、外设、存储、时钟复位等都由ST公司开发。

在编程之前,对STM32的总线结构、存储结构、外设寄存器等有个大致了解,有助于理解编程中的一些操作。此外,中断与异常(Nested Vectored Interrupt Controller,NVIC)、时钟复位(Reset and Clock,RCC)也很重要,且与编程紧密相关,在后面相关实验章节里再专门讲解。

对于开发者,掌握一款MCU的开发需要重点关注四大模块:时钟复位、中断异常、存储映射和外设寄存器组。
7(5W4V33QN%_HDN(3KY@%Y0.png


图 6.1.1 STM32组成示意图



6.1.1 STM32总线结构
总线(Bus)是各种信号线的集合,是嵌入式系统中各部件之间传输数据信息、地址信息和控制信息的公共通道。

与总线相关的主要参数有总线宽度、总线频率和总线带宽。总线宽度是指总线能同时传输的数据位数,如8位、32位、64位;总线频率是指总线的工作速度,频率越高,速度越快;总线带宽用来描述总线传输数据的快慢,总线带宽=总线宽度x总线频率/8,单位为MB/s。

STM32的总线结构如图 6.1.2 所示,可以分为6部分。

POOG$LJZ}GGY@D21_@24LHP.png


图 6.1.2 STM32总线结构框图



①ICode总线(Instruction bus):用于访问存储空间里指令的总线;

②DCode总线(Data bus):用于访问存储空间里数据的总线;

③System总线:用于访问指令、数据以及调试模块接口;

④DMA总线:用于内存与外设之间的数据传输;

⑤Bus matrix(总线矩阵):用于总线之间的访问优先级管理控制;

⑥APB总线:用于外设接口的数据传输;ARM公司推出AMBA片上总线结构,该总线主要包含先进高速总线(Advanced High-speed  Bus,AHB)和先进外设总线(Advanced Peripheral Bus,APB),分别连接高速设备和低速设备。基于这个总线结构,ICode、Dcode、System Bus都是AHB总线。这里AHB系统总线经过两个AHB-APB桥转换成了两个APB总线。APB1上挂接有DAC、UART等外设,其最高频率可达36MHz;APB2上挂接有ADC、GPIO等外设,其最高频率可达72MHz。

在MCU每次复位后,所有的外设时钟都会默认处于关闭状态。因此,在使用外设前需要操作复位和时钟寄存器(Reset and Clock Control,RCC)开启所需外设的时钟。


6.1.2 STM32存储结构
CPU通过总线访问各个外设,现在通往外设的“路”已经铺好,还需要规定各个外设的“门牌号”,以便精准控制每个外设。ARM Cortex-M3系列的处理器,采用存储器与I/O设备(外设)统一编址的方式,将部分存储器地址范围用于外设,这种通过存储器地址访问外设的方式,称为存储器地址映射。

对于32位的处理器,可寻址的范围为232字节,即,也就是0x00000000至0xFFFFFFFF。ARM将这4G空间从低地址到高地址依次划分为代码区(Code)、片上SRAM区(SRAM)、片上外设(Peripheral)、片外RAM(External RAM)、片外外设(External Device)和系统级(System level),如图 6.1.3 所示。

`~(Z_AEJE)U)H`}RX92D{9G.png


图 6.1.3 ARM Cortex-M3存储器映射结构图

ARM公司只是大概的规定了存储器空间的映射,允许各芯片厂商在指定范围内自行定义和使用这些存储空间,未分配的空间为保留的地址空间。

STM32在ARM规定的基础上,将4G空间分为了Block0、Block1、Block2、……、Block7,共8块,每块大小为512MB,如下表 6.1.1 所示,详细结构如图 6.1.4 所示。

K[A[LRLZ`${)YZBM)K6V03H.png


表 6.1.1 STM32存储器映射结构



JOI(~`EIH8F1V)_B]{LIL1K.png


图 6.1.4 STM32存储器映射结构

①0x0000 0000 ~ 0x1FFF FFFF(512MB):作为代码区,用于存放下载的代码。系统上电后,将从该部分读取代码;

②0x2000 0000 ~ 0x3FFF FFFF(512MB):作为SRAM区,用于存放运行代码。系统上电后,将从Flash读取代码,放到SRAM里,CPU再从SRAM读取代码运行;

③0x4000 0000 ~ 0x5FFF FFFF(512MB):作为片上外设区,用于存放厂商外设寄存器。要操作外设,即修改这里对应的外设寄存器;注意这里的RCC和Port B外设的地址范围,后面很快就会用到;

④0x6000 0000 ~ 0x9FFF FFFF(1GB):作为片外RAM,用于扩展RAM。当SRAM或者Flash不够用时,MCU通过FSMC外接其它IC芯片,则在这个地址范围读写IC芯片数据;

⑤0xA000 0000 ~ 0xDFFF FFFF(1GB):作为片外外设区,用于读写扩展IC芯片的寄存器。ST只用了这里的一半空间,另外一空间未使用;

⑥0xE000 0000 ~ 0xFFFF FFFF(512MB):作为内核外设区,用于存放Cortex-M3内核的内部外设。Cortex-M3内核的内部外设有NVIC、Systick等;

在Block0、Block1圈出的三个范围,分别对应前面介绍的三个启动模式。当从主存储器启动,则是从Flash启动;当从系统存储器启动,则是从System memory启动;当从SARM启动,则是从SRAM启动。

对于开发人员,通常就是对Block2的片上外设寄存器进行读写操作,以控制外设资源,实现所需效果。


6.1.3 STM32寄存器

寄存器是用来存储二进制数据的时序逻辑电路,由众多晶体管组成。

前面提到的寄存器,都是外设寄存器。这些外设寄存器由芯片厂商设计,与存储器统一编址,常用C语言的指针来表示外设寄存器地址,实现对外设寄存器的访问和操作。

在嵌入式系统中,除了外设寄存器,还有一类叫CPU内部寄存器。这些内部寄存器由ARM设计,在CPU内部,常用汇编语言直接操作,用于暂存参与运算的数据和内核的一些控制。

开发人员,通常只操作外设寄存器实现需求功能,后面实验会详细讲解外设寄存器。而内部寄存器在实际开发中接触会比较少,后面汇编点灯实验会涉及部分相关知识,本小结简单介绍下内部寄存器。

ARM Cortex-M3微处理器的内部寄存器,又分为普通寄存器和特殊功能寄存器。普通寄存器如图 6.1.5 所示。

@{[MGP)8435JFZY(NLTJ@(7.png


图 6.1.5 Cortex-M3通用寄存器



R0-R12(General-Purpose Registers):用于数据操作的32位通用寄存器;一些16位的Thumb指令,只能访问低寄存器(R0~R7);

R13(Stack Pointers,SP)Cortex-M3包含两个堆栈指针寄存器;同一时刻只能看到其中一个;

主堆栈指针寄存器(Main Stack Pointer,MSP):操作系统(OS)内核和异常处理程序使用的默认堆栈指针;

进程堆栈指针寄存器(Process Stack Pointer,PSP):用于用户代码;

R14(Link Register,LR):链接寄存器;调用子例程时,返回地址将存储在链接寄存器中;

R15(Program Counter,PC):程序计数器;总是指向下一条指令所在单元的地址,可以写入该寄存器以控制程序流;


Cortex-M3处理器还具有许多特殊寄存器,如图 6.1.6 所示。

P19NVD8WP`A5VJF61{RYIGA.png


图 6.1.6 Cortex-M3特殊寄存器



xPSR(Program Status registers):程序状态寄存器;用于存放程序运作中的各种状态信息以及中断等状态;由应用状态寄存器(APSR)、中断状态寄存器(IPSR)和执行状态寄存器(EPSR)组成;

PRIMASK、FAULTMASK和BASEPRI:中断屏蔽寄存器;用于控制异常和中断的屏蔽;

CONTROL:控制寄存器;用于定义特权状态和当前使用哪一个堆栈指针;


【总结】

STM32由ARM公司设计的Cortex-M3内核与ST公司开发的外设资源组成。

Cortex-M3内核有内部寄存器,主要用于运算和内核的控制,这块对于初学者较难,暂时了解即可。

Cortex-M3内核通过总线和外设连接,重点了解大部分外设都挂载APB即可。

STM32采用存储器与外设统一编址的方式,控制外设,则对应操作指定地址的外设寄存器即可,这是后续实验的重点。



6.2 使用汇编开发
汇编语言(Assembly Language)是一种用于电子计算机、微处理器、微控制器或其它可编程器件的低级语言。

在单片机出现之初,由于性能限制,都是使用汇编进行开发。随着技术的发展,制程工艺的提升,单片机的处理速度越来越快,越来越多的单片机使用C语言开发。如今,一些低端MCU还在使用汇编开发;一些高要求程序优化的场合也会使用汇编;MCU/MPU的启动初始化部分也是汇编。本小结就带领读者感受下如何使用汇编操作开发板LED灯。

在编写代码前,本应该分析《开发板原理图》和《参考手册》,从而得知需要操作哪些外设寄存器,但这不是本小结主要内容,具体的分析方法放在后面对应的实验章节,读者暂时无需深入理解以下内容的由来:

1. 从《开发板原理图》可知,控制GPIOB 0引脚,即可控制开发板三色灯的红色灯;

2. 从前面STM32总线结构分析可知,GPIOA挂载APB2上,由RCC控制;

3. 从前面STM32存储结构分析可知,RCC起始地址为0x4002 1000,再仔细查看《参考手册》RCC寄存器部分,可知寄存器RCC_APB2ENR(偏移地址:0x18)的第2位(IOPAEN),设置为1则GPIO A组的使能;

4. 从前面STM32存储结构分析可知,GPIO A起始地址为0x4001 0800,再仔细查看《参考手册》GPIO寄存器部分,可知寄存器GPIOx_CRL(偏移地址:0x00)的第4:5位(MODEy),设置为1则GPIO A1为输出,寄存器GPIOx_ODR(偏移地址:0x0C)的第1位(ODRy),设置为1则GPIO A1为输出高,设置为0则GPIO A1为输出低;



有了以上基础,就可以编程控制LED灯了,本章涉及的代码位于100ASK_STM32F103_MINI开发板资料的“5_程序源码\0_单片机开发模式的发展\1_使用汇编开发\”。

如代码段 6.2.1 所示。汇编代码对初学者不友好,读者对代码内容不理解也正常,也无需深入理解汇编指令,这里主要目的是展示如何用汇编操作寄存器。

代码段 6.2.1 汇编操作寄存器(startup_stm32f10x_md.s)

  1. ; Reset handler

  2. Reset_Handler   PROC



  3.     ; 使能GPIOA

  4.     LDR R0, =(0x40021000 + 0x18)  ; RCC_APB2ENR

  5.     LDR R1, [R0]

  6.     ORR R1, R1, #(1<<2)

  7.     STR R1, [R0]



  8.     ; 设置GPIOA1为输出引脚

  9.     LDR R0, =(0x40010C00 + 0)  ; GPIOA_ CRL

  10.     LDR R1, [R0]

  11.     ORR R1, R1, #(1<<4)

  12.     STR R1, [R0]



  13. MainLoop

  14.     ; 设置GPIOA1输出高电平

  15.     LDR R0, =(0x40010800 + 0xC)  ; GPIOA_ODR



  16.     LDR R1, [R0]

  17.     ORR R1, R1, #(1<<1)

  18.     STR R1, [R0]

  19.     BL Delay



  20.     ; 设置GPIIOA1输出低电平

  21.     LDR R0, =(0x40010800 + 0xC)  ; GPIOA_ODR

  22.     LDR R1, [R0]

  23.     BIC R1, R1, #(1<<1)

  24.     STR R1, [R0]

  25.     BL Delay

  26.     B MainLoop



  27. Delay

  28.     LDR R0, =300000

  29. DelayLoop

  30.     SUBS R0, #1

  31.     BNE DelayLoop

  32.     BX LR

  33.     NOP

  34.     ENDP

  35.     END
复制代码

4~8行:设置外部寄存器RCC_APB2ENR的第2位(IOPAEN)为1,使能GPIO A组的时钟;

5行:将0x40021018(RCC_APB2ENR的基地址+偏移地址)放入内部寄存器R0中;

6行:将0x40021018地址的值(此时RCCC_APB2ENR寄存器的值),放入内部寄存器R1;

7行:将R1的Bit2设置为1,并将设置后的结果放入R1;

8行:将R1的内容,放入R0所指向的地址,也就是将修改后的数据放入RCCC_APB2ENR寄存器;

10~14行:设置外部寄存器GPIOA_ CRL的第4:5位(MODE)为1,让GPIO A1为输出模式;

16~30行:设置外部寄存器GPIOA_ODR的第0位(ODR)先后为1和0,让GPIO A1为输出高、低电平;

32~40行:循环减R0实现延时效果;

以上汇编代码就实现了开发板用户LED灯(蓝色)交替闪烁效果,读者可以打开配套资料的“5_程序源码\0_单片机开发模式的发展\1_使用汇编开发\ Project\Led_Reg.uvprojx”工程,编译、下载,体验效果。

可以感受到,使用汇编编写程序,生涩难懂,因此越来越少的单片机使用汇编来编写代码,下面再来体验下C语言实现一样的效果。


6.3 C语言操作寄存器开发
在使用C语言操作寄存器前,仍需要先分析《开发板原理图》和《参考手册》,从而得知需要操作哪些外设寄存器,假设读者已经了解需要操作哪些外设寄存器。

本章涉及的代码位于100ASK_STM32F103_MINI开发板资料的“5_程序源码\0_单片机开发模式的发展\2_C语言操作寄存器开发\”。

使用C语言之前,需要先设置栈,如代码段 6.3.1 所示,在上电复位后立即设置栈,随后跳入main函数执行。

代码段 6.3.1 设置栈(startup_stm32f10x_md.s)

  1. ; Reset handler

  2. Reset_Handler   PROC

  3.                 IMPORT  main

  4.                 LDR     SP, =0x20000000+0x100

  5.                 BL      main

  6.                 ENDP

  7.                 END
复制代码

代码段 6.3.2 C语言操作寄存器(main.c)

  1. #define RCC_APB2ENR  (0x40021000 + 0x18)

  2. #define GPIOA_BASE   (0x40010800)

  3. #define GPIOA_CRL    (GPIOA_BASE + 0)

  4. #define GPIOA_ODR    (GPIOA_BASE + 0X0c)



  5. void delay(volatile long i)

  6. {

  7.     while (i--);

  8. }



  9. int main(void)

  10. {

  11.     volatile unsigned int *pRccApb2Enr;

  12.     volatile unsigned int *pGpioaCrl;

  13.     volatile unsigned int *pGpioaOdr;



  14.     pRccApb2Enr = (volatile unsigned int *)RCC_APB2ENR;

  15.     pGpioaCrl   = (volatile unsigned int *)GPIOA_CRL;

  16.     pGpioaOdr   = (volatile unsigned int *)GPIOA_ODR;



  17.     /* 1. 使能GPIOB的时钟

  18.       * GPIO是挂载在APB2上的,所以我们要使能APB2的外设时钟使能位

  19.       * 从RCC_APB2ENR寄存器描述中我们可以看到APB2ENR[8:2]是GPIO[G:A]时钟的控制位,控制GPIO时钟是失能或者使能

  20.       * 开发板上的LED的GPIO组是使用的GPIOA,即要使能APB2ENR[2]位,为其赋值“1”即可打开GPIOA的时钟 */

  21.     *pRccApb2Enr |= (1<<2);



  22.     /* 2. 设置GPIO为输出功能:

  23.      * MODE_0=1,PB0输出模式,输出速率最大10MHz

  24.      */

  25.   *pGpioaCrl |= (1<<4);



  26.     while (1)

  27.     {

  28.     *pGpioaOdr |= (1<<0);

  29.         delay(1000000);

  30.     *pGpioaOdr &= ~(1<<0);

  31.         delay(1000000);

  32.     }

  33. }
复制代码


主函数如代码段 6.3.2 所示。

1~4行:用宏定义了需要用到的各外设寄存器地址:RCC_APB2ENR、GPIOA_ CRL、GPIOA_ODR;

6~9行:循环递减传入的变量i,实现延时效果;

13~15行:定义指针变量;

17~19行:设置指针指向对应寄存器;

25~30行:设置RCC_APB2ENR、GPIOA_ CRL对应位;

32~38行:循环修改GPIOA_ODR实现LED灯交替闪烁;

以上代码就实现了开发板用户LED灯(蓝色)交替闪烁效果,读者可以打开配套资料的“5_程序源码\0_单片机编程模式的发展\ 2_C语言操作寄存器开发\ Project\Led_Reg.uvprojx”工程,编译、下载,体验效果。

使用C语言后,只需定义指针变量指向对应寄存器,修改该指针变量的值,即可修改对应寄存器,操作上方便了很多。


6.4 C语言使用标准库开发
前面的两种开发方式,适用于任何一款芯片,但需要仔细阅读《参考手册》找到对应寄存器,然后用指针变量指向寄存器。

ST公司为了让用户更快上手开发,产生用户粘性,将外设寄存器提前定义好,准备一些常用接口函数供用户使用,这就是标准库的雏形。

下面来感受下使用标准库的简便性。使用标准库通常不需要知道外设寄存器地址,只需要分析《开发板原理图》得知会用到哪一个引脚。

本章涉及的代码位于100ASK_STM32F103_MINI开发板资料的“5_程序源码\0_单片机开发模式的发展\2_C语言使用标准库开发\”。

首先使用C语言需要设置栈,这些初始化操作标准库已经帮忙完成了,我们只需要编写主函数即可,如代码段 6.4.1 所示。

代码段 6.4.1 C语言使用标准库开发(main.c)

  1. #include "main.h"

  2. #include "stm32f10x.h"

  3. #include "driver_led.h"



  4. void delay(volatile long i)

  5. {

  6.     while (i--);

  7. }



  8. int main(void)

  9. {



  10.     // 初始化LED

  11.     LedGpioInit();



  12.     // 点亮LED灯

  13.         while(1)

  14.         {

  15.             GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);

  16.             delay(1000000);

  17.             GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);

  18.             delay(1000000);

  19.         }

  20. }
复制代码


5~8行:循环递减传入的变量i,实现延时效果;

14行:调用编写的“LedGpioInit()”函数,初始化需要的GPIO,该函数定义在“driver_led.c”里,如代码段 6.4.2 所示;

17~23行:循环修改GPIOA_ODR实现LED灯交替闪烁;这里不再涉及寄存器操作,只需要调用标准库提供的“GPIO_WriteBit()”函数即可,该函数需要三个参数,分别是:GPIO端口、该端口引脚号、电平高低。这里操作GPIOA 1引脚,因此传入“GPIOA”、“GPIO_Pin_1”、“Bit_SET”或“Bit_RESET”,使用这些宏定义,用户基本就无须查阅《参考手册》,上手相对容易很多;

代码段 6.4.2 GPIO初始化(driver_led.c)

  1. #include "driver_led.h"



  2. /*

  3. *  函数名:void LedGpioInit(void)

  4. *  输入参数:无

  5. *  输出参数:无

  6. *  返回值:无

  7. *  函数作用:初始化LED的引脚,配置为推挽输出

  8. */

  9. void LedGpioInit(void)

  10. {

  11.     // 定义GPIO的结构体变量

  12.     GPIO_InitTypeDef GPIO_InitStructure;

  13.     // 使能LED的GPIO对应的时钟

  14.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);



  15.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;         // 选择LED的引脚

  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  // 设置为推挽输出模式

  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 引脚反转速度设置为快



  18.     // 初始化引脚配置

  19.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  20. }
复制代码

15行:使用标准库提供的“RCC_APB2PeriphClockCmd()”,传入需要设置的外设名字、是否使能;

13~22行:将GPIO属性封装为结构体,通过设置结构体成员的属性,完成对GPIO的设置;



以上代码就实现了开发板用户LED灯(蓝色)交替闪烁效果,读者可以打开配套资料的“5_程序源码\0_单片机编程模式的发展\ 3_C语言使用标准库开发\ Project\ Led_Standard.uvprojx”工程,编译、下载,体验效果。

使用标准库后,基本不涉及外设寄存器的地址,同时提供很多函数实现相关功能的操作,用户只要熟悉之后,很快就能举一反三,修改相关传入参数,实现自定义需求。


6.5 C语言使用HAL库开发
ST公司先后推出了两套主要库:标准外设库(Standard Peripherals Library)和HAL库(Hardware Abstraction Layer)。标准外设库是STM32最早发布的固件库,对STM32芯片进行了完整的封装,包含所有外设的性能特征,每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。因为发布比较早,教程比较多,目前仍有不少开发者使用。标准外设库是针对某一系列STM32芯片而设计的,没有可移植性,目前该库已将停止了更新、研发,最近几年发布的新STM32芯片已经不再支持。

HAL库是ST公司这几年极力推荐的官方库,目前支持STM32全系产品,可以说HAL库就是用来取代之前的标准外设库的。相比标准外设库,HAL库具有更高的抽象整合水平,API集中关注外设的公共函数功能,使得可以轻松实现从一个STM32产品移植到另一个不同的STM32系列产品。此外还有LL库(Low Layer),相比其它固件库更接近硬件层,一般和HAL库结合使用,可以看作是HAL库的补充。

本章涉及的代码位于100ASK_STM32F103_MINI开发板资料的“5_程序源码\0_单片机开发模式的发展\2_C语言使用HAL库开发\”。

HAL库和标准库的使用区别不大,也无需知道外设寄存器地址,主函数如代码段 6.5.1 所示。

代码段 6.5.1 C语言使用HAL库开发(main.c)

  1. #include "main.h"

  2. #include "driver_led.h"



  3. int main(void)

  4. {

  5.     // 初始化HAL库函数必须要调用此函数

  6.     HAL_Init();

  7.     // 系统时钟即AHB/APB时钟配置

  8.     SystemClock_Config();



  9.     // 初始化LED

  10.     LedGpioInit();



  11.     // 点亮LED灯

  12.     while(1)

  13.     {

  14.       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

  15.       HAL_Delay(1000);

  16.       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

  17.       HAL_Delay(1000);

  18.     }

  19. }
复制代码

6~9行:使用HAL的一些初始化操作;

11~12行:调用编写的“LedGpioInit()”函数,初始化需要的GPIO,该函数定义在“driver_led.c”里,如代码段 6.5.2 所示;

15~21行:通过调用HAL提供的“HAL_GPIO_WritePin”函数控制引脚输出的电平高低;HAL库还提供延时函数“HAL_Delay()”,用户不用再自己编写延时函数;

代码段 6.5.2 GPIO初始化(driver_led.c)

  1. #include "driver_led.h"



  2. /*

  3. *  函数名:void LedGpioInit(void)

  4. *  输入参数:无

  5. *  输出参数:无

  6. *  返回值:无

  7. *  函数作用:初始化LED的引脚,配置为上拉推挽输出

  8. */

  9. void LedGpioInit(void)

  10. {

  11.     // 定义GPIO的结构体变量

  12.     GPIO_InitTypeDef GPIO_InitStruct = {0};

  13.     // 使能LED的GPIO对应的时钟

  14.     __HAL_RCC_GPIOA_CLK_ENABLE();



  15.     GPIO_InitStruct.Pin = GPIO_PIN_1;         // 选择LED的引脚

  16.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出模式

  17.     GPIO_InitStruct.Pull = GPIO_PULLUP;         // 默认上拉

  18.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;// 引脚反转速度设置为快



  19.     // 初始化引脚配置

  20.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);



  21. }
复制代码

15行:使用HAL库提供的“__HAL_RCC_GPIOB_CLK_ENABLE()”使能GPIO A端口时钟;

13~23行:将GPIO属性封装为结构体,通过设置结构体成员的属性,完成对GPIO的设置;


以上代码就实现了开发板用户LED灯(蓝色)交替闪烁效果,读者可以打开配套资料的“5_程序源码\0_单片机编程模式的发展\ 4_C语言使用HAL库开发\ Project\ Led_Hal.uvprojx”工程,编译、下载,体验效果。

使用HAL库的体验和标准库差不多,但HAL兼顾了其它ST芯片,用户可以无缝过渡到ST其它芯片的使用。各开发模式之间的差异如表 6.5.1 所示。

2ICK}7KSL2]XHSVZ{G5YNYM.png


表 6.5.1 各开发模式差异



【总结】

本章开始讲解了一些STM32结构的基础知识,这些知识对STM32的整体理解会有很大帮助,读者应多理解。

随后介绍的四种开发模式,读者重点理解C语言操作寄存器开发和使用HAL库开发。后续的实验会以HAL库为主,但读者也应理解HAL库的本质也是操作寄存器,因此理解如何操作寄存器,对以后学习、调试,都会有帮助。     

作者:攻城狮子黄


收藏 评论0 发布时间:2022-8-30 13:39

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版