CubeMx-freeRTOS智能门锁

前言:本文基于之前的标准库的写的 freeRTOS小项目练习—智能门锁 用CubeMx进行移植,以此学习CubeMX和HAL库。

目录

一、项目的基本配置

二、配置相关项

三、项目移植

四、模块通信

五、完整项目工程代码

一、项目的基本配置


1、RCC中选择外置晶振

2、SYS中选定Debug方法,Serial Wire

3、配置系统频率,同时要选定外部晶振源HSE、使能CSS。

4、Project Manager

  • 工程名以及保存路径不能含中文
  • 选定自己的编译器Toolchain/IDE
  • Code Generator中选定用到什么库就复制什么库;选择.c/.h文件分别生成

5、GENERATE CODE


二、配置相关项


1、配置串口printf重定向:记得开启 MicroLIB

#include "usart.h"
/* USER CODE BEGIN 0 */
#include <stdio.h>
int fputc(int ch, FILE *f)	
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
	return (ch);
}

/* USER CODE END 0 */

UART_HandleTypeDef huart1;

2、freeRTOS的配置;

MDK的编译器不能使用V6版本会报错:

我这里是将ARM_CM3进行替换(因为我用的103ZET6是Cortex-M3的核),而非ARM_CM4F(ARM_CM4F目录,是针对Cortex-M4 FPU功能的),查看port.c的引用路局为可以发现为ARM_CM3

【Keil】CubeMX配置的FreeRTOS利用V6编译出错_ac6 freertos编译不通过_米杰的声音的博客-CSDN博客

参考文章: 

 FreeRTOS+CubeMX系列第一篇——初识FreeRTOS_cubemx freertos_冬瓜~的博客-CSDN博客

CubeMX使用FreeRTOS编程指南_cubemx freertos_Top嵌入式的博客-CSDN博客

继续配置:

  • Config parameters 堆栈大小设置TOTAL_HEAPS = 15360
  • Advanced settings :Enabled Newlib settings
  • V10版本的流缓冲区和消息缓冲区(用于数据量大长度不定)
  • 任务优先级的理解 任务优先级分配和修改  这样freeRTOS设置了56个优先级对应配置中的MAX_PRIORITIES FreeRTOS 任务优先级问题

 补充:中断优先级和任务优先级区别
初学者也容易在这两个概念上面出现问题。 简单的说,这两个之间没有任何关系,不管中断的优先级是多少,中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。另外对于 STM32F103,F407 和 F429 来说,中断优先级的数值越小,优先级越高。 而 FreeRTOS的任务优先级是,任务优先级数值越小,任务优先级越低

 


三、项目移植

将这个项目进行CubeMX的移植

1:RC552

①:直接用图形化配置添加RC552的任务

②:RC552改用硬件SPI MFRC-522 无线射频IC卡驱动教程

③:存在问题print汉字输出错误

        

④:基于CubeMX、HAL库修改开发

⑤:在Keil中添加自己的.c/.h文件后要保存,这样用CubeMX重新生成代码时才不会被删除。


用  strncmp((char *)readUid,(char *)UID,4) 

替换 (cid[0] == ID[0]) && (cid[1] == ID[1])&& (cid[2] == ID[2]) && (cid[3] == ID[3])  做对比

C 库函数 – strncmp()

2:AS608

①:HAL库配置外部中断 外部中断基础

