STM32F1 YF-S201C 水流量检测计 瞬时、累计流量检测

发布时间 2023-03-23 00:04:19作者: yangrourou

因为毕设中要用到YF-S201C这个传感器检测瞬时水流量和累计水流量,找遍了整个网络,没有找到一个比较中意的,于是参考了一些大神的自己组装了一个,适用于STM32F103zet6。

首先先简单介绍一下这所需器件:

YF-S201C:

 

该模块以霍尔传感器为核心器件,每流经1L水就会产生300个脉冲(4分管),它一般分为两种型号,一种为4分管,一种为6分管,型号不同单位水流量产生的脉冲数不同,本文以4分管为例。

流量计算公式:

瞬时流量 = (脉冲频率 / 300个脉冲) * 60s= 脉冲频率 / 5.0(流量系K)

累计流量 = 对瞬时流量做累加= (脉冲频率 / 300个脉冲)

 

程序设计:

外部中断检测脉冲个数,time3定时器计时1S

核心代码如下:

main函数:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "YFS201C.h"
 
/************************************************
日期:2023.3.22
功能:采用YF_S201C检测水流量,并通过串口发送检测结果
接线:RX->PA9
            TX->PA10
            LED->PE5
            
            YF_S201C
            黄线->PD2
            红线->VCC
            黑线->GND
************************************************/
 int main(void)
 {        
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);     //串口初始化为115200
     LED_Init();                 //LED端口初始化
    KEY_Init();          //初始化与按键连接的硬件接口
    Exit2_Config();            //外部中断检测脉冲个数
    TIM3_Int_Init(9999,7199);    //计时1S
     while(1)
    {
        Flow_Read();
    }     
 }

YFS201C.h

#ifndef _YFS201C_H
#define _YFS201C_H

#include "stm32f10x.h"
#include "usart.h"
#include "led.h"

typedef struct
{
    uint8_t receive_flag;
    uint16_t pluse_1s;
    
    float instant;
    float acculat;
}GOLBAL_FLOW;

extern GOLBAL_FLOW  golbal_flow;

void Exit2_Config(void);
void Flow_Read(void);
void TIM3_Int_Init(u16 arr,u16 psc);

#endif

YFS201C.c

#include "YFS201C.h"

GOLBAL_FLOW golbal_flow;

#define Flow_Model_4       1            //4分管定义为1;6分管定义为0
#define MODE_4_K               5.0f
#define MODE_4_PLUSE_CNT_1L         300.0f
#define MODE_6_K               5.5f
#define MODE_6_PLUSE_CNT_1L    330.0f
#define    FLOW_FULL                         1000000


//用PD2的外部中断来获取低电平的脉冲
void Exit2_Config(void)
{
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource2);
  
  //Config EXTI2 line
  EXTI_ClearITPendingBit(EXTI_Line2);
  EXTI_InitStructure.EXTI_Line = EXTI_Line2;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;    //下降沿触发中断
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
  
  NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; 
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; 
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; 
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure);
}
  
void EXTI2_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line2) != RESET)
  {
    golbal_flow.pluse_1s++;           //下降沿采集脉冲数
  }
  EXTI_ClearITPendingBit(EXTI_Line2); //清除Line2的中断标志位
}

void Flow_Read(void)
{
    if(golbal_flow.receive_flag)
    {
        if(golbal_flow.pluse_1s > 0)
        {
      #ifdef Flow_Model_4
            /*计算公式:
                累计流量 = 对瞬时流量做积分
                                 = (脉冲频率 / 300个脉冲)    //1L需要300个脉冲,脉冲频率HZ
            */
            golbal_flow.acculat += golbal_flow.pluse_1s / MODE_4_PLUSE_CNT_1L;   //单位L
                
            /*计算公式:
                        瞬时流量 = (脉冲频率 / 300个脉冲) * 60s 
                                         = 脉冲频率 / 5.0(流量系K)
            */
            golbal_flow.instant = golbal_flow.pluse_1s / MODE_4_K;  //单位(L/min)
      
      #else
          /*计算公式:
                累计流量 = 对瞬时流量做积分
                                 = (脉冲频率 / 330个脉冲)    //1L需要330个脉冲,脉冲频率HZ
            */
            golbal_flow.acculat += golbal_flow.pluse_1s / MODE_6_PLUSE_CNT_1L;   //单位L
                
            /*计算公式:
                        瞬时流量 = ((脉冲频率 + 3) / 330个脉冲) * 60s 
                                         = (脉冲频率 + 3) / 5.5(流量系K)
            */
            golbal_flow.instant = (golbal_flow.pluse_1s + 3) / MODE_6_K;  //单位(L/min)
      #endif
      
      if(golbal_flow.acculat >= FLOW_FULL)
            {
                golbal_flow.acculat = 0;
            }
        }
        else
        {
            golbal_flow.instant  = 0;
        }
                
        printf("瞬间流量:%.2f(L/min) 累计流量:%.2f(L)\n",golbal_flow.instant,golbal_flow.acculat);
                
        golbal_flow.receive_flag = 0;                  //接收完成标志位清零
    
    golbal_flow.pluse_1s = 0;
        
        LED0=!LED0;   //LED1灯 取反提示系统正常运行
    }
}

void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //①时钟 TIM3 使能
    
    //定时器 TIM3 初始化
    TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIM3
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //允许更新中断
    
    //中断优先级 NVIC 设置
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级 3 级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
    NVIC_Init(&NVIC_InitStructure); //④初始化 NVIC 寄存器
    TIM_Cmd(TIM3, ENABLE); //⑤使能 TIM3
}


//定时器 3 中断服务程序
void TIM3_IRQHandler(void) //TIM3 中断
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志
        golbal_flow.receive_flag = 1;
    }
}

顺便附上源码,如需自提

链接:https://pan.baidu.com/s/1Cd9dxTipS4WHoBfXgBRAcQ
提取码:li3z