当前位置: 首页 > news >正文

使用STM32CubeMX和Keil在STM32上创建并运行一个简单的FreeRTOS多任务程序

目标

利用FreeRTOS运行两个任务,分别为点灯和OLED屏的显示。

利用STM32CubeMX生成Keil工程和相关初始化代码

知识回顾

之前已经利用STM32CubeMX生成过Keil工程和相关初始化代码了,可以去回顾一下,详情见:https://blog.csdn.net/wenhao_ir/article/details/146909781

选择芯片

打开STM32CubeMX,然后按下面的截图依次操作:
在这里插入图片描述
STM32F103C8T6:
在这里插入图片描述

在这里插入图片描述
双击上图红线的部分启动创建工程:
在这里插入图片描述

System Core配置

配置RCC(时钟源选择)

在这里插入图片描述
在这里插入图片描述

配置SYS(调试接口选择)

在这里插入图片描述

配置GPIO(配置PC组的第13个引脚为输出引脚)

接下来对GPIO的PC组的第13个引脚进行选择配置。
首先切换到“Pinout&Configuration项”:

在这里插入图片描述
然后按下面的操作找到引脚:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
设置成输出引脚:
在这里插入图片描述
在这里插入图片描述
这样对GPIO引脚的配置就完了。

配置I2C1控制器

在这里插入图片描述
在这里插入图片描述
参数那里用默认的配置就行了。

Clock Configuration(时钟配置)

在这里插入图片描述
在这里插入图片描述
输入完后点击回车键:
在这里插入图片描述
计算完成后的截图如下:
在这里插入图片描述

配置FreeRTOS

FreeRTOS的版本选择

在这里插入图片描述
在这里插入图片描述

FreeRTOS的核心参数配置

各界面尺寸调整下,把“Config parameters”调整到方便查看的大小:
在这里插入图片描述
看下FreeRTOS的关键参数对不对:
在这里插入图片描述

FreeRTOS的任务管理配置

使用 STM32CubeMX,可以手工添加任务、队列、信号量、互斥锁、定时器等等。但是本
课程不想严重依赖 STM32CubeMX,所以不会使用 STM32CubeMX 来添加这些对象,而是手写代
码来使用这些对象。
使用 STM32CubeMX 时,有一个默认任务,此任务无法删除,只能修改其名称和函数类型,
如下图所示:
在这里插入图片描述

工程项的配置

K003_FreeRTOS_my1
在这里插入图片描述
这里说明一下为什么Firmware Package Name and Version那里要改为V1.8.5,因为V1.8.6与之前在博文 https://blog.csdn.net/wenhao_ir/article/details/146674379 中安装的STM32F1xx_DFP不兼容。

在这里插入图片描述

生成工程

以上内容配置完成后,就可以点击生成工程了。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

用Keil打开生成的工程并配置好Debugger

用Keil打开生成的工程

在这里插入图片描述

配置好Debugger

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

添加LED的driver代码并进行测试

添加LED的相关C文件到工程

在工程目录E:\Keil_project\K003_FreeRTOS_my1\Drivers中新建目录my_driver
在这里插入图片描述

下载并解压:01_freertos_template.zip
在这里插入图片描述

在这里插入图片描述
把下面这4个文件复制到目录E:\Keil_project\K003_FreeRTOS_my1\Drivers\my_driver
在这里插入图片描述

在这里插入图片描述
说明一下,其实这里我们是想用driver_led.c,但是driver_led.c用到了driver_timer.c,所以driver_timer.c也要一并复制过来。

工程中增另一个group来添加以上文件:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
把目录E:\Keil_project\K003_FreeRTOS_my1\Drivers\my_driver添加到工程 的include目录中:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主函数中添加相关代码

打开文件E:\Keil_project\K003_FreeRTOS_my1\Core\Src\freertos.c
然后加入下面的代码:

# include "driver_led.h"

......

Led_Test();

在这里插入图片描述

编译工程

在这里插入图片描述
在这里插入图片描述

烧写测试

在这里插入图片描述
在这里插入图片描述
然后发现绿灯一闪一炒了~~~~测试成功。

添加OLED的driver代码并进行测试

先把OLED模块插到开发板上

在这里插入图片描述

添加OLED的相关C文件到工程

注意:以下的操作是在上一个目录的基础上进行的。

复制下面4个文件到目录E:\Keil_project\K003_FreeRTOS_my1\Drivers\my_driver
在这里插入图片描述
在这里插入图片描述

然后工程中添加上文件driver_lcd.cdriver_oled.c
在这里插入图片描述
说明一下:driver_lcd.c是对driver_oled.c进行调用,也就是说driver_lcd.c是更抽象的一层。
在这里插入图片描述
在这里插入图片描述

复制字库文件到相关目录

在这里插入图片描述
上面这个文件复制到:E:\Keil_project\K003_FreeRTOS_my1\Drivers\my_driver
在这里插入图片描述

主函数中添加相关代码

# include "driver_lcd.h"
......
LCD_Test();

在这里插入图片描述
在这里插入图片描述

编译工程

在这里插入图片描述
在这里插入图片描述
上面的警告不用管。

烧写测试

在这里插入图片描述
此时发现OLED屏有显示了。

编写程序实现两个测试程序同时运行

代码修改和编写