②:移植之前的失败参考新方式 串口空闲中断的方式  AS608((HAL库 )

STM32CubeMX串口USART中断发送接收数据

 

对于这段函数的理解:串口不定长数据改用空闲中断的方式


/*指纹模块初始化*/
uint8_t as608_init(void)
{
    //设置uart3接收中断
    HAL_UART_Receive_IT(&AS608_UART,USART2_RX_BUF,sizeof( USART2_RX_BUF));//接收数据,且产生中断
    //使能空闲中断
    __HAL_UART_ENABLE_IT(&AS608_UART,UART_IT_IDLE);//
    
    return AS608_Check();
}

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
    //串口接收不定长数据
    //判断是否为空闲中断,如果是就认为接收数据完成    
    if(__HAL_UART_GET_FLAG(&AS608_UART,UART_FLAG_IDLE) != RESET)
    {
        //认为数据接收完成,进行处理
        //1、清除空闲中断
        __HAL_UART_CLEAR_IDLEFLAG(&AS608_UART);
        
        //2、获取接收大小

        //3、清空接收状态

        AS608_UART.RxXferCount = sizeof(USART2_RX_BUF);
        AS608_UART.pRxBuffPtr = USART2_RX_BUF;
        USART2_RX_STA = 1;//接收数据完成
        return ;    
    }
    
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

3:CPU使用情况 添加系统任务状态及任务运行显示

①:设置一个是freeRTOS心跳(1ms)10倍小(0.1ms)的定时器,以及中断

1. auto-reload precload=Disable:自动重装载寄存器写入新值后,计数器立即产生计数溢出,然后开始新的计数周期
2. auto-reload precload=Enable:自动重装载寄存器写入新值后,计数器完成当前旧的计数后,再开始新的计数周期

所以这里Disable或者Enable都可以。

任务栈的大小要够大因为有任务信息要打印栈太小会导致任务失败

②:开启freeRTOS的

GENERATE_RUN_TIME_STATSUSE_TRACE_FACILITYUSE_STATS_FORMATTING_FUNCTIONS

③:创建按键任务来触发

void key_Task(void *argument)
{
  /* USER CODE BEGIN key_Task */
  /* Infinite loop */
	uint8_t CPU_RunInfo[400];
	uint8_t key;
  for(;;)
  {
	memset(CPU_RunInfo,0,sizeof(CPU_RunInfo));
	vTaskList((char *)&CPU_RunInfo);		//获取任务列表
	printf("---------------------------------------------\r\n");
	printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");
	printf("%s", CPU_RunInfo);
	printf("---------------------------------------------\r\n");

	memset(CPU_RunInfo,0,400);
	vTaskGetRunTimeStats((char *)&CPU_RunInfo);		//获取任务运行状态
	printf("任务名       运行计数         利用率\r\n");
	printf("%s", CPU_RunInfo);
	printf("---------------------------------------------\r\n");
	
	 osDelay(1000);
  }
  /* USER CODE END key_Task */
}

//统计CPU利用率的TIM7定时器中断函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM7)
    {
        g_osRuntimeCounter++;//g_osRuntimeCounter为一个全局变量
    }
} 

实现FreeRTOSConfig.h中定义的两函数

void configureTimerForRunTimeStats(void)
{
    g_osRuntimeCounter = 0;
}

unsigned long getRunTimeCounterValue(void)
{
    return g_osRuntimeCounter;
}

最后CubeMX配置完后要手动打开配置的定时器,自动生成的不会打开。

没有打开的话运行占用率是不会打印出来,只会打印出与任务信息;

要自己打开定时器

  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim7);
  /* USER CODE END 2 */

④:模块中的delay_ms全部用freeRTOS的osDelay任务利用率会降低

 4:舵机 HAL库PWM输出驱动舵机

①:定时器的配置

②:要注意项目中的延迟应该都用freeRTOS的延迟函数,这样才能切换到别的任务运行,而不是死等。

③:这里配置的是PWM的占空比,舵机0°对应的是500,但是配置成500舵机精度问题会到不了一直卡死,所以这里配置大一点。

 4:ESP866

①:按照之前的移植

②:串口不定长数据改用空闲中断的方式

四、模块通信

之前采用的事件组的方式进行同步现在改用任务通知的ICP通信方式

任务完整代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 <stdio.h>
#include "myconfig.h"
#include "tim.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void Set_Angle(float angle);
void Suspen_Servo(void);
void Warn(void);
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define EVENT1 (0X01 << 0)
#define EVENT2 (0X01 << 1)
#define EVENT3 (0X01 << 2)
#define ULONG_MAX (0xFFFFFFFF)

/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
extern volatile uint8_t finger_status;
uint8_t err=0;

