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

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

電流計算公式:

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

電壓計算公式:

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

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

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


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


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

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

在本項目中,通過 TIM3 定時器中斷實現(xiàn) 1s 采集一次電流、電壓值,定時器配置如下
可以通過按鍵中斷控制數(shù)碼管顯示電壓值還是電流值,這里配置擴展板中三個按鍵為
外部中斷模式,三個按鍵對應(yīng)引腳分別為 PF7、PF8、PF9,配置如下
另外,這里還需要繼續(xù)設(shè)置“ Pin Reservation”給“ Cortex-M4”,否則
STM32CubeMX 不會生生成 GPIO 初始化相關(guān)代碼。具體操作:在剛才選擇的引腳上,鼠
標(biāo)右鍵選擇“ Pin Reservation”->“ Cortex-M4

打開 GPIO 標(biāo)簽,對 PF9、PF8 和 PF7 引腳進行配置

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


上述配置完成后,在 Code Generator 處選擇為每個外設(shè)生成單獨的 C 和 H 文件,這樣
設(shè)置方便閱讀代碼
完成以上設(shè)置后,Ctrl+S 保存,會提示是否需要生成代碼,選擇 Yes 即可自動生成代
碼。系統(tǒng)會自動生成 System Clock 代碼
CubeIDE?代碼實現(xiàn)
生成初始代碼以后,在?usart.c?文件?USER CODE BEGIN 1?與?USER CODE END 1?之間添
加?printf?的重定向函數(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)建了一個?RPMSG tty?通道,用于實現(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、?注冊回調(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ù)以后,將會調(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文件,編寫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?文件,編寫數(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ù)中進行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ù)中,判斷按鍵是否按下,進而改變標(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);
?}
}?
完整代碼可以參考光盤實驗源碼路徑:【\6_工業(yè)電表\實驗源碼\EX_ADC】
M4?程序?qū)腴_發(fā)板
程序編譯沒問題以后,點擊“debug”下載調(diào)試,會將對應(yīng)的?elf?文件下載到
/lib/fireware/目錄下
進入內(nèi)核終端下,查看對應(yīng)目錄下文件,如下所示
進入/usr/local/projects/ 目錄下,可以查看含有所創(chuàng)工程名的目錄
進入目錄下,包含文件如圖所示

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

如果使用 M4 去采集的話要去修改設(shè)備樹文件,使 A7 不能采集 adc。
首先進入內(nèi)核源碼下的 dts 設(shè)備樹文件夾下,創(chuàng)建新的設(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è)備樹文件
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 拷貝到開發(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
開發(fā)板在啟動 uboot 后,會要求選擇一個顯示模組,如下圖:
默認(rèn)模組為:OpenSTLinux 該選項不包含任何顯示的模組。我們可以通過修改系統(tǒng)下的
stm32mp157a-fsmp1a_extlinux.conf 配置文件來更改默認(rèn)的模組。 首先需先連接串口線
或者使用 ssh 遠程登錄到開發(fā)板的控制臺。
我們將上面編譯好的模組添加到 stm32mp157a-fsmp1a_extlinux.conf 配置文件里
root@fsmp1a:# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf
添加下面紅框里的選項,保存退出。
這樣再去啟動 M4 采集程序就不會有沖突了
微信小程序開發(fā)環(huán)境搭建
微信小程序開發(fā)工具簡介
微信小程序是小程序中的一種,英文名 Wechat Mini Program,是一種不需要下載安
裝即可使用的應(yīng)用,它實現(xiàn)了應(yīng)用“觸手可及”的夢想,用戶掃一掃或搜一下即可打開應(yīng)
用。
全面開放申請后,主體類型為企業(yè)、政府、媒體、其他組織或個人的開發(fā)者,均可申
請注冊小程序。微信小程序、微信訂閱號、微信服務(wù)號、微信企業(yè)號是并行的體系。
以下是小程序所涉及的技術(shù)概括:
? JSON
JSON(JavaScript Object Notation)是一種輕量級的數(shù)據(jù)交換格式。它是基于
ECMAScript(w3c 制定的 js 規(guī)范)的一個子集,采用完全獨立于編程語言的文本格式來存
儲和表示數(shù)據(jù)。簡潔和清晰的層次結(jié)構(gòu)使得 JSON 成為理想的數(shù)據(jù)交換語言。易于人的閱讀
和編寫,同時也易于機器解析和生成,并有效提升網(wǎng)絡(luò)傳輸效率。
? XML
XML(Extensible Markup Language),中文名為可擴展標(biāo)記語言,標(biāo)準(zhǔn)通用標(biāo)記語言
的子集,是一種用于標(biāo)記電子文件使其具有結(jié)構(gòu)性的標(biāo)記語言。
? CSS
層疊樣式表(Cascading Style Sheets)是一種用來表現(xiàn) HTML(標(biāo)準(zhǔn)通用標(biāo)記語言的
一個應(yīng)用)或 XML(標(biāo)準(zhǔn)通用標(biāo)記語言的一個子集)等文件樣式的計算機語言。CSS 不僅可
以靜態(tài)的修飾網(wǎng)頁,還可以配合各種腳本語言動態(tài)的對網(wǎng)頁各元素進行格式化。
? JavaScript
JavaScript,是一種直譯式腳本語言,是一種動態(tài)類型、弱類型、基于原型的語言,
內(nèi)置支持類型。它的解釋器被稱為 JavaScript 引擎,是瀏覽器的一部分,廣泛用于客戶端
的腳本語言。
申請微信小程序
登錄微信公眾平臺,注冊賬號,選擇小程序。https://mp.weixin.qq.com/

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


然后登錄自己的郵箱,查閱郵件,點擊鏈接進行激活。進入步驟 3,信息登記,按照網(wǎng)
頁要求,依次輸入信息,身份信息,管理員微信信息,即可激活成功。
? 返回微信公眾平臺,輸入剛剛注冊的賬戶密碼,會需要用管理員微信掃碼登錄,登錄后,
下載普通小程序開發(fā)者工具
點擊開發(fā),選擇開發(fā)設(shè)置,獲取小程序 ID,以備后續(xù)開發(fā)需求。
微信小程序開發(fā)工具下載完成后,進行默認(rèn)安裝即可。
創(chuàng)建新項目工程
打開微信小程序開發(fā)者工具,點擊創(chuàng)建新工程,填寫自己的 APPID,選擇默認(rèn)模板,語
言選擇 JavaScript,點擊新建
?
新建工程完成為如下界面
打開主界面的右上角的詳情按鈕,找到本地設(shè)置,將“增強編譯”和“不校驗合法域名”
這兩個選項進行勾選,因為在小程序的開發(fā)階段,盡量把這兩勾選上
打開 app.json 文件,可以更改微信小程序的標(biāo)題,改為“工程 demo”。然后按下 Ctrl
+ S 快捷鍵進行保存,即可完成編譯,調(diào)試輸出。查看現(xiàn)象
代碼實現(xiàn)
A7adc?采集線程
這里直接去讀取/sys/bus/iio/devices/iio:device3/in_voltage0_raw?和
/sys/bus/iio/devices/iio:device3/in_voltage1_raw?文件的數(shù)據(jù)進行計算。通過信號的方式發(fā)送計算完成的電流和電壓給主線程。
#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+");//讀寫方式打開
?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ù)的程序啟動起來,然后會在根目錄下的 dev 目錄下生成兩個串口文
件。
?system("cd EX_ADC_CM4/ ;./fw_cortex_m4.sh start");
這句代碼是 到 EX_ADC_CM4 路徑下 啟動 m4 程序