因为我们在工程中引入了FreeRTOS,所以虽然两个测试程序都是while循环,所以还是可以同时运行:
在这里插入图片描述
在这里插入图片描述
具体的源码分析见视频的第2分44秒开始看…

修改E:\Keil_project\K003_FreeRTOS_my1\Core\Src\freertos.c的函数StartDefaultTask,函数StartDefaultTask是第一个任务的回调函数:
在这里插入图片描述
依照已有的 defaultTaskHandle再创建一个名叫LcdTask的任务:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

freertos.c修改后的完整源代码

修改后的E:\Keil_project\K003_FreeRTOS_my1\Core\Src\freertos.c完整源代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
# include "driver_led.h"
# include "driver_lcd.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
osThreadId_t LcdTaskHandle;

const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

const osThreadAttr_t LcdTask_attributes = {
  .name = "LcdTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

void LcdTask(void *argument);

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
	LcdTaskHandle = osThreadNew(LcdTask, NULL, &LcdTask_attributes);
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* 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 */
	Led_Test();
  /* USER CODE END StartDefaultTask */
}

void LcdTask(void *argument)
{
	LCD_Test();
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

再修改下driver_oled.c

然后我们把E:\Keil_project\K003_FreeRTOS_my1\Drivers\my_driver\driver_oled.c中的函数OLED_Test也修改一下,使最终我们的OLED屏上能不断计数。
在这里插入图片描述

void OLED_Test(void)
{
	int cnt = 0;
	
  OLED_Init();
	// 清屏
	OLED_Clear();

    
	while (1)
	{
		// 在(0, 0)打印'A'
		OLED_PutChar(0, 0, 'A');
		// 在(1, 0)打印'Y'
		OLED_PutChar(1, 0, 'Y');
		// 在第0列第2页打印一个字符串"Hello World!"
		OLED_PrintString(0, 2, "Hello World!");
		OLED_PrintSignedVal(0, 4, cnt++);
	}
}

编译运行

在这里插入图片描述
在这里插入图片描述

下载测试

在这里插入图片描述
在这里插入图片描述
然后我们发绿色的LED在闪,同时OLED屏上也不断在计数…
在这里插入图片描述

附完整工程文件

https://pan.baidu.com/s/17m8R7hpnigDqcmNST8Pd_w?pwd=h9rx


文章转载自:
http://boughten.zzyjnl.cn
http://anthology.zzyjnl.cn
http://blackjack.zzyjnl.cn
http://altair.zzyjnl.cn
http://anaplasty.zzyjnl.cn
http://applewood.zzyjnl.cn
http://calcium.zzyjnl.cn
http://blockboard.zzyjnl.cn
http://belvedere.zzyjnl.cn
http://aeromedicine.zzyjnl.cn
http://chorizon.zzyjnl.cn
http://albacore.zzyjnl.cn
http://chirurgeon.zzyjnl.cn
http://calumniation.zzyjnl.cn
http://centesimo.zzyjnl.cn
http://avenger.zzyjnl.cn
http://actinoid.zzyjnl.cn
http://carrolline.zzyjnl.cn
http://ackey.zzyjnl.cn
http://antemundane.zzyjnl.cn
http://bessy.zzyjnl.cn
http://aortoiliac.zzyjnl.cn
http://ambiguous.zzyjnl.cn
http://cadastration.zzyjnl.cn
http://catania.zzyjnl.cn
http://aglimmer.zzyjnl.cn
http://cca.zzyjnl.cn
http://anosmia.zzyjnl.cn
http://chassid.zzyjnl.cn
http://carnivore.zzyjnl.cn
http://www.dtcms.com/a/107744.html

相关文章:

  • 前端面试常考算法题目详解
  • W3C XML Schema 活动
  • 物理备份工具Xtrabackup备份和恢复原理详解
  • GitHub 趋势日报 (2025年04月01日)
  • ★ Linux ★ 环境变量和程序地址空间
  • Servlet 点击计数器
  • PCL RANSAC探测多条空间直线(指定方向)
  • 对话Dify.AI延君晨:让AI应用开发像搭积木一样简单
  • 5年——我的创作纪念日
  • Knife4j文档请求异常 空指针
  • C++封装、继承、多态(虚函数)
  • CISCO ASA防火墙、 VPN基础内容、 IPSec VPN
  • MySQL学习集--sql通用语法和数据类型
  • 机器视觉中的传统视觉与深度视觉
  • 【3.软件工程】3.4 原型及相关模型
  • 2025年3月31日 GGG2
  • 笔记1——数据通信网络基础
  • Ogcloud东南亚SD-WAN专线:经济高效、快速稳定!
  • KingbaseES物理备份还原之备份还原
  • arcgis10.8 Toolbox中没有找到conversion tools模块
  • 工业4.0时代下的人工智能新发展
  • syslog 与 Linux 内核日志系统全面解析
  • 【kafka】Kafka的Topic
  • 实战打靶集锦-35-GitRoot
  • 软件定义无线电39
  • SpringMVC和SpringBoot是否线程安全?
  • 2.5/Q2,GBD数据库最新文章解读
  • 从代码学习深度学习 - NLP之文本预处理 PyTorch版
  • 深度解析Python代码中的广告信息提取与JSON处理
  • C++实用函数:remove_if