Stm32mp157開(kāi)發(fā)板學(xué)生畢業(yè)選題設(shè)計(jì)嵌入式linux+qt物聯(lián)網(wǎng)工業(yè)電表項(xiàng)目
stm32mp157開(kāi)發(fā)板FS-MP1A是華清遠(yuǎn)見(jiàn)自主研發(fā)的一款高品質(zhì)、高性價(jià)比的Linux+單片機(jī)二合一的嵌入式教學(xué)級(jí)開(kāi)發(fā)板。開(kāi)發(fā)板搭載ST的STM32MP157高性能微處理器,集成2個(gè)Cortex-A7核和1個(gè)Cortex-M4 核,A7核上可以跑Linux操作系統(tǒng),M4核上可以跑FreeRTOS、RT-Thread等實(shí)時(shí)操作系統(tǒng)。開(kāi)發(fā)板搭配仿真器、顯示屏、攝像頭、資源擴(kuò)展板等豐富的擴(kuò)展模塊,可拓展物聯(lián)網(wǎng)、人工智能等相關(guān)技術(shù)學(xué)習(xí),還可以拓展豐富的項(xiàng)目實(shí)戰(zhàn),非常貼合企業(yè)當(dāng)下開(kāi)發(fā)需求,是一款嵌入式Linux入門(mén)進(jìn)階必備開(kāi)發(fā)板!
可學(xué)習(xí)技術(shù):嵌入式Linux應(yīng)用/系統(tǒng)/驅(qū)動(dòng)開(kāi)發(fā)、ARM裸機(jī)開(kāi)發(fā)、Qt界面編程、STM32單片機(jī)、FreeRTOS、人工智能機(jī)器視覺(jué)等。其中ARM Cortex-A7裸機(jī)開(kāi)發(fā)課程是華清遠(yuǎn)見(jiàn)獨(dú)有特色課程,可關(guān)注:https://www.bilibili.com/video/BV1Xe4y1i7vm/,持續(xù)更新中。

可實(shí)戰(zhàn)項(xiàng)目:14個(gè)Linux+Qt綜合項(xiàng)目案例,6個(gè)MP1A物聯(lián)網(wǎng)拓展項(xiàng)目
1、Linux+Qt綜合項(xiàng)目案例:華清遠(yuǎn)見(jiàn)stm32mp157開(kāi)發(fā)板優(yōu)勢(shì)特色部分,包括音樂(lè)播放器、智慧家庭、智能工業(yè)電表、智能出行助手、智能貓眼、環(huán)境監(jiān)測(cè)、智能安防、智能語(yǔ)音識(shí)別等10余個(gè)項(xiàng)目案例,涉及家居、醫(yī)療、農(nóng)業(yè)多種應(yīng)用方向,在案例中使用了多種物聯(lián)網(wǎng)和嵌入式技術(shù),包括OT開(kāi)發(fā)、linux應(yīng)用開(kāi)發(fā)、linux驅(qū)動(dòng)開(kāi)發(fā)、物聯(lián)網(wǎng)云端接入、MQTT協(xié)議、json字符串等知識(shí)點(diǎn)。
關(guān)注公眾號(hào)“華清遠(yuǎn)見(jiàn)在線實(shí)驗(yàn)室”(微信號(hào):hqyjlab),回復(fù)“mp157項(xiàng)目”,即可領(lǐng)取項(xiàng)目配套文檔及源碼。
基于Linux+Qt的工業(yè)電表項(xiàng)目
項(xiàng)目簡(jiǎn)介:
智能工業(yè)電表主要實(shí)現(xiàn)數(shù)據(jù)的實(shí)時(shí)測(cè)量、統(tǒng)計(jì)、傳輸、存儲(chǔ)和處理功能,實(shí)時(shí)地將電表的計(jì)量信息以數(shù)字形式傳送到云端進(jìn)行管理,便于遠(yuǎn)程系統(tǒng)分析、運(yùn)行和維護(hù)。項(xiàng)目主要涉及傳感器采集電流電壓,多核心通訊,設(shè)備連接云端,微信小程序通過(guò)云端遠(yuǎn)程間接操控?cái)?shù)據(jù)庫(kù)等多種知識(shí)。
開(kāi)發(fā)平臺(tái):
華清遠(yuǎn)見(jiàn)stm32mp157開(kāi)發(fā)板豪華套餐(開(kāi)發(fā)板+仿真器+五寸屏+攝像頭+資源擴(kuò)展板+tf卡+讀卡器)
項(xiàng)目實(shí)戰(zhàn):
A7 采集 ADC 實(shí)驗(yàn)原理
打開(kāi)擴(kuò)展板原理圖對(duì)照擴(kuò)展板可以看到擴(kuò)展板有一個(gè)電流監(jiān)測(cè)電路,可以通過(guò) ANA0
電壓改變計(jì)算擴(kuò)展板的電流,如下圖:

