STM32 ARM Cortex-M 32 位微控制器编程简介

在这篇深入的文章中,您将了解如何使用各种开发工具为 STM32 Cortex-M 32 位微控制器开发嵌入式固件。

分享

STM32 系列是一些最流行的微控制器,广泛用于各种产品。

他们还拥有来自多个微控制器开发论坛的出色支持基础。

STMicroelectronics 的该系列微控制器基于 ARM Cortex-M 32 位处理器内核。

STM32 微控制器提供大量串行和并行通信外设,可以与各种电子元件连接,包括传感器、显示器、相机、电机等。所有 STM32 变体都带有内部闪存和 RAM。

STM32可用的性能范围非常广泛。

一些最基本的变体包括 STM32F0 和 STM32F1 子系列,它们的起始时钟频率仅为 24 MHz,并且可提供少至 16 个引脚的封装。

在另一个极端性能方面,STM32H7 的工作频率高达 400 MHz,并提供多达 240 个引脚的封装。

更高级的模型可与浮点单元 (FPU) 一起用于具有严格数值处理要求的应用程序。

这些更先进的模型模糊了微控制器和微处理器之间的界限。

最后,STM32L 子系列专为使用小电池运行的低功耗便携式应用而设计。

开发工具

需要开发工具来开发代码、对微控制器进行编程和测试/调试代码。开发工具包括:

  • 编译器
  • 调试器
  • 在线串行编程器 (ICSP)

编程STM32

通过在线串行编程器 (ICSP) 对 STM32 进行编程。

有多种软件开发工具可用于在 STM32 微控制器上进行代码开发。

这些软件工具可作为集成开发环境 (IDE) 使用,它将所有必要的工具组合到一个集成环境中。

两个常见的开发包包括:

  • Keil MDK ARM (uVison5 IDE) – MDK ARM IDE 是一个非常稳定的开发环境,可以免费下载。它允许开发最大为 32 KB 的程序大小的代码。要开发更大的程序,需要在此处购买许可版本。
  • CoIDE – 一个免费工具链,它基于精简版的 Eclipse IDE 与嵌入式 ARM 版本的免费 G​​CC 编译器集成。

还有几个其他 IDE 可用于 STM32 微控制器。

但是,本文重点介绍使用非常流行的 Keil MDK ARM uVision5 IDE 开发和烧写程序。

除了软件工具之外,还需要一个在线串行编程器 (ICSP) 来对实际微控制器上的代码进行编程和测试。

ICSP 需要通过 USB 端口将微控制器连接到 PC 软件工具。

ARM Cortex-M 微控制器支持两种编程协议:JTAG(由电子行业协会联合测试行动组命名)和串行线调试 (SWD)。

有几种支持这些协议的 ICSP 程序员可用,包括:

  • U-Link 2
  • J-Link
  • ST-Link

开发第一个应用程序

从一个现成的基本代码框架开始总是最容易的。然后,添加微控制器的特定应用和型号所需的代码。

幸运的是,STMicroelectronics 提供了一个非常有用的图形工具,称为 STM32CubeMx,它有助于为您选择的任何 STM32 微控制器创建基本应用项目。

它还可用于在微控制器的多路复用引脚上配置外设。

STM32CubeMX 工具可以从这里下载。STM32Cube 附带一套适用于所有类型外设的广泛驱动程序,并支持与代码预集成的可选 FreeRTOS(免费实时操作系统)。

以下部分详细描述了如何为 STM32F030 微控制器创建一个简单的 UART 应用程序,以响应在终端窗口上键入的任何内容。

  • 安装 STM32CubeMX 软件。
  • 运行应用程序并选择New Project。然后它将打开MCU Selector窗口,如下所示。
  • 双击以选择正在使用的微控制器型号。在这种情况下,我们使用的是 STM32F030K6。然后它会将您带到所选微控制器的引脚分配页面。
在 STM32CubeMX 中设置新项目的屏幕截图

STM32F030K6 是一个 ARM Cortex-M0 内核,具有 32KB 的闪存和 4KB 的 RAM 存储器。

示例代码启用使用 PA9 和 PA10 引脚来接收和发送串行数据的 UART,如下图绿色引脚所示。

屏幕截图显示了 STM32CubeMX 中 STM32F030K6 的引脚排列

在配置选项卡下配置 UART 设置,然后选择 UART 设置,如下所示。

在NVIC 设置选项卡下启用 NVIC 全局中断选项。

屏幕截图显示如何配置 UART 设置 STM32CubeMX

接下来,导航到Project->Settings以添加新的项目名称并选择要使用的工具链 IDE。

对于本示例,将项目名称设置为“UARTEcho”并选择 Keil-MDK5 IDE 进行项目开发。

最后,通过单击Project -> Generate Code 生成项目代码

