搜索
您的当前位置:首页STM32Cube官方例程学习指南(Lu)

STM32Cube官方例程学习指南(Lu)

来源:爱问旅游网
STM32Cube官方例程学习指南

STM32CubeMX是ST官方提供的一个代码生成工具。使用该工具,通过图形化的配置方法,就能快速生成STM32的各种片上外设的初始化代码。CubeMX生成的软件工程使用HAL库,HAL库是ST以后主推的外设驱动库。另外CubeMX还提供了FATFS、FreeRTOS、LWIP、USB库等中间件的支持,配置之后生成软件工程,工程文件就包含了相应代码。 本文档以STM32F4系列为例,简要地分析官方提供的Cube例程。希望能够帮助CubeMX初学者快速掌握STM32的常用外设使用方法。文档不求全面,只讲常用的外设,对不常用的只进行概况性地描述。同时,文档只对例程进行直接分析,不对其他文件进行详述。

第一部分 准备工作

首先是下载STM32CubeF4支持包,可以到与非网ST社区搜索STM32CubeF4,然后下载

当前版本已经更新到V1.13.0。点击附件中的STM32CubeF4,转到下载链接地址。附件大小300M左右。 本人当前使用的是V1.9.0版本的,例程相差不大,后面就用V1.9.0版本的例程进行分析。

下载后解压,得到如下图的文件,其中例程放在Projects文件夹中:

1 / 34

打开Projects文件夹,可以看到前12个文件夹分别官方提供的12款评估板,后面我们仅以STM324xG_EVAL评估板的例程为讲解内容。

STM324xG_EVAL文件夹中,Examples文件夹存放的就是片上外设的使用例程。 (Applications文件夹是STM324xG_EVAL相关的一些高级应用例程,如FreeRTOS、FatFs、LwIP、USB等,有一定基础之后可以学习这里面的内容。本文不作分析。)

Examples文件夹提供了27个外设对应文件夹,每个文件夹包含若干个例程,后面将对常用的外设例程(不是全部)进行简要分析。

2 / 34

第二部分 例程分析

下面将挑选常用外设的例程进行分析,顺序是从简单的到复杂的。

第一章:GPIO

GPIO共有两个例程:外部中断和IO翻转。

1. GPIO_IOToggle

打开…\\GPIO_IOToggle\\MDK-ARM文件夹下的MDK工程,打开main.c文件。

如main.c文件开头的描述,本例程描述如何配置GPIO和通过HAL API函数使用GPIO。

看main函数:

3 / 34

分析:从注释可以看出,GPIO的控制只需要3个步骤,使能GPIO时钟、配置GPIO模式、控制GPIO状态。前两个步骤的代码不需要用户手动输入,完全有STM32CubeMX生成,用户只需要在CubeMX中用图形化界面进行配置。(详细操作步骤可参考本人编写的STM32Cube学习笔记,或者其他STM32Cube入门教程。)步骤3的重点在 HAL_GPIO_TogglePin()函数,在控制GPIO反转的。其他控制GPIO输出状态的函数还有HAL_GPIO_WritePin()。

2. GPIO_EXTI

该例程演示如何使用GPIO的外部中断功能。

打开…\\GPIO_EXTI\\MDK-ARM文件夹下的MDK工程,打开main.c文件。先看main函数:

main函数只有个语句,分3个部分。第一部分是系统时钟配置。第二部分是板级支持配置,本例中是初始化两个LED控制口。第三部分是配置外部中断。这三个部分的代码功能都可以通过CubeMX配置生成,不需要用户输入。

最后,要在回调函数中实现中断响应的功能代码。

HAL_GPIO_EXTI_Callback()函数是HAL库的外部中断回调函数,所有的外部中断都是使用该函数。然后在处理时,判断是哪个引脚号对应的中断。

第二章:UART

UART共有三个例程。

4 / 34

1. UART_Printf

打开…\\UART_Printf\\MDK-ARM文件夹下的MDK工程,打开main.c文件。