電流計(jì)算公式:

說(shuō)明:參考原理圖可知 ADC 的參考電壓是 3.3V,所以電壓計(jì)算按照 3.3V 計(jì)算,
CountADC 為 ADC 讀到的當(dāng)前數(shù)值。STM32MP1 的 ADC 支持多種精度,這里以 16 位精
度計(jì)算,量程 0~3.3V 對(duì)應(yīng) CountADC 為 0~216 。
除電流監(jiān)測(cè)電路外擴(kuò)展板上還有一個(gè)通過(guò)可調(diào)電阻改變電壓的電源測(cè)量電路,可通過(guò)
ANA1 測(cè)量可調(diào)電阻的電壓,如下圖

電壓計(jì)算公式:

以上兩個(gè)電路測(cè)量都是通過(guò) ADC 完成,對(duì)應(yīng)底板與擴(kuò)展板接口可確認(rèn),ANA1 和
ANA2 為 STM32MP1 的兩個(gè) ADC 通道,如下圖:

查看芯片手冊(cè)可知 ANA0 和 ANA1 在單端通道工作模式下可以作為 ADC1 的通道 0 和
通道 1,也可作為 ADC2 的通道 0 和通道 1,本文將其作為 ADC1 的通道 0 和通道 1 使
用。

系統(tǒng)啟動(dòng)后可以查看目錄/sys/bus/iio/devices/
root@fsmp1a:~# ls /sys/bus/iio/devices/
iio:device0 iio:device1 iio:device2 iio:device3
如果系統(tǒng)中有多個(gè) iio 設(shè)備,這里可能會(huì)有很多個(gè) iio 設(shè)備目錄,確定哪個(gè)目錄是我們
的設(shè)備對(duì)應(yīng)目錄,可以通過(guò)查看/sys/bus/iio/devices/iio:device*/name 信息確認(rèn):
root@fsmp1a:~# cat /sys/bus/iio/devices/iio:device*/name
0-0040
ap3216c
max30102
48003000.adc:adc@0
由顯示信息可以確認(rèn) iio:device3 是當(dāng)前設(shè)備對(duì)應(yīng)目錄
查看當(dāng)前兩路 ADC 的值:
root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device3/in_voltage0_raw
15047
root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device3/in_voltage1_raw
58808
in_voltage0_raw/in_voltage1_raw 文件讀到的數(shù)據(jù)是當(dāng)前采集到的數(shù)據(jù)。
當(dāng)前 ADC 的精度:
root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device3/scan_elements/in_voltage0_type
le:u16/16>>0
root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device3/scan_elements/in_voltage1_type
le:u16/16>>0
in_voltage0_type/ in_voltage1_type 文件讀到的數(shù)據(jù)是當(dāng)前 ADC 通道的精度,由讀到的
數(shù)據(jù)可以看出兩個(gè)通道均為 16bit 精度。
那么即可通過(guò)一個(gè)線程去讀寫(xiě) in_voltage0_raw/in_voltage1_raw 的數(shù)據(jù)并且通過(guò)計(jì)算得
到電流和電壓。
M4 采集 ADC 實(shí)驗(yàn)原理
關(guān)于 ADC 的原理圖及采集原理,可以參考第一章部分,本章介紹 M4 中對(duì) ADC 數(shù)據(jù)
的采集。
M4 部分功能概述
M4 部分首先實(shí)現(xiàn) ADC 數(shù)據(jù)的采集與處理,通過(guò)定時(shí)器中斷實(shí)現(xiàn) 1s 采集一次電流
的、電壓值,并可以將采集數(shù)據(jù)顯示到數(shù)碼管中,可由按鍵決定顯示的是電壓值還是電流
值。另外,實(shí)現(xiàn)與 A7 核的數(shù)據(jù)通信,當(dāng) M4 收到 A7 傳來(lái)的數(shù)據(jù)時(shí),便會(huì)將采集的電壓、
電流值打包成 JSON 字符串,然后發(fā)送給 A7。
CubeIDE ADC 工程創(chuàng)建
打開(kāi) cubeIDE,進(jìn)入 cubeMX 配置界面,因?yàn)樾枰獙?shí)現(xiàn) A7 與 M4 通信,需要配置
IPCC 與 OPENAMP 部分,如下圖所示


然后配置 ADC 用于采集電壓值與電流值,這里使用 ADC1 采集 ANA0 通道,ADC2
采集 ANA1 通道,配置如下


