当前位置: 首页 > news >正文

嵌入式学习 day63 LCD屏幕驱动、ADC驱动、HC-SR04、ds18b20

一、LCD屏幕驱动

        1、LCD 4.3寸屏幕驱动适配

        (1) 设备树修改:

        ① 进入内核目录,并打开设备树文件

        ② 将lcdif接口中对应的7寸1024*600屏幕配置注释,打开4.3寸800*480屏幕配置

注:如果设置4.3寸屏幕为RGB888模式,将bits-per-pixel设置为<24>,如果将LCD设置为
RGB565模式,将bits-per-pixel设置为<16>

        ③ 编译设备树文件并更新设备树文件

        (2) 屏幕驱动:

        ① 内核中已经适配了lcdif驱动接口,可以通过lcdif对应的compatible选项查找匹配驱动

        ② 查找内容如下,可以阅读下LCD驱动源码

        2、函数接口

        二、ADC驱动

        1、概念:

        当我们使用的传感器本质是ADC或者DAC器件的时候,可以考虑使用IIO驱动框架。IIO全称(Industrial I/O),指工业I/O,IIO就是为ADC或者DAC类传感器准备的,大家常用的陀螺仪、加速度计、电压/电流测量芯片、光照传感器、压力传感器内部都有ADC,然后通过IIC和SPI等传输给SOC,所以都可以使用IIO子系统实现。

        2、使能内核IIO相关配置

 make menuconfig

        3、适配内核ADC驱动

        (1)设备树:

        ① 打开内核中的设备树文件

        ② 在iomuxc节点中添加pinctrl_adc节点配置

        ③ 在regulator节点中添加ADC基准电压管理节点

        ④ 在根节点中添加adc1节点配置

        ⑤ 保存并重新编译设备树

        ⑥ 将dtb文件拷贝到tftp管理目录

        (2)在内核中添加ADC驱动:

        ①在内核目录修改配置

        ② 重新编译内核镜像

        ③ 将内核镜像拷贝到tftp管理目录下

        (3)测试ADC驱动:

        ①测试ADC驱动:

        ②查看iio子系统下的节点

        ③ 应用程序编写

我们可以通过文件IO直接读取以上两个iio设备节点的信息
最终电压计算公式:

        4、应用层驱动编写(光照传感器)

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>//12位ADC/* 字符串转数字,将浮点小数字符串转换为浮点数数值 */
#define SENSOR_FLOAT_DATA_GET(ret, index, str, member)\
ret = file_data_read(file_path[index], str);\
dev->member = atof(str);\/* 字符串转数字,将整数字符串转换为整数数值 */
#define SENSOR_INT_DATA_GET(ret, index, str, member)\
ret = file_data_read(file_path[index], str);\
dev->member = atoi(str);\/* adc iio 框架对应的文件路径 */
static char *file_path[] = {
"/sys/bus/iio/devices/iio:device0/in_voltage_scale",
"/sys/bus/iio/devices/iio:device0/in_voltage1_raw",
};/* 文件路径索引,要和 file_path 里面的文件顺序对应 */
enum path_index {
IN_VOLTAGE_SCALE = 0,
IN_VOLTAGE_RAW,
};/*
* ADC 数据设备结构体
*/
struct adc_dev{int raw;float scale;float act;
};struct adc_dev imx6ulladc;/*
* @description : 读取指定文件内容
* @param – filename : 要读取的文件路径
* @param - str : 读取到的文件字符串
* @return : 0 成功;其他 失败
*/
static int file_data_read(char *filename, char *str)
{int ret = 0;FILE *data_stream;data_stream = fopen(filename, "r"); /* 只读打开 */if(data_stream == NULL) {printf("can't open file %s\r\n", filename);return -1;}ret = fscanf(data_stream, "%s", str);if(!ret) {printf("file read error!\r\n");} else if(ret == EOF) {/* 读到文件末尾的话将文件指针重新调整到文件头 */fseek(data_stream, 0, SEEK_SET); }fclose(data_stream); /* 关闭文件 */ return 0;
}/*
* @description : 获取 ADC 数据
* @param - dev : 设备结构体
* @return : 0 成功;其他 失败
*/
static int adc_read(struct adc_dev *dev)
{int ret = 0;char str[50];SENSOR_FLOAT_DATA_GET(ret, IN_VOLTAGE_SCALE, str, scale);SENSOR_INT_DATA_GET(ret, IN_VOLTAGE_RAW, str, raw);/* 转换得到实际电压值 mV */dev->act = (dev->scale * dev->raw)/1000.f;return ret;
}/*
* @description : main 主程序
* @param – argc : argv 数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{int ret = 0;if (argc != 1) {printf("Error Usage!\r\n");return -1;}while (1) {ret = adc_read(&imx6ulladc);if(ret == 0) { /* 数据读取成功 */printf("ADC 原始值:%d,电压值:%.3fV\r\n", imx6ulladc.raw, imx6ulladc.act);}usleep(100000); /*100ms */}return 0;
}

