❤️作者主页:凉开水白菜
❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步!
❤️专栏资料:https://pan.baidu.com/s/1nc1rfyLiMyw6ZhxiZ1Cumg?pwd=free
❤️点赞 👍 收藏 ⭐再看,养成习惯
订阅的粉丝可通过PC端左侧加我微信,可对文章的内容进行一对一答疑!
文章目录
前言
前面的章节多数的API使用都讲到中断专用和任务专用是分开的,为什么FreeRTOS会设计两套api函数呢?他们又有那些区别?
中断和任务的API区别
在任务中因为我们是多线程设计的模式可以允许任务阻塞等待,但是在中断中我们希望越快处理越好,我们可以来看看两套API函数的原形都有那些区别;
xQueueSend( xQueue, pvItemToQueue, xTicksToWait )
xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken )
如果查看其他的API使用函数我们可以发现在中断使用的API只是在任务API的末尾添加了FromISR,参数从xTicksToWait等待时间换成了pxHigherPriorityTaskWoken;
任务等待时间我们已经很清楚了我们只需要了解pxHigherPriorityTaskWoken参数,pxHigherPriorityTaskWoken就是用来保存函数的结果:是否需要切换任务
pdTRUE:函数的操作导致更高优先级的任务就绪了,ISR应该进行任务切换
pdFALSE:没有进行任务切换的必要
为什么需要任务切换?
当我们中断频繁触发的时候就会造成我们的任务频繁切换,这样会浪费较多的资源效率较慢,所以可以使用xHigherPriorityTaskWoken避免不必要的任务切换提高效率,简单来说就是将任务切换变为可控提高效率;
如何进行任务切换?
FreeRTOS的ISR函数中,使用两个宏进行任务切换:
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
这两个宏做的事情是完全一样的,在老版本的FreeRTOS中,
portEND_SWITCHING_ISR使用汇编实现
portYIELD_FROM_ISR使用C语言实现
新版本都统一使用portYIELD_FROM_ISR。
使用CubeMX创建工程
先前的使用代码移植的方法来创建我们的工程其实CubeMX是可以直接帮我们生成FreeRTOS工程的;
配置时钟
配置调试模式
这里必须选择否则有可能出现下载程序的问题,这里的基准时钟我们不能选择滴答时钟因为我们的FreeRTOS会使用我们的滴答时钟作为任务切换;
配置串口
后面我们做队列实验就拿串口1来做实验
配置按键外部中断;
配置中断服务函数
配置按键触发模式
配置FreeRTOS
这里我选择默认配置即可,如果前面的文章看了的话这里面的选项还是比较熟悉的
配置时钟
这里的8是这块板子的晶振,根据自己硬件实际情况选择即可
生成工程
库文件单独分析.c/.h
添加串口printf支持
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 0 */
示例
虽然FreeRTOS被重新封装了但是API基本都没有改变我们还是可以使用之前那一套即可;可以看到这里的内核启动是在while之前的所以我们的代码要卸载begin2的位置
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
需要注意的是我们的外设的中断配置优先级不要超过5,否则可能会在中断中卡死;
队列、信号量、互斥量、事件组、任务通知的使用方法和下面的类似;
外部中断按键(任务通知的中断使用)
外部中断服务函数,这个需要我们自己实现__weak()
/**
* @brief EXTI line detection callbacks.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
}
编译如果出现:“Error: L6218E: Undefined symbol xEventGroupSetBitsFromISR (referred from main.o).”
解决办法:INCLUDE_xTimerPendFunctionCall must be set to 1 to make the xEventGroupSetBitFromISR() function availabl 搜索 INCLUDE_xTimerPendFunctionCall 把它设置为1
完整main.c代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2022 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.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 PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
TaskHandle_t key_task_hand;
/*
* bit0: KEY0事件标志位
* bit1: KEY1事件标志位
* bit2: KEY2事件标志位
*/
#define KEY0_EVENT (1<<0)
#define KEY1_EVENT (1<<1)
#define KEY2_EVENT (1<<2)
#define KEY_ALL_ENEVT (KEY0_EVENT | KEY1_EVENT | KEY2_EVENT)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 按键0 */
if(GPIO_Pin == KEY0_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY0_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
/* 按键1 */
else if(GPIO_Pin == KEY1_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY1_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
/* 按键2 */
else if(GPIO_Pin == KEY2_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY2_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
if( xHigherPriorityTaskWoken == pdTRUE )
{
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch should be requested.
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}
static void AppKeyTask(void *par)
{
uint32_t key;
while(1)
{
xTaskNotifyWait(pdFALSE, // 进入函数前不清空
0xffffffff, // 退出函数后清空所有位
&key, // 得到按键值
portMAX_DELAY); // 永远等待
if((key & KEY0_EVENT) != 0)
{
printf("事件1执行!\r\n");
}
else if((key & KEY1_EVENT) != 0)
{
printf("事件2执行!\r\n");
}
else if((key & KEY2_EVENT) != 0)
{
printf("事件3执行!\r\n");
}
}
}
static void AppLedTask(void *par)
{
while(1)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
vTaskDelay(100);
}
}
static int AppBspInit()
{
printf("[%s] [%s] BSP Init success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatSems()
{
printf("[%s] [%s] Creat Sems success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatMutexs()
{
printf("[%s] [%s] Creat Mutexs success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatTimers()
{
printf("[%s] [%s] Creat Tasks success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatTasks()
{
/* 创建key_task任务 */
xTaskCreate((TaskFunction_t )AppKeyTask,"key",128,NULL,1, &key_task_hand);
/* 创建led_task任务 */
xTaskCreate((TaskFunction_t )AppLedTask,"led",128,NULL,2,NULL);
printf("[%s] [%s] Creat Tasks success\r\n", __DATE__, __TIME__);
return 1;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("---------------WELCOME TO FREERTOS BEGIN------------------\r\n");
/* 在实际开发中创建成功与否应该做相对应的判断 */
/* 硬件初始化 */
AppBspInit();
/* 创建信号量 */
AppCreatSems();
/* 创建互斥量 */
AppCreatMutexs();
/* 创建软件定时器 */
AppCreatTimers();
/* 创建任务 */
AppCreatTasks();
printf("[%s] [%s] Start Kernel success\r\n", __DATE__, __TIME__);
printf("---------------WELCOME TO FREERTOS END ------------------\r\n");
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* 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 */
printf("[%s] [%s] Start Kernel eRROR\r\n", __DATE__, __TIME__);
return -1;
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM2 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM2) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
实验效果:按下按键情况
串口接收中断(队列的中断使用)
实验目的:将串口接收到得数据打印出来,根据指令控制LED
完整main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2022 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "queue.h"
#include <string.h>
#include "timers.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 PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
TaskHandle_t key_task_hand; // 按键任务句柄
uint8_t uart1_ch; // 串口接收buff
QueueHandle_t uart1_queue; // 串口数据队列
TimerHandle_t uart1_timer; // 串口接收定时器
char uart1_buff[128] = { 0 }; // 串口数据接收buff
char uart1_cur = 0; // 串口数据位置
#define UART_QUEUE_LEN 1024
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
BaseType_t xHigherPriorityTaskWoken=pdFALSE;
BaseType_t err;
if(huart->Instance==USART1)
{
// 串口接收中断接收一次就会关系所以我们需要重新开启串口空闲接收
HAL_UART_Receive_IT(&huart1,&uart1_ch,1);
err=xQueueSendFromISR(uart1_queue,&uart1_ch,&xHigherPriorityTaskWoken);//发送消息到队尾
if(err==errQUEUE_FULL) // 添加到队列失败
{
printf("xQueue is full,send message fail to pc\r\n");
}
if( xHigherPriorityTaskWoken == pdTRUE )
{
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch should be requested.
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}
}
/*
* bit0: KEY0事件标志位
* bit1: KEY1事件标志位
* bit2: KEY2事件标志位
*/
#define KEY0_EVENT (1<<0)
#define KEY1_EVENT (1<<1)
#define KEY2_EVENT (1<<2)
#define KEY_ALL_ENEVT (KEY0_EVENT | KEY1_EVENT | KEY2_EVENT)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 按键0 */
if(GPIO_Pin == KEY0_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY0_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
/* 按键1 */
else if(GPIO_Pin == KEY1_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY1_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
/* 按键2 */
else if(GPIO_Pin == KEY2_EXTI_Pin)
{
xTaskNotifyFromISR(key_task_hand, KEY2_EVENT, eSetBits, &xHigherPriorityTaskWoken);
}
if( xHigherPriorityTaskWoken == pdTRUE )
{
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch should be requested.
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
}
static void AppKeyTask(void *par)
{
uint32_t key;
while(1)
{
xTaskNotifyWait(pdFALSE, // 进入函数前不清空
0xffffffff, // 退出函数后清空所有位
&key, // 得到按键值
portMAX_DELAY); // 永远等待
if((key & KEY0_EVENT) != 0)
{
printf("事件1执行!\r\n");
}
else if((key & KEY1_EVENT) != 0)
{
printf("事件2执行!\r\n");
}
else if((key & KEY2_EVENT) != 0)
{
printf("事件3执行!\r\n");
}
}
}
static void AppLedTask(void *par)
{
while(1)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
vTaskDelay(100);
}
}
static void AppTimerUart1Callback(TimerHandle_t xTimer)
{
printf("接收数据:%s\r\n", uart1_buff);
if(!strcmp(uart1_buff, "ON"))
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
printf("LED ON!\r\n");
}
if(!strcmp(uart1_buff, "OFF"))
{
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
printf("LED OFF!\r\n");
}
memset(uart1_buff,0, sizeof(uart1_buff));
uart1_cur = 0;
}
static void AppUart1Task(void *par)
{
uint8_t ch;
BaseType_t err;
while(1)
{
err = xQueueReceive( uart1_queue, &ch, portMAX_DELAY );
if(err == pdPASS)
{
uart1_buff[uart1_cur++] = ch;
}
xTimerStart(uart1_timer, portMAX_DELAY);
}
}
static int AppBspInit()
{
//开启串口空闲接收, uart1_buff是接收存放得变量, 1表示接收一个数据进入中断
HAL_UART_Receive_IT(&huart1,&uart1_ch,1);
printf("[%s] [%s] BSP Init success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatSems()
{
printf("[%s] [%s] Creat Sems success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatMutexs()
{
printf("[%s] [%s] Creat Mutexs success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatTimers()
{
/* 单次20tick的定时器 20ms没接收到串口数据表示接收完成 */
uart1_timer = xTimerCreate("uart_timer",200,pdFALSE,NULL,AppTimerUart1Callback);
printf("[%s] [%s] Creat Tasks success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatQueues()
{
uart1_queue = xQueueCreate(UART_QUEUE_LEN,sizeof(uint8_t));//UART_QUEUE_LEN队列的队列长度,单位为字节
printf("[%s] [%s] Creat Queues success\r\n", __DATE__, __TIME__);
return 1;
}
static int AppCreatTasks()
{
/* 创建key_task任务 */
xTaskCreate((TaskFunction_t )AppKeyTask,"key",128,NULL,1, &key_task_hand);
/* 创建led_task任务 */
xTaskCreate((TaskFunction_t )AppLedTask,"led",128,NULL,0,NULL);
/* 创建uart1_task任务 */
xTaskCreate((TaskFunction_t )AppUart1Task,"uart",1024,NULL,2,NULL);
printf("[%s] [%s] Creat Tasks success\r\n", __DATE__, __TIME__);
return 1;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("---------------WELCOME TO FREERTOS BEGIN------------------\r\n");
/* 在实际开发中创建成功与否应该做相对应的判断 */
/* 硬件初始化 */
AppBspInit();
/* 创建信号量 */
AppCreatSems();
/* 创建互斥量 */
AppCreatMutexs();
/* 创建队列 */
AppCreatQueues();
/* 创建软件定时器 */
AppCreatTimers();
/* 创建任务 */
AppCreatTasks();
printf("[%s] [%s] Start Kernel success\r\n", __DATE__, __TIME__);
printf("---------------WELCOME TO FREERTOS END ------------------\r\n");
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* 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 */
printf("[%s] [%s] Start Kernel eRROR\r\n", __DATE__, __TIME__);
return -1;
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM2 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM2) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
实验现象
结尾
我是凉开水白菜,我们下文见~