另外,還需要將 ADC 設(shè)置為中斷模式,但優(yōu)先級(jí)設(shè)置不同,ADC1 的優(yōu)先級(jí)高于
ADC2 的優(yōu)先級(jí),配置如下

因?yàn)樾枰玫綌?shù)碼管顯示采集的電流、電壓值,這里通過(guò) SPI 進(jìn)行控制,使用 SPI 默
認(rèn)引腳,分別對(duì) PE11、PE12、PE13 和 PE14 配置為 SPI4_NSS、SPI4_SCK、SPI4_MISO
和 SPI4_MOSI。切換到 SPI4 標(biāo)簽,勾選給“M4”,“Mode”選擇“Full-Duplex-Master”,使用
硬件片選,選擇“Hardware NSS Output Signal”,其配置如下圖所示。

在本項(xiàng)目中,通過(guò) TIM3 定時(shí)器中斷實(shí)現(xiàn) 1s 采集一次電流、電壓值,定時(shí)器配置如下

可以通過(guò)按鍵中斷控制數(shù)碼管顯示電壓值還是電流值,這里配置擴(kuò)展板中三個(gè)按鍵為
外部中斷模式,三個(gè)按鍵對(duì)應(yīng)引腳分別為 PF7、PF8、PF9,配置如下

另外,這里還需要繼續(xù)設(shè)置“ Pin Reservation”給“ Cortex-M4”,否則
STM32CubeMX 不會(huì)生生成 GPIO 初始化相關(guān)代碼。具體操作:在剛才選擇的引腳上,鼠
標(biāo)右鍵選擇“ Pin Reservation”->“ Cortex-M4

打開(kāi) GPIO 標(biāo)簽,對(duì) PF9、PF8 和 PF7 引腳進(jìn)行配置

如果實(shí)現(xiàn)開(kāi)發(fā)板與電腦串口通信,這里可以通過(guò) 485 總線實(shí)現(xiàn),即配置 UART5,如下
所示


上述配置完成后,在 Code Generator 處選擇為每個(gè)外設(shè)生成單獨(dú)的 C 和 H 文件,這樣
設(shè)置方便閱讀代碼

完成以上設(shè)置后,Ctrl+S 保存,會(huì)提示是否需要生成代碼,選擇 Yes 即可自動(dòng)生成代
碼。系統(tǒng)會(huì)自動(dòng)生成 System Clock 代碼

