Blog
基于智能液晶顯示模塊的水質(zhì)監(jiān)測設(shè)備
什么是水質(zhì)監(jiān)測設(shè)備?
它是利用光學(xué)傳感器、離子選擇性傳感器對水質(zhì)進(jìn)行檢測,并將結(jié)果清晰展示在液晶屏幕上,可以通過觸摸屏幕操作和控制。該設(shè)備被廣泛的應(yīng)用于地表水、工業(yè)污水、飲用水源水質(zhì)監(jiān)測、調(diào)查和篩選領(lǐng)域。其優(yōu)點(diǎn)是操作簡便,顯示結(jié)果清晰直觀,除了實(shí)時的顯示,還可以形成記憶曲線,用于長期的跟蹤和研究。
本項(xiàng)目是基于Topway的7寸智能液晶顯示模塊,型號HMT070ETD-1D
分辨率:1024x600
接口:RS232 RJ45
工作電壓:11V~26V
工作溫度:-20°C ~ 70°C
寬視角:是
外形尺寸:185.9mm x 109.5mm x 25.4mm
尺寸:7"
視窗 :154.21mm x 85.92mm
觸摸屏:CTP
一、項(xiàng)目需求分析:
1.?? ?采集數(shù)據(jù)(定時采集水體的PH值和溫度,以及環(huán)境的溫濕度)
2.?? ?顯示在屏幕上(將采集的值實(shí)時顯示在屏幕上)
3.?? ?曲線展示(以曲線的形式將一段時間內(nèi)的變量值顯示在屏幕上)
二、項(xiàng)目流程
1、屏幕內(nèi)容設(shè)計
1)一張背景圖作為顯示時間、日期和實(shí)時數(shù)據(jù)的主頁
2)2個圖標(biāo)和2個坐標(biāo)軸作為水質(zhì)曲線頁面
3)2個圖標(biāo)和2個坐標(biāo)軸作為溫度和濕度的顯示頁面
4)使用TOPWAY SGTools工具創(chuàng)建工程
導(dǎo)入圖片和圖標(biāo)
5)選擇字庫,菜單欄中的工具-字體設(shè)置中可以選擇合適的字庫
6)創(chuàng)建所有頁面
控件使用情況如下:
7)編輯圖標(biāo)
調(diào)整控件可以使用工具欄中的對齊工具,可以拯救強(qiáng)迫癥患者
8)添加變量并綁定編輯
根據(jù)實(shí)際使用情況新建變量,這里只使用了16位數(shù)字變量和曲線變量
在對應(yīng)的控件屬性VP地址里綁定對應(yīng)的變量的地址,同時也可以修改顏色大小等。
9)添加觸摸鍵
10)使用TOPWAY的屏內(nèi)RTC時鐘功能, 并使用"RTC鍵盤(PIP)”替代,讓開發(fā)設(shè)計更加便捷。
2、硬件設(shè)計
3、軟件設(shè)計
1) 編寫LCD 驅(qū)動程序
根據(jù)協(xié)議內(nèi)容,編寫16位數(shù)字變量的動
/**
brief LCD發(fā)送16位變量
param adr:變量地址
param dt:發(fā)送的變量
return 無
*/
voidlcd_send_pv16(uint32_tadr,uint16_tdt)
{
? ? uint8_tsend_buf[32];
? ? uint8_tidx = 0;
? ? send_buf[idx++] = 0xaa;
? ? send_buf[idx++] = 0x3d;
? ? adr = ntohl(adr);//大小端轉(zhuǎn)換
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&adr, sizeof(uint32_t));
? ? idx += sizeof(uint32_t);
? ? dt = ntohs(dt);//大小端轉(zhuǎn)換
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&dt, 2);
? ? idx += 2;
? ? send_buf[idx++] = 0xcc;
? ? send_buf[idx++] = 0x33;
? ? send_buf[idx++] = 0xc3;
? ? send_buf[idx++] = 0x3c;
? ? send_data1(send_buf, idx);
}
LCD左推進(jìn)寫曲線數(shù)據(jù)
/**
brief LCD左推進(jìn)寫曲線數(shù)據(jù)
param adr:變量地址
param adr_curve:插入位置
param dt:發(fā)送的變量
return 無
*/
voidlcd_send_curve(uint32_tadr,uint16_tadr_curve,uint16_tdt)
{
? ? uint8_tsend_buf[64];
? ? uint8_tidx = 0;
? ? send_buf[idx++] = 0xaa;
? ? send_buf[idx++] = 0x4e;
? ? adr = ntohl(adr);
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&adr, sizeof(uint32_t));
? ? idx += sizeof(uint32_t);
? ? adr_curve = ntohs(adr_curve);
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&adr_curve, sizeof(uint16_t));
? ? idx += sizeof(uint16_t);
? ? dt = ntohs(dt);
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&dt, sizeof(uint16_t));
? ? idx += sizeof(uint16_t);
? ? send_buf[idx++] = 0xcc;
? ? send_buf[idx++] = 0x33;
? ? send_buf[idx++] = 0xc3;
? ? send_buf[idx++] = 0x3c;
? ? send_data1(send_buf, idx);
}
?
跳轉(zhuǎn)頁面的驅(qū)動
/**
brief LCD跳轉(zhuǎn)頁面
param page:頁面地址
return 無
*/
voidlcd_send_page(uint16_tpage)
{
? ? uint8_tsend_buf[64];
? ? uint8_tidx = 0;
? ? send_buf[idx++] = 0xaa;
? ? send_buf[idx++] = 0x70;
? ? page = ntohs(page);
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&page, sizeof(uint16_t));
? ? idx += sizeof(uint16_t);
? ? send_buf[idx++] = 0xcc;
? ? send_buf[idx++] = 0x33;
? ? send_buf[idx++] = 0xc3;
? ? send_buf[idx++] = 0x3c;
? ? send_data1(send_buf, idx);
}
?
設(shè)置時間的驅(qū)動
/**
brief LCD設(shè)置時間
param page 無
return 無
*/
voidlcd_send_time(void)
{
? ? uint8_tsend_buf[64];
? ? uint8_tidx = 0;
? ? send_buf[idx++] = 0xaa;
? ? send_buf[idx++] = 0x9c;
? ? memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&my_rtc, sizeof(MYRTC));
? ? idx += sizeof(MYRTC);
? ? send_buf[idx++] = 0xcc;
? ? send_buf[idx++] = 0x33;
? ? send_buf[idx++] = 0xc3;
? ? send_buf[idx++] = 0x3c;
? ? send_data1(send_buf, idx);
}
?
讀取時間的驅(qū)動
/**
brief LCD讀取時間
param page 無
return 無
*/
voidlcd_read_time(void)
{
? ? uint8_tsend_buf[64];
? ? uint8_tidx = 0;
? ? send_buf[idx++] = 0xaa;
? ? send_buf[idx++] = 0x9b;
? ? send_buf[idx++] = 0xcc;
? ? send_buf[idx++] = 0x33;
? ? send_buf[idx++] = 0xc3;
? ? send_buf[idx++] = 0x3c;
? ? send_data1(send_buf, idx);
}
?
接收LCD數(shù)據(jù)的程序
voidlcd_pro(void)
{
? ? staticuint32_ttimer_lcd = 0;
? ? if (timer6 - timer_lcd<9)
? ? ? ? return;
? ? timer_lcd = timer6;
? ? if (lcd_rx.len<5)
? ? ? ? return;
? ? if (lcd_rx.rx_buff[0] != 0xaa)
? ? {
? ? ? ? memset((uint8_t*)&lcd_rx.rx_buff, 0, lcd_rx.len);
? ? ? ? lcd_rx.len = 0;
? ? ? ? return;
? ? }
? ? else
? ? {
? ? ? ? switch (lcd_rx.rx_buff[1])
? ? ? ? {
? ? ? ? case0x79://觸摸
? ? ? ? ? ? lcd.page = lcd_rx.rx_buff[3];
? ? ? ? ? ? lcd.touch_id = lcd_rx.rx_buff[4];
? ? ? ? ? ? break;
? ? ? ? case0x77://下發(fā)數(shù)據(jù)
? ? ? ? ? ? if(lcd_rx.rx_buff[3] == 0x08)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if(lcd_rx.rx_buff[5] == 0x0A)//年
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.year = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? elseif(lcd_rx.rx_buff[5] == 0x0C)//月
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.month = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? elseif(lcd_rx.rx_buff[5] == 0x0E)//日
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.day = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? elseif(lcd_rx.rx_buff[5] == 0x10)//時
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.hour = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? elseif(lcd_rx.rx_buff[5] == 0x12)//分
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.min = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? elseif(lcd_rx.rx_buff[5] == 0x14)//秒
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? my_rtc.sec = lcd_rx.rx_buff[7];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? lcd_send_time();
? ? ? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? case0x9B://讀取時間
? ? ? ? ? ? memcpy((uint8_t*)&my_rtc, (uint8_t*)&lcd_rx.rx_buff[2], sizeof(MYRTC));
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? memset((uint8_t*)&lcd_rx.rx_buff, 0, lcd_rx.len);
? ? ? ? lcd_rx.len = 0;
? ? }
}
?
2) PH值采集
這里用的傳感器是模擬信號,可以直接使用單片機(jī)的AD去采集值,轉(zhuǎn)化為電壓之后,根據(jù)擬合后的公式直接轉(zhuǎn)換為PH值,程序如下
voidph_pro(void)
{
? staticuint32_ttimer_ph = 0;
? uint16_tadc_value = 0;
? floatvol = 0.0;
? if (timer6 - timer_ph>PH_COLLECT_TIME)
? {
? ? HAL_ADC_Start(&hadc1); ? ? ? ? ? ? ? ? ?//啟動ADC單次轉(zhuǎn)換
? ? HAL_ADC_PollForConversion(&hadc1, 50); ?//等待ADC轉(zhuǎn)換完成
? ? if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
? ? {
? ? ? adc_value = HAL_ADC_GetValue(&hadc1); ? //讀取ADC轉(zhuǎn)換數(shù)據(jù)
? ? ? vol = ((double)adc_value/4096)*3.3*2;//轉(zhuǎn)化為實(shí)際電壓值
? ? ? printf("sensor log:adc_value = %d, vol = %.2fV.\n", adc_value, vol);
? ? ? ph_buf[FILTER_N] = (uint16_t)((5.9647*vol+22.255)*10);//轉(zhuǎn)換為PH值
? ? ? for (i = 0; i <FILTER_N; i++)
? ? ? {
? ? ? ? ? ph_buf[i] = ph_buf[i + 1]; ? // 所有數(shù)據(jù)左移,低位仍掉
? ? ? }
? ? ? pv.ph = MedianFilter(ph_buf, FILTER_N); //中值平均濾波
? ? ? printf("sensor log:ph %d\r\n", pv.ph);
? ? }
? ? lcd_send_pv16(0x080000,pv.ph);//給LCD發(fā)送數(shù)據(jù)
? ? lcd_send_curve(0x060000,224,pv.ph);//給LCD左推進(jìn)發(fā)送曲線
? ? timer_ph += PH_COLLECT_TIME;
? }
}
?
3) 水溫數(shù)據(jù)采集
使用的是經(jīng)典的DS18B20,單總線獲取溫度,程序如下
voidds18b20_pro(void)
{
? uint16_ti = 0;
? staticuint32_ttimer_ds18b20 = 0;
? if (timer6 - timer_ds18b20>DS_COLLECT_TIME)
? {
? ? te_buf[FILTER_N] = DS18B20_Get_Temp();
? ? for (i = 0; i<FILTER_N; i++)
? ? {
? ? ? ? te_buf[i] = te_buf[i + 1]; ? // 所有數(shù)據(jù)左移,低位仍掉
? ? }
? ? pv.te = MedianFilter(te_buf, FILTER_N); //中值平均濾波
? ? lcd_send_pv16(0x080002, pv.te);//給LCD發(fā)送數(shù)據(jù)
? ? lcd_send_curve(0x0600e0,224,pv.te+100);//給LCD左推進(jìn)發(fā)送曲線
? ? printf("sensor log:te %d\r\n", pv.te);
? ? timer_ds18b20 += DS_COLLECT_TIME;
? }
?
4) 環(huán)境溫度數(shù)據(jù)采集
使用的是國產(chǎn)的AHT10,IIC協(xié)議獲取溫濕度,程序如下
voidaht_pro(void)
{
? uint16_ti = 0;
? staticuint32_ttimer_aht = 0;
? if (timer6 - timer_aht>AHT_COLLECT_TIME)
? {
? ? AHT10ReadData(&tem_buf[FILTER_N], &hum_buf[FILTER_N]);
? ? for (i = 0; i<FILTER_N; i++)
? ? {
? ? ? ? hum_buf[i] = hum_buf[i + 1]; ? // 所有數(shù)據(jù)左移,低位仍掉
? ? ? ? tem_buf[i] = tem_buf[i + 1]; ? // 所有數(shù)據(jù)左移,低位仍掉
? ? }
? ? pv.tem = MedianFilter(tem_buf, FILTER_N); //中值平均濾波
? ? pv.hum = MedianFilter(hum_buf, FILTER_N); //中值平均濾波
? ? printf("sensor log:tem %d\r\n", pv.tem);
? ? printf("sensor log:hum %d\r\n", pv.hum);
? ??
? ? lcd_send_curve(0x0602a0,224,pv.tem+100);//給LCD左推進(jìn)發(fā)送曲線
? ? lcd_send_curve(0x0601c0,224,pv.hum);//給LCD左推進(jìn)發(fā)送曲線
? ??
? ? lcd_send_pv16(0x080004,pv.hum);//給LCD發(fā)送數(shù)據(jù)
? ? lcd_send_pv16(0x080006,pv.tem);//給LCD發(fā)送數(shù)據(jù)
? ? timer_aht += AHT_COLLECT_TIME;
? }
}
?
5)?? ?LCD操作流程圖
4.測試
1) 主頁
2) 水質(zhì)曲線界面
3) 環(huán)境溫濕度曲線界面
5、總結(jié)
本項(xiàng)目用到的硬件:NUCLEO-G070RB及硬件擴(kuò)展板、PH溫度采集傳感器、Topway智能顯示模塊HMT070ETD-1D;
開發(fā)工具及版本:TOPWAY SGTools V9.35、STM32CuBeMx V6.4.0 、KEILMDK V5.25、PhotoShop。
其中TOPWAY智能顯示屏HMT070ETD-1D讓工程師擺脫繁瑣的UI和觸摸屏編程,主機(jī)只需要通過簡單的串口命令把數(shù)據(jù)傳輸?shù)街悄茱@示屏,屏幕把顯示、接收用戶輸入等工作全部接管過來。編程,它具有如下產(chǎn)品特點(diǎn):
支持寬電壓供電工作;
同時支持PC下載和U盤升級兩種模式;
支持遠(yuǎn)程協(xié)議通信控制,遠(yuǎn)程顯示工程升級;
支持電容屏支持多功能觸摸按鍵;
支持Lua腳本多功能開發(fā);
使用SGTools工具便捷使得開發(fā)過程十分簡便。