项目目的
本项目是水藻过滤自动填装原液装置,通过对水箱内的液位进行探测,满足条件时输出一个水泵驱动信号,添加过滤后的水,进一步进行处理提高过滤纯度,由于过滤后的藻类留存在水箱中,水箱内的液位不断上升,所以没有固定的液位作为阈值启停水泵。
实现方案
本项目使用超声波传感器作为液位测量的工具,读取到距离信息后通过串口回传数据,STM32将距离信息显示在OLED屏幕上,当测得的距离高于80cm即液位过深,此时水箱中的水位过低,达到启动水泵加水的条件,输出启动信号。当测得的距离低于30cm,水位过高,达到水箱上限,关闭水泵。当液位在一个大于50cm的值保持过久,系统判定此时为藻类留存抬高水位,满足启动水泵加水。
问题与复盘
本项目实现顺序为点亮OLED-串口通信实现-数据转码-控制算法
OLED的点亮
本次项目使用了IIC ,SPI 两种OLED屏幕进行测试,并更换STM32与C51平台进行测试,测试结果都无法驱动OLED,检查电源SCL,SDA都有信号,难以排查问题。但基本确认硬件平台出现问题的可能性很低,在更换一块新的OLED后,开始对软件代码进行排查,发现中景园提供的部分代码的时序与STM32提供例程中的IIC有几个延时的误差,中景园没有提供延时,有两种方案,一、确保32例程IIC的可靠性后对相关时序代码进行移植,二、重新找一个OLED程序,在此基础上开始后续工作的开展。出于方便考虑我选择了第二种,重新在51黑上下载了项目工程之后,发现成功驱动了OLED屏幕。
在调节UI的过程中,发现输入其他中文后(此项目原本就有中文显示)屏幕不再点亮,应该是其字库中未包括输入的汉字,使用英文正常,便使用英文作为UI的界面
目前需要在此工程上开展后续的工作,有两个方案,一、在此工程上添加串口,按键等代码,二、将IIC部分转移至原有的一个工程,其中有调试完毕的串口起始帧处理。最终选择方案二,将OLEDiic和OLEDh文件转移至原工程,至此OLED显示工作已完毕,可以正常显示项目UI界面。
串口调试
超声波传感器传输的数据为4个八位数据,第一位为0xff 起始帧,数据高八位,数据低八位,校验位,波特率为9600。因此在串口接收中断处理函数中需要对起始帧进行判断,由于没有结束帧,但由于每一组数据为固定长度,所以可以在起始帧后计数的方式完成一组数据的读取存放。
具体代码为:
1void UART4_IRQHandler(void)2{3u8 r;45if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) 6{7r =USART_ReceiveData(UART4);//(USART1->DR);8if((USART4_RX_STA&0x8000)==0)9{10if(USART4_RX_STA&0x4000)//如果第七位被置高说明此时已检测到起始帧11{12if(t<=3)//检测到起始帧且位数不到三个13{14t++;15USART4_RX_BUF[t&0X3FFF]=r;//自加并存入数组1617}18else 19{20USART4_RX_STA|=0x8000;//读取位数到三个之后将第八位置高作为 21 //一组数据接收完成的标志22t=0;23}24}25else26{27if(r==0xFF)//检测起始帧28USART4_RX_STA|=0x4000;//检测到之后将计数的第七位置高29else30{31USART4_RX_STA++;32if(USART4_RX_STA>(USART4_REC_LEN-1))//过长时间没检测到 接收错误清零33USART4_RX_STA=0; 34} 35}36}37else38USART4_RX_STA=0;//数据接收完成后清零39} 40}
以上程序完成对起始帧为0xff,后有连续三帧的数据的收取。
值得注意的是 t计数起始帧后收取的帧数和USART4_RX_STA 一样需要进行全局变量的定义 extern u8 t;这样避免了每次出中断处理函数之后会被清零的问题,这个问题导致只能计数到1便被清零。
串口调试推荐在debug模式下进行调试,可以逐行运行查看计数逻辑和条件进入是否有问题,但逐行调试会无法抓取连续的帧,将待观察的量添加到watch。
小插曲部分:在想要Debug时出现一个小问题,尝试debug时,出现flash download的报错,option-debug-setting-flash download没有单片机对应flash下载算法,这个是报错的直接原因。点击ADD也找不到STM32F103ZET对应的算法。推测可能是芯片包的问题,进行了重新的下载安装,甚至将keil5重新下载后安装原始的stm32F1系统的支持包,打开原工程在option-device中任未找到对应的芯片型号,但在芯片包中已经安装芯片。如果重新建立工程可以选择STM32F1的芯片,在原工程中却无法更换此芯片。
至此我意识到问题的根源和我想象的不一样,一番搜索中找到了类似的情况,推测应该是keil4和keil5的问题,这个工程一打开就有版本不对应的报错,如果此时选择上面的按钮,就能升级到kei5就可以使用keil5的芯片包,之前没找到是因为没有对keil4进行对应芯片包的下载。更新完工程后成功实现代码的debug。
数据转码
接收到的数据为16进制,要使其在OLED屏幕上进行十进制数据的显示,需要进行处理,此处用到了一个很巧妙的方式进行处理。
u16 hex2uint(void *a) //16进制转10进制{return *(u16 *)a;}
此处用了强制类型转换,对四位16进制数据进行拼接,使其显示时为十进制,输出至OLED屏。
因为这是传感器传回的数据,是直接的二进制数据,所以使用强制类型转换和字符拼接的方式是可行的。有的时候,输入的数据为ASCII码,此时需要进行的处理不能使用此方式,如在另一个单片机系统或者操作系统上位机传回的数据,很可能是字符串或ASCII码,此时需要使用其他方式先取出各位的数值,再进行转换。
控制算法
到此系统已实现,实时显示串口传回的数据在OLED屏上,目前需要根据数据确定水泵的启停,很简单的直接的方式为用define设定最大值和最小值。在达到最大值时启动,最小值时暂停。
至于变化过小的停止检测使用以下的平均值求差的策略。
if(dis>=waterM)//waterM的值为500介于H=800和L=300之间{sum=sum+dis;countime++;avg=sum/countime;//计算每一时刻的平均值delta=dis-avg;if(delta<=10)//变化小于1cm时进行计数holdtime++;if(holdtime>=300)//持续时长可以通过修改holdtime来改变{enginON();holdtime=0;}}
持续时长过长便会判定为水位不变,需要重新加水。