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

共2条 1/1 1 跳转至

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

菜鸟
2025-01-23 17:19:12     打赏

【Let'sdo第四期-液体流量检测仪DIY】过程帖03 驱动模块&流量检测


我们接线成功后,先测试是否能驱动继电器

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10); //继电器
Hal_Delay(1000);//延时时间尽量长,不要频繁开关继电器

在while(1)里测试这段代码,如果继电器1S吸合,1S断开,那就是驱动成功了!

如果没有驱动成功,请先检查接线,尤其是供电部分~


检测外部中断的脉冲信号 - 检测流量传感器的数据

流量传感器输出的是脉冲信号,需要在抽水泵工作的时候,有水流经过,这个传感器才会产生脉冲,然后我们需要计数这个脉冲,我使用外部中断的方式来累积计数

具体接线可以查看上一篇文章哦~代码如下

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_2)
    {
        flow_cnt ++;
    }
}


流量检测


流量检测的思路


累积流量:用按键控制继电器的开关,在OLED上显示脉冲计数,

实际测试时候,打开继电器,抽水1000ml,得到一个计数值x1,

多次测量x2,x3,取x1,x2,x3的平均值x,x/1000 = 每毫升水的计数值,

这个数值可以定义成一个宏,供电电压不同,这个数值不同,数值需要自己实测!!!


我的数据是这样的:

#define CNT_Flow_1ML 355.357f


瞬时流量:我取的20ms的计数值,计数值*50 = 1S的计数值,然后用这个值除以CNT_Flow_1ML,得到1S的流量,单位是ml/S


我的思路应该没有问题,比较巧妙,而且没有用到定时器,又偷个懒哈哈哈



裸机代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 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 "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "OLED.h"
#include "myoldkey.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

uint32_t OLED_Tick;
uint32_t Func_Tick;
uint32_t flow_cnt;
uint32_t key_tick;
float Moment_Flow = 1.2f;		// 瞬间流量
float Cumulative_Flow = 0.0f;	// 累计流量

int8_t textnum;

uint16_t TargetFlow = 0;    //目标水量 - 100ML
uint32_t Target_CNT = 0;

void OLED_Show_Func(void);
void JDQ_Func(void);
void key_proc(void);

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

// CNT:164157 --- 650ML


#define CNT_Flow_1ML 355.357f
//#define CNT_Flow_1ML 533.295f
/* 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);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* 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_TIM3_Init();
  /* USER CODE BEGIN 2 */
  
    OLED_Init();
    OLED_Clear();
    OLED_ShowChinese(8*6, 0, "得捷");

    OLED_Printf(0, 16, OLED_8X16, "   Waiting... ");
    OLED_Update();
    HAL_Delay(1800);
    OLED_Clear();
    
    HAL_TIM_Base_Start_IT(&htim3);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // 继电器 off
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    OLED_Show_Func();
//    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);    // 继电器 on
//    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    // 继电器 off
    JDQ_Func();
    key_proc();
      
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 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.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();
  }

  /** 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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

void OLED_Show_Func(void)
{
    if (uwTick - OLED_Tick <= 200)
        return;
    OLED_Tick = uwTick;
    
    OLED_Clear();
    
    char tempStr[20];
    
    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);

    OLED_Update();
}

void JDQ_Func(void)
{
    static uint32_t Last_CNT;   //上次计数
    static uint32_t error_Flow;  //前后两次的流量差
    
    if (uwTick - Func_Tick <= 20)   //如果要修改这个20ms,就需要重新计算瞬间流量
        return;
    Func_Tick = uwTick;

    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;
}

void key_proc(void)
{
    if (uwTick - key_tick <= 10)
        return;
    key_tick = uwTick;
    
    if (Key[1].short_flag == 1)
    {
        Key[1].short_flag = 0;
        TargetFlow += 100;                      //目标值+=100
//        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_10); //继电器
//        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); // 继电器 on
    }
}


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_2)
    {
        flow_cnt ++;
    }
}


/* 定时器回调函数 1ms */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t tim3_cnt;
    static uint8_t keyscan_cnt;
    
    if (htim->Instance == TIM3)
    {
        if (tim3_cnt ++ >= 500)
        {
            // LED T
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // LED
            tim3_cnt = 0;
        }
        
        if (keyscan_cnt ++ >= 20)
        {
            key_serv_long();
            keyscan_cnt = 0;
        }
    }
}


/* USER CODE END 4 */

/**
  * @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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */



以上就是本篇文章的全部内容了

如果有问题,欢迎大佬指正哦~虚心接受





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

院士
2025-01-24 14:15:28     打赏
2楼

谢谢分享本DIY的全过程。


共2条 1/1 1 跳转至

回复

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