【Let'sdo第四期-液体流量检测仪DIY】过程帖04 使用FreeRTOS
将裸机代码完善成FreeRTOS框架下的代码
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // LED
vTaskDelay(500);
}
/* USER CODE END StartDefaultTask */
}手动创建三个任务,分别是按键任务,继电器任务,OLED任务
TaskHandle_t xTaskOLED_Handle; // OLED显示任务句柄 TaskHandle_t xTaskKey_Handle; // 按键任务句柄 TaskHandle_t xTaskRelay_Handle; // 继电器任务句柄 BaseType_t xRelay_Handle = xTaskCreate(Relay_Task, "Relay_Task", 128, NULL, (UBaseType_t)osPriorityNormal, &xTaskRelay_Handle); BaseType_t xKey_Handle = xTaskCreate(KEY_Task, "KEY_Task", 128, NULL, (UBaseType_t)osPriorityNormal + 1, &xTaskKey_Handle); BaseType_t xOLED_Handle = xTaskCreate(OLED_Show_Func, "OLED_Task", 256, NULL, (UBaseType_t)osPriorityNormal + 2, &xTaskOLED_Handle);
创建一个软件定时器,10ms扫描一次按键,刷新按键任务的键值
xTimerKey = xTimerCreate( "KeyScanTimer", // 定时器名称 (10), // 定时器周期,10 ms pdTRUE, // 自动重装 (void *)0, // 定时器 ID,这里没有特殊用途 (TimerCallbackFunction_t)vScanKeyCallback // 定时器到期时调用的函数 );
#include "TaskFunction.h"
TimerHandle_t xTimerKey;
uint32_t flow_cnt = 0;
uint8_t OLED_View_Flag = 0; //OLED界面切换FLAG
float Moment_Flow = 0.0f; // 瞬间流量
float Cumulative_Flow = 0.0f; // 累计流量
uint16_t TargetFlow = 0; //目标水量 - 100ML
uint32_t Target_CNT = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_2)
{
flow_cnt ++;
}
}
// 软件定时器-扫描按键-回调函数
void vScanKeyCallback(TimerHandle_t xTimer)
{
// 定时 10ms获取一次按键键值
// static unsigned char led;
key_serv_double();
// 测试软件定时器是否正常工作
// if (++led >= 100) // 1S
// {
// HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // LED
// led = 0;
// }
}
void OLED_Show_Func(void *params)
{
OLED_Init();
OLED_Clear();
OLED_ShowChinese(8*6, 0, "得捷");
OLED_Printf(0, 16, OLED_8X16, " Waiting... ");
OLED_Update();
vTaskDelay(1800);
OLED_Clear();
for(;;)
{
char tempStr[20];
if (OLED_View_Flag == 0)
{
OLED_ShowChinese(8 * 2, 16 * 0, "瞬间流量");
OLED_ShowChar(8 * 10, 16 * 0 + 8, ':', OLED_6X8); // 显示:
// sprintf(tempStr, "%d %d ", flow_cnt, TargetFlow);
sprintf(tempStr, " %.1f mL/s %d ", Moment_Flow, TargetFlow);
OLED_Printf(8 * 4, 16 * 1 + 5, OLED_6X8, tempStr);
OLED_ShowChinese(8 * 2, 16 * 2, "累计流量");
OLED_ShowChar(8 * 10, 16 * 2 + 8, ':', OLED_6X8); // 显示:
Cumulative_Flow = (float)flow_cnt / CNT_Flow_1ML;
sprintf(tempStr, " %.2f mL", Cumulative_Flow);
OLED_Printf(8 * 4, 16 * 3 + 5, OLED_6X8, tempStr);
}
else
{
OLED_ShowChinese(8*6, 16*1, "得捷");
sprintf(tempStr, "Target:%d ", TargetFlow);
OLED_Printf(8 * 4, 16 * 2 + 5, OLED_6X8, tempStr);
}
OLED_Update();
vTaskDelay(100);
}
}
void KEY_Task(void *argument)
{
xTimerStart(xTimerKey, 0);
KEY_GPIO_Init(); // 按键引脚的初始化
for(;;)
{
if (Key[1].short_flag == 1)
{
TargetFlow += 100; //目标值+=100
Key[1].short_flag = 0;
}
if (Key[1].long_flag == 1)
{
TargetFlow += 10;
// Key[1].long_flag = 0;
}
if (Key[1].double_flag == 1)
{
OLED_Clear();
OLED_View_Flag++; // 界面的切换
if (OLED_View_Flag >= 2) // 2个界面
OLED_View_Flag = 0;
Key[1].double_flag = 0;
}
vTaskDelay(100);
}
}
void Relay_Task(void *argument)
{
static uint32_t Last_CNT; //上次计数
static uint32_t error_Flow; //前后两次的流量差
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 默认 继电器 off
// HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
for(;;)
{
Target_CNT = TargetFlow*CNT_Flow_1ML;
if (flow_cnt <= TargetFlow*CNT_Flow_1ML) // 当前小于目标,未到,开继电器
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
}
else if (flow_cnt >= TargetFlow*CNT_Flow_1ML) //如果当前计数值 >= 目标计数值,关闭继电器
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 继电器 off
}
error_Flow = flow_cnt - Last_CNT; //前后两次的流量差 20ms
Moment_Flow = (float)(error_Flow * (1000/20)) / CNT_Flow_1ML; //计算瞬间流量 // error_Flow * (1000/20) === 20ms的流量*50, 等于1S的流量
Last_CNT = flow_cnt;
vTaskDelay(20); // 不能修改这个20ms,需要和计算公式同步修改
}
}头文件#ifndef __TASKFUNCTION_H #define __TASKFUNCTION_H #include "stm32f1xx_hal.h" #include "OLED.h" #include "myoldkey.h" #include "FreeRTOS.h" #include "task.h" #include "timers.h" #define CNT_Flow_1ML 355.357f extern TimerHandle_t xTimerKey; void vScanKeyCallback(TimerHandle_t xTimer); // 软件定时器-扫描按键-回调函数 void OLED_Show_Func(void *params); // OLED显示任务 void KEY_Task(void *params); // 按键任务 void Relay_Task(void *argument); // 继电器任务 #endif
代码:https://gitee.com/Yancl0416/diy-liquid-flow-detector
我要赚赏金