如main.c文件开头描述,本例演示了如何将printf()函数的输出功能映射到串口上。

看main函数:

main函数分为3部分。第一部分是系统初时钟配置。第二部分是初始化UART。第三部分是使用printf()函数输出一个语句。在126~133行,就是实现过程。

5 / 34

其中PUTCHAR_PROTOTYPE是一个宏,该宏已经在main文件开头给出。

因此,对于MDK-ARM使用的编译器,126~133的函数等效于。

实现该函数并包含stdio.h文件之后,程序中就可以用printf()通过UART输出字符串了。

2. UART_Hyperterminal_IT

打开…\\ UART_Hyperterminal_IT\\MDK-ARM文件夹下的MDK工程,打开main.c文件。 该例程演示如何使用串口发送和接收中断。

看main函数:

在main函数中已经标注了各个步骤的序号。步骤1就是初始化串口,和上一个例子形式差不多。步骤2是演示HAL_UART_Transmit_IT()函数的用法,该函数的功能是将aTxStartMessage[]数组的TXSTARTMESSAGESIZE个字节数据发送出去,并使能发送完成中断,当发送完成后会调用一次HAL_UART_TxCpltCallback()回调函数。步骤3是演示HAL_UART_Receive_IT ()函数的用法,用法和发送函数类似。功能是使能UART接收中断,接收的数据存入缓冲数组aRxBuffer[],在接收数据量达到RXBUFFERSIZE字节时调用一次HAL_UART_RxCpltCallback()回调函数。用户可以在回调函数中添加数据处理的代码。

6 / 34

步骤4是等待串口空闲。步骤5是再次发送数据。

步骤6、7、8,过程和前面类似,注释已经说明清楚。

本例中回调函数的内容很简单,就是点亮LED。

3. UART_Hyperterminal_DMA

该例程演示如何使用串口DMA发送和接收及中断,和UART_Hyperterminal_IT结构完全相同,只是把函数的后缀都改成了_DMA。而且回调函数都是一样的。

7 / 34

第三章:TIM

TIM共有18个例程。定时器是STM32中用途最多变的外设。下面分析几个典型应用例程。

1. TIM_TimeBase

打开…\\TIM_TimeBase\\MDK-ARM文件夹下的MDK工程,打开main.c文件。 该例程是定时器最基本的应用,即定时中断功能。

看main函数:

一共只有两个步骤。步骤1是配置定时器,步骤2是启动定时器并使能中断。步骤1是通过CubeMX配置生成代码。步骤2需要用户手动添加。

8 / 34

HAL_TIM_PeriodElapsedCallback()是定时器Update中断回调函数。所有定时器的更新中断都使用该回调函数接口。因此,如果开启了多个定时器更新中断时,应该对中断源进行判断,如下图:

2. TIM_PWMOutput

打开…\\TIM_PWMOutput\\MDK-ARM文件夹下的MDK工程,打开main.c文件。 该例程演示怎么使用定时器的PWM模式产生4路PWM信号。

看main函数:

步骤1是配置TIM外设。步骤2是配置PWM通道。这两步骤的代码可由CubeMX配置生。

9 / 34

步骤3是启动各个PWM通道,就是调用HAL_TIM_PWM_Start()函数。该步骤的代码要用户添加。 经过上述3个步骤,就可以在相应引脚输出PWM信号了。

3. TIM_InputCapture

打开…\\ TIM_InputCapture \\MDK-ARM文件夹下的MDK工程,打开main.c文件。 该例程演示TIM的输入捕获功能,用该功能测量信号的频率或周期。

看main函数:

步骤1配置TIM外设,步骤2配置输入捕获通道。

10 / 34

步骤3启动输入捕获功能,并使能相应中断。

对捕获值的处理在中断回调函数中进行。一共捕获两次,两次捕获值的差值就是乘以定时器时钟周期,就得到信号的周期,其倒数就是信号频率。

4. TIM_PWMInput