构建和刷新代码

现在打开生成的 MDK-ARM 工程文件 UARTEcho\MDK-ARM\UartEcho.uprojx。

到目前为止,该程序只是初始化 UART 外设并在无限循环中停止。

需要注意的是,STM32Cube 生成/* USER CODE BEGIN x *//* USER CODE END x */注释块来实现用户特定的代码。用户代码必须写在这些注释块中。

每当使用修改后的配置重新生成代码时,STMCube 工具都会将用户代码保留在这些用户注释块中。

接下来,在 main.c 源文件中定义一个全局变量以从 UART 接收一个字节:

/* USER CODE BEGIN PV */
/* 私有变量 ————————————– ——————-*/
静态 uint8_t recv_data 

;
/* 用户代码结束 PV */

完成所有初始化代码后,使驱动程序接收 1 个字节。以下函数使能 RXNE 中断位。

/* 用户代码开始 2 */
HAL_UART_Receive_IT 

( & 

; 硬件1 

, & 

; 接收数据

, 1 );
/* 用户代码结束 2 */

现在,添加一个回调函数来处理接收中断并传输接收到的字节。/* 用户代码开始0 */

void HAL_UART_RxCpltCallback 

( UART_HandleTypeDef 

* huart 

)
{
HAL_UART_Transmit 

( huart 

, huart 

– > pRxBuffPtr , 1 , 1000 ) 

; } /* 用户代码结束 0 */

最后,我们需要编译代码并将其闪存(下载)到微控制器。

安装 Keil MDK ARM IDE 后,可以使用 ST-LINK V2、J-Link 和 Ulink2 的驱动程序。

默认情况下将选择 ST-Link 调试器。转到Projects–>Options for Target并在Debug选项卡中选择使用的 ICSP 编程器。

通过选择Flash->Download来刷新代码。

微控制器现在将回显通过 UART 接收到的任何数据。它可以通过使用 USB 转串口转换器连接到 PC。

在 PC 上,使用 115200-8-N-1 的设置打开带有终端应用程序的 COM 端口。

现在从终端发送的任何内容都将通过微控制器回显。

中断系统

STM32 中断系统基于 ARM Cortex M 内核 NVIC 外设。

除了 ARM 内核的 16 个中断通道外,STM32 MCU 还支持多个可屏蔽中断通道。

例如 STM32F0 MCU 系列支持 32 个可屏蔽中断。下表给出了该系列 MCU 的异常和中断向量表。

