文章目录
-
- 摘要
- [1. 环境准备与工具安装](#1. 环境准备与工具安装)
-
- [1.1 硬件准备](#1.1 硬件准备)
- [1.2 软件环境搭建](#1.2 软件环境搭建)
- [1.3 工具链配置](#1.3 工具链配置)
- [2. Buildroot系统构建](#2. Buildroot系统构建)
-
- [2.1 获取Buildroot源码](#2.1 获取Buildroot源码)
- [2.2 配置Buildroot](#2.2 配置Buildroot)
- [2.3 构建根文件系统](#2.3 构建根文件系统)
- [3. Linux内核配置与编译](#3. Linux内核配置与编译)
-
- [3.1 获取内核源码](#3.1 获取内核源码)
- [3.2 内核配置选项](#3.2 内核配置选项)
- [3.3 编译内核](#3.3 编译内核)
- [4. DHT11温湿度传感器驱动开发](#4. DHT11温湿度传感器驱动开发)
-
- [4.1 创建驱动文件](#4.1 创建驱动文件)
- [4.2 创建Makefile](#4.2 创建Makefile)
- [4.3 编译驱动](#4.3 编译驱动)
- [5. 设备树配置](#5. 设备树配置)
-
- [5.1 创建设备树 overlay](#5.1 创建设备树 overlay)
- [5.2 编译设备树 overlay](#5.2 编译设备树 overlay)
- [6. 系统集成与部署](#6. 系统集成与部署)
-
- [6.1 创建启动脚本](#6.1 创建启动脚本)
- [6.2 配置Buildroot overlay](#6.2 配置Buildroot overlay)
- [6.3 创建测试应用程序](#6.3 创建测试应用程序)
- [6.4 编译测试程序](#6.4 编译测试程序)
- [7. 系统烧录与测试](#7. 系统烧录与测试)
-
- [7.1 制作SD卡镜像](#7.1 制作SD卡镜像)
- [7.2 启动系统并测试](#7.2 启动系统并测试)
- [7.3 常见问题处理](#7.3 常见问题处理)
- [8. 成果展示与验证](#8. 成果展示与验证)
-
- [8.1 系统功能验证](#8.1 系统功能验证)
- [8.2 性能测试结果](#8.2 性能测试结果)
- 技术图谱
- 总结
摘要
本教程详细介绍了如何为STM32MP157开发板构建嵌入式Linux系统,使用Buildroot制作根文件系统,并开发DHT11温湿度传感器驱动,最终实现数据采集与显示。
1. 环境准备与工具安装
1.1 硬件准备
- STM32MP157开发板(推荐正点原子或野火系列)
- DHT11温湿度传感器模块
- 杜邦线若干
- MicroSD卡(16GB以上)
- USB转串口调试工具
1.2 软件环境搭建
bash
# 更新系统
sudo apt update
sudo apt upgrade -y
# 安装必要工具
sudo apt install -y build-essential git libncurses5-dev libssl-dev \
bison flex libelf-dev u-boot-tools device-tree-compiler \
python3 python3-pip python3-venv gcc-arm-linux-gnueabihf
# 创建工作目录
mkdir -p ~/stm32mp157-project/{buildroot,linux,kernel,drivers}
cd ~/stm32mp157-project
1.3 工具链配置
bash
# 下载ARM工具链
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
# 解压并设置环境变量
tar xf gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz
echo 'export PATH=$PATH:~/stm32mp157-project/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc
2. Buildroot系统构建
2.1 获取Buildroot源码
bash
cd ~/stm32mp157-project/buildroot
# 克隆Buildroot仓库
git clone https://git.buildroot.net/buildroot
cd buildroot
git checkout 2022.02.1 # 使用稳定版本
2.2 配置Buildroot
bash
# 创建配置文件
make stm32mp157_defconfig
make menuconfig
配置选项说明:
- Target options → ARM (little endian)
- Toolchain → Custom toolchain
- System configuration → Root filesystem overlay
- Kernel → Linux kernel (使用外部自定义内核)
Buildroot配置
Target Options
Toolchain
System Configuration
Kernel
ARM little endian
STM32MP157
Custom toolchain
Kernel Headers 5.10
Root filesystem overlay
Dev management: Dynamic
Use external Linux
Custom kernel config
2.3 构建根文件系统
bash
# 开始构建
make -j$(nproc)
# 构建完成后输出路径
echo "输出目录: $(pwd)/output/images/"
3. Linux内核配置与编译
3.1 获取内核源码
bash
cd ~/stm32mp157-project/linux
# 获取ST官方内核
git clone https://github.com/STMicroelectronics/linux.git
cd linux
git checkout v5.10-stm32mp
# 配置内核
make ARCH=arm stm32mp157_defconfig
make ARCH=arm menuconfig
3.2 内核配置选项
确保以下选项启用:
Device Drivers →
→ Hardware Monitoring support
→ DHT11 humidity/temperature sensor
→ Industrial I/O support →
→ Humidity sensors
→ Temperature sensors
File systems →
→ DOS/FAT/NT Filesystems →
→ VFAT (Windows-95) fs support
→ Pseudo filesystems →
→ /proc file system support
3.3 编译内核
bash
# 编译内核和模块
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- -j$(nproc)
# 编译设备树
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs
# 安装模块到临时目录
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- \
INSTALL_MOD_PATH=../output modules_install
4. DHT11温湿度传感器驱动开发
4.1 创建驱动文件
创建文件:~/stm32mp157-project/drivers/dht11.c
c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#define DRIVER_NAME "dht11"
#define DHT11_DATA_BITS 40
struct dht11_data {
struct device *dev;
struct gpio_desc *gpio;
int temperature;
int humidity;
struct timer_list timer;
struct completion completion;
int data[DHT11_DATA_BITS];
int edge_counter;
};
static irqreturn_t dht11_irq_handler(int irq, void *dev_id)
{
struct dht11_data *data = dev_id;
static ktime_t last_time;
ktime_t current_time = ktime_get();
s64 delta;
if (data->edge_counter < 2) {
/* 忽略前两个边沿(启动信号) */
data->edge_counter++;
last_time = current_time;
return IRQ_HANDLED;
}
delta = ktime_us_delta(current_time, last_time);
last_time = current_time;
if (data->edge_counter - 2 < DHT11_DATA_BITS) {
int bit_index = data->edge_counter - 2;
/* 超过40μs为1,否则为0 */
data->data[bit_index] = delta > 40 ? 1 : 0;
}
data->edge_counter++;
if (data->edge_counter >= DHT11_DATA_BITS + 2) {
complete(&data->completion);
}
return IRQ_HANDLED;
}
static void dht11_timer_callback(struct timer_list *t)
{
struct dht11_data *data = from_timer(data, t, timer);
complete(&data->completion);
}
static int dht11_read_data(struct dht11_data *data)
{
int i, humidity = 0, temperature = 0;
unsigned long timeout;
/* 发送开始信号 */
gpiod_direction_output(data->gpio, 0);
mdelay(18);
gpiod_direction_input(data->gpio);
/* 准备读取数据 */
data->edge_counter = 0;
reinit_completion(&data->completion);
mod_timer(&data->timer, jiffies + msecs_to_jiffies(10));
timeout = wait_for_completion_timeout(&data->completion,
msecs_to_jiffies(10));
del_timer(&data->timer);
if (!timeout) {
dev_err(data->dev, "DHT11读取超时\n");
return -ETIMEDOUT;
}
/* 解析数据 */
for (i = 0; i < 16; i++) {
humidity = (humidity << 1) | data->data[i];
}
for (i = 16; i < 32; i++) {
temperature = (temperature << 1) | data->data[i];
}
/* 校验和验证 */
if (((humidity + temperature) & 0xFF) != data->data[32]) {
dev_err(data->dev, "DHT11校验和错误\n");
return -EIO;
}
data->humidity = humidity;
data->temperature = temperature;
dev_info(data->dev, "温度: %d°C, 湿度: %d%%\n",
temperature, humidity);
return 0;
}
static ssize_t temperature_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dht11_data *data = dev_get_drvdata(dev);
int ret = dht11_read_data(data);
if (ret)
return ret;
return sprintf(buf, "%d\n", data->temperature);
}
static ssize_t humidity_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct dht11_data *data = dev_get_drvdata(dev);
int ret = dht11_read_data(data);
if (ret)
return ret;
return sprintf(buf, "%d\n", data->humidity);
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, temperature, 0);
static SENSOR_DEVICE_ATTR_RO(humidity1_input, humidity, 0);
static struct attribute *dht11_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_humidity1_input.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(dht11);
static int dht11_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dht11_data *data;
int irq, ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
platform_set_drvdata(pdev, data);
/* 获取GPIO */
data->gpio = devm_gpiod_get(dev, NULL, GPIOD_IN);
if (IS_ERR(data->gpio)) {
dev_err(dev, "无法获取GPIO\n");
return PTR_ERR(data->gpio);
}
/* 获取中断 */
irq = gpiod_to_irq(data->gpio);
if (irq < 0) {
dev_err(dev, "无法获取IRQ\n");
return irq;
}
/* 初始化完成量和定时器 */
init_completion(&data->completion);
timer_setup(&data->timer, dht11_timer_callback, 0);
/* 注册中断处理程序 */
ret = devm_request_irq(dev, irq, dht11_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRIVER_NAME, data);
if (ret) {
dev_err(dev, "无法请求IRQ\n");
return ret;
}
dev_info(dev, "DHT11驱动加载成功\n");
return 0;
}
static int dht11_remove(struct platform_device *pdev)
{
struct dht11_data *data = platform_get_drvdata(pdev);
del_timer(&data->timer);
return 0;
}
static const struct of_device_id dht11_of_match[] = {
{ .compatible = "dht11", },
{ }
};
MODULE_DEVICE_TABLE(of, dht11_of_match);
static struct platform_driver dht11_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = dht11_of_match,
.dev_groups = dht11_groups,
},
.probe = dht11_probe,
.remove = dht11_remove,
};
module_platform_driver(dht11_driver);
MODULE_AUTHOR("Embedded Linux Developer");
MODULE_DESCRIPTION("DHT11 Temperature and Humidity Sensor Driver");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
4.2 创建Makefile
创建文件:~/stm32mp157-project/drivers/Makefile
makefile
obj-m += dht11.o
KDIR ?= ../linux
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf-
clean:
make -C $(KDIR) M=$(PWD) clean
4.3 编译驱动
bash
cd ~/stm32mp157-project/drivers
make
DHT11驱动工作流程
初始化
数据读取
数据处理
GPIO配置
中断注册
定时器初始化
发送开始信号
等待响应
边沿检测
超时处理
数据解析
校验和验证
单位转换
sysfs接口
5. 设备树配置
5.1 创建设备树 overlay
创建文件:~/stm32mp157-project/dts/dht11-overlay.dts
dts
/dts-v1/;
/plugin/;
/ {
compatible = "st,stm32mp157";
fragment@0 {
target = <&pinctrl>;
__overlay__ {
dht11_pins: dht11-pins {
pins = "PA6"; /* 使用PA6引脚 */
bias-pull-up;
};
};
};
fragment@1 {
target-path = "/";
__overlay__ {
dht11: dht11@0 {
compatible = "dht11";
pinctrl-names = "default";
pinctrl-0 = <&dht11_pins>;
gpios = <&gpioa 6 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
};
};
5.2 编译设备树 overlay
bash
# 编译设备树 overlay
dtc -@ -I dts -O dtb -o dht11-overlay.dtbo dht11-overlay.dts
# 将 overlay 复制到 Buildroot 的 overlay 目录
cp dht11-overlay.dtbo ~/stm32mp157-project/buildroot/output/overlay/
6. 系统集成与部署
6.1 创建启动脚本
创建文件:~/stm32mp157-project/scripts/init-dht11.sh
bash
#!/bin/bash
# 加载DHT11驱动
modprobe industrialio
insmod /lib/modules/$(uname -r)/extra/dht11.ko
# 创建设备节点
mknod /dev/dht11 c 240 0
# 设置权限
chmod 666 /dev/dht11
echo "DHT11驱动初始化完成"
6.2 配置Buildroot overlay
bash
cd ~/stm32mp157-project/buildroot/output/target
# 创建必要的目录
mkdir -p etc/init.d lib/modules/$(uname -r)/extra
# 复制驱动模块
cp ~/stm32mp157-project/drivers/dht11.ko lib/modules/$(uname -r)/extra/
# 复制启动脚本
cp ~/stm32mp157-project/scripts/init-dht11.sh etc/init.d/S90dht11
chmod +x etc/init.d/S90dht11
# 更新模块依赖
depmod -b . -a $(uname -r)
6.3 创建测试应用程序
创建文件:~/stm32mp157-project/apps/dht11-test.c
c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_PATH "/sys/bus/platform/devices/dht11@0/"
int read_sysfs_value(const char *path) {
int value;
FILE *file = fopen(path, "r");
if (file == NULL) {
perror("无法打开文件");
return -1;
}
if (fscanf(file, "%d", &value) != 1) {
fclose(file);
return -1;
}
fclose(file);
return value;
}
int main() {
int temperature, humidity;
printf("DHT11温湿度传感器测试程序\n");
while (1) {
temperature = read_sysfs_value(DEVICE_PATH "temp1_input");
humidity = read_sysfs_value(DEVICE_PATH "humidity1_input");
if (temperature >= 0 && humidity >= 0) {
printf("温度: %.1f°C, 湿度: %.1f%%\n",
temperature / 10.0, humidity / 10.0);
} else {
printf("读取数据失败\n");
}
sleep(2);
}
return 0;
}
6.4 编译测试程序
bash
arm-none-linux-gnueabihf-gcc -o dht11-test dht11-test.c -static
cp dht11-test ~/stm32mp157-project/buildroot/output/target/usr/bin/
7. 系统烧录与测试
7.1 制作SD卡镜像
bash
cd ~/stm32mp157-project/buildroot/output/images/
# 使用dd命令烧录镜像
sudo dd if=sd-card.img of=/dev/sdX bs=4M status=progress
sync
7.2 启动系统并测试
bash
# 通过串口连接开发板
minicom -D /dev/ttyUSB0 -b 115200
# 系统启动后,测试驱动
dmesg | grep dht11 # 查看驱动加载信息
# 运行测试程序
dht11-test
7.3 常见问题处理
问题1:驱动加载失败
解决方法:检查GPIO配置和设备树设置
问题2:数据读取不稳定
解决方法:增加去抖动处理,调整时序参数
问题3:权限问题
解决方法:确保/dev节点权限正确
8. 成果展示与验证
8.1 系统功能验证
bash
# 验证驱动加载
lsmod | grep dht11
# 验证sysfs接口
ls /sys/bus/platform/devices/dht11@0/
# 实时数据读取
cat /sys/bus/platform/devices/dht11@0/temp1_input
cat /sys/bus/platform/devices/dht11@0/humidity1_input
8.2 性能测试结果
温度测量范围:0-50°C ±2°C
湿度测量范围:20-90%RH ±5%
响应时间:<2秒
采样间隔:≥2秒
技术图谱
STM32MP157 Buildroot系统
硬件层
系统层
应用层
STM32MP157芯片
DHT11传感器
GPIO接口
Linux 5.10内核
Buildroot根文件系统
设备树配置
驱动框架
温湿度采集驱动
sysfs接口
用户空间程序
数据展示
总结
本教程详细介绍了从零开始为STM32MP157构建嵌入式Linux系统的完整流程,包括:
- 环境搭建:交叉编译工具链和开发环境配置
- 系统构建:使用Buildroot制作定制根文件系统
- 内核移植:Linux内核配置、编译和设备树定制
- 驱动开发:DHT11温湿度传感器驱动完整实现
- 系统集成:驱动部署和应用程序开发
- 测试验证:系统功能验证和性能测试
通过本教程,读者可以掌握嵌入式Linux系统开发的完整技能栈,并能够将这些技术应用到其他嵌入式项目中。整个系统具有稳定性高、资源占用少、易于定制等优点,非常适合工业控制和物联网应用场景。