Linux development board Internet of Things project actual combat environmental testing students' graduation project first choice

The stm32mp157 development board FS-MP1A is a high-quality, cost-effective Linux+MCU two-in-one embedded teaching-level development board independently developed by Huaqing Vision. The development board is equipped with ST's STM32MP157 high-performance microprocessor, which integrates 2 Cortex-A7 cores and 1 Cortex-M4 core. The A7 core can run the Linux operating system, and the M4 core can run FreeRTOS, RT-Thread and other real-time operating systems. . The development board is equipped with rich expansion modules such as emulators, display screens, cameras, and resource expansion boards, which can expand the learning of related technologies such as the Internet of Things and artificial intelligence, and can also expand rich project practice, which is very suitable for the current development needs of enterprises. A must-have development board for entry-level embedded Linux!

Learnable technologies : Embedded Linux application/system/driver development, ARM bare-metal development, Qt interface programming, STM32 single-chip microcomputer, FreeRTOS, artificial intelligence machine vision, etc. Among them, the ARM Cortex-A7 bare-metal development course is a unique course of Huaqing Foresight, which can be followed: https://www.bilibili.com/video/BV1Xe4y1i7vm/ , which is being continuously updated.

14 Linux+Qt comprehensive project cases, 6 MP1A IoT expansion projects

Public account "Huaqing Vision Online Lab", reply "mp157 project", and you can get the supporting documents and source code of the project.

Linux+Qt comprehensive project case : Huaqing Yuanjian stm32mp157 development board advantages and features, including music player, smart home, smart industrial meter, smart travel assistant, smart peephole, environmental monitoring, smart security, smart voice recognition and more than 10 projects The case involves a variety of application directions in home furnishing, medical care, and agriculture. In the case, a variety of Internet of Things and embedded technologies are used, including OT development, linux application development, linux driver development, Internet of Things cloud access, MQTT protocol, and json characters String and other knowledge points.

Environmental detection project based on Linux+Qt

Project function introduction:

(1) It is designed with an environmental monitoring function, which collects the ambient temperature, humidity, and light in real time through the temperature, humidity, and light sensors and displays them on the LCD screen.

(2) It is designed with device control function, which can control 3 LED lights, fan and buzzer by controlling the touch screen.

(3) Design the intelligent detection function. Users can modify the threshold of intelligent detection according to their own needs. After the intelligent detection is turned on, the device will be activated when the environment reaches the threshold. For example, if the temperature threshold is set to 28 degrees Celsius, when the ambient temperature reaches 28 degrees Celsius, the fan will be turned on automatically. Set the first-level lighting to 50lux, the second-level lighting to 30lux, and the third-level lighting to 1lux. When the light intensity is less than 50lux, one led light will be turned on, and when the light intensity is less than 30lux, two led lights will be turned on. When the light intensity is less than 1lux, three led lights will be turned on. All on.

Development Platform:

Huaqing Yuanjian stm32mp157 development board luxury package (development board + emulator + five-inch screen + camera + resource expansion board + tf card + card reader)

Project combat:

Qt development environment construction

Description of host development environment

1) This document mainly introduces the Qt program development under the linux environment;

2) The host Qt version is 5.14.1;

Host Qt environment construction and use

Qt Creator installation

Copy qt-creator-opensource-linux-x86_64-4.10.1.run (Qt experimental source code\tool software) to the ubuntu host, you can use the shared folder or tfp to save the file in the home directory Downloads directory. We need to give the installer executable permissions in the terminal

We can use the graphical file manager to view

Double-click the "qt-creator-opensource-linux-x86_64-4.10.1.run" icon to run the installer.

The following interface appears:

Wait for the program verification to complete and click "Next"

Here we need to log in or register an account. If we have registered before, we can log in directly. If you have not registered, you need to register a new account and log in. Here the author has already registered an account, so log in directly. After successful login, the following interface appears, click Next

Choose the installation path here

You can directly default, Next

The components to be installed in this way can be directly defaulted

Here we need to agree to the user agreement

This interface tells us how much space we need to take up after the installation is complete. Click the "Install" button to start the installation.

After the installation is complete, the following interface appears

点击“Finish”按钮后将弹出 Qt Creator 主界面

点击“Cancel”按钮后即可正常使用