二、HC-SR04(超声波测距)(gpio)

        1、概念:

        HC-SR04 是一款低成本、非接触式的超声波测距模块,通过发射和接收 40kHz 超声波实现距离检测,广泛应用于机器人避障、智能停车、液位监测等场景。其核心优势是体积小巧、接口简单、测距精度高(±3mm),且兼容 Arduino、STM32 等主流控制器。

        2、接口定义

        3、性能参数

        4、GPIO工作模式时序

工作模式同老版本HC-SR04。外部MCU给模块Trig脚一个大于10uS的高电平脉冲;模块会给出一个与距离等比的高电平脉冲信号,可根据脉宽时间“T”算出:

                距离=T*C/2        (C为声速)

        声速温度公式:c={331.45+0.61t/C)m*s-1(其中330.45是在0℃)

0℃声速:330.45M/S
20℃声速:342.62M/S
40℃声速:354.85M/S

        5、驱动程序:

        (1)设备树:

        (2)驱动层编写

#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/gpio.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <asm/delay.h>static int gpio_trig = 0;
static int gpio_echo = 0;static ssize_t hcsr04_read(struct file *fp, char __user *puser, size_t n, loff_t *off)
{int cnt = 0;long nret = 0;struct timeval start_time;struct timeval end_time;gpio_direction_output(gpio_trig, 0);gpio_set_value(gpio_trig, 1);udelay(10);gpio_set_value(gpio_trig, 0);gpio_direction_input(gpio_echo);while (0 == gpio_get_value(gpio_echo));do_gettimeofday(&start_time);while (gpio_get_value(gpio_echo));do_gettimeofday(&end_time);cnt = (end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec);nret = copy_to_user(puser, &cnt, sizeof(cnt));if (nret) {pr_info("copy_to_user failed\n");return -1;}return sizeof(cnt);
}static struct file_operations fops = {.read = hcsr04_read,
};static struct miscdevice misc_hcsr04 = {.minor = MISC_DYNAMIC_MINOR,.name = "misc_hcsr04",.fops = &fops,
};static int hcsr04_probe(struct platform_device *pdev)
{int ret = 0;ret = misc_register(&misc_hcsr04);if (ret) {pr_info("misc_register failed\n");return -1;}gpio_trig = of_get_named_gpio(pdev->dev.of_node, "gpio-trig", 0);if (gpio_trig < 0) {pr_info("of_get_named_gpio failed\n");return -1;}gpio_echo = of_get_named_gpio(pdev->dev.of_node, "gpio-echo", 0);if (gpio_echo < 0) {pr_info("of_get_named_gpio failed\n");return -1;}ret = devm_gpio_request(misc_hcsr04.this_device, gpio_trig, "pute-hcsr04_trig");if (ret) {pr_info("devm_gpio_request failed\n");return -1;}ret = devm_gpio_request(misc_hcsr04.this_device, gpio_echo, "pute-hcsr04_echo");if (ret) {pr_info("devm_gpio_request failed\n");return -1;}gpio_direction_output(gpio_trig, 0);gpio_direction_output(gpio_echo, 0);pr_info("probe ok\n");return 0;
}static int hcsr04_remove(struct platform_device *pdev)
{int ret = 0;ret = misc_deregister(&misc_hcsr04);if (ret) {pr_info("misc_register failed\n");return -1;}return 0;
}static struct platform_device_id hcsr04_idtable[] = {{.name = "putehcsr04"},{},
};static struct of_device_id hcsr04_of_match_table[] = {{.compatible = "pute,putehcsr04"},{},
};static struct platform_driver hcsr04_driver = {.probe = hcsr04_probe,.remove = hcsr04_remove,.driver = {.name = "putehcsr04",.owner = THIS_MODULE,.of_match_table = hcsr04_of_match_table,},.id_table = hcsr04_idtable,
};module_platform_driver(hcsr04_driver);MODULE_AUTHOR("pute");
MODULE_LICENSE("GPL");

        (3)应用层编写

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>int main(void)
{int fd = 0;int time_us = 0;double distence = 0;fd = open("/dev/misc_hcsr04", O_RDWR);if (-1 == fd){perror("fail to open");return -1;}while (1){read(fd, &time_us, sizeof(time_us));distence = (340.0 / 10000.0 * time_us)/2;printf("time_us = %d, distence = %.2lf cm\n", time_us, distence);usleep(250000);}close(fd);return 0;
}

