> 文章列表 > Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

stm32mp157开发板FS-MP1A是华清远见自主研发的一款高品质、高性价比的Linux+单片机二合一的嵌入式教学级开发板。开发板搭载ST的STM32MP157高性能微处理器,集成2个Cortex-A7核和1个Cortex-M4 核,A7核上可以跑Linux操作系统,M4核上可以跑FreeRTOS、RT-Thread等实时操作系统。开发板搭配仿真器、显示屏、摄像头、资源扩展板等丰富的扩展模块,可拓展物联网、人工智能等相关技术学习,还可以拓展丰富的项目实战,非常贴合企业当下开发需求,是一款嵌入式Linux入门进阶必备开发板!

可学习技术:嵌入式Linux应用/系统/驱动开发、ARM裸机开发、Qt界面编程、STM32单片机、FreeRTOS、人工智能机器视觉等。其中ARM Cortex-A7裸机开发课程是华清远见独有特色课程,可关注:https://www.bilibili.com/video/BV1Xe4y1i7vm/,持续更新中。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

可实战项目:14个Linux+Qt综合项目案例,6个MP1A物联网拓展项目

1、Linux+Qt综合项目案例:华清远见stm32mp157开发板优势特色部分,包括音乐播放器、智慧家庭、智能工业电表、智能出行助手、智能猫眼、环境监测、智能安防、智能语音识别等10余个项目案例,涉及家居、医疗、农业多种应用方向,在案例中使用了多种物联网和嵌入式技术,包括OT开发、linux应用开发、linux驱动开发、物联网云端接入、MQTT协议、json字符串等知识点。

公众号“华清远见在线实验室”,回复“mp157项目”,即可领取项目配套文档及源码。

基于Linux+Qt的工业电表项目

项目简介:

智能工业电表主要实现数据的实时测量、统计、传输、存储和处理功能,实时地将电表的计量信息以数字形式传送到云端进行管理,便于远程系统分析、运行和维护。项目主要涉及传感器采集电流电压,多核心通讯,设备连接云端,微信小程序通过云端远程间接操控数据库等多种知识。

开发平台:

华清远见stm32mp157开发板豪华套餐(开发板+仿真器+五寸屏+摄像头+资源扩展板+tf卡+读卡器)

项目实战:

A7 采集 ADC 实验原理

打开扩展板原理图对照扩展板可以看到扩展板有一个电流监测电路,可以通过 ANA0

电压改变计算扩展板的电流,如下图:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

电流计算公式:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

说明:参考原理图可知 ADC 的参考电压是 3.3V,所以电压计算按照 3.3V 计算,CountADC 为 ADC 读到的当前数值。STM32MP1 的 ADC 支持多种精度,这里以 16 位精度计算,量程 0~3.3V 对应CountADC 为 0~216 。除电流监测电路外扩展板上还有一个通过可调电阻改变电压的电源测量电路,可通过ANA1 测量可调电阻的电压,如下图

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

电压计算公式:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

以上两个电路测量都是通过 ADC 完成,对应底板与扩展板接口可确认,ANA1 和ANA2 为 STM32MP1 的两个 ADC 通道,如下图:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

扩展板与底板接口对照图

查看芯片手册可知 ANA0 和 ANA1 在单端通道工作模式下可以作为 ADC1 的通道 0 和

通道 1,也可作为 ADC2 的通道 0 和通道 1,本文将其作为 ADC1 的通道 0 和通道 1 使

用。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

系统启动后可以查看目录/sys/bus/iio/devices/

root@fsmp1a:~# ls /sys/bus/iio/devices/

iio:device0 iio:device1 iio:device2 iio:device3

如果系统中有多个 iio 设备,这里可能会有很多个 iio 设备目录,确定哪个目录是我们的设备对应目录,可以通过查看/sys/bus/iio/devices/iio:device*/name 信息确认:

root@fsmp1a:~# cat /sys/bus/iio/devices/iio:device*/name

0-0040

ap3216c

max30102

48003000.adc:adc@0

由显示信息可以确认 iio:device3 是当前设备对应目录

查看当前两路 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 文件读到的数据是当前采集到的数据。

当前 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 文件读到的数据是当前 ADC 通道的精度,由读到的数据可以看出两个通道均为 16bit 精度。

那么即可通过一个线程去读写 in_voltage0_raw/in_voltage1_raw 的数据并且通过计算得到电流和电压。

M4 采集 ADC 实验原理

关于 ADC 的原理图及采集原理,可以参考第一章部分,本章介绍 M4 中对 ADC 数据的采集。

