成果展示视频:【【Let's do第四期】DIY液体流量检测仪-项目展示】 https://www.bilibili.com/video/BV1vXwpeXEwy/?share_source=copy_web&vd_source=281b35e9473c706c635ce0c93be77625
EETV成果视频链接:https://v.eepw.com.cn/video/play/id/16226
经过一段时间的学习,成功的完成了指定任务,本期给大家分享一下我制作成果的过程。话不多说,开始整活!
第一阶段要分析题目:
搭建keil环境,实现开发板测试,利用定时器实现LED亮灭1秒。
OLED 显示文字信息。
继电器控制抽水泵通断。
实现流量计测量功能
实现定量 100ML,200ML 水量控制
以上是实现的目的,接下来我们使用收到的实物开始了解器件
NUCLEO-F103RB开发板自带STLink调试器,内置电源供电单元,还有很多引出的引脚。
OLED 显示屏使用的IIC协议,因此此器件需要使用硬件的IIC引脚,若引脚不方便,也可以使用软件模拟的II协议,这样任意引脚都支持。
抽水泵是防水的可以直接放入水中,但需要一个5V的开关驱动。
继电器模块能够实现信号的开关,我们使用继电器模块来实现开关水泵。
电源模块可以很方便的输出5V和3.3V,我们本次使用12V DC供电,输出的5V电压用于驱动继电器和水泵。
液体流量传感器,输出是一个方波信号,可以根据脉冲数来计算出水量。
软件框架我采用熟悉并简单的KEIL+STM32Cubemx来实现功能。
以上两款软件不多说,完STM32都回使用的两款软件,也是最好入门的。
根据我们所需要多功能和实物,先做个硬件原理图。

接下来结合硬件接线的特性,分配功能引脚。

以下是我分配引脚功能的说明:
引脚PC13:使用开发板上自带的KEY按键作为我们选择出水量和开关水泵功能。功能的定义为,单按为选择出水量,有100ML和200ML,双击开启继电器,长按则为关闭继电器(在校准流量和调试时使用)。
引脚PA2,PA3:是串口2引脚,可以用于串口输出,用于调试,我们此次使用串口2进行调试程序。
引脚PA5:是板载的LED灯,用于运行的指示灯。0.5S亮灭表示系统正在运行。使用定时器实现。
引脚PA8:用于驱动继电器的,高电平打开继电器,低电平则关闭继电器
引脚PA11:用于捕获水流量脉冲数的引脚。设置为下降沿触发,打开上拉电阻提高获取稳定性。

引脚PA13 PA14:用于程序下载或者Debug调试。很常用
引脚PB8 PB9:模拟IIC协议,用于驱动OLED屏幕,显示设置参数和水流量等信息。
引脚分配好之后,我们生成Keil软件框架,实现我们的功能。
软件方面我使用了一下资源
SSD1306的库,可以使用这个库很方便的驱动OLED屏幕,只需要修改驱动引脚即可。

我是用了取模软件实现了汉字的显示。因此效果如下:

2.使用网络上开源的按键库multi_button,来实现按键的单击,双击,长按等检测。
void Button_Callback(void *button)
{
PressEvent btn_event_val;
btn_event_val = get_button_event((struct Button *)button);
if((struct Button *)button == &Button1)
{
if(btn_event_val == SINGLE_CLICK)
{
// usartPrintf(huart1,"---> key1 单击按下事件 <---\r\n");
key1.Single_flag=1;
}
else if(btn_event_val == DOUBLE_CLICK)
{
key1.Double_flag=1;
// usartPrintf(huart1,"---> key1 双击按下事件 <---\r\n");
}
else if(btn_event_val == LONG_PRESS_START)
{
key1.Long_flag=1;
// usartPrintf(huart1,"---> key1 达到长按事件阈值触发一次 <---\r\n");
}
else if(btn_event_val == LONG_PRESS_HOLD)
{
// key1.Single_flag=1;
// usartPrintf(huart1,"---> key1 长按保持 <---\r\n");
}
}
}那么对于操控的逻辑而言,我写了以下代码实现按键切换阈值和开关水泵。
if (key1.Single_flag)
{
// 处理按键按下的情况
if (water_flag == 1)
{
water_amount = 100; // 设置显示100
water_flag = 2; // 改变状态标志
}
else if (water_flag == 2)
{
water_amount = 200; // 设置显示200
water_flag = 1; // 改变状态标志
}
My_Key_clear(); // 清除按键标志
}
//手动启动水泵
if (key1.Double_flag)
{
Relay1_ON();
golbal_flow.acculat = 0.0;//清空累计流量
My_Key_clear(); // 清除按键标志
}
//手动关闭水泵
if (key1.Long_flag)
{
Relay1_OFF();
My_Key_clear(); // 清除按键标志
} 3.我用定时器实现脉冲计数和LED运行灯的功能,此代码写在定时器中断函数即可,非常的方便,其中还有个定时器用于检测按键。
//硬件定时器
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//1S
if (htim == (&htim2))
{
golbal_flow.receive_flag = 1;
}
//1s
if (htim == (&htim3))
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
usartPrintf(huart2,"瞬间流量:%.2f L/min 累计流量:%.2f mL \r\n",golbal_flow.instant,golbal_flow.acculat);
Page_Main();
}
//0.05S
if (htim == (&htim4))
{
button_ticks(); //按键检测
}
}4.采集的流量脉冲数我写在了,PA11的中断里面,然后配合脉冲转流量的函数实现水流量的检测,具体的软件框架见开源链接的附件中。
在采集流量准确度上,我阅读了相关资料,水流量的采集与水管,传感器的位置(最好是水平),供电电压有关系,排除以上,我还另外做了100ml和500ml的真实脉冲数,根据多次测试和记录,取平均值,这样出水流量就准确了。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == YFS401_Pin)
{
__HAL_GPIO_EXTI_CLEAR_IT(YFS401_Pin);
golbal_flow.pluse_1s++; //下降沿采集脉冲数
usartPrintf(huart2,"触发次数:%.d \r\n",golbal_flow.pluse_1s);
}
}
void Flow_Read(void)
{
// 根据 Flow_Model 选择不同的流量参数
float flowKValue = flowK[flowModel];
float pulseCntValue = pulseCntPerLiter[flowModel];
if(golbal_flow.pluse_1s > 0)
{
golbal_flow.acculat += (golbal_flow.pluse_1s * 1000 / pulseCntValue); //将累计的流量转换成mL
pluse1L+=golbal_flow.pluse_1s; //总脉冲数
golbal_flow.instant = golbal_flow.pluse_1s / flowKValue; //单位(L/min)
if(golbal_flow.acculat >= 1000000) //最大累计流量1000L
{
golbal_flow.acculat = 0;
}
}
else
{
golbal_flow.instant = 0;
}
// usartPrintf(huart2,"瞬间流量:%.2f(L/min) 累计流量:%.2f mL 累计脉冲数:%d \r\n",golbal_flow.instant,golbal_flow.acculat,pluse1L);
golbal_flow.receive_flag = 0; //接收完成标志位清零
golbal_flow.pluse_1s = 0; //脉冲数清零
}5.得到了水流量,那么只需要一个简单的判断函数就可以达到我们想要的 水流量了。我这里使用了标志位作为我判断的一句,因此函数非常的 简单。
//如果当前的水量等于我设定的水量,则停止继电器
if(water_amount <= golbal_flow.acculat)
{
Relay1_OFF();
}6.在OLED屏幕上,我的软件框架也非常的简单。
void Page_Main(void)
{
char arry_dis[3]={0};
//设定流量:ml
OLED_ShowChinese(5,0,7,16,1);
OLED_ShowChinese(21,0,8,16,1);
OLED_ShowChinese(37,0,2,16,1);
OLED_ShowChinese(53,0,3,16,1);
OLED_ShowString(69,0,(uint8_t *)":",16,1);
sprintf(arry_dis,"%d", water_amount);
OLED_ShowString(80,0,(uint8_t *)arry_dis,16,0);
OLED_ShowString(110,0,(uint8_t *)"mL",16,1);
//瞬间流量
OLED_ShowChinese(5,20,11,16,1);
OLED_ShowChinese(21,20,12,16,1);
OLED_ShowChinese(37,20,2,16,1);
OLED_ShowChinese(53,20,3,16,1);
OLED_ShowString(69,20,(uint8_t *)":",16,1);
sprintf(arry_dis,"%.2f", golbal_flow.instant);
OLED_ShowString(80,20,(uint8_t *)arry_dis,16,1);
// OLED_ShowString(115,20,(uint8_t *)"L/min",12,1);
//累计流量
OLED_ShowChinese(5,40,13,16,1);
OLED_ShowChinese(21,40,14,16,1);
OLED_ShowChinese(37,40,2,16,1);
OLED_ShowChinese(53,40,3,16,1);
OLED_ShowString(69,40,(uint8_t *)":",16,1);
sprintf(arry_dis,"%.1f", golbal_flow.acculat);
OLED_ShowString(80, 40, (uint8_t *)arry_dis, 16, 1);
OLED_ShowString(115,40,(uint8_t *)"mL",16,1);
OLED_Refresh();
}以上就是主要代码和实现功能的方式,很高兴您能看到这里。结合我拍摄的功能演示视频以开源的资料。希望可以帮助你。
代码链接: https://pan.baidu.com/s/1Wg280VO-Ehv6YTXEwpzQZg?pwd=mbp5 提取码: mbp5
在这个液体流量控制项目中,我通过STM32开发板成功实现了小抽水泵与继电器的流量控制功能,并结合霍尔效应传感器,准确测量了液体的传播时间,实现了瞬时流量和累计流量的监测。项目的基础任务包括使用Keil环境完成开发板测试、实现LED灯的定时亮灭、OLED显示文字信息以及继电器控制抽水泵的开关。进阶任务则成功实现了流量计测量功能,并能够精准控制100ML和200ML水量的定量控制。
感谢DigiKey联合EEPW举办的此次活动,不仅有老师在线讲解还有众多群友的帮助完成任务。期待下一次的活动。DigiDigiKey联合EEPWKey联DigiKey联合EEPW合EEPWDigiKey联合EEPW
我要赚赏金