Qt5.14.1 安装

复制到 qt-opensource-linux-x64-5.14.1.run(Qt 实验源码\工具软件)到 ubuntu 主机中,可以采用共享文件夹的方式也可以使用 tfp 方式将文件存入家目录下的 Downloads 目录。进入所在文件夹,先给执行权限

输入命令

chmod +x ./qt-opensource-linux-x64-5.14.1.run

安装在命令行输入

./qt-opensource-linux-x64-5.14.1.run

会有可视化引导安装,一直 next 就行了

在选择安装组件的时候要是不知道选择那些就全选了 大概有 4 个 G 左右

下载 gcc 和 g++

sudo apt-get install gcc g++

下载 cmake

sudo apt-get install cmake

下载链接库

sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev

Qt Creator 配置

1)配置 GCC

运行 QtCreator 后,依次点击"Tool"->"Options",出现选项对话框,在左侧点击"Kits",右 边选择"Compilers"标签。 检查有没有下图标注的 C++和 C ,般按上面步骤执行后都会有

点击右侧"Add"按钮,弹出下拉列表后,选择"GCC"的"C"

填写信息如下,"Name"为"Auto-GCC","Compiler path"点击旁边的"Browse.."按钮选择编译器的路径,例子中的路径是 “/usr/bin/gcc”

2)配置 G++

点击右侧"Add"按钮,弹出下拉列表后,选择"GCC"的"C++",下面的文本框填写"Name" 为"Auto-G++","Compiler path"点击旁边的"Browse.."按钮选择编译器的路径,例子中的路径是" /usr/bin/g++"。

填写完成后,点击"Apply"。

3)配置 qmake

选择"Qt Versions"标签,如果有下面红框中的文本,可以跳过下面步骤

如果没有,在右侧点击"Add..."

会弹出 qmake 路径选择对话框,这里以"

/home/linux/Qt5.14.1/5.14.1/gcc_64/bin/qmake"为例子。 选择”qmake”文件后,点击"Open"按钮

"Version name"改为" Qt %{Qt:Version} GCC"。然后点击"Apply"按钮。

4)配置 Kits

点击左侧"Kits",右侧选择"Kits"标签。检查有没有下图红框选中的文本,如果有可以跳过下面步骤

然后没有,点击 Add:

在弹出的对话框中"Name"为"Desktop","Device Type"选择"Desktop"选项, "Sysroot"选择目标设备的系统目录,"Compiler"选择之前配置的名称"Auto-GCC"和"Auto-G++","Qt version"选择之前配 置的名称"Qt 5.14.1GCC",其它默认即可,最后点击"Apply"和"OK"按钮。

Qt Creator 新建工程

注意:工程路径最好不要包含中文、特殊字符、空格等。

我们可以新建一个“qt”文件夹,该文件夹用作我们以后存放源代码。

打开 Qt Creator,在欢迎页面点击 “New”按钮,来新建一个工程。

在出现的新建项目窗口中,我们选则“Application”->“Qt Widgets

Application”,然后点击右下方“Choose…”按钮,来创建一个桌面 Qt 应用。

我们在这里设置项目介绍和源码位置,我们这里创建一个名为“HelloWorld”的示例项目,设置完成之后点击 next

直接点击 next

随后进行细节设置,主要设置要创建的源码文件的基本类信息,包括类名等。这里我们可以根据自己的项目特点进行设置。需要说明的一点就是基类的选择,这里基类有 QMainWindow、QWidget、QDialog 三种,它们的不同之处如下:

  • QMainWindow 类提供一个带有菜单条,工具条和一个状态条的主应用程序窗口。主窗口通常提供一个大的中央窗口部件,以及周围菜单,工具条,和一个状态栏。QMainWindow 窗口经常被继承,使得封装中央部件,菜单,工具条,状态栏等都变得很容易,当用户点击它的时候,相应的槽就会被调用;

  • QWidget 类是所有用户界面对象的基类,窗口部件是用户界面的一个基本单元,它从窗口系统接收鼠标,键盘和其他消息,并在屏幕上绘制自己。一个窗口部件可以被他的父窗口或者是其他窗口挡住一部分;

  • QDialog 类是对话框窗口的基类,对话框窗口主要用于短期任务和用户进行短期通讯的顶级窗口,QDialog 可以是模态对话框或者是非模态对话框。QDialog 支持扩展并带有返回值,他们可以带有默认值;我们在这里选择 QDialog 类即可,点击 next 完成类信息设置。