我們向串口文件寫入{“vol”:ture}后,m4 程序會自動采集并將數(shù)據(jù)寫入串口,只需要讀
取串口就能拿到數(shù)據(jù)了。通過信號的方式發(fā)送計算完成的電流和電壓給主線程。
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ā)送來的電流和電壓值會在 ui 界面顯示出來。
這里使用繪制事件寫了一個電表的類 Dial,可以直接拿來使用。
?
使用 Dial 類 實例化兩個對象,一個電流表 一個電壓表。


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

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

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


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


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

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

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

編寫 index.wxml,這個文件是用來編寫頁面的布局。

編寫 index.wxss,這個文件是用來配置頁面的屬性。

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

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

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

注:可以直接把我們的小程序源碼導(dǎo)入使用。源碼路徑【6_工業(yè)電表\微信小程序源碼
\Electricity】
實驗源碼?
實驗源碼分為 A7 采集 ADC 數(shù)據(jù)和 M4 采集 ADC 數(shù)據(jù),源碼路徑【6_工業(yè)電表\實驗源碼\6_ammeter_A7】和【6_工業(yè)電表\實驗源碼\6_ammeter_M4】。
注意事項
件。詳細參考【FS-MP1A 開發(fā)教程】中 50.5 linux 源碼編譯章節(jié)
1. 進入在鏡像中拿到的 linux 源碼下的 dts 路徑下:
linux@ubuntu:~cd linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts
2. 新建設(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. 進入內(nèi)核頂層目錄編譯
linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$ make dtbs?
6. 拷貝編譯好的設(shè)備樹文件到開發(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)啟動選項
root@fsmp1a:~# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf

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

9. 在開發(fā)板運行時,需要導(dǎo)入中文字庫,否則會因為識別不了中文。
將【6_工業(yè)電表 \工具軟件\wqy-zenhei-0.9.47-nightlybuild.tar.gz 或 wqyzenhei-0.8.38-1.tar.gz】復(fù)制到 ubuntu 下。并使用 scp 命令將文件拷貝到開發(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 五寸屏運行此項目,需要進行屏幕旋轉(zhuǎn)以適應(yīng)屏幕,具體步驟如
下:在/etc/profile.d/qt-eglfs.sh 添加環(huán)境變量如下:


下面變量的 event0 設(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