工程搭建教程——CubeMX+STM32F4+FreeRTOS+USART1基础工程搭建
前言
内容简介:本文介绍使用CubeMX与Keil工具,对STM32F4进行基础工程搭建、FreeRTOS系统搭建与USART1串口的收发小实验。
详细介绍:
个人感觉,嵌入式比如STM32,学的时候不试试搭建系统,和用Arduino可能没有什么区别,甚至用起来可能还比Arduino更难用。笔者也是在这个思想的引导下,尝试自己学习了一些FreeRTOS的使用方法。
FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对μC/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。——百度百科
有信心尝试说自己想尝试设计更稳定的系统的同学自然是应该去试一试,这些实时操作系统内核给单片机系统带来的功能改善。
同样的,随着工程进一步复杂,不可能说我的系统就像Arduino写个简单的loop函数那样不容易出错。在这些嵌入式系统的编写过程中,会遇到各种各样的错误,需要各位一点点自习排查错误所在。
硬件参考:
这里我使用了STM32F401CCU6开发板作为工程搭建的平台(便宜又好用)。
此外需要ST-link下载器(下载程序专用、使用SWD接口)和CH340通讯器(用于串口通讯)作为辅助工具,可以考虑加块面包板组装下,用起来方便一点。
两个小工具随便买个就行,win10系统也能自动配置驱动。
文件保存方法:
CubeMX好像不兼容中文,建议在自己资料盘建立一个英文目录用于工程搭建。
没啥其他讲究
一、硬件连接示意
使用ST-link进行系统调试
使用CH340进行串口通讯,将RX接入PA9,TX接入PA10,记得接一下地线。
我使用的板子是这样接的。
这样的结构会占用两个USB接口,略有麻烦,下篇文章将会介绍蓝牙的接入方法。
二、CubeMX工程设置
1、STM32F401基础配置
启动软件后,使用ACCESS TO MCU SELECTOR
选择自己使用的芯片,我这里使用STM32F401CCU6作为平台,有其他需要的同学,直接换,不用担心配置问题。Start Project
Pinout&Configuration
系统配置界面,左侧栏框是各个外设的设置区,我们先操作“Pinout&Configuration”选栏
“RCC”:配置高速时钟源,选择Crystal/Ceramic Resonator
“SYS”:配置Debug方式,选择Serial Wire。
配置Timerbase Source,这里是由于FreeRTOS的缘故,我们使用TIM1定时器。
Clock Configuration
时钟树他本来长这个样
这里我们需要注意几个部分。
变量名 | 意义 | 推荐值 |
---|---|---|
Input frequency | 外部晶振频率 | 看自己用的板子,这里我们用25Mhz |
HCLK | 系统时钟频率 | 建议直接最大值(比如84MHz) |
PLL Source Mux | 内部晶振或外部晶振 | 这里用外部HSE |
简单地说,选择HSE后,改写HCLK值,系统可以自动部署其他变量,结果像下图一样,
Project Manager
工程名称与工程位置自按需设置,Toolchain/IDE选择自己所用的编译器,比如MDK-ARM V5.27。选择最新版FW_F4库函数。
至此就可以点击GENERATE CODE生成工程文件了
2、生成工程文件夹介绍
相关工程文件夹功能如下:
Core 存放上层实现代码,比如各位封装的库可以扔这里,其中h头文件存在Inc文件夹中,c库文件存在Src文件夹中。
Drivers 存放驱动文件,比如HAL库。
MDK-ARM存放工程文件,比如Keil的工程文件就在这里。
相关驱动随时可以使用FreeRTOS_test01.ioc进行改写,但请留意下Project Manager下的 Code Generator,记得Keep User Code when re-generating,具体写法待会儿会讲。
至此可以跳到 处,尝试下自己的代码有没有问题。
3、FreeRTOS配置与串口配置
FreeRTOS配置
选择Middleware-FreeRTOS
Interface中选择CMSIS_V2
没错,这样就能用了
此外,留意下下边Tasks and Queues,其中的defaultTask我们之后会用到。
串口配置
选择Connectivity-USART1
Mode中选择Asynchronous
底下Parameter Settings可以考虑改一改波特率,具体看自己选用值,默认值115200,下一篇博客中使用蓝牙作为通讯器,将会改写这个波特率。
!!!此外留意下串口中断的问题,由于FreeRTOS只允许5以上的中断级别,需要中断的话请设置大于等于5的值,具体操作会在下一篇蓝牙中讲。
请不要忘记生成相关代码
三、Keil代码改写
1.无FreeRTOS编写
对于大部分使用正点原子教程的同学,初见这个工程树可能会有些手足无措,对于6个月前的我也是这样,因此这里我会介绍下这个工程树应该怎么用
CubeMX工程有个特点,用户只能在
/* USER CODE BEGIN*/
/* USER CODE END */
之间编写代码。在这里编写,即便是重新生成工程文件,也不会被改写。
main.c文件中,请定位到main函数中,我们先做个简单的实验(如果同学已经配置FreeRTOS,请用双斜杠屏蔽掉osKernelStart();,这样任务调度就不会启动),我们在while函数中加入串口传输信息。
main.c
/* USER CODE BEGIN PV */
uint8_t USART1_BUF[] = "Hello world\r\n";
/* USER CODE END PV */
/* Start scheduler */
//osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_UART_Transmit(&huart1,USART1_BUF,sizeof(USART1_BUF),0xffff);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
编译后上传单片机测试,留意按一下重启按钮,效果如图。
2.使用FreeRTOS任务编写
上一个方案我们使用while直接循环,下边我们使用FreeRTOS的任务实现效果。
打开freeRTOS.c文件,进行如下代码编写
freeRTOS.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
uint8_t USART1_BUF2[] = "Hello FreeRTOS\r\n";
/* USER CODE END Variables */
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
HAL_UART_Transmit(&huart1,USART1_BUF2,sizeof(USART1_BUF2),0xffff);
osDelay(1000);
}
/* USER CODE END StartDefaultTask */
}
请留意回到main.c中把osKernelStart();还原了。
其中USART1_BUF的信息不会被发送,原因在于osKernelStart将会开启程序调度,也就是说while (1)中的函数都不可能会运行,请各位自行删除掉多余代码。可以把USART1_BUF2改成USART1_BUF。
3.printf重映射
这里进行printf函数重映射,使得可以直接使用printf在串口一中打印数据,定位到usart.c文件中。
usart.c
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,10);
return(ch);
}
/* USER CODE END 1 */
回到FreeRTOS.c中,编写代码
freeRTOS.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "usart.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
uint8_t USART1_BUF[] = "Hello FreeRTOS\r\n";
/* USER CODE END Variables */
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
printf("USART1: %s", USART1_BUF);
osDelay(1000);
}
/* USER CODE END StartDefaultTask */
}
至此本教程结束,如果您觉得不错,还望老板给个赞,我会继续为大家提供相关工程教程!
附录
参考下篇博客