三、ds18b20(单总线数字温度传感器)(gpio)

        1、概念:

        DS18B20 是由美国 Maxim(美信)公司推出的 单总线数字温度传感器,其核心优势是通过一根信号线(DQ 线)实现 “供电 + 数据传输”(支持寄生电源模式),同时具备测量精度高、抗干扰能力强、布线简单等特点,广泛应用于各类温度监测场景。

注:单总线:

        2、结构:

        3、操作步骤

        (1)初始化:复位脉冲

        (2)发送ROM命令(搜索、获取DS18b20编号、选择ds18b20编号)

        0xCC:跳过ROM命令

        (3)发送功能命令

        0x44:开始一次温度采集

        (4)等待400ms

        (5)初始化:复位脉冲

        (6)发送ROM命令(搜索、获取DS18b20编号、选择ds18b20编号)

        0xCC:跳过ROM命令

        (7)发送功能命令

0xBE去读前两个字节的温度,先低后高LSB

        (8)获得温度

        4、时序

        (1)初始化时序

        ①.将GPIO设置为输出
②.将GPIO拉高保持闲时为高
③.开始复位时将总线拉低500us
④.将总线拉高
⑤.等待60us
⑥.将GPIO设置为输入
⑦.等待低电平到来
⑧.等待高电平到来(60-240us)
⑨.等待360us
⑩.将GPIO设置为输出,高电平,准备开始发送数据

        (2)读/写时序:封装发送1个字节接口

        写:

        ①将总线拉低15us
②.如果发0,继续拉低100us拉高如果发1,拉高45us
③.等待lu

        读:

        ①将总线拉低5us

        ②.拉高

        ③.GPIO设置为input模式

        ④.睡眠7us

        ⑤读总线电平,如果为低电平、说明从机发送0,如果为高电平,说明从机发送1

        ⑥睡眠1us

        5、驱动程序

        (1)设备树

        (2)驱动层编写