该例程演示用TIM的输入捕获功能能测量PWM信号的占空比。 打开…\\ TIM_PWMInput \\MDK-ARM文件夹下的MDK工程。

11 / 34

关键步骤就是同一个定时器开启了两个输入捕获通道,一个捕获上升沿,另一个捕获下降沿。

在捕获中断回调函数中进行数据处理。两次相邻的上升沿的时间差就是PWM信号周期,这两次上升沿之间有个下降沿,该下降沿和第一次上升沿的时间差就是PWM信号的占空比。

5. TIM_OCActive

该例程演示用TIM的比较匹配功能输出4路PWM信号。 打开…\\ TIM_OCActive \\MDK-ARM文件夹下的MDK工程。

步骤1配置TIM外设。

步骤2配置各通道的输出比较参数,包括输出模式、极性、比较值等。

12 / 34

步骤3点亮LED1,这一步无关紧要。 步骤4启动各通道比较匹配输出功能。

6. TIM_OCInactive

该例程和TIM_OCActive的步骤完全相同,只是PWM输出信号的进行了取反,并且在步骤4中启动个通道时使能了比较匹配中断。最后在中断函数中分别控制LED的熄灭。

7. TIM_OCToggle

该例程演示如何用TIM的比较输出功能的翻转模式,输出4路频率不同的50%占空比的方波信号。 打开…\\ TIM_OCToggle \\MDK-ARM文件夹下的MDK工程。

步骤1配置TIM外设。

13 / 34

步骤2配置输出比较通道参数,包括输出模式、极性、比较值等。

步骤3启动各通道的输出比较功能,并使能中断。

关键的步骤是中断回调函数中。因为其实TIM硬件并不能同时输出多路不同频率的PWM信号,这里是通过不断修正各个通道的比较值,才实现了4路不同频率的方波信号。

8. TIM_OnePulse

该例程演示如何用TIM输出单脉冲信号。通过通道2输入信号,上升沿触发通道1产生脉冲信号。 打开…\\ TIM_OnePulse \\MDK-ARM文件夹下的MDK工程。

14 / 34

看main函数:

步骤1配置TIM外设。

步骤2配置通道1为单脉冲模式,输入通道是通道2。

步骤3启动单脉冲通道2。

从步骤1的注释中,详细描述了单脉冲的的产生过程和参数计算。

15 / 34

9. TIM_DMA

该例程演示通过TIM更新请求触发DMA更新TIM的输出比较值,以改变PWM的占空比。 打开…\\TIM_DMA \\MDK-ARM文件夹下的MDK工程。

看main函数:

步骤1配置TIM外设。在此RepetitionCounter是一个重要参数,等于3就是3个周期触发一次更新请求。

步骤2配置PWM通道参数,包括输出模式、极性、脉冲宽度。步骤3以DMA模式启动PWM输出,注意HAL_TIM_PWM_Start_DMA()函数的最后两个参数,一个是数据地址,一个是数据量。

程序运行的过程:TIM的定时周期由变量uhTimerPeriod确定,由于RepetitionCounter=3,TIM经过3个定时周期就触发一次DMA传输。DMA传输是将aCCValue_Buffer[]的数据传入TIM的CHANNEL_3的比较匹配寄存器中,即改变PWM的占空比。第一次DMA传输的是aCCValue_Buffer[0],第二次传输aCCValue_Buffer[1],第三次传输aCCValue_Buffer[2]。三次DMA传输就完成了整个循环周期。第四次又传输aCCValue_Buffer[0],如此往下循环。

10. TIM_DMABurst

该例程演示通过TIM更新请求触发DMA突发传输更新TIM的ARR、RCR、CCR1寄存器的值,以改变PWM的周期、占空比。

打开…\\TIM_DMABurst \\MDK-ARM文件夹下的MDK工程。

16 / 34

步骤1配置TIM外设。

步骤2配置PWM通道。步骤3启动PWM输出。步骤4启动DMA突发传输。

注意HAL_TIM_DMABurst_WriteStart()中几个被标注的参数,他们只有可用的有效取值,查看该函数在stm32f4xx_hal_tim.c的位置,有详细的说明。

