【以imx6ull的智能家居温湿度监控系统】为例,搞懂 Linux 驱动和应用开发的区别

项目原作者为:基于imx6ull的智能家居温湿度监控系统
如有侵权,请联系我删除
本博文以正点原子的 imx6ull 开发板为例,以一个智能家居小项目为demo说明 linux 驱动开发和应用开发的联系。并对源码作了小白式的学习和说明

0. 个人简介 && 授权须知

image-20230911133730620

📋 个人简介

  • 💖 作者简介:大家好,我是喜欢记录零碎知识点的菜鸟打工人。😎
  • 📝 个人主页:欢迎访问我的博客主页🔥…
    • https://blog.csdn.net/qq_39217004?spm=1010.2135.3001.5343
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 📣 系列专栏:嵌入式Linux开发 🍁 🍁
  • 💬格言:写文档啊不是写文章,重要的还是直白!🔥

转载文章,禁止声明原创;不允许直接二次转载,转载请根据原文链接联系作者

若无需改版,在文首清楚标注作者及来源/原文链接,并删除【原创声明】,即可直接转载。
但对于未注明转载来源/原文链接的文章,我将保留追述的权利。

https://blog.csdn.net/qq_39217004?spm=1010.2135.3001.5343

作者:积跬步、至千里

image-20230911133724204

项目名字:基于imx6ull的智能家居温湿度监控系统

项目功能:

  • 1.通过sht20温湿度芯片采样温湿度,可在手机APP上订阅温湿度
  • 2.在手机APP上控制imx6ull开发板上的LED的亮灭。
  • 3.oled上显示温湿度采样值以及实时时间
  • 4.当温度超过预警值时,oled屏幕显示高温报警,打开蜂鸣器报警

项目执行之前,先手动加载驱动文件,然后运行应用程序:

1. 【应用层】项目初始化

  1. 读取 ini 配置文件中的 mqtt broker 信息
  2. 安装信号(kill crtl+c 网络重连)
  3. 初始化日志系统
  4. 初始化 mqtt 客户端
  5. 初始化 oled

接下来就项目中用的的知识,开始学习。

【加载驱动文件】

insmode i2c_sht20.ko

insmode chrdevled.ko

insmode spi_oled.ko

【执行应用程序】

./TEMP_HUM_APP shiyansshi

那么在成熟的项目中,开机 如何自动加载所需要的驱动,并且执行自定义的引用程序呢?

(这个暂且不探讨)

1.1 ini 文件解析器

实现将 mqtt.ini 文件中的内容解析出来,通过函数传参的形式,存储在自定义的结构体中 s_mosquitto_data mqtt_data;

C语言开源库iniparser解析ini文件

iniparser开源库详解

1.2 signal 的初始化

对进程接收到的一些信号进行处理方式的设置。

  1. 进程收到SIGTERM 或者 SIGINT 信号时,会调用 sign_handle 函数来进行相应处理。
  2. 进程收到 SIGPIPE 信号时,会直接忽略该信号。SIGPIPE 信号通常在往一个已经关闭的管道写数据等情况下产生

在这里插入图片描述

1.3 log 初始化

int logger_init(char *filename, int loglevel)

  1. 若传入的参数是 NULL 就使用 标准输出 stdout,g_logger.fp 指针指向 stderr(通常 stderr 是标准错误输出流),也就是把log打印到终端呈现出来
  2. 若传入的参数不空,,g_logger.fp 指针指向打开的文件句柄,fopen(filename, “a”); a 是以追加的形式打开的,就会把 log 记录到文件中

初始化完成后,比如我要记录一个错误:

strerror(errno) 中的 errno 是一个全局变量,他记录最近一次错误的值,也就是 mosquitto_lib_init 函数的错误返回值,

通过 strerror() 函数转化为字符的形式打印出来

//mosquitto 初始化
if( mosquitto_lib_init() != MOSQ_ERR_SUCCESS )      {
       	log_error( "mosquitto lib init failure:%s\n", strerror(errno) );
			goto Cleanup_mosq_lib;
 }

下面研究一下,log_error 函数,最终调用了 log_generic 函数,该函数的作用是:

  • 功能是按照特定的格式将日志信息输出到 【预先配置好的日志输出目标】这取决于 g_logger.fp 的指向

    • (1)g_logger.fp 指针指向打开的文件句柄,fopen(filename, “a”); 时,输出到日志文件中
    • (2)g_logger.fp 指针指向 stderr(通常 stderr 是标准错误输出流)时,就将信息打印出来到终端窗口
  • 注意: fflush 函数。调用 fflush 函数强制将输出缓冲区中的数据立即写入到对应的输出目标(文件或者标准输出)。这样做可以确保日志信息能及时被输出,而不是等待缓冲区满了才写入,尤其在一些需要实时查看日志的场景下比较重要。

1.4 mqtt 初始化

mosquitto库中常见的函数应用总结

// 初始化
mosquitto_lib_init
  
// 创建一个新的客户端
mosquitto_new
  
//设置连接代理账号密码
mosquitto_username_pw_set(mosq,mqtt_data.user,mqtt_data.password)

// 设置收到订阅消息后的回调函数
mosquitto_message_callback_set(mosq,dra_message_callback);  

1.5 其他

OLED 初始化、温湿度传感器初始化、应该在 open 的时候就调用驱动层 完成了

2. 【应用层】项目整体逻辑

解释 README.md 文件中的流程图:

while(!p_stop)
{
   // oled 刷屏
  
  // mqtt 连接
  
  // 时间采样,读取温湿度,oled显示 + mqtt 上报
}

关于循环条件 p_stop 的说明:

  1. 初始化赋值为 0,因此 while 是执行的
  2. 当进程收到设定的信号,SIGTERMSIGINT 时,执行sign_handle回调函数,将 p_stop 变量置 1 ,所以 while 就停止执行了

3. 【驱动层】分析

驱动层 driver 文件夹下,有 makefile 文件,make指令可以将驱动文件编译为 .ko 文件,分别是:

  • spi_oled.ko
  • i2c_sht20.ko
  • chrdevled.ko

使用前,先加载驱动,本例子是手动加载的 需要 insmod 相应的 ko 文件

3.1 以 iic 驱动为例

当 insmod i2c_oled.ko 加载驱动文件指令之后,首先回调 i2c_driver 的 probe 函数,该函数固定的套路,向内核注册并添加一个设备:

  1. 注册设备号 alloc_chrdev_region
  2. 初始化字符设备 cdev_init
  3. 添加一个字符设备 cdev_add
  4. 创建 class class_create
  5. 创建设备 device_create
  • 定义一个全局变量,用作和应用层数据交互 unsigned char *oled_data; //用作缓冲的全局变量

  • 向内核申请分配一段空间 oled_data = kmalloc(1024,GFP_KERNEL);

  • 设置页面的预留属性 SetPageReserved(virt_to_page(oled_data));

  • read 时,将数据从内核空间复制到用户空间 copy_to_user

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hh_linux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值