这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第四期-液体流量检测仪DIY】过程帖04

共1条 1/1 1 跳转至

【Let'sdo第四期-液体流量检测仪DIY】过程帖04

菜鸟
2025-01-24 11:46:57     打赏

【Let'sdo第四期-液体流量检测仪DIY】过程帖04 使用FreeRTOS

将裸机代码完善成FreeRTOS框架下的代码


任务说明

一共创建了四个任务,CubeMX创建的默认任务,用来当做LED指示灯,代表系统正在运行中,系统卡死则LED不再闪烁。

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 // 定时器到期时调用的函数
  );


任务函数

完整代码可以见最下方的Gitee链接

#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










关键词: 第四     液体     流量     检测仪     过程     任务    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]