直接点击 next 按钮即可。

然后进行工具选择,该页面可以选择我们创建的工程可以使用的工具,选择想要使用的编译器模块,例如下图 。点击 next

最后我们设置汇总信息,如果不需要版本控制等功能,直接点击完成finish 即可。

随后我们就进入到了主界面,这时候 Qt 已经帮我们做好了一些准备工作,包括创建了一些文件,写好了一些前置代码等等。

我们可以点击左边 protect 栏,来查看我们的编译选项。

我们可以在左下角选择编译 Debug 版或者 Release 版,即调试版或发行版。

左下角绿色剪头是编译并运行,锤子是仅编译,我们可以直接点击绿色小箭头将我们导入的工程编译并运行起来。

点击运行按钮后,我们可以看到 HelloWorld 窗口运行起来了。

Qt Creator导入工程

我们可以将已存在的 Qt 程序项目直接打开,这里以上一章节的HelloWorld 程序为例。首先我们确定源码存在的位置,如 HelloWorld 程序源码在 /home/linux/qt/helloworld 路径下点击欢迎页面的“Open” 按钮可以打开已有的工程

找到我们刚才解压好的源码,选择“helloworld.pro”文件并点击打开

接下来我们就可以进入到代码编辑界面了。

左上角是项目栏,点击项目名称左边的小箭头可以展开项目目录

我们可以点击左边项目栏,来查看我们的编译选项。需注意的是构建设置中的路径应与工程路径处于同级目录下。

我们可以在左下角选择编译 Debug 版或者 Release 版,即调试版或发行版。

左下角绿色剪头是编译并运行,锤子是仅编译,我们可以直接点击绿色小箭头将我们导入的工程编译并运行起来

点击运行按钮后,我们可以看到 HelloWorld 窗口运行起来了。

Qt Creator 文件说明

通过上面两个章节,我们学习到了 Qt 程序的新建与导入的方法,也知道了Qt 会帮我们做一些基础工作,比如帮我们建立了一些文件,那么这些文件都是干什么用的呢?我们以HelloWorld 程序来说明一下。

以“.pro”为后缀名的文件,为 Qt 的项目管理文件,存储项目设置的文件;

“Qt += core gui”表示项目中加入 core gui 模块。core gui 是 Qt 用于GUI 设计的类库模块,如果创建的是控制台(console)应用程序,就不需要添加 core gui。

Qt 类库以模块的形式组织各种功能的类,根据项目涉及的功能需求,在项目中添加适当的类库模块支持。例如,如果项目中使用到了涉及数据库操作的类就需要用到 sql(数据库)模块,在 pro 文件中需要在后面加上 sql:

1 Qt += core gui sql

“greaterThan(QT_MAJOR_VERSION, 4): QT += widgets”,这是个条件执行语句,表示当 Qt 主版本大于 4 时,才加入 widgets 模块。

“TARGET = HelloWorld”表示生成的目标可执行文件的名称,即编译后生成的可执行文件是 HelloWorld.exe。

“TEMPLATE = app”表示项目使用的模板是 app,是一般的应用程序。

后面的 SOURCES、HEADERS、FORMS 记录了项目中包含的源程序文件、头文件和窗体文件(.ui 文件)的名称。这些文件列表是 Qt Creator 自动添加到项目管理文件里面的,用户不需要手动修改。当添加一个文件到项目,或从项目里删除一个文件时,项目管理文件里的条目会自动修改。

文件夹“Header”中,存放的是所设计的窗体类的头文件;

文件夹“Sources”中,存放着源码文件。main.cpp 是实现 main()函数的程序文件,HelloWorld.cpp 是 widget.h 里定义类的实现文件。C++中,任何窗体或界面组件都是用类封装的,一个类一般有一个头文件(.h 文件)和一个源程序文件(.cpp 文件);

文件夹“Forms”中,存放着界面设计文件,“.ui”文件是一个 XML 格式存储的窗体上的元件及其布局的文件,双击项目文件目录树中的文件 ui,会打开一个集成在 Qt Creator 中的 Qt Designer 对窗体进行可视化设计;

