单片机与嵌入式
51单片机的寻址方式
51单片机的汇编指令系统
51汇编语言的伪指令
51汇编语言程序结构与程序示例
Keil C51程序设计
Keil C51的库函数
PIC单片机的基本结构
PIC单片机的汇编语言指令
PIC单片机的C语言编程
ATmega16单片机基本结构
ATmega16单片机的汇编语言
ATmega128单片机的结构
STM32单片机基础
使用STM32CubeMX开发STM32单片机
uC/OS-II嵌入式操作系统
uC/OS-II在STM32F10xx上的移植
FreeRTOS系统介绍
Linux系统介绍
Linux系统编程
嵌入式Linux编程
STM32是ST公司开发的基于ARM Cortex-M系列的32位单片机,在市场上很流行。但Cortex-M系列是32位单片机,内部资源很多,配置使用比较复杂,特别是项目配置很繁琐,要配置成功有比较大的难度也很耗时,而且在不同的开发平台也有差别。为了方便使用,ST公司推出了一套STM32CubeMX软件,用于通过设置一些基本功能,自动形成项目配置,并产生适应对应开发平台的一部分框架代码,开发者在此基础上再填入需要的程序代码就比较方便了。
1.STM32CubeMX的下载和安装:
STM32CubeMX软件的下载网址为:http://www.st.com/en/development-tools/stm32cubemx.html
网页下方有Get Software按钮,点击并接收相应协议后就可以下载。ST对新用户可能会要求提供一个邮件地址用于推广。
在其上方,还有对应不同系列的软件包,可以根据常用的系列进行下载,软件使用时需要安装这些软件包。
下载完成后解压,里面有个SetupSTM32CubeMX-*.exe安装文件,点击后就可以根据提示进行安装。安装完成后就会在系统菜单及桌面上产生对应的图标,点击后就可以运行。
2.STM32CubeMX的基本配置:
运行STM32CubeMX后,会显示下面的界面:
点击New Project,就会打开一个界面,用于新项目的配置:
在界面左侧可以选择需要的芯片型号,也可以根据需要的资源由软件来推荐相应的型号列表。
软件根据用户的选择,把对应的型号列表显示在下面的列表中,其中列出封装、价格、Flash容量、RAM容量、IO口数量等主要参数。点选后就可以使能上面的按钮,在其中可以查看点选芯片的特性、框图、Datasheet、相关文件及资源等。
最右一个按钮是Start Project,点击后会打开项目配置页面:
项目配置中有几个按钮,最左侧为Pinout,用于配置项目中需要使用的内部资源及相应管脚,其中SYS中的SysTick是默认配置的,一般情况下需要使用外部晶振,需要在RCC中进行配置,这里使用的是High Speed Clock(HSE),然后右侧主界面中相应的芯片引脚变绿,表示使用的管脚。
一定要注意,SYS中的Debug选项一般一定要配置,用于生成代码后烧入程序。如果忘记配置,烧入一次程序后可能无法再次用swd写入,需要通过将boot0置高才能修改,很麻烦。建议首先设置此选项。
然后是Clock Configuration,用于配置芯片内部资源的时钟。因为前面已经配置了HSE,所以这个界面中HSE就已经变蓝,表示可用,在其中可以改变频率值,这里使用常用的8MHz晶振。因为使用外部晶振,在System Clock Mux中选择HSE源,用于SYSCLK及AHB、APB总线的时钟。
然后是Configuration按钮,如果设置使用相关资源,这里可以进行进一步的配置。如果前面的一些功能配置中有冲突或时钟配置有问题,软件可以进行自动检查,并进行提示,甚至可以选择适当的时钟设置。
最后还有一个Power Consumption Calculator按钮,用于计算各种状态下的功耗,包括Run、Sleep、Stop、Standby等。
点击界面中的绿色的+按钮,可以打开设置界面,选择一种电源模式,设置对应模式使用的外设Peripherals资源,下面就能自动计算出所消耗的电流。
如果选择使用电池,还会出现一个选择电池的界面,其中有多种常用电池的参数,可以作为选用电池的参考。一般常用的备用电池是Li-MnO2,但这种电池有时不能支持运行状态,只能用于保存数据。
加入多种状态的功耗项后,会出现一个图表,这对预估系统的耗电情况非常有用,特别是电池供电情况下。
3.STM32CubeMX的菜单:
STM32CubeMX界面中只有简单的几个菜单。首先是File菜单,基本都是与项目有关,包括创建、打开、存储、关闭等,比较简单。
而Help菜单中有一个重要的菜单项,就是Install New Libraries,可以用于安装ST网站中下载的各系列的软件包,这样更方便使用。
点击这个菜单后,会打开一个New Libraries Manager界面。
左下角有一个From Local按钮,点击后出现Select文件包的界面,找到下载的各系列软件包的存放位置,安装需要的软件包。
安装软件包需要一段时间,会出现进度条提示:
安装完成后,回到库管理界面,相应的固件包列表前面的方框变绿,表示已经安装成功。
还有一个Pinout菜单,在其中可以设置或清除一些引脚的输入/输出功能,但一般是在程序中用代码设置。
最重要的是Project菜单,其中有Generate Code菜单项:
点击菜单后后出现一个设置界面,需要在其中填入需要产生的项目名,选择路径。要选择一种IDE开发平台,这里使用Keil5,所以选择MDK-ARM V5,。下面有Firmware Package设置项,如果前面安装了相应的软件包,这里就会自动选择了,否则就需要手动选择已解压的软件包存放位置。
这个界面还有几个标签按钮,可以使用默认设置,在Advanced Settings中查看已经设置的资源。这是一个最简单的演示项目,所以只用GPIO和RCC。
点击下面的OK按钮,会出现一个Code Generation提示框。
一般使用Open Project按钮,然后会自动打开电脑中安装的相应开发软件,这里使用的是Keil uVision 5。
打开刚才使用STM32CubeMX建立的项目,可以看到其中已有4个文件夹,Drivers/CMSIS、Application/MDK-ARM、Drivers/STM32F1xx_HAL_Driver、Application/User,分别放置相应的配置文件。
在主界面中打开main.c,其中引用了main.h和stm32f1xx_hal.h两个头文件,自动产生的代码中定义了SystemClock_Config()和MX_GPIO_Init()两个函数,在后面有这两个函数的代码。在自动产生的主函数main()的代码中使用了HAL_Init()、SystemClock_Config()和MX_GPIO_Init()函数,并提示了填入相应代码的位置,while (1){}中的代码是空的。最后面还定义了_Error_Handler()和assert_failed()两个错误处理函数,其中也可以填入相应的用户代码。
4.一个简单的示例:
单片机最简单的使用就是用一个引脚控制LED,这里也使用STM32CubeMX实现对STM32F103芯片一个引脚的输出电平控制。STM32单片机在上电时所有外设都是未使能的,以节省能耗。如果要使用某个端口,就需要配置RCC,使能这个端口,一般是用代码实现的。但在STM32CubeMX中,可以使用图形界面对端口引脚进行配置。在Pinout界面中,鼠标点击对应的引脚:
这里要设置的引脚是PA5,鼠标点击后出现一个设置复选列表,选择GPIO_Output点击,即设为输出引脚。
然后PA5变为绿色,表示已经使用。这时再打开Configuration标签按钮,显示设置界面:
界面中点击GPIO,出现已经设置使用的GPIO引脚,这里只有PA5。点击此列项,下方出现设置界面。
PA5的配置中,输出电平可设为低或高,GPIO模式有推挽Push Pull和开漏Open Drain两种,而最大输出速率有低、中、高三种。设置完成后,使用Project菜单的Generate Code菜单项,产生改变了的代码,其中主函数main()中的代码为:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
上述代码是系统根据用户设置自动产生的,其中只有三行有效代码,分别为HAL_Init()、SystemClock_Config()、MX_GPIO_Init(),并有相应注释,分别为系统初始化、系统时钟配置和GPIO初始化。其他注释部分则标注了用户代码放置的位置,如USER CODE BEGIN x/USER CODE END x,用户编写的代码需要放置在其间,这样使用STM32CubeMX改变配置并重新产生代码时不会被覆盖。我们需要的功能很简单,只需要加入几条语句即可:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
其中,HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET)将GPIOA端口的PIN5设为1,而HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET)则是将GPIOA端口的PIN5设为0,HAL_Delay(500)则为延时函数。
在后面的代码中,有SystemClock_Config()和MX_GPIO_Init()函数的代码,其中GPIO_Init()函数的代码为:
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
代码中,__HAL_RCC_GPIOA_CLK_ENABLE(),用于配置GPIOA的RCC,即使能GPIOA端口;后面用HAL_GPIO_Init()函数配置了GPIO端口的引脚、模式、速率等,这些代码都是按用户设置自动产生的。
可见,通过STM32CubeMX编写STM32程序要简明很多,因为很多配置都是软件按需求自动设好了,用户自己的需求是通过使用系统提供的函数写入代码中的特定位置来实现。通过这样的方式设计应用程序,避开了复杂繁琐的系统配置过程,完成设计更有效率,但一些设置方式及系统提供的函数需要时间熟悉,目前的教材中原来的编程方式比较多,需要转换。