M4 部分功能概述

M4 部分首先实现 ADC 数据的采集与处理,通过定时器中断实现 1s 采集一次电流的、电压值,并可以将采集数据显示到数码管中,可由按键决定显示的是电压值还是电流值。另外,实现与 A7 核的数据通信,当 M4 收到 A7 传来的数据时,便会将采集的电压、电流值打包成 JSON 字符串,然后发送给 A7。

CubeIDE ADC 工程创建

打开 cubeIDE,进入 cubeMX 配置界面,因为需要实现 A7 与 M4 通信,需要配置IPCC 与 OPENAMP 部分,如下图所示

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

然后配置 ADC 用于采集电压值与电流值,这里使用 ADC1 采集 ANA0 通道,ADC2采集 ANA1 通道,配置如下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

另外,还需要将 ADC 设置为中断模式,但优先级设置不同,ADC1 的优先级高于ADC2 的优先级,配置如下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

因为需要用到数码管显示采集的电流、电压值,这里通过 SPI 进行控制,使用 SPI 默认引脚,分别对 PE11、PE12、PE13 和 PE14 配置为 SPI4_NSS、SPI4_SCK、SPI4_MISO和 SPI4_MOSI。切换到 SPI4 标签,勾选给“M4”,“Mode”选择“Full-Duplex-Master”,使用硬件片选,选择“Hardware NSS Output Signal”,其配置如下图所示。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

在本项目中,通过 TIM3 定时器中断实现 1s 采集一次电流、电压值,定时器配置如下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

可以通过按键中断控制数码管显示电压值还是电流值,这里配置扩展板中三个按键为外部中断模式,三个按键对应引脚分别为 PF7、PF8、PF9,配置如下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

另外,这里还需要继续设置“ Pin Reservation”给“ Cortex-M4”,否则STM32CubeMX 不会生生成 GPIO 初始化相关代码。具体操作:在刚才选择的引脚上,鼠标右键选择“ Pin Reservation”->“ Cortex-M4

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

打开 GPIO 标签,对 PF9、PF8 和 PF7 引脚进行配置

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

如果实现开发板与电脑串口通信,这里可以通过 485 总线实现,即配置 UART5

如下所示

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

上述配置完成后,在 Code Generator 处选择为每个外设生成单独的 C 和 H 文件,这样设置方便阅读代码

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

完成以上设置后,Ctrl+S 保存,会提示是否需要生成代码,选择 Yes 即可自动生成代码。系统会自动生成 System Clock 代码

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

CubeIDE 代码实现

生成初始代码以后,在 usart.c 文件 USER CODE BEGIN 1 与 USER CODE END 1 之间添

加 printf 的重定向函数,实现 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

这里创建了一个 RPMSG tty 通道,用于实现 A7 与 M4 之间的数据传输

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、 注册回调函数以按通道接收消息

if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID,

VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)

{

Error_Handler();

}

3、 虚拟串口回调函数

M4 接收到数据以后,将会调用该回调函数,需要将接收的数据复制到用户内存,修改接收标志位,通知用户完成数据接收。

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数据采集函数

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) ; //等待转换完成

sum_value = HAL_ADC_GetValue(hadc) ; //读取原始数值

sum_value = (sum_value * 3300) >> 16; //转化为电压值 mV

HAL_ADC_Stop_IT(hadc);

return sum_value;

}

添加 driver_m74hc.c 文件,编写数码管显示函数

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) //发送数据

{

Error_Handler();

}

return 0;

}

然后在主函数中循环调用数码管显示函数

另外,在TIM回调函数中进行ADC电压、电流值的采集

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

if(htim->Instance == TIM3) //TIM3 周期 1s

{

value_c = GetAdcValue(&hadc1);

value_v = GetAdcValue(&hadc2); //得到电压 mV

}

}

在中断回调函数中,判断按键是否按下,进而改变标志位,用于决定数码管显示电压值还是电流值。

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;

}

在主函数中轮询判断接收标志位,当置位以后,解析接收到的 JSON 字符串,另外将采集的电流、电压值以 JSON 字符串的形式发送给 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_工业电表\\实验源码\\EX_ADC】

M4 程序导入开发板

程序编译没问题以后,点击“debug”下载调试,会将对应的 elf 文件下载到

/lib/fireware/目录下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

进入内核终端下,查看对应目录下文件,如下所示

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

进入/usr/local/projects/ 目录下,可以查看含有所创工程名的目录

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

进入目录下,包含文件如图所示

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