该例程的运行过程,在…\\TIM_DMABurst 文件夹的readme.txt文件有描述。

“每次更新的DMA请求,DMA就传输3个Half Word到定时器的寄存器,起始寄存器为ARR。 在DMA更新请求中,0x0FFF被传入ARR,0x0000传入RCR,0x0555传入CCR1。”

对比例程代码,传输3个Half Word,这是由HAL_TIM_DMABurst_WriteStart()的最后一个参数值TIM_DMABURSTLENGTH_3TRANSFERS确定的。传输的传输的三个值0x0FFF、0x0000、0x0555,就是数组aSRC_Buffer[3]的3个元素。对应的三个寄存器ARR、RCR、CCR1,它们的地址是连续的。触发事件是TIM更新,由参数TIM_DMA_UPDATE确定。

readme.txt的描述传输单位是“Half Word”,可能有误。因为HAL_TIM_DMABurst_WriteStart()的第四个参数的类型是(uint32_t*),而且TIM的所有寄存器占用空间是32bit(虽然都只使用了低16bit),即上面的ARR、RCR、CCR1实际地址间隔是4字节。所以可以判断,DMA传输的单位是Word而不是Half Word。

17 / 34

11. TIM_ComplementarySignals

该例程演示使用TIM1产生3对互补PWM信号。

打开…\\ TIM_ComplementarySignals \\MDK-ARM文件夹下的MDK工程。

步骤1是TIM外设基本配置。

步骤2配置PWM通道占空比等参数,另外还设置了互补通道的死区时间、参数锁定等。

18 / 34

步骤3就是启动各个PWM通道和互补通道的输出。

12. 另外7个例程只作简要说明 ①TIM_6Steps例程:

演示如何用高级定时器输出6步PWM信号,这个在无刷电机控制中使用比较多。 readme.txt文件给出了例程的说明,并给出了6步状态表,以及各通道的波形示意图。

19 / 34

②TIM_7PWMOutput例程:

演示如何用定时器输出7路PWM信号。它们的频率是相同的,且每一对互补输出引脚的占空比是联动的。

③TIM_Synchronization和④TIM_ParallelSynchro例程: 这两个例程是差不多的,都是演示定时器并行同步。它们的readme.txt都有一个TIM连接示意图。

两个例程都是用一个定时器触发TIM3和TIM4,使这两个定时器同步。

⑤TIM_CascadeSynchro例程:

演示如何将TIM串联使用,将一个TIM的事件输出作为另一个TIM的触发输入。

20 / 34

⑥TIM_ExtTriggerSynchro例程:

和TIM_CascadeSynchro例程相似,只是TIM1使用外部信号触发进行启动和停止。

⑦TIM_Encoder例程: 演示编码器接口的使用。

第四章:ADC

ADC共有7个例程。

21 / 34

1.ADC_RegularConversion_Polling

这是最简单和常用的方法,即查询。使用方法非常简单。

步骤1配置ADC外设,步骤2配置ADC通道。这两个步骤在CubeMX中进行配置即可,不需要用户添加代码。

步骤3~5是要用户添加的。步骤也很简单,就是调用划线的那几个函数:启动转换、等待转换结束、查询状态、获取转换值。

22 / 34

2.ADC_RegularConversion_Interrupt 演示ADC转换完成中断的使用。

步骤非常简单。步骤1、2配置ADC外设和ADC通道。步骤3调用HAL_ADC_Start_IT()函数启动ADC转换并使能转换完成中断。

然后在ADC转换完成中断回调函数中,获取转换值。

3.ADC_RegularConversion_DMA 演示ADC转换+DMA的使用。

23 / 34

步骤和ADC_RegularConversion_Interrupt相同。步骤3中调用的是HAL_ADC_Start_DMA()函数,转换完成后转换值会通过DMA传输到变量uhADCxConvertedValue中,并产生一次转换完成中断。