UI 设计器有以下一些功能区域:

组件面板:窗口左侧是界面设计组件面板,分为多个组,如 Layouts、Buttons、Display Widgets 等,界面设计的常见组件都可以在组件面板里找到。

中间主要区域是待设计的窗体。如果要将某个组件放置到窗体上时,从组件面板上拖放一个组件到窗体上即可。

Signals 和 Slots 编辑器与 Action 编辑器是位于待设计窗体下方的两个编辑器。Signals 和 Slots 编辑器用于可视化地进行信号与槽的关联,Action 编辑器用于可视化设计 Action。

布局和界面设计工具栏:窗口上方的一个工具栏,工具栏上的按钮主要实现布局和界面设计。

对象浏览器(Object Inspector):窗口右上方是 Object Inspector,用树状视图显示窗体上各组件之间的布局包含关系,视图有两列,显示每个组件的对象名称(ObjectName)和类名称。

属性编辑器(Property Editor):窗口右下方是属性编辑器,是界面设计时最常用到的编辑器。属性编辑器显示某个选中的组件或窗体的各种属性及其取值,可以在属性编辑器里修改这些属性的值。属性编辑器的内容分为两列,左侧为属性的名称,右侧为属性的值。属性又分为多个组,实际上表示了类的继承关系,位于下方的类属性组继承自位于上方的类属性组;

如果我们需要新建资源文件、源码文件等,可以在项目文件夹出点击鼠标右键,选择 Add New;如果我们有新的文件需要添加,可以在项目文件夹出点击鼠标右键,选择 Add Existing Files。

Qt Creator 帮助文档

Qt 的帮助文档是伴随我们学习 Qt 开发的好伙伴。在 Qt 开发过程中,我们会面临图形接口使用的问题,它不像 C 语言那样就那么几个函数接口,图形接口的接口数量可以用海量来形容,常用的我们可能能记住,其它的就没有必要去记了,用到什么就去帮助文档查看用法是比较方便的。我们可以按 F1 按键,或通过上方导航栏的“help->contects”来进入帮助文档。

上方的前进后退按钮方便我们查看文档,如返回到上一步,返回到下一步。

我们可以通过帮助文档来查看以下几个部分:类使用的相关介绍;

查看相关类的使用介绍,我们可以先进入到帮助文档,然后在左上角选择“Search”。笔者这里以 QWidget 类为例,输入我们想要查找的类的名字,然后双击查找结果来查看说明。

也可以先将鼠标移动到想要查询的类的位置,如图所示,将鼠标移动至“QWidget”处,然后按“F1”键,即可跳转到相应的帮助文档。

我们可以通过再按一次“F1”键来全窗口查看帮助文档,按“Esc”键可以退出。

部分常用的成员元素包括以下几项:

公有成员函数:操作部件属性的相关函数;

公有槽函数:Qt 类中已经定义好的槽函数,直接可与信号相连接;

信号:软中断,如按下按钮触发 pressed() 信号等;

保护成员函数:通常事件所对应的虚函数放在此处;

事件:常用事件,如操作鼠标触发的鼠标事件;

滚动鼠标滚轮,向下即可看到“Qwdget Class”类的相关说明了。

部分常用的成员元素包括以下几项:

公有成员函数:操作部件属性的相关函数;

公有槽函数:Qt 类中已经定义好的槽函数,直接可与信号相连接;

信号:软中断,如按下按钮触发 pressed() 信号等;

保护成员函数:通常事件所对应的虚函数放在此处;

事件:常用事件,如操作鼠标触发的鼠标事件;

滚动鼠标滚轮,向下即可看到“Qwdget Class”类的相关说明了。

1) 查看所用的部件的相应成员函数。

我们可以查找到该类所用部件的相应成员函数的使用方法、功能、参数、返回值等等,我们以“按钮”控件,即“QPushButton Class”类为例,我们通过索引搜索的方式,来找到这个类

我们可以通过点击“Public Functions” 来查看“QPushButton”这个类中的成员函数。

这里以“QPushButton(const QString &text, QWidget *parent =Q_NULLPTR)”为例,我们点击函数名字可以进入到函数详情中。我们可以看到相应的描述为:以“text”为显示内容,以“parent”为父对象,构造一个push 按钮。“text”“parent”为函数参数,由于是构造函数,所以此函数没有返回值。