#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/gpio.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <asm/delay.h>extern void msleep(unsigned int msecs);
static int ds18b20_probe(struct platform_device *pdevice);
static int ds18b20_remove(struct platform_device *pdevice);
static ssize_t ds18b20_read(struct file *fp, char __user *puser, size_t n, loff_t *off);static int ds18b20gpio;static struct file_operations fops = {.owner = THIS_MODULE,.read = ds18b20_read,
};static struct miscdevice misc_ds18b20 = {.minor = MISC_DYNAMIC_MINOR,.name = "misc_ds18b20",.fops = &fops,
};static struct of_device_id  ds18b20_of_match_table[] = {{.compatible = "pute,puteds18b20"},{},
};static struct platform_device_id ds18b20_id_table[] = {{.name = "puteds18b20"},{},
};static struct platform_driver ds18b20_platform_drvier = {.driver = {.name = "puteds18b20",.of_match_table = ds18b20_of_match_table,},.id_table = ds18b20_id_table,.probe = ds18b20_probe,.remove = ds18b20_remove,
};static int ds18b20_probe(struct platform_device *pdevice)
{int ret = 0;struct device_node  *dtsds18b20node = NULL;ret = misc_register(&misc_ds18b20);if (ret)pr_info("misc_register failed\n");dtsds18b20node = pdevice->dev.of_node;ds18b20gpio = of_get_named_gpio(dtsds18b20node, "gpio-ds18b20", 0);if (ds18b20gpio < 0)pr_info("of_get_named_gpio failed\n");ret = gpio_request(ds18b20gpio, "puteds18b20");if (ret)pr_info("gpio_request failed\n");ret = gpio_direction_output(ds18b20gpio, 1);if (ret)pr_info("gpio_direction_output failed\n");pr_info("ds18b20 probe success!\n");return 0;
}static int ds18b20_remove(struct platform_device *pdevice)
{int ret = 0;gpio_free(ds18b20gpio);ret = misc_deregister(&misc_ds18b20);if (ret)pr_info("misc_deregister failed\n");pr_info("ds18b20 remove success!\n");return 0;
}static int ds18b20_reset(void)
{int timeout = 20;//拉低480-960usgpio_set_value(ds18b20gpio, 0);udelay(500);gpio_set_value(ds18b20gpio, 1);udelay(60);//等待低电平到来gpio_direction_input(ds18b20gpio);timeout = 20;while (gpio_get_value(ds18b20gpio) && timeout--){udelay(1);}if (timeout < 0)return -1;//等待高电平到来while (!gpio_get_value(ds18b20gpio));udelay(360);gpio_direction_output(ds18b20gpio, 1);return 0;
}static void ds18b20_writebit(unsigned char data)
{//拉低 > 1usgpio_set_value(ds18b20gpio, 0);udelay(5);if (data)gpio_set_value(ds18b20gpio, 1);udelay(115);gpio_set_value(ds18b20gpio, 1);udelay(3);return;
}static void ds18b20_writebyte(unsigned char byte)
{int i = 0;for (i = 0; i < 8; i++){ds18b20_writebit(byte & 0x01);byte >>= 1;}return;
}static unsigned char ds18b20_readbit(void)
{unsigned char data = 0;//拉低 > 1usgpio_set_value(ds18b20gpio, 0);udelay(5);gpio_set_value(ds18b20gpio, 1);gpio_direction_input(ds18b20gpio);udelay(7);data = gpio_get_value(ds18b20gpio);gpio_direction_output(ds18b20gpio, 1);udelay(50);return data;
}static unsigned char ds18b20_readbyte(void)
{unsigned char byte = 0;int i = 0;for (i = 0; i < 8; i++){if (ds18b20_readbit())byte |= 0x1 << i;}return byte;
}static int ds18b20_readvalue(unsigned long *pvalue)
{int ret = 0;unsigned short th = 0;unsigned short tl = 0;//初始化设备ret = ds18b20_reset();if (-1 == ret)return -1;//跳过ROM(0xcc)ds18b20_writebyte(0xcc);//操作存储器(0x44)ds18b20_writebyte(0x44);//等待转换完成msleep(500);//初始化设备ret = ds18b20_reset();if (-1 == ret)return -1;//跳过ROM(0xcc)ds18b20_writebyte(0xcc);//操作存储器(0xBE)ds18b20_writebyte(0xbe);//读取数据(前2个字节)tl = ds18b20_readbyte();th = ds18b20_readbyte();*pvalue = ((th << 8) | tl); return 0;
}static ssize_t ds18b20_read(struct file *fp, char __user *puser, size_t n, loff_t *off)
{unsigned long ret = 0;unsigned long value = 0;ret = ds18b20_readvalue(&value);if (ret != 0)return -1;ret = copy_to_user(puser, &value, sizeof(value));if (ret)pr_info("copy_to_user failed\n");return sizeof(value);
}static int __init ds18b20_drv_init(void)
{int ret = 0;ret = platform_driver_register(&ds18b20_platform_drvier);if (ret)pr_info("platform_driver_register failed");return 0;
}static void __exit ds18b20_drv_exit(void)
{platform_driver_unregister(&ds18b20_platform_drvier);return;
}module_init(ds18b20_drv_init);
module_exit(ds18b20_drv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("haiersen");

        (3)应用层

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(void)
{int fd = 0;unsigned long value = 0;fd = open("/dev/misc_ds18b20", O_RDWR);if (-1 == fd){perror("fail to open");return -1;}while (1){read(fd, &value, sizeof(value));printf("value = %.2lf\n", value * 0.0625);sleep(1);}close(fd);return 0;
}

http://www.xdnf.cn/news/1439083.html

相关文章:

  • 什么是好的系统设计
  • LangGraph MCP智能体开发
  • 【JavaEE】(22) Spring 事务
  • 飞算JavaAI炫技赛:一天完成学生成绩综合统计分析系统开发(含源码)
  • 【Axure高保真原型】区间缩放柱状图
  • 数据结构从青铜到王者第二十话---Map和Set(3)
  • 漫谈《数字图像处理》之图像清晰化处理
  • 配置机载电脑开机自启动ros2节点和配置can0
  • 【第四章:大模型(LLM)】10.微调方法与实战-(1)Prompt Tuning
  • C++ 多线程编程
  • c++多线程(1)------创建和管理线程td::thread
  • logging:报告状态、错误和信息消息
  • 《用 Flask + SQLAlchemy 构建任务管理应用:从基础架构到实战优化》
  • 面试题:JVM与G1要点总结
  • 哪些AI生成PPT的软件或网站支持多平台使用?都支持哪些平台?
  • Linux之centos 系统常用命令详解(附实战案例)
  • 多路复用 I/O 函数——`select`函数解析
  • 一次惊心动魄的线上事故:记一次内存泄漏Bug的排查与解决全过程
  • 从一道面试题开始:如何让同时启动的线程按顺序执行?
  • Bug排查日记:从发现到解决的完整记录
  • 在word中使用lateX公式的方法
  • 力扣115:不同的子序列
  • Unity Android 文件的读写
  • Delphi 5 中操作 Word 表格时禁用鼠标交互
  • 更新远程分支 git fetch
  • 揭开PCB隐形杀手:超周期报废的技术真相
  • AI编码生产力翻倍:你必须掌握的沟通、流程、工具与安全心法
  • 一键掌握服务器健康状态与安全风险
  • 同步工具的底层依赖:AQS
  • Kubernetes 中为 ZenTao 的 Apache 服务器添加请求体大小限制