CubeIDE 代碼實(shí)現(xiàn)
生成初始代碼以后,在 usart.c 文件 USER CODE BEGIN 1 與 USER CODE END 1 之間添
加 printf 的重定向函數(shù),實(shí)現(xiàn) UART5 與 printf 綁定。
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
PUTCHAR_PROTOTYPE
{
?HAL_UART_Transmit(&huart5,(uint8_t*)&ch,1,HAL_MAX_DELAY);
?return ch;
}
#endif
這里創(chuàng)建了一個(gè) RPMSG tty 通道,用于實(shí)現(xiàn) A7 與 M4 之間的數(shù)據(jù)傳輸
1、 初始化 RPMSG tty 虛擬串口
printf("Virtual UART0 OpenAMP-rpmsg channel creation\r\n");
?if (VIRT_UART_Init(&huart0) != VIRT_UART_OK) {
?printf("VIRT_UART_Init UART0 failed.\r\n");
?Error_Handler();
}?
2、 注冊(cè)回調(diào)函數(shù)以按通道接收消息
if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID,
VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)
?{
?Error_Handler();
?}?
3、 虛擬串口回調(diào)函數(shù)
M4 接收到數(shù)據(jù)以后,將會(huì)調(diào)用該回調(diào)函數(shù),需要將接收的數(shù)據(jù)復(fù)制到用戶內(nèi)存,修改接收標(biāo)志位,通知用戶完成數(shù)據(jù)接收。
void VIRT_UART0_RxCpltCallback(VIRT_UART_HandleTypeDef *huart)
{
printf("Msg received on VIRTUAL UART0 channel: %s \n\r", (char *)
huart->pRxBuffPtr);
?/* copy received msg in a variable to sent it back to master processor in
main infinite loop*/
?VirtUart0ChannelRxSize = huart->RxXferSize < MAX_BUFFER_SIZE?
huart->RxXferSize : MAX_BUFFER_SIZE-1;
?memcpy(VirtUart0ChannelBuffRx, huart->pRxBuffPtr, VirtUart0ChannelRxSize);
VirtUart0RxMsg = SET;
}
添加driver_adc.c文件,編寫(xiě)ADC數(shù)據(jù)采集函數(shù)
uint32_t GetAdcValue(ADC_HandleTypeDef *hadc)
{
?uint32_t sum_value;
if( HAL_ADC_Start_IT(hadc) != HAL_OK)
?{
Error_Handler();
?}
?while(HAL_ADC_PollForConversion(hadc, 300) != HAL_OK) ; //等待轉(zhuǎn)換完成
?sum_value = HAL_ADC_GetValue(hadc) ; //讀取原始數(shù)值
?sum_value = (sum_value * 3300) >> 16; //轉(zhuǎn)化為電壓值 mV
?HAL_ADC_Stop_IT(hadc);
?return sum_value;
}
添加 driver_m74hc.c 文件,編寫(xiě)數(shù)碼管顯示函數(shù)
uint8_t num[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void M74HC595_ReadDataTest(uint16_t data)
{
uint8_t data1,data2, data3,data4;
data1 = data/1000;
data2 = data%1000/100;
data3 = data%100/10;
data4 = data%10;
num[data1] = (num[data1] & 0x7f);
?rw_595_Register(0X01,num[data1]);
?HAL_Delay(1);
?num[data2] = (num[data2] & 0x7f);
?rw_595_Register(0X02,num[data2]);
HAL_Delay(1);
num[data3] = (num[data3] & 0x7f);
?rw_595_Register(0X04,num[data3]);
?HAL_Delay(1);
?num[data4] = (num[data4] & 0x7f);
?rw_595_Register(0X08,num[data4]);
?HAL_Delay(1);
}
uint8_t rw_595_Register(uint8_t reg,uint8_t data)
{
uint8_t txdata[2] = {reg, data};
?if(HAL_SPI_Transmit(&hspi4, txdata ,2,300) != HAL_OK) //發(fā)送數(shù)據(jù)
?{
?Error_Handler();
?}
?return 0;
}
然后在主函數(shù)中循環(huán)調(diào)用數(shù)碼管顯示函數(shù)
另外,在TIM回調(diào)函數(shù)中進(jìn)行ADC電壓、電流值的采集
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
?if(htim->Instance == TIM3) //TIM3 周期 1s
?{
?value_c = GetAdcValue(&hadc1);
?value_v = GetAdcValue(&hadc2); //得到電壓 mV
?}
}
在中斷回調(diào)函數(shù)中,判斷按鍵是否按下,進(jìn)而改變標(biāo)志位,用于決定數(shù)碼管顯示電壓值還是電流值。
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_9:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_9) == GPIO_PIN_SET) /* KEY1 */
?vol_cur++;
break;
case GPIO_PIN_8:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_8) == GPIO_PIN_SET) /* KEY3 */
?vol_cur++;
break;
case GPIO_PIN_7:
if(HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_7) == GPIO_PIN_SET) /* KEY2 */
?vol_cur++;
break;
}
if(vol_cur >= 2)
vol_cur = 0;
}
在主函數(shù)中輪詢判斷接收標(biāo)志位,當(dāng)置位以后,解析接收到的 JSON 字符串,另外將采集的電流、電壓值以 JSON 字符串的形式發(fā)送給 A7,其代碼如下
while (1)
?{
?OPENAMP_check_for_message();
?if (VirtUart0RxMsg)
?{
?VirtUart0RxMsg = RESET;
?usr = cJSON_CreateObject();
?cJSON_AddNumberToObject(usr,"vol",value_v);
?cJSON_AddNumberToObject(usr,"cur",value_c);
?out = cJSON_Print(usr);
?if(out == NULL)
?{
printf("--------error----------\n");
?}
?printf("out : %s \n",out);
?strcpy((char *)BuffTx,out);
?if( VIRT_UART_Transmit(&huart0, BuffTx, strlen((const char
*)BuffTx)) != VIRT_UART_OK)
?{
?Error_Handler();
?}
?cJSON_Delete(usr);
?memset(VirtUart0ChannelBuffRx, 0 ,VirtUart0ChannelRxSize);
?memset(BuffTx, 0 ,strlen((const char *)BuffTx));
?}
?if(vol_cur)
?M74HC595_ReadDataTest(value_c);
else
M74HC595_ReadDataTest(value_v);
?}
}?
完整代碼可以參考光盤(pán)實(shí)驗(yàn)源碼路徑:【\6_工業(yè)電表\實(shí)驗(yàn)源碼\EX_ADC】
M4 程序?qū)腴_(kāi)發(fā)板
程序編譯沒(méi)問(wèn)題以后,點(diǎn)擊“debug”下載調(diào)試,會(huì)將對(duì)應(yīng)的 elf 文件下載到
/lib/fireware/目錄下

進(jìn)入內(nèi)核終端下,查看對(duì)應(yīng)目錄下文件,如下所示