还有一些函数是继承自其它类的,例如“Public Functions”中有 21 个继承自“QAbstractButton”类的函数,我们点击“QAbstractButton”即可查看。击“QAbstractButton”即可查看

同样我们可以点击相应的函数进入查看详情。如查看“voidsetText(const QString &text)”。

2) 查看所用的部件的信号。

我们这里还是以“PushButton”为例,我们点击“Public Slots”。

可以看到“PushButton”本身有一个“void showMenu()”的信号,并且有很多继承自其他类的信号。

一般来说我们用的“PushButton”的信号,最多的是用到其继承自基类“QAbstractButton”中的几个信号,分别是点击(按下后抬起)、按压(单按下)、释放(单抬起)等

我们可以点击相应信号查看详情

3) 查看所用的部件的事件(所对应的虚函数如何编写)。

部件常用事件主要在 “QWidget”中声明,选择“Events”即可查看相关说明。

每个事件都对应着事件函数。

点击事件函数可查看详情

项目总体设计介绍

(1)设计有环境监测功能,通过温湿度、光照传感器实时采集环境温度、湿度、光照显示到 LCD 屏上。

(2)设计有设备控制功能,通过控制触摸屏来进行控制 3 个 LED 灯、风扇、蜂鸣器。

(3)设计智能检测功能,用户可以根据自己的需求修改智能检测的阈值,开启智能检测后,当环境达到阈值后会启动设备。比如设置温度阈值为 28 摄氏度,当环境温度达到 28 摄氏度时,会自动开启风扇。设置一级照明为 50lux,二级照明为 30lux,三级照明为 1lux,当光照强度小于 50lux 会开启一个 led 灯,小于 30lux 会开启 2 个 led 灯,当光照强度小于 1lux 时,3 个 led 灯会全部开启

M4 部分实验原理

M4 部分功能概述

M4 核部分主要实现两个功能,首先可以接收 A7 核发送的指令,根据指令控制风扇、蜂鸣器以及 LED 灯工作,同时 M4 部分可以采集环境光、温湿度传感器数据,将采集数值打包成 JSON 字符串然后发送给 A7。另外,通过按键可以控制数码管显示采集的温湿度、环境光数据。

cubeIDE 功能配置

首先打开 cubeIDE,创建一个新工程,进入 cubeMX 配置界面,因为需要实现 A7 与 M4 通信,需要配置 IPCC 与 OPENAMP 部分,如下图所示

配置 I2C1 用于采集温湿度、环境光传感器数据,这里分别选择 PF14、PF15 引脚用作 I2C1_SDA 和 I2C1_SCL 功能

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

Output Signal”,其配置如下图所示

扩展板 LED 灯对应的 GPIO 引脚分别为 PE8、PE10、PF10,这里左键点击设置为 GPIO_Output

可以通过按键中断控制数码管显示的数值,这里配置扩展板的按键为PF9,如下所示

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

打开 GPIO 标签,对 PF9 引脚进行配置

实验中还用到了蜂鸣器与风扇,查看原理图得,对应管脚分别为 PB6 与PE9,分别配置为 TIM4 与 TIM1 功能,在本次实验中,系统默认时钟频率为64MHz,TIM 配置如下所示

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

另外,在本次实验中,A7 与 M4 数据通信和数码管显示相当于同时运行,可以通过配置 FreeRTOS 实现多任务运行。切换到中间件“Middleware”的“FREERTOS”,默认自动勾选给 M4 了,然后接口“Interface”选择

“CMSIS_V2”。为了运行其他任务,这里需要切换到“Tasks and Queues”标签,可以看到看到默认有个“defaultTask”任务,我们点击“Add”再新增一个任务,如图所示

上述配置完成以后,还要注意一点,因为用到 FreeRTOS,这里我们不能为每一种外设生成头文件,如下所示

配置完成以后保存,然后生成初始化代码,其间会出现如下提示框,选择“Yes”

代码实现

生成初始代码以后,在 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_si7006.c文件,编写温湿度数据采集函数

uint8_t SI7006_Init(void)

