提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
昨天懒了休息了一天,今天继续肝软件定时器
一、FreeRTOS软件定时器是什么?
FreeRTOS软件定时器是FreeRTOS自带的定时器。主要包括,定时器的创建、开始、停止、复位,其中定时器创建又分为单次定时器和循环定时器。
当定时器运行时触发复位,下次开始是重新开始计算定时时间。
二、定时器API介绍
1.定时器配置
按照下面选中的条件编译代码编写添加
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1)
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2)
然后修改configUSE_TIMERS的宏
然后在主函数main.c添加Timers.h头文件
到这里就配置完成了
2.定时器创建
老规矩这里只讲动态创建定时器
/*
创建动态定时器
pcTimerName:定时器的名字
xTimerPeriodInTicks:定时器的定时节拍(ms)
uxAutoReload:单次循环还是多次循环 pdTRUE单次 pdFALSE 多次
pvTimerID:第几个定时器
pxCallbackFunction:定时器执行函数
这个是带TimerHandle_t返回值类型的函数
成功:其他值
失败:NULL
*/
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
3.定时器开始
这个是一个宏定义,主体源码看xTimerGenericCommand();
/*
开启定时器
xTimer:定时器句柄
xTicksToWait:任务阻塞时间
这是带BaseType_t的返回值的函数
成功:pdTRUE
失败:pdFLASE
*/
#define xTimerStart( xTimer, xTicksToWait ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
4.定时器停止
又是一个宏。具体源码看xTimerGenericCommand();
/*
停止定时器
xTimer:定时器句柄
xTicksToWait:任务阻塞时间
这是带BaseType_t的返回值的函数
成功:pdTRUE
失败:pdFLASE
*/
#define xTimerStop( xTimer, xTicksToWait ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) )
5.定时器复位
又是一个宏。具体源码看xTimerGenericCommand();
/*
复位定时器
xTimer:定时器句柄
xTicksToWait:任务阻塞时间
这是带BaseType_t的返回值的函数
成功:pdTRUE
失败:pdFLASE
*/
#define xTimerReset( xTimer, xTicksToWait ) \
xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
2.案例
这里因为我想和原子一样使用按键于是我就自己写了一个简单的按键读取。记住这里有个坑就是key0和key1需要设置成上拉输入,不然读不出值。记住一定要看电路图
key.c
#include "Key.h"
static void Key_GPIO_init(void){
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Pin=Key1;
GPIO_Init.Mode=GPIO_MODE_INPUT;
GPIO_Init.Pull=GPIO_PULLDOWN;
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_Init(GPIO_KEY1,&GPIO_Init);
GPIO_Init.Pin=Key2|Key3;
GPIO_Init.Mode=GPIO_MODE_INPUT;
GPIO_Init.Pull=GPIO_PULLUP;
__HAL_RCC_GPIOE_CLK_ENABLE();
HAL_GPIO_Init(GPIO_KEY2_3,&GPIO_Init);
}
static void Non_delay_ms(uint32_t time){
for(int i=0;i<time;i++){
for(int j=0;j<1200;j++){
__nop();
}
}
}
uint8_t Key_config(void){
uint8_t Key_Value;
uint8_t key_statc;
Key_GPIO_init();
if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY1,Key1))==1){
Non_delay_ms(100);
if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY1,Key1))==1){
return Key_Value=1;
}
}else if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY2_3,Key2))==0){
Non_delay_ms(100);
if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY2_3,Key2))==0){
return Key_Value=2;
}
}else if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY2_3,Key3))==0){
Non_delay_ms(100);
if((Key_Value=HAL_GPIO_ReadPin(GPIO_KEY2_3,Key3))==0){
return Key_Value=3;
}
}
return Key_Value=0;
}
key.h
#ifndef __Key_H
#define __Key_H
#include "main.h"
#define Key1 GPIO_PIN_0
#define GPIO_KEY1 GPIOA
#define Key2 GPIO_PIN_3
#define Key3 GPIO_PIN_4
#define GPIO_KEY2_3 GPIOE
uint8_t Key_config(void);
#endif
main.c
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "Timers.h"
#include "stdio.h"
#include "Key.h"
#ifdef __GNUC__ //printf重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
TaskHandle_t HandlerTask1;
TaskHandle_t Task_Name4;
BaseType_t xReturn;
SemaphoreHandle_t Task1semaphore;
TimerHandle_t AutoTimerTask;
TimerHandle_t OneTimerTask;
void AutoTimerFunction(TimerHandle_t xTimer);
void OneTimerFunction(TimerHandle_t xTimer);
void SystemClock_Config(void);
StackType_t xTask3Static[128];
StaticTask_t xTaskTCB;
StackType_t xIdle3Static[128];
StaticTask_t xIdleTCB;
StackType_t xTimerStatic[526];
StaticTask_t xTimerTCB;
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize ){
*ppxIdleTaskTCBBuffer=&xIdleTCB;
*ppxIdleTaskStackBuffer=xIdle3Static;
*pulIdleTaskStackSize=128;
}
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t * pulTimerTaskStackSize ){
* ppxTimerTaskTCBBuffer=&xTimerTCB;
* ppxTimerTaskStackBuffer=xTimerStatic;
* pulTimerTaskStackSize=526;
}
void AutoTimerFunction(TimerHandle_t xTimer){
printf("AutoTimer Begin...\r\n");
}
void OneTimerFunction(TimerHandle_t xTimer){
printf("OneTimer Begin...\r\n");
}
void Task1Function( void * param){
for(;;){
vTaskDelay(100);
}
}
void Task2Function(void* param){
uint8_t num;
for(;;)
{
num=Key_config();
if(AutoTimerTask!=NULL & OneTimerTask!=NULL){
switch(num){
case 1:
xTimerStart(AutoTimerTask,0);
break;
case 2:
xTimerStart(OneTimerTask,0);
break;
case 3:
xTimerStop(AutoTimerTask,0);
xTimerStop(AutoTimerTask,0);
break;
}
}
vTaskDelay(100);
}
}
void Task3Funtion(void* param){
TickType_t st_time=xTaskGetTickCount();
while(1){
uint32_t num =1;
xTaskDelayUntil(&st_time,30);
}
}
void Task4Funtion(void* param){
taskENTER_CRITICAL();
//创建timer
AutoTimerTask=xTimerCreate((const char *) "AutoTimer",
(TickType_t) 1000,
(UBaseType_t) pdTRUE,
(void*) 1,
(TimerCallbackFunction_t) AutoTimerFunction
);
OneTimerTask=xTimerCreate((const char *) "OneTimer",
(TickType_t) 2000,
(UBaseType_t) pdFALSE,
(void*) 2,
(TimerCallbackFunction_t) OneTimerFunction
);
//创建任务
xReturn=xTaskCreate(Task1Function,"Task1",128,NULL,2,&HandlerTask1);
xTaskCreate(Task2Function,"Task2",128,NULL,2,NULL);
xTaskCreateStatic(Task3Funtion,"Task3",128,NULL,2,xTask3Static,&xTaskTCB);
if(xReturn == pdPASS){
uint8_t buffS[20]="Task1 Create OK..\r\n";
HAL_UART_Transmit(&huart1,(uint8_t*)buffS,strlen(buffS)*sizeof(char),HAL_MAX_DELAY);
}
vTaskDelete(Task_Name4);
taskEXIT_CRITICAL();
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
xTaskCreate(Task4Funtion,"Task4",600,NULL,1,&Task_Name4);
vTaskStartScheduler();
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif /* USE_FULL_ASSERT */
效果展示
总结
定时器其实也bnan,主要包括了创建,开始,停止,复位。
天下风云出我辈,一入江湖岁月摧。