進(jìn)入/usr/local/projects/ 目錄下,可以查看含有所創(chuàng)工程名的目錄

進(jìn)入目錄下,包含文件如圖所示

執(zhí)行 ./fw_cortex_m4.sh start 啟動(dòng) m4 程序
執(zhí)行 ./fw_cortex_m4.sh stop 關(guān)閉 m4 程序
M4 程序功能簡(jiǎn)介
使用擴(kuò)展板電流監(jiān)測(cè)電路,可以通過(guò) ANA0 電壓改變計(jì)算擴(kuò)展板的電流。
這里開(kāi)發(fā)板板用的是雙核心,可以用 A7 采集,也可以用 M4 采集。因?yàn)閮烧卟荒芡瑫r(shí)
采集,會(huì)產(chǎn)生沖突。所以要修改設(shè)備樹(shù)文件。
我們默認(rèn)的設(shè)備樹(shù)文件里面的 A7 的 adc status 是打開(kāi)的,這時(shí)載入此設(shè)備樹(shù)系統(tǒng)啟
動(dòng)后可以查看目錄/sys/bus/iio/devices/
root@fsmp1a:~# ls /sys/bus/iio/devices/ iio:device0 iio:device1 iio:device2
iio:device3
此時(shí) device3 里的文件就是我們 A7 采集 adc 的文件。

如果使用 M4 去采集的話要去修改設(shè)備樹(shù)文件,使 A7 不能采集 adc。
首先進(jìn)入內(nèi)核源碼下的 dts 設(shè)備樹(shù)文件夾下,創(chuàng)建新的設(shè)備樹(shù)文件
?
linux@ubuntu:$ cd ~/fsmp1a/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts
linux@ubuntu:~/fsmp1a/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ vi
stm32mp157a-fsmp1a-extended-noadc-rgb070.dts

將 adc 的 status 設(shè)為 disabled 保存退出。
返回內(nèi)核源碼的主目錄編譯設(shè)備樹(shù)文件
linux@ubuntu:$cd ~/fsmp1a/linux/fsmp1a-linux-5.4.31
linux@ubuntu:~/fsmp1a/linux/fsmp1a-linux-5.4.31$ make dtbs
linux@ubuntu:$ cd ~/fsmp1a/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts
將編譯好的 dtb 文件 stm32mp157a-fsmp1a-extended-noadc-rgb070.dtb 拷貝到開(kāi)發(fā)板
根目錄下的 boot 目錄
linux@ubuntu:~/fsmp1a/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$
scp stm32mp157a-fsmp1a-extended-noadc-rgb070.dtb root@192.168.10.131:/boot
開(kāi)發(fā)板在啟動(dòng) uboot 后,會(huì)要求選擇一個(gè)顯示模組,如下圖:

默認(rèn)模組為:OpenSTLinux 該選項(xiàng)不包含任何顯示的模組。我們可以通過(guò)修改系統(tǒng)下的
stm32mp157a-fsmp1a_extlinux.conf 配置文件來(lái)更改默認(rèn)的模組。 首先需先連接串口線
或者使用 ssh 遠(yuǎn)程登錄到開(kāi)發(fā)板的控制臺(tái)。
我們將上面編譯好的模組添加到 stm32mp157a-fsmp1a_extlinux.conf 配置文件里
root@fsmp1a:# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf
添加下面紅框里的選項(xiàng),保存退出。