{

HAL_I2C_Init(&hi2c1);

SI7006_WriteByte(SI7006CMD_RESET);

return 0;

}

uint8_t SI7006_WriteByte(uint8_t reg)

{

uint8_t write_data = reg;

if(HAL_I2C_Master_Transmit(&hi2c1, SI7006_ADDR | SI7006_W ,

(uint8_t*)&write_data, 1, 300) != HAL_OK)

{

Error_Handler();

}

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);

return 0;

}

uint16_t SI7006_ReadWord(uint8_t reg)

{

uint16_t read_data = 0;

if(HAL_I2C_Master_Transmit(&hi2c1, SI7006_ADDR | SI7006_W ,

(uint8_t*)&reg, 1, 300) != HAL_OK) //发送命令

{

Error_Handler();

}

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);

if(HAL_I2C_Master_Receive(&hi2c1, SI7006_ADDR | SI7006_R ,

(uint8_t*)&read_data, 2, 300) != HAL_OK) //接收 word 数据

{

Error_Handler();

}

return read_data;

}

uint16_t SI7006_Read_Data(uint16_t cmd)

{

uint16_t data = 0,data_low = 0,data_high = 0;

data = SI7006_ReadWord(cmd); //采集温湿度

data_low = (data & 0xff); //进行高低字节转换

data_high = (data >> 8) & 0xff;

data = (data_low << 8) + data_high;

return data;

}

uint16_t SI7006_Readhum(void)

{

uint16_t hum = 0;

hum = SI7006_Read_Data(SI7006CMD_RH_HOLD);

hum = (125*hum/65536 - 6);

return hum;

}

uint16_t SI7006_Readtem(void)

{

uint16_t tem = 0;

tem = SI7006_Read_Data(SI7006CMD_TEMP_HOLD);

tem = ((17572*tem)/65536 - 4685);

return tem;

}

添加 driver_ap3216.c 文件,编写环境光数据采集函数

uint8_t AP3216_Init(void)

{

uint8_t ret_value = 0;

AP3216_WriteOneByte(SYS_CONFIG_ADDR, SYS_SW_RESET);

HAL_Delay(50);

AP3216_WriteOneByte(SYS_CONFIG_ADDR, SYS_ALS_ACT);

HAL_Delay(50);

ret_value = AP3216_ReadOneByte(SYS_CONFIG_ADDR);

if(ret_value != SYS_ALS_ACT)

{

printf("read error \n");

}

printf("\r I2C Configuration register: 0x%x \n", SYS_CONFIG_ADDR);

printf("\r I2C Configuration value: 0x%x \n", SYS_ALS_ACT);

printf("\r I2C Read configuration value: 0x%x \n", ret_value);

return 0;

}

uint8_t AP3216_WriteOneByte(uint8_t reg, uint8_t data)

{

uint16_t write_data = reg | (data<<8)

if(HAL_I2C_Master_Transmit(&hi2c1, AP3216_ADDR | AP3216_W ,

(uint8_t*)&write_data, 2, 300) != HAL_OK)

{

Error_Handler();

}

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);

return 0;

}

uint8_t AP3216_ReadOneByte(uint8_t reg)

{

uint8_t read_data = 0;

if(HAL_I2C_Master_Transmit(&hi2c1, AP3216_ADDR | AP3216_W ,

(uint8_t*)&reg, 1, 300) != HAL_OK)

{

Error_Handler();

}

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);

if(HAL_I2C_Master_Receive(&hi2c1, AP3216_ADDR | AP3216_R ,

(uint8_t*)&read_data, 1, 300) != HAL_OK)

{

Error_Handler();

}

return read_data;

}

uint16_t AP3216_Read_ALS_Data()

{

uint8_t als_l = 0, als_h = 0;

uint16_t data;

als_l = AP3216_ReadOneByte(ALS_DATA_LOW);

als_h = AP3216_ReadOneByte(ALS_DATA_HIGH);

data = (als_h<<8) | (als_l);

return data;

}

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

uint8_t num[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

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;

}

void M74HC595_ReadDataTest(uint16_t data,uint8_t sign)

{

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

if(sign == 0) //sign = 1 为整数, = 0 为小数

num[data2] = (num[data2] | 0x80);

else

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

}

添加 driver_pwm.c 文件,编写风扇与蜂鸣器控制函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

