基于TOPWAY液晶屏的水質檢測儀設計
四、軟件設計
本文引用地址:http://cafeforensic.com/article/202204/433019.htm1、LCD驅動編寫
根據協(xié)議內容,編寫寫16位數字變量的驅動
/**
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);//大小端轉換
memcpy((uint8_t*)&send_buf[idx], (uint8_t*)&adr, sizeof(uint32_t));
idx += sizeof(uint32_t);
dt = ntohs(dt);//大小端轉換
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左推進寫曲線數據
/**
brief LCD左推進寫曲線數據
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);
}
跳轉頁面的驅動
/**
brief LCD跳轉頁面
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);
}
設置時間的驅動
/**
brief LCD設置時間
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);
}
讀取時間的驅動
/**
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數據的程序
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ā)數據
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值采集
這里用的傳感器是模擬信號,可以直接使用單片機的AD去采集值,轉化為電壓之后,根據擬合后的公式直接轉換為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單次轉換
HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC轉換完成
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
adc_value = HAL_ADC_GetValue(&hadc1); //讀取ADC轉換數據
vol = ((double)adc_value/4096)*3.3*2;//轉化為實際電壓值
printf("sensor log:adc_value = %d, vol = %.2fV.n", adc_value, vol);
ph_buf[FILTER_N] = (uint16_t)((5.9647*vol+22.255)*10);//轉換為PH值
for (i = 0; i <FILTER_N; i++)
{
ph_buf[i] = ph_buf[i + 1]; // 所有數據左移,低位仍掉
}
pv.ph = MedianFilter(ph_buf, FILTER_N); //中值平均濾波
printf("sensor log:ph %drn", pv.ph);
}
lcd_send_pv16(0x080000,pv.ph);//給LCD發(fā)送數據
lcd_send_curve(0x060000,224,pv.ph);//給LCD左推進發(fā)送曲線
timer_ph += PH_COLLECT_TIME;
}
}
3、池水溫度值采集
使用的是經典的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]; // 所有數據左移,低位仍掉
}
pv.te = MedianFilter(te_buf, FILTER_N); //中值平均濾波
lcd_send_pv16(0x080002, pv.te);//給LCD發(fā)送數據
lcd_send_curve(0x0600e0,224,pv.te+100);//給LCD左推進發(fā)送曲線
printf("sensor log:te %drn", pv.te);
timer_ds18b20 += DS_COLLECT_TIME;
}
}
4、環(huá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]; // 所有數據左移,低位仍掉
tem_buf[i] = tem_buf[i + 1]; // 所有數據左移,低位仍掉
}
pv.tem = MedianFilter(tem_buf, FILTER_N); //中值平均濾波
pv.hum = MedianFilter(hum_buf, FILTER_N); //中值平均濾波
printf("sensor log:tem %drn", pv.tem);
printf("sensor log:hum %drn", pv.hum);
lcd_send_curve(0x0602a0,224,pv.tem+100);//給LCD左推進發(fā)送曲線
lcd_send_curve(0x0601c0,224,pv.hum);//給LCD左推進發(fā)送曲線
lcd_send_pv16(0x080004,pv.hum);//給LCD發(fā)送數據
lcd_send_pv16(0x080006,pv.tem);//給LCD發(fā)送數據
timer_aht += AHT_COLLECT_TIME;
}
}
5、LCE操作流程圖
五、展示
主界面
水質曲線界面
環(huán)境溫濕度曲線界面
效果杠杠的,大屏高分辨率,操作簡單高效,真是一次完美的開發(fā)體驗?。?!
評論