成果展示视频:【【Let's do第四期】DIY液体流量检测仪-项目展示】 https://www.bilibili.com/video/BV1wJfZYpEsj/?vd_source=1b092d899318d2ac63cda1ed6ce04937
EETV成果视频链接:https://v.eepw.com.cn/video/play/id/16227
本期给大家分享一下我的制作成果。
液体流量监测仪:
按键双击快速控制水泵开关;
按键长按 选择开关状态,或者选择定量值设定,任意值可设,由于精度差异,设定步进值为50ml;
总流量累计;
功能模块设计调试:
搭建keil环境;
OLED 显示。
继电器控制抽水泵通断。
实现流量计测量功能。
实现定量 任意 水量控制。
KEY_FLAG Key_s; //声明一个按键结构体变量 /*=========================== 单击 双击 长按 =============================*/ void key_det_1(void) { Key_s.key_1 = (~Buttons_GetState()) & (1 << 0); // printf ("%d\\n\\r",Key_s.key_1); if(Key_s.key_flag_1 == 1) //单击 { Key_s.key_flag_1 = 0; Key_s.key_resault = 1; } else if(Key_s.key_flag_1 == 2) //长按 { Key_s.key_flag_1 = 0; Key_s.key_resault = 2; } else if(Key_s.key_flag_1 == 3)//双击 { Key_s.key_flag_1 = 0; Key_s.key_resault = 3; } switch(Key_s.key_state) { case 0: if(Key_s.key_1 == 0) //按下 { if(++Key_s.key_cnt_1 > 5) //主循环进来一次 作用:按下消抖 { Key_s.key_cnt_1 = 0; Key_s.key_state = 1; } } else { Key_s.key_cnt_1 = 0; } break; case 1: if(Key_s.key_1 == 1) //松开 { Key_s.key_cnt_1 = 0; Key_s.key_state = 2; return; } if(++Key_s.key_cnt_1 >= 200) { Key_s.key_cnt_1 = 0; Key_s.key_state = 3; Key_s.key_flag_1 = 2; //长按事件 return; } break; case 2: if(Key_s.key_1 == 0) //按下 { Key_s.key_cnt_1 = 0; Key_s.key_state = 3; Key_s.key_flag_1 = 3; //双击判断 return; } if(++Key_s.key_cnt_1 >= 40) // 计时超过400ms判断为单击事件 { Key_s.key_cnt_1 = 0; Key_s.key_flag_1 = 1; //单击事件 Key_s.key_state = 3; return; } break; case 3: if(Key_s.key_1 == 1) //松开 { Key_s.key_state = 0; } break; default: Key_s.key_state = 0; } Key_s.key_flag_1 = 0; }
void UI_Disply(void) { switch(StrFlow.step) { case 0: OLED_ShowChinese(16*0,16+5,0,16,1); OLED_ShowChinese(16*1,16+5,1,16,1); OLED_ShowChinese(16*2,16+5,2,16,1); OLED_ShowChinese(16*3,16+5,3,16,1); OLED_ShowChinese(16*4,16+5,4,16,1); OLED_ShowChinese(16*5,16+5,5,16,1); OLED_ShowChinese(16*6,16+5,6,16,1); OLED_ShowChinese(16*7,16+5,7,16,1); StrFlow.step = 1; OLED_Refresh(); delay_ms(2000); OLED_Clear(); break; case 1: OLED_ShowChinese(16*0,16*0,8,16,1); OLED_ShowChinese(16*1,16*0,4,16,1); OLED_ShowChar(16*2 ,16*0,':',16,1); OLED_ShowChinese(16*0,16*1+5*1,2,16,1); OLED_ShowChinese(16*1,16*1+5*1,3,16,1); OLED_ShowChar(16*2 ,16*1+5*1,':',16,1); OLED_ShowChinese(16*0,16*2+5*2,2,16,1); OLED_ShowChinese(16*1,16*2+5*2,4,16,1); OLED_ShowChar(16*2 ,16*2+5*2,':',16,1); OLED_ShowNum(OLED_X_I ,16*0 ,StrFlow.SetmL,5,16,1); OLED_ShowNum(OLED_X_I ,16*1+5*1,StrFlow.QmL,5,16,1); OLED_ShowNum(OLED_X_I ,16*2+5*2,StrFlow.TotalmL*1,5,16,1);//0. OLED_ShowString(16*5+5,16*0, "ml", 16,1); OLED_ShowString(16*5+5,16*1+5*1,"ml/S",16,1); OLED_ShowString(16*5+5,16*2+5*2,"ml", 16,1); if(!StrFlow.Ctr_Relay) { OLED_ShowString(128-25,16*0, "OFF",16,1); } else { OLED_ShowString(128-25,16*0, "ON ",16,1); } StrFlow.step = 0xFF; break; default: OLED_ShowNum(OLED_X_I ,16*1+5*1,StrFlow.QmL,5,16,1); OLED_ShowNum(OLED_X_I ,16*2+5*2,StrFlow.TotalmL,5,16,1); switch(Key_s.key_resault) { case CLICK_DOUBLE: (StrFlow.Ctr_Relay == 0)?(StrFlow.Ctr_Relay = 1):(StrFlow.Ctr_Relay = 0); if(!StrFlow.Ctr_Relay) { GPIO_PinWrite (GPIOA, 8, Switch_Relay(false)); } else { FlowSetup(); GPIO_PinWrite (GPIOA, 8, Switch_Relay(true)); } break; case CLICK_LONG: switch(GetCursor) { case 0: GetCursor = 1; if(!StrFlow.Ctr_Relay) { Switch_Relay(false); } else if(1==StrFlow.Ctr_Relay) { Switch_Relay(true); } break; case 1: GetCursor = 2; OLED_ShowNum(OLED_X_I ,16*0 ,StrFlow.SetmL,5,16,0); break; default: if(StrFlow.SetmL>10 && StrFlow.Ctr_Relay==1) { GPIO_PinWrite (GPIOA, 8, Switch_Relay(true)); } break; } break; case CLICK: switch(GetCursor) { case 1: (StrFlow.Ctr_Relay == 0)?(StrFlow.Ctr_Relay = 1):(StrFlow.Ctr_Relay = 0); if(!StrFlow.Ctr_Relay) { OLED_ShowString(128-25,16*0, "OFF",16,1); } else { OLED_ShowString(128-25,16*0, "ON ",16,1); } GetCursor = 2; break; case 2: OLED_ShowNum(OLED_X_I ,16*0 ,StrFlow.SetmL+=50,5,16,0); break; } break; } Key_s.key_resault = 0; break; } }
以上就是主要代码和实现功能的方式,很高兴您能看到这里。 希望可以帮助你。
由于没有多少事件细化代码,代码比较乱,就不开源了,如果群友们有要求,那我就抽时间整理后再开源。
在这里先感谢DigiKey联合EEPW举办的此次活动,不仅有老师在线讲解还有众多群友的帮助完成任务。期待下一次的活动。