if(htim->Instance==TIM4) //beep

{

__HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,9999);

}

if(htim->Instance==TIM1) //fan

{

__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,level *

3000);

}

}

void TIM4_PWM_START(void)

{

if(HAL_TIM_Base_Start_IT(&htim4) != HAL_OK)

{

Error_Handler();

}

HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);

}

void TIM4_PWM_STOP(void)

{

if(HAL_TIM_Base_Start_IT(&htim4) != HAL_OK)

{

Error_Handler();

}

HAL_TIM_PWM_Stop(&htim4,TIM_CHANNEL_1);

}

void TIM1_PWM_START(void)

{

if(HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)

{

Error_Handler();

}

HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

}

void TIM1_PWM_STOP(void)

{

if(HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)

{

Error_Handler();

}

HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);

}

在 StartDefaultTask() 任务中实现 A7 与 M4 的数据传输,在 StartTask02

() 任务中实现控制数码管显示采集的传感器数值,相关代码如下

void StartDefaultTask(void *argument)

{

/* USER CODE BEGIN 5 */

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

}

if(VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID,

VIRT_UART0_RxCpltCallback) != VIRT_UART_OK)

{

printf("callback 0 error \n");

Error_Handler();

}

AP3216_Init();

SI7006_Init();

/* Infinite loop */

for(;;)

{

OPENAMP_check_for_message();

if (VirtUart0RxMsg)

{

VirtUart0RxMsg = RESET;

usr = cJSON_CreateObject();

#if 1

json = cJSON_Parse((char *)VirtUart0ChannelBuffRx);

json_led1 = cJSON_GetObjectItem(json,"led1");

json_led2 = cJSON_GetObjectItem(json,"led2");

json_led3 = cJSON_GetObjectItem(json,"led3");

json_beep = cJSON_GetObjectItem(json,"beep");

json_fan = cJSON_GetObjectItem(json,"fan");

if( strcmp((char*)json_led3->string,"led3") == 0)

{

printf("led1 light \n");

if(json_led3->valueint == 1)

HAL_GPIO_WritePin(GPIOE,

GPIO_PIN_8,GPIO_PIN_SET);

else

HAL_GPIO_WritePin(GPIOE,

GPIO_PIN_8,GPIO_PIN_RESET);

}

else if( strcmp((char*)json_led2->string,"led2") == 0)

{

printf("led2 light \n");

if(json_led2->valueint == 1)

HAL_GPIO_WritePin(GPIOF,

GPIO_PIN_10,GPIO_PIN_SET);

else

HAL_GPIO_WritePin(GPIOF,

GPIO_PIN_10,GPIO_PIN_RESET);

}

else if( strcmp((char*)json_led1->string,"led1") == 0)

{

printf("led1 light \n");

if(json_led1->valueint == 1)

HAL_GPIO_WritePin(GPIOE,

GPIO_PIN_10,GPIO_PIN_SET);

else

HAL_GPIO_WritePin(GPIOE,

GPIO_PIN_10,GPIO_PIN_RESET);

}

else if( strcmp((char*)json_beep->string,"beep") == 0)

{

printf("beep work \n");

if(json_beep->valueint == 1)

TIM4_PWM_START();

else

TIM4_PWM_STOP();

}

else if( strcmp((char*)json_fan->string,"fan") == 0)

{

printf("fan work \n");

switch(json_fan->valueint)

{

case 1 :

case 2 :

case 3:

level = json_fan->valueint;

TIM1_PWM_START();

break;

case 0:

TIM1_PWM_STOP();

break;

}

}

#endif

value_als = AP3216_Read_ALS_Data();

value_tem = SI7006_Readtem();

value_hum = SI7006_Readhum();

cJSON_AddNumberToObject(usr,"als",value_als);

cJSON_AddNumberToObject(usr,"tem",value_tem);

cJSON_AddNumberToObject(usr,"hum",value_hum);

out = cJSON_Print(usr);

printf("the out: %s \n",out);

strcpy((char *)BuffTx,out);

if( VIRT_UART_Transmit(&huart0, BuffTx, strlen((const char

*)BuffTx)) != VIRT_UART_OK)

{

printf("transmit error \n");

}

memset(BuffTx, 0 ,strlen((const char *)BuffTx));

cJSON_Delete(usr);

memset(VirtUart0ChannelBuffRx, 0 ,VirtUart0ChannelRxSize);

cJSON_Delete(json);

cJSON_Delete(json_led1);

cJSON_Delete(json_led2);

cJSON_Delete(json_led3);

cJSON_Delete(json_beep);

cJSON_Delete(json_fan);

}

}