打断描述向量地址
预订的0x00000000
重置重置0x00000004
NMI不可屏蔽中断。RCC 时钟安全系统 (CSS) 链接到 NMI 向量0x00000008
硬故障所有类别的故障0x0000000C
SVCall通过 SWI 指令调用系统服务0x0000002C
待定SV系统服务的待处理请求0x00000038
系统记号系统滴答计时器0x0000003C
WWDG窗口看门狗中断0x00000040
PVD_VDDIO2PVD 和 VDDIO2 提供比较器中断(结合 EXTI 线 16 和 31)0x00000044
实时时钟RTC 中断(组合 EXTI 第 17、19 和 20 行)0x00000048
闪光Flash 全局中断0x0000004C
RCC_CRSRCC 和 CRS 全局中断0x00000050
EXTI0_1EXIT 线[1:0] 中断0x00000054
EXTI2_3EXIT 线[3:2] 中断0x00000058
EXTI4_15EXIT 线[15:4] 中断0x0000005C
TSC触摸感应中断0x00000060
DMA_CH1DMA 通道 1 中断0x00000064
DMA_CH2_3
DMA2_CH1_2
DMA 通道 2 和 3 中断
DMA2 通道 1 和 2 中断
0x00000068
DMA_CH4_5_6_7
DMA2_CH3_4_5
DMA 通道 4、5、6 和 7 中断
DMA2 通道 3、4 和 5 中断
0x0000006C
ADC_COMPADC 和 COMP 中断(组合 EXTI 线 21 和 22)0x00000070
TIM1_BRK_UP_TRG_COMTIM1 中断、更新、触发和换向中断0x00000074
TIM1_CCTIM1 捕捉比较中断0x00000078
TIM2TIM2 全局中断0x0000007C
TIM3TIM3 全局中断0x00000080
TIM6_DACTIM6 全局中断和 DAC 欠载中断0x00000084
TIM7TIM7 全局中断0x00000088
TIM14TIM14 全局中断0x0000008C
TIM15TIM15 全局中断0x00000090
TIM16TIM16 全局中断0x00000094
TIM17TIM17 全局中断0x00000098
I2C1I2C1 全局中断(结合 EXTI 23 行)0x0000009C
I2C2I2C2 全局中断0x000000A0
SPI1SPI1 全局中断0x000000A4
SPI2SPI2 全局中断0x000000A8
USART1USART1 全局中断(结合 EXTI 25 行)0x000000AC
UART2USART2 全局中断(结合 EXTI 26 行)0x000000B0
USART3_4_5_6_7_ 8USART3、USART4、USART5、USART6、USART7、USART8全局中断(结合EXTI线28)0x000000B4
CEC_CANCEC 和 CAN 全局中断(结合 EXTI 线 270x000000B8
USBUSB 全局中断(结合 EXTI 18 行)0x000000BC

扩展中断和事件控制器 (EXTI)

STM32 MCU 具有扩展中断和事件控制器,用于管理外部和内部异步事件/中断,并向 CPU/中断控制器生成事件请求,并向电源管理器生成唤醒请求。

一条或多条 EXTI 线中的每一条都映射到 NVIC 中断向量之一。

对于外部中断线,要产生中断,应配置并启用中断线。

这是通过使用所需的边沿检测对两个触发寄存器进行编程并通过将“1”写入中断屏蔽寄存器中的相应位来启用中断请求来完成的。

外部中断和 GPIO 映射

系统上可用的每个 GPIO 都可以配置为生成中断。但是每条 EXTI 中断线都映射到多个 GPIO 引脚。

例如,所有可用 GPIO 端口(A、B、C 等)上的 PIO0 将映射到 EXTI0 线。所有端口的 PIO1 都将映射到 EXTI1 线,依此类推。

一些 EXTI 行被组合成一个 NVIC 向量。例如,EXTI4_15 映射到单个向量地址,因此从 PIO4 到 PIO15 的所有中断都将有一个中断例程。

但是可以通过读取中断挂起寄存器来识别中断的来源。

使用 STM32 MCU 设计系统时要考虑的一件重要事情是选择用于中断的 GPIO 引脚。

MCU 在设备上可能有超过 16 个可用的 GPIO,但只有 16 个外部中断线可用。

例如,EXTI_0 可以映射到 PA0 或 PB0,但不能同时映射到两者。

因此,在为外部中断选择引脚时,应该选择它们,以便它们可以唯一地映射到 EXTI 线之一。

以下部分介绍如何使用 STM32 Cube 配置中断。

截图配置中断STM32CubeMX

选择配置选项卡并选择必须为其配置中断的硬件模块。模块配置窗口打开。

然后选择 NVIC 设置选项卡并启用全局中断。

启用模块中断的代码将在 HAL_<module>_MSPInit(…) 函数的 stm32f0xx_hal_msp.c 中生成。

/* USART1 中断初始化 */
HAL_NVIC_SetPriority 

( USART1_IRQn 

, 0 , 0 ) ;
HAL_NVIC_EnableIRQ 

( USART1_IRQn 

) ;

STM32 Cube 生成的代码将有所有中断的 IRQ_Handler 实现。启用中断后,代码将包含在应用程序中。

通常生成的代码已经处理了 IRQ 并清除了产生中断的标志。

然后它调用与为模块生成中断的事件相对应的应用程序回调。

作为驱动程序的一部分,STM32 HAL(硬件抽象层)为每个模块内的每种事件类型实现回调。

在此示例中,应从 stm32f0xx_hal_UART.c 文件复制Rx 传输完成回调。

驱动程序中的回调函数将使用 __weak链接器属性实现。

用户需要通过删除其中一个应用程序文件中的 __weak 属性来实现必要回调函数的副本,然后在该函数中编写所需的特定处理。

/**
* @brief Rx 传输完成回调。
* @param huart UART 句柄。
* @retval None
*/

__weak 

void HAL_UART_RxCpltCallback 

( UART_HandleTypeDef 

* huart 

)
{
/* 防止未使用的参数编译警告 */
UNUSED 

( huart 

) ;

/* 注意:这个函数不要修改,当需要回调时,
可以在用户文件中实现 HAL_UART_RxCpltCallback。
*/

}

结论

本教程介绍如何编写与 STM32 系列微控制器配合使用的应用程序。

还有其他几种编写应用程序的方法,但讨论的 STM32Cube 是一种简单直观的入门方法。

该工具简化了微控制器外设的初始化。它还提高了代码的可维护性,特别是当有需要将信号重新映射到不同引脚的硬件版本时。

使用 STM32Cube 工具的另一个优点是它可以为微控制器生成用户配置报告。

在本报告中,它详细介绍了时钟树、引脚映射和硬件模块配置,这些都非常有用。

还有几个其他代码库和示例程序可用于所有 STM32 变体。还包括对多个 IDE 的支持。

如果您的项目需要复杂的 32 位微控制器,那么我强烈推荐 STM32 系列。它们不仅功能强大且受欢迎,而且 STM32 微控制器的价格也相当实惠。