工程搭建教程——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 */
}

在这里插入图片描述
至此本教程结束,如果您觉得不错,还望老板给个赞,我会继续为大家提供相关工程教程!

附录

参考下篇博客

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是使用FreeRTOSCubeMXSTM32F4板上实现串口空闲中断的示例代码: 1. 在CubeMX中配置串口和FreeRTOS - 打开CubeMX,选择您的STM32F4板子和您想要使用的串口。 - 在“Pinout & Configuration”选项卡中,配置串口引脚。 - 在“Clock Configuration”选项卡中,配置串口时钟。 - 在“Configuration”选项卡中,启用FreeRTOS并配置任务和堆栈大小。 2. 编写串口空闲中断处理程序 在您的main.c文件中添加以下代码: ```c #include "stm32f4xx_hal.h" #include "FreeRTOS.h" #include "task.h" #include "queue.h" UART_HandleTypeDef huart1; TaskHandle_t xTaskHandle; QueueHandle_t xQueueHandle; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(xQueueHandle, &huart->Instance->DR, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void vTask(void *pvParameters) { uint8_t buffer[16]; while (1) { if (xQueueReceive(xQueueHandle, &buffer, portMAX_DELAY) == pdTRUE) { // 处理接收到的数据 } } } int main(void) { HAL_Init(); SystemClock_Config(); /* 初始化串口 */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); /* 创建队列 */ xQueueHandle = xQueueCreate(16, sizeof(uint8_t)); /* 创建任务 */ xTaskCreate(vTask, "Task", 128, NULL, 1, &xTaskHandle); /* 启用空闲中断 */ __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); HAL_UART_Receive_DMA(&huart1, (uint8_t *)&huart1.Instance->DR, 1); vTaskStartScheduler(); while (1); } ``` 在上述代码中,我们创建了一个名为vTask的任务,它会等待从队列中接收到数据。当串口接收到数据时,HAL_UART_RxCpltCallback处理程序会将数据发送到队列中。任务vTask可以使用xQueueReceive函数从队列中获取数据。 我们还启用了串口空闲中断,并使用HAL_UART_Receive_DMA函数启动DMA传输。 3. 运行代码 在编译和烧录代码后,您应该能够使用串口发送数据并在vTask任务中接收数据。串口空闲中断会在接收完成后触发,向队列中发送接收到的数据。任务vTask会从队列中获取数据并进行处理。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值