/* USER CODE END 5 */

}

void StartTask02(void *argument)

{

/* USER CODE BEGIN StartTask02 */

/* Infinite loop */

for(;;)

{

switch(vol_cur)

{

case 1:

M74HC595_ReadDataTest(value_als,1);

break;

case 2:

M74HC595_ReadDataTest(value_tem,0);

break;

case 3:

M74HC595_ReadDataTest(value_hum,0);

break;

}

}

/* USER CODE END StartTask02 */

}

M4 部分调试、执行

程序编译没问题以后,点击“debug”下载调试,会将生成的 elf 文件下载到开发板/lib/fireware/目录下

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

在/usr/local/projects/ 目录下,可以看到含有所创工程名的目录

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

此时执行 ./fw_cortex_m4.sh start便可以启动 M4 程序。

源码分析

环境监测模块和智能检测模块

启动 m4 程序后会生成一个串口设备,m4 程序采集温湿度、环境光照信息。将采集到的数据写入到串口,a7 通过实时读取串口的数据,对数据进行解析、计算获得温湿度和光照的数值,再使用信号的方式传给主线程,实时显示到 UI 界面上,实现环境的温湿度和光照的监测。

使用 sqlite3 数据库进行存储用户设置的温度开启风扇的阈值、照明等级。用户每次改变阈值后都会存储到数据库里,当关闭程序后,下次启动会从数据库读取上次保存的数值,不用每次都重新设置阈值,更加人性化。

如果开启了智能检测,每次采集到数据后会跟用户设置的阈值进行比较,如果采集的温度大于设置的温度阈值,就会自动开启风扇;如果设置一级照明为 50lux,二级照明为 30lux,三级照明为 1lux,当光照强度小于 50lux 会开启一个 led 灯,小于 30lux 会开启 2 个 led 灯,当光照强度小于 1lux 时,3 个led 灯会全部开启。从而实现智能检测的功能

设备控制模块

只需要向相应的设备文件写入数据就能实现对 LED 灯、风扇、蜂鸣器的控制。在 QT 程序中,只需点击按键后触发 clicked 信号,进入相应的槽函数,向串口设备文件写入数据,M4 程序对数据进行采集,根据数据的不同,通过实现对设备的控制,核心代码如下

void MainWindow::led1_on_btnSlot()

{

QString ctrl ="{\"led1\":1}";

thread_collentdata.ctrlEnv = false;

write(fd, ctrl.toUtf8(), ctrl.length());

qDebug()<<"write fd:"<<fd<<" success"<<" data = "<<ctrl;

ui->pushButton->setEnabled(true);

}

设备树编译

使用 M4 程序进行数据采集的时候,因为 A7 和 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$ cp stm32mp157a-fsmp1aextended-rgb070.dts stm32mp157a-fsmp1a-extended-noi2c1-rgb070.dts

3. 修改复制的文件,将 i2c1 节点关闭

4. 修改 Makefile

linux@ubuntu:~/linux/fsmp1a-linux-5.4.31/arch/arm/boot/dts$ vi Makefile

加入以下内容。

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-fsmp1a

extended-noi2c1-rgb070.dtb [email protected]:/boot

7. 修改默认启动选项

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

8. 重启开发板

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

源码路径【8_环境检测\实验源码\8_EnvironmentalTest】

注意事项

1.在开发板运行时,需要导入中文字库,否则会因为识别不了中文。将【8_环境检测\工具软件\wqy-zenhei-0.9.47-nightlybuild.tar.gz 或wqy-zenhei-0.8.38-1.tar.gz】复制到 ubuntu 下。并使用 scp 命令将文件拷贝到开发板的 usr/share/fonts 目录下,使用 tar 命令解压后即可。

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

[email protected]:/usr/share/fonts/

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

步骤如下:

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

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

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

Guess you like

Origin blog.csdn.net/u014170843/article/details/129315554