/* USER CODE END Variables */
/* Definitions for Start */
osThreadId_t StartHandle;
const osThreadAttr_t Start_attributes = {
  .name = "Start",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityBelowNormal,
};
/* Definitions for LED */
osThreadId_t LEDHandle;
const osThreadAttr_t LED_attributes = {
  .name = "LED",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for AS608 */
osThreadId_t AS608Handle;
const osThreadAttr_t AS608_attributes = {
  .name = "AS608",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal1,
};
/* Definitions for KEY */
osThreadId_t KEYHandle;
const osThreadAttr_t KEY_attributes = {
  .name = "KEY",
  .stack_size = 512 * 4,
  .priority = (osPriority_t) osPriorityNormal2,
};
/* Definitions for SERVO */
osThreadId_t SERVOHandle;
const osThreadAttr_t SERVO_attributes = {
  .name = "SERVO",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal3,
};
/* Definitions for ESP */
osThreadId_t ESPHandle;
const osThreadAttr_t ESP_attributes = {
  .name = "ESP",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal4,
};

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

/* USER CODE END FunctionPrototypes */

void Start_Task(void *argument);
void led_Task(void *argument);
void AS608_Task(void *argument);
void key_Task(void *argument);
void Servo_Task(void *argument);
void ESP_Task(void *argument);

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

/* Hook prototypes */
void configureTimerForRunTimeStats(void);
unsigned long getRunTimeCounterValue(void);

/* USER CODE BEGIN 1 */
/* Functions needed when configGENERATE_RUN_TIME_STATS is on */
__weak void configureTimerForRunTimeStats(void)
{
	
}

__weak unsigned long getRunTimeCounterValue(void)
{
return 0;
}
/* USER CODE END 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 Start */
  StartHandle = osThreadNew(Start_Task, NULL, &Start_attributes);

  /* creation of LED */
  LEDHandle = osThreadNew(led_Task, NULL, &LED_attributes);

  /* creation of AS608 */
  AS608Handle = osThreadNew(AS608_Task, NULL, &AS608_attributes);

  /* creation of KEY */
  KEYHandle = osThreadNew(key_Task, NULL, &KEY_attributes);

  /* creation of SERVO */
  SERVOHandle = osThreadNew(Servo_Task, NULL, &SERVO_attributes);

  /* creation of ESP */
  ESPHandle = osThreadNew(ESP_Task, NULL, &ESP_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

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

}

/* USER CODE BEGIN Header_Start_Task */
/**
  * @brief  Function implementing the Start thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_Start_Task */
void Start_Task(void *argument)
{
  /* USER CODE BEGIN Start_Task */
	
	MFRC_Init();
	PCD_Reset();
 	printf("RC522初始化完成\r\n");
	osStatus_t result;
	uint8_t readUid[5]; 
	uint8_t UID[5]={0x83,0xFE,0x28,0xA1};//
	BaseType_t xReturn = pdPASS;

	unsigned char cid[4];
  /* Infinite loop */
  for(;;)
  {
	  
	if(!readCard(readUid,NULL))
	{
		printf("卡号:%.2X-%.2X-%.2X-%.2X\r\n",readUid[0],readUid[1],readUid[2],readUid[3]);
		if(!strncmp((char *)readUid,(char *)UID,4))
		{
			//比对卡号正确要做什么
			printf("卡号正确\r\n");
			xReturn = xTaskNotify((TaskHandle_t)SERVOHandle,
								   (uint32_t)EVENT3,
								   (eNotifyAction)eSetBits);
			if(xReturn == pdTRUE)	printf("send event3 succeed\r\n");
			else printf("send event3 fail\r\n");
		
		}else{
			//比对卡号错误要做什么
			printf("卡号错误\r\n");
			err++;
			Suspen_Servo();
		}
	}
	  osDelay(100);
  }
  /* USER CODE END Start_Task */
}

/* USER CODE BEGIN Header_led_Task */
/**
* @brief Function implementing the LED thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_led_Task */
void led_Task(void *argument)
{
  /* USER CODE BEGIN led_Task */
	printf("led_Task\r\n");
  /* Infinite loop */
  for(;;)
  {
	HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
	  osDelay(1000);
  }
  /* USER CODE END led_Task */
}

/* USER CODE BEGIN Header_AS608_Task */
/**
* @brief Function implementing the AS608 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_AS608_Task */
void AS608_Task(void *argument)
{
  /* USER CODE BEGIN AS608_Task */
	osStatus_t result;
	printf("AS608_Task\r\n");
	as608_init();
	BaseType_t xReturn = pdPASS;

//  /* Infinite loop */
  for(;;)
  {
    if(finger_status == FINGER_EXIST)
	{
		finger_status = FINGER_NO_EXIST;
		if(press_FR())
		{
			xReturn = xTaskNotify((TaskHandle_t)SERVOHandle,
								   (uint32_t)EVENT1,
								   (eNotifyAction)eSetBits);
			if(xReturn == pdTRUE)	printf("send event1 succeed\r\n");
			else printf("send event1 fail\r\n");
		}
		else
		{
			err++;
			Suspen_Servo();
		}
	}
	  osDelay(100);
  }
  /* USER CODE END AS608_Task */
}

/* USER CODE BEGIN Header_key_Task */
/**
* @brief Function implementing the KEY thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_key_Task */
void key_Task(void *argument)
{
  /* USER CODE BEGIN key_Task */
  /* Infinite loop */
	uint8_t CPU_RunInfo[400];
	uint8_t key;
  for(;;)
  {
	key=KEY_Scan(0);   //扫描按键 
	if(key == KEY_UP_PRESS)
	{
		memset(CPU_RunInfo,0,sizeof(CPU_RunInfo));
		vTaskList((char *)&CPU_RunInfo);		//获取任务列表
		printf("---------------------------------------------\r\n");
		printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");
		printf("%s", CPU_RunInfo);
		printf("---------------------------------------------\r\n");

		memset(CPU_RunInfo,0,400);
		vTaskGetRunTimeStats((char *)&CPU_RunInfo);		//获取任务运行状态
		printf("任务名       运行计数         利用率\r\n");
		printf("%s", CPU_RunInfo);
		printf("---------------------------------------------\r\n");
	}
	else if(key == KEY1_PRESS)
	{
		HAL_TIM_Base_Stop_IT(&htim4);
		printf("舵机任务恢复\r\n");
		vTaskResume(SERVOHandle);
		err = 0;
	}
	
	 osDelay(10);
  }
  /* USER CODE END key_Task */
}

/* USER CODE BEGIN Header_Servo_Task */
/**
* @brief Function implementing the SERVO thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Servo_Task */
void Servo_Task(void *argument)
{
  /* USER CODE BEGIN Servo_Task */
	uint8_t key;
	BaseType_t xReturn = pdPASS;
	uint32_t r_event = 0;
  /* Infinite loop */
  for(;;)
  {
	xReturn = xTaskNotifyWait(0x00,ULONG_MAX,&r_event,portMAX_DELAY);
	if(xReturn == pdTRUE)
	{
		if(r_event | EVENT1| EVENT2 | EVENT3)
		{
			Warn();
			printf("OPEN\r\n");
			Set_Angle(0);
			osDelay(1000);
			Set_Angle(170);
			osDelay(1000);
			err = 0;
		}
	}			
    osDelay(10);
  }
  /* USER CODE END Servo_Task */
}

/* USER CODE BEGIN Header_ESP_Task */
/**
* @brief Function implementing the ESP thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_ESP_Task */
void ESP_Task(void *argument)
{
  /* USER CODE BEGIN ESP_Task */
	ESP8266_Init();
	osStatus_t result;
	BaseType_t xReturn = pdPASS;
  /* Infinite loop */
  for(;;)
  {
    if(USART3_RX_STA)
	{
		if(strstr((const char*)USART3_RX_BUF,"on"))	
		{
			printf("%s\r\n",USART3_RX_BUF);	
			xReturn = xTaskNotify((TaskHandle_t)SERVOHandle,
								  (uint32_t)EVENT2,
								  (eNotifyAction)eSetBits);
			if(xReturn == pdTRUE)	printf("send event2 succeed\r\n");
			else printf("send event2 fail\r\n");
		}
		memset(USART3_RX_BUF,0,sizeof(USART3_RX_BUF));
        USART3_RX_STA = 0;
	}
	  osDelay(1000);
  }
  /* USER CODE END ESP_Task */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void Set_Angle(float angle)
{
	int servo_temp;
	if(angle > 180) angle = 180;
	else if(angle < 0) angle = 0;
	servo_temp = angle*2000/180 + 600;
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,(uint16_t)servo_temp);
}

//Suspen_Servo
void Suspen_Servo(void)
{
	printf("ERRO:%d",err);
	if(err == 3)
	{
		HAL_TIM_Base_Start_IT(&htim4);
		vTaskSuspend(SERVOHandle);
		printf("舵机任务挂起\r\n");
	}

}
void Warn(void)
{
	HAL_TIM_Base_Start_IT(&htim4);
	osDelay(100);
	HAL_TIM_Base_Stop_IT(&htim4);
	osDelay(100);
	HAL_TIM_Base_Start_IT(&htim4);
	osDelay(100);
	HAL_TIM_Base_Stop_IT(&htim4);
}
/* USER CODE END Application */

实验效果同库函数的效果一样 详见freeRTOS小项目练习—智能门锁_rtos项目_kedvellek的博客-CSDN博客

①:学习cubeMX的配置 用于开发STM的确实方便

②:HAL库学习,HAL库与标准库比会更加简单感觉

③:freeRTOS的进一步了解学习

                                                                                                                                23.5.28

五、完整项目工程代码

(用的是普中的PZ6806L开发板)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值