這樣再去啟動(dòng) M4 采集程序就不會(huì)有沖突了
微信小程序開(kāi)發(fā)環(huán)境搭建
微信小程序開(kāi)發(fā)工具簡(jiǎn)介
微信小程序是小程序中的一種,英文名 Wechat Mini Program,是一種不需要下載安
裝即可使用的應(yīng)用,它實(shí)現(xiàn)了應(yīng)用“觸手可及”的夢(mèng)想,用戶掃一掃或搜一下即可打開(kāi)應(yīng)
用。
全面開(kāi)放申請(qǐng)后,主體類型為企業(yè)、政府、媒體、其他組織或個(gè)人的開(kāi)發(fā)者,均可申
請(qǐng)注冊(cè)小程序。微信小程序、微信訂閱號(hào)、微信服務(wù)號(hào)、微信企業(yè)號(hào)是并行的體系。
以下是小程序所涉及的技術(shù)概括:
? JSON
JSON(JavaScript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式。它是基于
ECMAScript(w3c 制定的 js 規(guī)范)的一個(gè)子集,采用完全獨(dú)立于編程語(yǔ)言的文本格式來(lái)存
儲(chǔ)和表示數(shù)據(jù)。簡(jiǎn)潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語(yǔ)言。易于人的閱讀
和編寫(xiě),同時(shí)也易于機(jī)器解析和生成,并有效提升網(wǎng)絡(luò)傳輸效率。
? XML
XML(Extensible Markup Language),中文名為可擴(kuò)展標(biāo)記語(yǔ)言,標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言
的子集,是一種用于標(biāo)記電子文件使其具有結(jié)構(gòu)性的標(biāo)記語(yǔ)言。
? CSS
層疊樣式表(Cascading Style Sheets)是一種用來(lái)表現(xiàn) HTML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言的
一個(gè)應(yīng)用)或 XML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言的一個(gè)子集)等文件樣式的計(jì)算機(jī)語(yǔ)言。CSS 不僅可
以靜態(tài)的修飾網(wǎng)頁(yè),還可以配合各種腳本語(yǔ)言動(dòng)態(tài)的對(duì)網(wǎng)頁(yè)各元素進(jìn)行格式化。
? JavaScript
JavaScript,是一種直譯式腳本語(yǔ)言,是一種動(dòng)態(tài)類型、弱類型、基于原型的語(yǔ)言,
內(nèi)置支持類型。它的解釋器被稱為 JavaScript 引擎,是瀏覽器的一部分,廣泛用于客戶端
的腳本語(yǔ)言。
申請(qǐng)微信小程序
登錄微信公眾平臺(tái),注冊(cè)賬號(hào),選擇小程序。https://mp.weixin.qq.com/

按照步驟依次注冊(cè),輸入郵箱,密碼,驗(yàn)證碼等,同意協(xié)議進(jìn)行注冊(cè)


然后登錄自己的郵箱,查閱郵件,點(diǎn)擊鏈接進(jìn)行激活。進(jìn)入步驟 3,信息登記,按照網(wǎng)
頁(yè)要求,依次輸入信息,身份信息,管理員微信信息,即可激活成功。
? 返回微信公眾平臺(tái),輸入剛剛注冊(cè)的賬戶密碼,會(huì)需要用管理員微信掃碼登錄,登錄后,
下載普通小程序開(kāi)發(fā)者工具

點(diǎn)擊開(kāi)發(fā),選擇開(kāi)發(fā)設(shè)置,獲取小程序 ID,以備后續(xù)開(kāi)發(fā)需求。

微信小程序開(kāi)發(fā)工具下載完成后,進(jìn)行默認(rèn)安裝即可。
創(chuàng)建新項(xiàng)目工程
打開(kāi)微信小程序開(kāi)發(fā)者工具,點(diǎn)擊創(chuàng)建新工程,填寫(xiě)自己的 APPID,選擇默認(rèn)模板,語(yǔ)
言選擇 JavaScript,點(diǎn)擊新建
?

新建工程完成為如下界面

打開(kāi)主界面的右上角的詳情按鈕,找到本地設(shè)置,將“增強(qiáng)編譯”和“不校驗(yàn)合法域名”
這兩個(gè)選項(xiàng)進(jìn)行勾選,因?yàn)樵谛〕绦虻拈_(kāi)發(fā)階段,盡量把這兩勾選上
打開(kāi) app.json 文件,可以更改微信小程序的標(biāo)題,改為“工程 demo”。然后按下 Ctrl
+ S 快捷鍵進(jìn)行保存,即可完成編譯,調(diào)試輸出。查看現(xiàn)象


代碼實(shí)現(xiàn)
A7adc 采集線程
這里直接去讀取/sys/bus/iio/devices/iio:device3/in_voltage0_raw 和
/sys/bus/iio/devices/iio:device3/in_voltage1_raw 文件的數(shù)據(jù)進(jìn)行計(jì)算。通過(guò)信號(hào)的方式發(fā)送計(jì)算完成的電流和電壓給主線程。
#define ESC_KEY 0x1b
#define R_1K 1000
#define R_100K (100 * R_1K)
#define R_10 10
#define R_0D1 0.1
CollectThread::CollectThread()
{
}
int CollectThread::read_data(QString path)
{
?char buf[32] = {0};
?FILE* fp0 = fopen(path.toUtf8(), "r+");//讀寫(xiě)方式打開(kāi)
?memset(buf, 0, sizeof(buf));
?fgets(buf, sizeof(buf), fp0);
?QString str = buf;
?return str.toInt();
}
void CollectThread::run()
{
?int data = 0;
?QString current_file = "/sys/bus/iio/devices/iio:device3/in_voltage0_raw";
?QString voltage_file = "/sys/bus/iio/devices/iio:device3/in_voltage1_raw";
?float current_float;
float voltage_float;
?QString current;
?QString voltage;
?while(1)
?{
?if (isrun)
?{
?data = read_data(current_file);
?current_float =((((float)3300 * data)/ 65536)/ (R_10 + R_100K + R_1K))
* R_1K / R_0D1;
?current = QString::number(current_float,'f',2);
?data = read_data(voltage_file);
?voltage_float = (float)3300 * data / 65536;
?voltage = QString::number(voltage_float,'f',2);
?emit currentAndvoltage(current,voltage);
?sleep(1);
?}
?}
}
void CollectThread::stop()
{
isrun =false;
}
M4adc 采集線程
這里先將 m4 采集數(shù)據(jù)的程序啟動(dòng)起來(lái),然后會(huì)在根目錄下的 dev 目錄下生成兩個(gè)串口文
件。
?system("cd EX_ADC_CM4/ ;./fw_cortex_m4.sh start");
這句代碼是 到 EX_ADC_CM4 路徑下 啟動(dòng) m4 程序