执行 ./fw_cortex_m4.sh start 启动 m4 程序

执行 ./fw_cortex_m4.sh stop 关闭 m4 程序

M4 程序功能简介

使用扩展板电流监测电路,可以通过 ANA0 电压改变计算扩展板的电流。

这里开发板板用的是双核心,可以用 A7 采集,也可以用 M4 采集。因为两者不能同时

采集,会产生冲突。所以要修改设备树文件。

我们默认的设备树文件里面的 A7 的 adc status 是打开的,这时载入此设备树系统启

动后可以查看目录/sys/bus/iio/devices/

root@fsmp1a:~# ls /sys/bus/iio/devices/ iio:device0 iio:device1 iio:device2

iio:device3

此时 device3 里的文件就是我们 A7 采集 adc 的文件。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

A7 扩展板设备树

如果使用 M4 去采集的话要去修改设备树文件,使 A7 不能采集 adc。

首先进入内核源码下的 dts 设备树文件夹下,创建新的设备树文件

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

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

将 adc 的 status 设为 disabled 保存退出。

返回内核源码的主目录编译设备树文件

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 拷贝到开发板

根目录下的 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

开发板在启动 uboot 后,会要求选择一个显示模组,如下图:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

默认模组为:OpenSTLinux 该选项不包含任何显示的模组。我们可以通过修改系统下的

stm32mp157a-fsmp1a_extlinux.conf 配置文件来更改默认的模组。 首先需先连接串口线

或者使用 ssh 远程登录到开发板的控制台。

我们将上面编译好的模组添加到 stm32mp157a-fsmp1a_extlinux.conf 配置文件里

root@fsmp1a:# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf

添加下面红框里的选项,保存退出。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

这样再去启动 M4 采集程序就不会有冲突了

微信小程序开发环境搭建

微信小程序开发工具简介

微信小程序是小程序中的一种,英文名 Wechat Mini Program,是一种不需要下载安

装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应

用。

全面开放申请后,主体类型为企业、政府、媒体、其他组织或个人的开发者,均可申

请注册小程序。微信小程序、微信订阅号、微信服务号、微信企业号是并行的体系。

以下是小程序所涉及的技术概括:

⚫ JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它是基于

ECMAScript(w3c 制定的 js 规范)的一个子集,采用完全独立于编程语言的文本格式来存

储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人的阅读

和编写,同时也易于机器解析和生成,并有效提升网络传输效率。

⚫ XML

XML(Extensible Markup Language),中文名为可扩展标记语言,标准通用标记语言

的子集,是一种用于标记电子文件使其具有结构性的标记语言。

⚫ CSS

层叠样式表(Cascading Style Sheets)是一种用来表现 HTML(标准通用标记语言的

一个应用)或 XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS 不仅可

以静态的修饰网页,还可以配合各种脚本语言动态的对网页各元素进行格式化。

⚫ JavaScript

JavaScript,是一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,

内置支持类型。它的解释器被称为 JavaScript 引擎,是浏览器的一部分,广泛用于客户端

的脚本语言。

申请微信小程序

登录微信公众平台,注册账号,选择小程序。https://mp.weixin.qq.com/

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

按照步骤依次注册,输入邮箱,密码,验证码等,同意协议进行注册

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

然后登录自己的邮箱,查阅邮件,点击链接进行激活。进入步骤 3,信息登记,按照网页要求,依次输入信息,身份信息,管理员微信信息,即可激活成功。

返回微信公众平台,输入刚刚注册的账户密码,会需要用管理员微信扫码登录,登录后,

下载普通小程序开发者工具

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

点击开发,选择开发设置,获取小程序 ID,以备后续开发需求。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

微信小程序开发工具下载完成后,进行默认安装即可。

创建新项目工程

打开微信小程序开发者工具,点击创建新工程,填写自己的 APPID,选择默认模板,语

言选择 JavaScript,点击新建

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

新建工程完成为如下界面

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

打开主界面的右上角的详情按钮,找到本地设置,将“增强编译”和“不校验合法域名”

这两个选项进行勾选,因为在小程序的开发阶段,尽量把这两勾选上

打开 app.json 文件,可以更改微信小程序的标题,改为“工程 demo”。然后按下 Ctrl

+ S 快捷键进行保存,即可完成编译,调试输出。查看现象

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

代码实现

A7adc 采集线程

这里直接去读取/sys/bus/iio/devices/iio:device3/in_voltage0_raw 和

/sys/bus/iio/devices/iio:device3/in_voltage1_raw 文件的数据进行计算。通过信号的方式发送计算完成的电流和电压给主线程。

