GEC6818传感器驱动实战:DHT11温湿度与MQ-2烟雾检测ko模块开发

发布时间:2026/9/8 18:50:07
GEC6818传感器驱动实战:DHT11温湿度与MQ-2烟雾检测ko模块开发 简介面向基于GEC6818开发板做毕业设计的电子、嵌入式方向学生这套驱动资源覆盖温湿度、红外、超声波、步进电机、继电器、光敏、烟雾火焰、ADC等常用外设模块基本满足智能家居、环境监测类项目的底层驱动需求。压缩包共含116个文件大小约21.38MB以.c源码、.ko驱动模块、Makefile编译脚本为主体另有接线说明txt、原理图PDF及测试程序等便于直接加载或二次修改后再用arm-linux-gcc交叉编译移植。每类传感器均配有驱动源码与编译产物省去在虚拟机中反复配置内核环境的步骤配合文档中的接线说明可快速验证硬件通路。目前已有2607人学习使用对初次接触GEC6818驱动开发、希望缩短毕设调试周期的读者有较强参考价值。 GEC6818是我用过一段时间的开发板三星S5P6818八核A53方案性能在国产板卡里算能打的做毕设选它很常见。但真正让人头疼的不是板子本身而是驱动。很多同学第一次在GEC6818上做温湿度、烟雾传感器的时候卡在同一个地方代码写好了交叉编译也过了但insmod加载就是报错或者加载成功却读不到数据。这篇文章我把自己调通的DHT11温湿度驱动、MQ-2烟雾驱动ko文件、源文件以及最关键的接线说明整个捋一遍适合正在做嵌入式Linux毕设、或者刚接触GEC6818字符设备驱动开发的同学直接参考。1. 开发环境搭建与整体思路确认1.1 为什么需要先确认内核版本和交叉编译器GEC6818出厂一般自带Linux 3.4.x或4.4.x的内核不同批次有差异而我们要编译ko驱动最核心的前提是编译ko所用内核源码的版本必须和板子上正在运行的内核版本完全一致包括编译器版本和内核配置选项都要对齐。否则insmod时大概率会遇到invalid module format或者一堆unknown symbol。我踩过的坑是一开始图省事直接用板子厂家提供的Ubuntu 16.04虚拟机里面已经装好了arm-linux-gnueabi-工具链但内核源码是另一个版本。第一次insmod DHT11驱动直接报错查了半小时发现版本号一个带一个不带。解决办法很简单下载与板子运行内核同版本的源码在源码根目录先做一次默认配置再编译内核自带的模块目录让Module.symvers和build软链接正常生成然后才编译自己的ko。实际操作时建议按下面这套流程走在板子上执行uname -r把内核版本号记下来例如3.4.39-s5p6818。从厂家提供的光盘或网盘里拿到对应的内核源码压缩包解压到Ubuntu建议路径用/home/你的用户名/kernel/linux-3.4.39之类不要放桌面或带中文的路径。安装工具链GEC6818一般用arm-linux-gnueabi-gcc4.8.3版本左右。安装完执行arm-linux-gnueabi-gcc -v确认版本。进入内核源码目录执行make ARCHarm CROSS_COMPILEarm-linux-gnueabi- distclean清理然后执行make ARCHarm CROSS_COMPILEarm-linux-gnueabi- s5p6818_defconfig有的厂家给的是tiny4412_defconfig或者自定义文件看实际提供情况最后执行make ARCHarm CROSS_COMPILEarm-linux-gnueabi- modules预编译一遍内核自带的模块。之所以要先编译一遍内核自带模块是为了生成完整的Module.symvers文件里面记录着导出符号的crc值。我们自己写的驱动如果依赖内核导出的函数比如gpio_request、class_create等依赖检查靠的就是它。没有这个文件交叉编译过程本身可能不报错但加载到板子上就是一连串的unknown symbol。1.2 驱动框架怎么选直接ko比内核编译更省事毕设场景下不建议为了加两个传感器就去重新编译整个内核镜像然后烧录到板子里。开发效率最高的做法是把驱动编译成可加载模块.ko通过insmod动态加载。这样做有几个好处第一修改驱动代码后只需要重新make拷贝ko文件到板子insmod替换不用反复烧写系统第二驱动都在应用层测试崩溃了直接rmmod再insmod系统不会死第三答辩演示的时候可以现场insmod、lsmod、rmmod展示往往更直观。我用的驱动框架是标准的字符设备驱动分配设备号动态、初始化cdev、创建设备类、生成设备节点。上层应用通过open/read接口读传感器数据方式为把传感器的原始电平或转换后的计算逻辑放到驱动read里实现。2. 源码结构和文件说明2.1 源码文件清单我这套代码整理下来主要包含下面这些文件可以参考dht11.cDHT11驱动源文件字符设备驱动框架单总线时序解析。mq2.cMQ-2烟雾传感器驱动源文件读取ADC或GPIO高低电平状态。Makefile与上面两个源文件配套通过obj-m方式编译。test_dht11.c、test_mq2.c应用层测试程序分别对应温湿度和烟雾读取。readme.txt接线和编译步骤速查。dht11.c里我把传感器型号对应的名字、GPIO引脚号、延时函数全部用宏定义写在文件头部比如#define DHT11_PIN S5P6818_GPIO_C(12)。GEC6818的GPIO编号方式和IMX系列、STM32MP1不一样它用的是S5P6818_GPIO开头的一系列宏分别对应GPIOA到GPIOK多组引脚。查阅原理图或者底板丝印之后把实际接到传感器的引脚换算成这样的宏写到宏定义里即可。这块换算如果搞不明白建议直接看厂家提供的gpio-cfg.h头文件里面对每个引脚的bank偏移和number定义得很清楚。2.2 Makefile组织方式Makefile看起来很简单但容易出错。核心内容如下obj-m dht11.o obj-m mq2.o KDIR : /home/你的用户名/kernel/linux-3.4.39 PWD : $(shell pwd) all: make -C $(KDIR) M$(PWD) ARCHarm CROSS_COMPILEarm-linux-gnueabi- modules clean: make -C $(KDIR) M$(PWD) ARCHarm CROSS_COMPILEarm-linux-gnueabi- clean很多同学会问为什么make -C $(KDIR)进入内核目录之后还要加M$(PWD)因为M$(PWD)告诉kbuild系统我要编译的是外部模块目录是当前路径。少了这个参数make会去编译整个内核加上之后kbuild只处理当前目录下的obj-m目标。ARCHarm和CROSS_COMPILEarm-linux-gnueabi-这两个参数必须写。不写ARCH的话kbuild有可能跑到x86架构的配置里不写CROSS_COMPILE的话用的就是gcc而不是arm交叉编译工具生成的可执行文件在PC上能跑但在arm板上会提示Exec format error。3. DHT11温湿度驱动解析3.1 DHT11单总线时序与编程要点DHT11是单总线数字温湿度传感器只有一根数据线。它靠一组严格的时序协议工作主机先拉低总线至少18ms然后再拉高20~40us之后释放总线等待DHT11的响应。响应信号是DHT11拉低80us左右再拉高80us左右。响应之后DHT11连续发送40位数据8位湿度整数、8位湿度小数、8位温度整数、8位温度小数、8位校验和。每一位数据的判断是利用高电平持续的时间长短区分的50us的低电平时钟信号后面如果高电平持续26~28us左右表示0高电平持续70us左右表示1。上拉电阻和线路电容对时序有一定影响实测发现Ubuntu里交叉编译时没有太大问题但在板子上系统调度可能会产生微秒级误差导致读出来的数据全是0xFF或者直接reset掉。为了尽量稳定我在驱动代码中关闭了内核抢占并且在关键引脚操作段使用preempt_disable加local_irq_save来锁住中断具体实现思想是这样的static int dht11_read_raw(int *humidity, int *temperature) { int err 0; unsigned long flags; int bits[40] {0}; int i 0; /* 请求GPIO并设置为输出方向 */ gpio_direction_output(DHT11_PIN, 0); local_irq_save(flags); /* 主机拉低至少18ms */ gpio_set_value(DHT11_PIN, 0); mdelay(20); /* 拉高 20~40us */ gpio_set_value(DHT11_PIN, 1); udelay(30); /* 释放总线切回输入 */ gpio_set_value(DHT11_PIN, 1); gpio_direction_input(DHT11_PIN); /* 等待DHT11拉低响应信号超时则失败 */ while (gpio_get_value(DHT11_PIN)) { if (i 10000) return -ETIMEDOUT; } /* 跳过80us低电平和80us高电平 */ while (!gpio_get_value(DHT11_PIN)) {} while (gpio_get_value(DHT11_PIN)) {} /* 读取40位数据每位先等50us低电平再读高电平持续时间 */ for (i 0; i 40; i) { while (!gpio_get_value(DHT11_PIN)) {} udelay(40); bits[i] gpio_get_value(DHT11_PIN); while (gpio_get_value(DHT11_PIN)) {} } local_irq_restore(flags); /* 组合成字节做校验和检查 */ /* ... */ return err; }这段代码里有一个经验点读每位数据时先等到低电平结束再延时40us左右去判高电平如果在40us之后依然是高说明这是一个1如果已经变低说明是0。这个采样点在不同板子上可能需要微调我调试的时候用逻辑分析仪抓过波形最后确定40us这个值在GEC6818上最稳妥。如果板子主频环境不一样可以小范围尝试35~50us。3.2 GPIO编号换算和接线注意DHT11接线非常简单一路VCC接3.3V另一路GND接GND数据脚接GPIO。需要注意的是如果面包板上用5V供电模块数据脚高电平是5V而GEC6818的GPIO最高只能承受3.3V建议加电平转换或者串联一个1K电阻分压再接入引脚。数据线和VCC之间最好接一个4.7K上拉电阻。DHT11模块一般已经自带如果是裸传感器必须自己加。GPIO号换算方面在驱动程序里写的是S5P6818_GPIO_C(12)这样的形式那说明接的是GPIOC组的第12个引脚。具体丝印上可能直接标GPIO_C12或者类似对应核心板上的物理引脚位置需要查底板原理图。动手前用万用表量一下引脚和GND之间的电压确认没接反就好。3.3 上层应用怎么读上层应用是通过文件节点来读的。insmod之后如果设备号是动态分配的再加上class_create并自动生成设备节点/dev/dht11应该是自动出现的。应用层代码大概长这样#include stdio.h #include fcntl.h #include unistd.h int main(void) { int fd; char buf[32] {0}; int ret; fd open(/dev/dht11, O_RDWR); if (fd 0) { perror(open); return -1; } while (1) { ret read(fd, buf, sizeof(buf)); if (ret 0) { printf(data: %s\n, buf); } sleep(2); } close(fd); return 0; }驱动里的read函数把温湿度格式化成字符串例如humidity58.0% temp25.0C拷到buf里返回给应用层。这样做的好处是应用层不用关心协议解析只需要打印字符串毕设答辩时好用。4. MQ-2烟雾传感器驱动解析4.1 MQ-2模块的两种输出方式MQ-2是半导体气敏传感器对液化气、丙烷、氢气、烟雾都比较敏感。模块上一般有两路输出一路AO模拟电压输出另一路DO数字电平输出TTL。DO输出的阈值可以通过板载电位器调节当气体浓度超过阈值时DO输出电平翻转。针对这两种输出驱动写起来是完全不同的思路DO模式当作数字输入用gpio_get_value读取应用层只需要判断有没有超过阈值。AO模式需要接到GEC6818的ADC通道驱动里要用到ADC子系统或平台自带的ADC控制器。毕设最简方案是优先用DO代码量小而且演示时把打火机的气体凑近传感器LED或者蜂鸣器状态变化很明显效果比较直观。AO模式的好处是可以量化浓度趋势但GEC6818的ADC接口资源和设备树配置情况因厂商资料而异调试成本更高。4.2 基于GPIO的烟雾检测驱动如果用DO输出驱动基本逻辑和按键驱动类似区别在于不需要防抖因为传感器输出本身就是缓慢变化的。关键代码static int mq2_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { int value; char kbuf[16]; int ret; value gpio_get_value(MQ2_PIN); if (value 0) snprintf(kbuf, sizeof(kbuf), smoke detected); else snprintf(kbuf, sizeof(kbuf), normal); ret copy_to_user(buf, kbuf, strlen(kbuf) 1); return ret 0 ? -EFAULT : strlen(kbuf) 1; }这里注意一个点MQ-2模块上的DO输出有的传感器浓度高时输出低电平有的是高电平取决于模块上比较器的接法。启动后可以先运行应用层程序观察看到底是高有效还是低有效。我的代码注释里特别标明了默认定义为低电平有效实际使用时根据自己模块调整这一个判断条件就行。4.3 ADC方式读取如果坚持要用AO模式GEC6818自带ADC控制器但不同厂家的BSP对ADC的支持程度不同。正常情况下需要通过平台提供的ADC驱动申请一个channel然后读取原始值。原始值是12bit取值范围0~4095对应0~1.8V部分底板可能是0~3.3V。气体浓度越高电压越大。如果不熟悉内核的IIO子系统可以直接在应用层访问/sys/bus/iio/devices/iio:device0/in_voltage0_raw这样的节点来读取电压原始值。这种方法有时更快更方便而且在应用层做换算灵活缺点是采样率上不去但对烟雾检测来说足够了。5. 接线说明、ko文件加载与测试5.1 接线速查表这里把自己实测的接线方式整理成表方便电工和软件不同背景的同学对照传感器引脚GEC6818对应位置说明DHT11 VCC3.3V引脚不能接5V数据线会超压DHT11 GNDGND共地必须接DHT11 DATAGPIOC12如GPIO_C12丝印模块自带4.7K上拉则无需外接MQ-2 VCC5V引脚MQ-2加热丝需要5V供电MQ-2 GNDGND与板卡共地MQ-2 DOGPIOB5如GPIO_B5丝印根据自己DM修改宏定义MQ-2 AO悬空若用DO模式如需ADC则接ADC通道接线之前一定先把板子断电不要在运行状态下插拔杜邦线。我曾经在板子运行的时候插MQ-2结果5V串到GPIO上把那一路GPIO烧了后面只能换引脚非常折腾。5.2 把ko文件传到开发板并加载编译完成后当前目录下会生成dht11.ko和mq2.ko用U盘、网络或者adb推送到板子任意目录我习惯放在/home/gec/ko下。然后执行insmod dht11.ko insmod mq2.ko如果一切正常lsmod能看到这两个模块ls /dev/dht11和ls /dev/mq2也能看到对应的设备节点。设备节点没有自动生成时可以在驱动源码里检查是否调用了device_create然后手动用mknod /dev/dht11 c 主设备号 0创建。接着编译并运行测试程序arm-linux-gnueabi-gcc -o test_dht11 test_dht11.c ./test_dht11看到类似humidity58.0% temp25.0C的输出说明驱动从下面到上面已经全部调通。这时候再进行烟雾测试拿一个打火机出气口远离传感器放气观察DO对应的打印信息变化。5.3 开机自动加载如果希望板子启动时自动加载ko两个方式最简单的方法在/etc/init.d/下的启动脚本里加两行insmod命令。标准化做法把ko拷贝到/lib/modules/3.4.39-s5p6818/目录执行depmod -a然后编辑/etc/modules添加模块名。第一种方法对毕设来说足够了简单直接不会影响系统原有启动过程。6. 常见问题与排查技巧实录6.1 insmod失败invalid module format最常见的问题没有之一。原因几乎都是内核版本或者编译环境不一致。排查方法modinfo dht11.ko查看vermagic。板子上执行cat /proc/version查看运行内核版本和编译工具链。两者不一致时回到内核源码目录重新make并重新编译ko。注意有些厂家的内核源码在上层加了少量补丁从uname -r看版本号相同还不够对不上extra version也会报错。建议完全用厂家配套的源码和工具链。6.2 insmod成功但read不到数据DHT11读不到数据大部分是GPIO编号换算错了。可使用命令在板子上手动导出GPIO进行测试。另外也有可能是延时不能太严苛导致时序问题尝试调整udelay(40)的值。还有一种典型情况是接线太长杜邦线超过20cm时DHT11通信极不稳定尽量缩短数据线距离。6.3 MQ-2一直输出正常或一直报警这个基本是和DO有效电平搞反了。反过来判断即可。同时如果打算用AO模式检查模块供电是否达到了5VMQ-2的加热电阻需要一定时间预热第一次上电大概两三分钟内输出不稳定等稳定后再测试。6.4 卸载模块提示Device or resource busy说明设备文件还在被打开。先关闭正在运行的测试程序再执行rmmod dht11。如果还是busy检查是不是有别的进程占用执行fuser /dev/dht11可以查看占用进程PID。7. 一点扩展想法GEC6818的驱动开发套路摸熟之后后面接其他传感器就顺手很多。比如想加一个OLED屏显示温湿度和烟雾状态可以复用这里的字符设备框架把显示驱动也做成ko应用层统一read数据再write到OLED节点整个系统的层次一下子就清晰了。也有人在这块板子上继续做Linux网络编程把温湿度烟雾数据通过socket上报到上位机或云平台这一套毕设的完整度会很高。驱动是没那么多玄学的反复看官方头文件反复用逻辑分析仪对比时序问题基本都能定位。我做这套东西时最大的体会是先把环境对齐做扎实后面的路就顺畅了。本文还有配套的精品资源点击获取