我們向串口文件寫(xiě)入{“vol”:ture}后,m4 程序會(huì)自動(dòng)采集并將數(shù)據(jù)寫(xiě)入串口,只需要讀
取串口就能拿到數(shù)據(jù)了。通過(guò)信號(hào)的方式發(fā)送計(jì)算完成的電流和電壓給主線程。
void CollectThread::run()
{
?system("cd EX_ADC_CM4/ ;./fw_cortex_m4.sh start");
?QString file = "/dev/ttyRPMSG0";
?int fd;
?float current_float;
?float voltage_float;
?QString current;
?QString voltage;
?char buf[512];
?QJsonObject json_object;
?fd = serInit(file);
?QString ctrl ="{\"vol\":true}";
?while(1)
?{
?write(fd, ctrl.toUtf8(), ctrl.length());
?memset(buf,0,sizeof(buf));
?read(fd, buf, sizeof(buf));
?json_object = QJsonDocument::fromJson(buf).object();
QStringList jsonlist = json_object.keys();
?qDebug()<<buf;
?qDebug()<<json_object;
?qDebug()<<jsonlist;
?if (jsonlist.indexOf("vol")==1)
?{
?QString key = jsonlist[jsonlist.size()-1];
?// QString key = jsonlist[jsonlist.size()];
?// qDebug()<<"vol:"<<json_object.value("vol").toInt();
?// qDebug()<<"cur:"<<json_object.value("cur").toInt();
?current_float = ((((float)3300 * json_object.value("cur").toInt())/
65536)/ (R_10 + R_100K + R_1K)) * R_1K / R_0D1;
?voltage_float = (float)3300 * json_object.value("vol").toInt() /
65536;
?qDebug()<< "current_float:" <<current_float;
?qDebug()<< "voltage_float:" <<voltage_float;
?current = QString::number(current_float,'f',2);
?voltage = QString::number(voltage_float,'f',2);
?emit currentAndvoltage(current,voltage);
?}
?sleep(1);
?}
}?
主線程
接收到數(shù)據(jù)采集線程發(fā)送來(lái)的電流和電壓值會(huì)在 ui 界面顯示出來(lái)。
這里使用繪制事件寫(xiě)了一個(gè)電表的類 Dial,可以直接拿來(lái)使用。
?
使用 Dial 類 實(shí)例化兩個(gè)對(duì)象,一個(gè)電流表 一個(gè)電壓表。



這個(gè)是對(duì)電表進(jìn)行初始化,包括設(shè)置電表的大小、量程、轉(zhuǎn)動(dòng)速度、顏色等。

并且建立信號(hào)槽的連接,當(dāng)采集線程發(fā)送采集的數(shù)據(jù)給主線程后,就進(jìn)入槽函數(shù)
這里將電流和電壓設(shè)置到電表上并且設(shè)置到 LcdNumber 控件上面。

數(shù)據(jù)庫(kù)存儲(chǔ)電量
使用 sqlite3 數(shù)據(jù)庫(kù)存儲(chǔ)剩余電量。當(dāng)剩余電量低于 5 時(shí),會(huì)彈窗,并且關(guān)閉電表顯
示數(shù)據(jù)的信號(hào)槽


通過(guò)微信小程序充值電費(fèi)
使用使用 mqtt 連接百度云。通過(guò)接收微信小程序客戶端發(fā)來(lái)的數(shù)據(jù),進(jìn)行數(shù)據(jù)庫(kù)數(shù)據(jù)
的修改。


微信小程序
第一步:創(chuàng)建新項(xiàng)目
? 打開(kāi)微信開(kāi)發(fā)者工具,新建項(xiàng)目,填寫(xiě)自己的 AppID,新建。

注意:創(chuàng)建工程的路徑一定不能有中文。
第二步:修改微信小程序代碼
? 修改 app.json 文件