#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 采集数据的程序启动起来,然后会在根目录下的 dev 目录下生成两个串口文

件。

system("cd EX_ADC_CM4/ ;./fw_cortex_m4.sh start");

这句代码是 到 EX_ADC_CM4 路径下 启动 m4 程序

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

我们向串口文件写入{“vol”:ture}后,m4 程序会自动采集并将数据写入串口,只需要读

取串口就能拿到数据了。通过信号的方式发送计算完成的电流和电压给主线程。

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);

}

}

主线程

接收到数据采集线程发送来的电流和电压值会在 ui 界面显示出来。

这里使用绘制事件写了一个电表的类 Dial,可以直接拿来使用。

使用 Dial 类 实例化两个对象,一个电流表 一个电压表。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

这个是对电表进行初始化,包括设置电表的大小、量程、转动速度、颜色等。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

并且建立信号槽的连接,当采集线程发送采集的数据给主线程后,就进入槽函数

这里将电流和电压设置到电表上并且设置到 LcdNumber 控件上面。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

数据库存储电量

使用 sqlite3 数据库存储剩余电量。当剩余电量低于 5 时,会弹窗,并且关闭电表显

示数据的信号槽

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

通过微信小程序充值电费

使用使用 mqtt 连接百度云。通过接收微信小程序客户端发来的数据,进行数据库数据的修改。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

微信小程序

第一步:创建新项目

 打开微信开发者工具,新建项目,填写自己的 AppID,新建。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

注意:创建工程的路径一定不能有中文。

第二步:修改微信小程序代码

修改 app.json 文件

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

下载支持 MQTT 协议和 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 目录下

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

编写 index.wxml,这个文件是用来编写页面的布局。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

编写 index.wxss,这个文件是用来配置页面的属性。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

编写 index.js,修改设备信息三元组。这个文件用来主要逻辑的编写

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

第三步:修改 socket 合法域名

 所有的程序编写完成之后,进入调试窗口,就会看到下面这种情况:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

说明没有在微信小程序的开发管理中添加这个域名所导致的。

 打开小程序开发网页:

https://mp.weixin.qq.com/wxamp/devprofile/get_profile?token=584612979&lang=

zh_CN

打开开发管理->开发设置->服务器域名,修改 socket 合法域名,添加这个域名即可。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

注:可以直接把我们的小程序源码导入使用。源码路径【6_工业电表\\微信小程序源码

\\Electricity】

实验源码

实验源码分为 A7 采集 ADC 数据和 M4 采集 ADC 数据,源码路径【6_工业电表\\实验源码\\6_ammeter_A7】和【6_工业电表\\实验源码\\6_ammeter_M4】。

注意事项

件。详细参考【FS-MP1A 开发教程】中 50.5 linux 源码编译章节

1. 进入在镜像中拿到的 linux 源码下的 dts 路径下:

linux@ubuntu:~cd linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts

2. 新建设备树文件

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

加入以下内容。

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

5. 进入内核顶层目录编译

linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$ make dtbs

6. 拷贝编译好的设备树文件到开发板

linux@ubuntu:~/linux/fsmp1a-linux-5.4.31$scparch/arm/boot/dts/stm32mp157a-fsmp1aextended-noadc-rgb070.dtb root@192.168.10.130:/boot

7. 修改默认启动选项

root@fsmp1a:~# vi /boot/mmc1_extlinux/stm32mp157a-fsmp1a-extended_extlinux.conf

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

8. 重启开发板

选择后,即可载入设备树文件

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

9. 在开发板运行时,需要导入中文字库,否则会因为识别不了中文。

将【6_工业电表 \\工具软件\\wqy-zenhei-0.9.47-nightlybuild.tar.gz 或 wqyzenhei-0.8.38-1.tar.gz】复制到 ubuntu 下。并使用 scp 命令将文件拷贝到开发板

的 usr/share/fonts 目录下,使用 tar 命令解压后即可

linux@ubuntu:~$ scp wqy-zenhei-0.8.38-1.tar.gz

root@192.168.10.128:/usr/share/fonts/

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

10. 如果使用 mipi 五寸屏运行此项目,需要进行屏幕旋转以适应屏幕,具体步骤如

下:在/etc/profile.d/qt-eglfs.sh 添加环境变量如下:

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目
Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

下面变量的 event0 设备需要填实际的触摸屏设备

Stm32mp157开发板学生毕业选题设计嵌入式linux+qt物联网工业电表项目

这里即填 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