在本例中,ADC转换完成中断回调函数没有作实质性的数据处理。实际应用中,可在此添加对转换值的处理代码。

4. ADC_TriggerMode

演示用TIM触发ADC转换的使用。

步骤1配置TIM8,设置UPDATE为OutputTrigger信号。 步骤2配置ADC,设置T8_TRGO为转换触发信号。 步骤3启动ADC转换,并使能中断。 步骤4启动TIM8。

运行时,每次TIM8产生更新信号,就触发一次ADC转换,并产生一次中断。

在ADC转换完成中断回调函数中,获取转换值。

5. ADC_InjectedConversion_Interrupt 演示ADC注入组转换的使用。

步骤1配置ADC。在ADC_Config()函数中,还配置了一个规则通道和一个注入通道。 步骤2是启动规则通道的转换,并使能中断。

24 / 34

步骤3是延时1秒钟。

步骤4启动注入通道的转换,并使能中断。

规则通道和注入通道的转换值,分别在不同的中断函数中获取。

6. ADC_DualModeInterleaved

演示ADC1和ADC2交错采样的应用。

基本步骤很简单。步骤1配置ADC1和ADC2外设。

在ADC_Config()函数中,除了给ADC1和ADC2分别配置了一个规则通道,还有一个重要步骤:多ADC模式配置,即多个ADC联合采样,这里配置为双ADC交错模式。

步骤2启动ADC2。

步骤3启动ADC1和ADC2多模转换,使能DMA并使能中断。

25 / 34

在本例的中断回调函数中,没有作数据处理。

本例程中ADC1和ADC2联合工作的过程,可以在..\\ADC\\ADC_TripleModeInterleaved文件夹的simulation.xls文件中看到示意图。

7. ADC_TripleModeInterleaved

该例程和ADC_DualModeInterleaved类似,只是增加了ADC3。其工作过程如下图所示。

注意,ADC_Config()函数中,步骤7配置通道时用的模式参数为ADC_DUALMODE_INTERL,即双模交错。本例要演示的是3个ADC交错采样,因此应为ADC_TRIPLEMODE_INTERL。本人为进行实测验证,在使用本例做参考时,请先进行验证。

26 / 34

第五章: DAC

DAC只有2个例程。

1. DAC_SimpleConversion

演示最基本的DAC转换的使用。

步骤1配置DAC外设,步骤2配置DAC通道。

步骤3设置转换数据,步骤4启动DAC转换。

2. DAC_SignalsGeneration 演示用DAC产生信号。

该例程中包含了两种信号的产生方法,一种是使用硬件直接产生三角波,另一种是通过TIM+DMA+ADC的实现阶梯波。后一种是产生波形的通用方法。

27 / 34

本例程中,用按键选择输出的波形。两种波形都需要TIM触发DAC的转换。

DAC_Ch1_TriangleConfig()函数的关键步骤,就是调用HAL_DACEx_TriangleWaveGenerate()进行三角波发生配置。

DAC_Ch1_EscalatorConfig()函数才是本例程的重点。

通过配置TIM6的TRGO作为DAC转换触发信号,并配置DMA传输,在触发转换时就循环将aEscalator8bit[]的元素传递到DAC转换输出。

28 / 34

第六章: DMA

DMA只有2个例程,都是MemToMem的应用,和外设相关的DMA例程放在了外设例程集文件夹中。

1. DMA_FLASHToRAM

演示用DMA将数据从FLASH传输至RAM。关键代码是DMA_Config()函数的最后几个步骤。

要特别注意的是,步骤4和步骤7是需要用户添加的代码,DMA_Config()函数的其他代码都可由CubeMX配置生成。

步骤4是指定回调函数,DMA的回调函数有4个,可查看stm32f4xx_hal_dma.h中DMA_HandleTypeDef结构体定义。

步骤7设置源和目标指针、传输大小,启动DMA传输,并使能中断。

2. DMA_FIFOMode