下載支持 MQTT 協(xié)議和 sha1 加密的 js 庫(kù)
下載 mqtt.js https://github.com/mqttjs/MQTT.js
下載 hex_hmac_sha1.js https://github.com/xihu-fm/aliyun-iot-clientsdk/tree/master/lib
? 將這兩個(gè)文件存放到 utils 目錄下

編寫(xiě) index.wxml,這個(gè)文件是用來(lái)編寫(xiě)頁(yè)面的布局。

編寫(xiě) index.wxss,這個(gè)文件是用來(lái)配置頁(yè)面的屬性。

編寫(xiě) index.js,修改設(shè)備信息三元組。這個(gè)文件用來(lái)主要邏輯的編寫(xiě)

第三步:修改 socket 合法域名
? 所有的程序編寫(xiě)完成之后,進(jìn)入調(diào)試窗口,就會(huì)看到下面這種情況:

說(shuō)明沒(méi)有在微信小程序的開(kāi)發(fā)管理中添加這個(gè)域名所導(dǎo)致的。
? 打開(kāi)小程序開(kāi)發(fā)網(wǎng)頁(yè):
https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=584612979&lang=
zh_CN
打開(kāi)開(kāi)發(fā)管理->開(kāi)發(fā)設(shè)置->服務(wù)器域名,修改 socket 合法域名,添加這個(gè)域名即可。

注:可以直接把我們的小程序源碼導(dǎo)入使用。源碼路徑【6_工業(yè)電表\微信小程序源碼
\Electricity】
實(shí)驗(yàn)源碼?
實(shí)驗(yàn)源碼分為 A7 采集 ADC 數(shù)據(jù)和 M4 采集 ADC 數(shù)據(jù),源碼路徑【6_工業(yè)電表\實(shí)驗(yàn)源碼\6_ammeter_A7】和【6_工業(yè)電表\實(shí)驗(yàn)源碼\6_ammeter_M4】。
注意事項(xiàng)
件。詳細(xì)參考【FS-MP1A 開(kāi)發(fā)教程】中 50.5 linux 源碼編譯章節(jié)
1. 進(jìn)入在鏡像中拿到的 linux 源碼下的 dts 路徑下:
linux@ubuntu:~cd linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts
2. 新建設(shè)備樹(shù)文件
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ vi stm32mp157a-fsmp1aextended-noadc-rgb070.dt
3.在新建的文件中填入以下代碼
#include "stm32mp157a-fsmp1a-extended-rgb070.dts"
/ {
?model = "HQYJ STM32MP157 FSMP1A EXTENDED RGB070 Discovery Board(A7 no
adc)";
?compatible = "st,stm32mp157a-fsmp1a-extended-noadc-rgb070", "st,stm32mp157";
};
&adc {
status = "disabled";
};
4. 修改 Makefile
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ vi Makefile
加入以下內(nèi)容。

5. 進(jìn)入內(nèi)核頂層目錄編譯
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$ make dtbs?
6. 拷貝編譯好的設(shè)備樹(shù)文件到開(kāi)發(fā)板
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$scparch/arm/boot/dts/stm32mp157a-fsmp1aextended-noadc-rgb070.dtb root@192.168.10.130:/boot
7. 修改默認(rèn)啟動(dòng)選項(xiàng)
root@fsmp1a:~# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf

8. 重啟開(kāi)發(fā)板
選擇后,即可載入設(shè)備樹(shù)文件

9. 在開(kāi)發(fā)板運(yùn)行時(shí),需要導(dǎo)入中文字庫(kù),否則會(huì)因?yàn)樽R(shí)別不了中文。
將【6_工業(yè)電表 \工具軟件\wqy-zenhei-0.9.47-nightlybuild.tar.gz 或 wqyzenhei-0.8.38-1.tar.gz】復(fù)制到 ubuntu 下。并使用 scp 命令將文件拷貝到開(kāi)發(fā)板
的 usr/share/fonts 目錄下,使用 tar 命令解壓后即可
linux@ubuntu:~$ scp wqy-zenhei-0.8.38-1.tar.gz
root@192.168.10.128:/usr/share/fonts/

10. 如果使用 mipi 五寸屏運(yùn)行此項(xiàng)目,需要進(jìn)行屏幕旋轉(zhuǎn)以適應(yīng)屏幕,具體步驟如
下:在/etc/profile.d/qt-eglfs.sh 添加環(huán)境變量如下:


下面變量的 event0 設(shè)備需要填實(shí)際的觸摸屏設(shè)備

這里即填 event0
export QT_QPA_EGLFS_ROTATION=90
export QT_QPA_EGLFS_NO_LIBINPUT=1
export
QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event0:rotate=90