该例程和DMA_FLASHToRAM功能完全相同,只是在配置的时候使能了FIFO。在CubeMX配置DMA的MemToMem模式时,默认使能FIFO,且无法禁止。

第七章: FLASH

FLASH只有2个例程,下面只分析最常用的擦写应用例程。

29 / 34

FLASH_EraseProgram

演示FLASH的擦除和写入操作。看main函数:

步骤1是解锁FLASH,这是擦除或写入操作FLASH的必要步骤。 步骤2是擦除,HAL_FLASHEx_Erase()函数使用了一个结构体,该结构体指定了擦除的起始扇区号、扇区数量等参数。

步骤3是涉及到缓存操作安全的,阅读注释说明即可。如果没有涉及到缓存,可以忽略。

步骤4是按Word写入FLASH。这里写入的数据都是DATA_32,其值是0x12345678。 步骤5是锁定FLASH。

30 / 34

步骤6是回读数据,验证写入是否正确。在应用中,此步骤是可选的。

要特别注意GetSector()函数,其功能是获取某个FLASH地址所在扇区号。该函数用了很多个if…else语句来实现,是因为STM32F4xx的FLASH扇区大小不一致。可以查看F4的资料,或者直接看本例的main.h文件:

F4把最大1M字节的FLASH划成了不均等的12个扇区,使用的时候一定要注意。

第八章: RTC

RTC有4个例程,下面只分析最常用的日历例程。

31 / 34

RTC_Calendar

演示如何使用RTC实现一个时钟/日历。看main函数:

步骤1配置RTC外设。(注意:这里并没有设置日期和时间。)

步骤2检测备份寄存器RTC_BKP_DR0是否为0x32F2。

如果不是,说明RTC已经被复位过了,即当前RTC的值是不可信的,要重新设置RTC时间。如果是,则只清除RESET_FLAG。

这里的0x32F2没有特殊含义,只是在RTC_CalendarConfig()函数中,写入RTC_BKP_DR0的值也是0x32F2。只要这两个值一致且不等于0即可。

步骤3就是读取RTC时间,并显示或者打印输出。

32 / 34

RTC_CalendarConfig()函数就是RTC时间重置函数。

HAL库对日期和时间设置分开用两个函数进行设置。设置日期用HAL_RTC_SetDate(),设置时间用HAL_RTC_SetTime()。

RTC_CalendarConfig()函数的第三步是向RTC_BKP_DR0备份寄存器写入0x32F2。 注意:用CubeMX配置生成代码时,main函数中的步骤1和RTC_CalendarConfig()函数步骤1、2是被放在MX_RTC_Init()函数中的。这样就会造成,每次上电都进行日期和时间的重置。这是不符合实际应用要求的。

所以,应该参考本例程的做法,将这两部分分开处理,利用备份寄存器判断是否需要重置RTC。

第九章: 其它例程简介

..\\CRC\\CRC_Example

演示如何使用STM32的CRC模块计算CRC。

只需要两个步骤。

33 / 34

..\\CRYP

这4个例程演示了DES、TDES和AES三种加密/解密算法的使用方法。

..\\HASH

这3个例程演示了几种HASH算法的使用方法。

.. \\IWDG\\IWDG_Example 独立看门狗的使用例程。

.. \\WWDG\\WWDG_Example 窗口看门狗的使用例程。

.. \\RNG\\RNG_MultiRNG

演示使用硬件模块生成随机数。

.. \\SMARTCARD\\SMARTCARD_T0

演示了智能卡的应用,使用的是T0通讯协议。所用外设是UART。因为程序包含了T0通讯协议处理,所以看上去比较复杂。

STM32Cube提供了smartcard的底层驱动,即stm32f4xx_hal_smartcard.c和.h文件,这属于HAL库。本例中ST还提供了smartcard 的T0协议支持文件,即smartcard.c和.h文件,这两个文件不属于HAL库。

S.D.Lu 于 深圳 2016年9月

E-mail:547068172@qq.com

34 / 34

因篇幅问题不能全部显示,请点此查看更多更全内容

Top