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

网站后台下载成人短期培训能学什么

网站后台下载,成人短期培训能学什么,长春网站建设q479185700惠,网站界面美观度RK3568 平台I2C协议与AGS10驱动开发一、I2C 总线协议基础二、I2C 通信过程详解三、AGS10 传感器概述四、AGS10驱动开发1. 硬件连接2. 设备树(DTS)配置3. 内核驱动开发五、调试与验证六、总结引言在嵌入式系统开发中,传感器数据采集是常见需求…

RK3568 平台I2C协议与AGS10驱动开发

  • 一、I2C 总线协议基础
  • 二、I2C 通信过程详解
  • 三、AGS10 传感器概述
  • 四、AGS10驱动开发
    • 1. 硬件连接
    • 2. 设备树(DTS)配置
    • 3. 内核驱动开发
  • 五、调试与验证
  • 六、总结

引言

在嵌入式系统开发中,传感器数据采集是常见需求。本文将详细介绍如何在 RK3568 平台上开发 AGS10 空气质量传感器的 Linux 驱动,同时深入解析 I2C 总线协议的工作原理。通过本文,你将掌握 I2C 通信的核心概念,并学会如何为特定传感器开发 Linux 内核驱动。

一、I2C 总线协议基础

I2C(Inter-Integrated Circuit)是由飞利浦公司开发的一种串行通信协议,广泛应用于短距离、低速的设备间通信。它具有以下特点:

  1. 双线制:仅需两根信号线
    SDA(Serial Data Line):数据传输线
    SCL(Serial Clock Line):时钟线
  2. 主从架构:
    主设备(Master):控制总线,发起通信
    从设备(Slave):被动响应主设备请求
  3. 寻址机制:
    每个从设备有唯一的 7 位或 10 位地址
    地址在通信开始时由主设备发送
  4. 传输速率:
    标准模式:100kHz
    快速模式:400kHz
    高速模式:3.4MHz
  5. 信号特征:
    开漏输出,需外接上拉电阻
    逻辑 0:低电平;逻辑 1:高阻态(由上拉电阻拉至高电平)

二、I2C 通信过程详解

I2C 通信的基本流程如下:

  1. 起始条件(Start):
    主设备在 SCL 为高电平时,将 SDA 从高电平拉至低电平
    标志一次通信的开始
  2. 地址帧:
    主设备发送从设备地址(7 位或 10 位)
    第 8 位为 R/W 位(0 表示写,1 表示读)
  3. 应答位(ACK/NACK):
    每传输 8 位数据后,接收方需发送一个 ACK(低电平)或 NACK(高电平)
    表示是否成功接收数据
  4. 数据传输:
    根据 R/W 位决定数据方向
    写操作:主设备→从设备
    读操作:从设备→主设备
  5. 停止条件(Stop):
    主设备在 SCL 为高电平时,将 SDA 从低电平拉至高电平
    标志一次通信的结束
  6. 重复起始条件(Repeated Start):
    在不发送 Stop 条件的情况下,再次发送 Start 条件
    用于连续传输不同地址的数据

三、AGS10 传感器概述

AGS10 是奥松电子推出的一款高精度空气质量传感器,用于检测空气中的挥发性有机化合物(VOCs)。其主要特性包括:
在这里插入图片描述
传感器采用标准I2C通信协议,适应多种设备。I2C的物理接口包含串行数据信号(SDA)与串行
时钟信号(SCL)两个接口。两个接口需通过1kΩ~10kΩ电阻上拉至VDD。SDA用于读、写传感器数
据。SCL上电必须保持高电平直到进行I2C通信开始,否则会引起I2C通讯不良。当I2C通信时SCL用于主机与传感器之间的通讯同步。多个I2C设备可以共享总线,但是只能允许一个主机设备出现在总线上。传感器I2C器件地址为0x1A(7-bit),写指令为0x34,读指令为0x35。通讯速率不高于15kHz。
在这里插入图片描述
在这里插入图片描述
命令集合:
在这里插入图片描述

四、AGS10驱动开发

1. 硬件连接

AGS10 SCL ---> RK3568 I2C3_SCL_MO
AGS10 SDA ---> RK3568 I2C3_SDA_MO
AGS10 GND ---> RK3568 GND
AGS10 VCC ---> RK3568 VCC3V3_SYS

在这里插入图片描述

2. 设备树(DTS)配置

在 RK3568 的设备树文件kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi中添加 ags10节点:
在这里插入图片描述

&i2c3 {  clock-frequency = <15000>;status = "okay";ags10: ags10@1a {compatible = "aosong,ags10";reg = <0x1A>;status = "okay";};
};

i2c3定义如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
在这里插入图片描述
i2c3引脚复用如下:
kernel/arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi
在这里插入图片描述

3. 内核驱动开发

i2c函数介绍:

函数原型

int i2c_master_send(struct i2c_client *client, const char *buf, int count);

功能

  • 向指定 I2C 从设备发送数据,适用于简单的写操作(如配置寄存器)。

参数

  • client:指向目标 I2C 设备的客户端结构体指针
  • buf:指向要发送的数据缓冲区
  • count:要发送的字节数

返回值

  • 成功:返回实际发送的字节数(通常等于count
  • 失败:返回负值错误码(如-ENODEV-EIO等)

函数原型

int i2c_master_recv(struct i2c_client *client, char *buf, int count);

功能

  • 从指定 I2C 从设备接收数据,适用于简单的读操作(如读取传感器数据)。

参数

  • client:指向目标 I2C 设备的客户端结构体指针
  • buf:指向接收数据的缓冲区
  • count:期望接收的字节数

返回值

  • 成功:返回实际发送的字节数(通常等于count
  • 失败:返回负值错误码(如-ENODEV-EIO等)

函数原型

int i2c_master_recv(struct i2c_client *client, char *buf, int count);

功能

  • 发送一个或多个 I2C 消息(struct i2c_msg数组),支持复杂的通信序列(如带重复 START 的复合操作)。

参数

  • adap:指向 I2C 适配器的指针
  • msgs:指向struct i2c_msg数组的指针
  • num:消息数组的长度(即消息数量)

返回值

  • 成功:返回实际成功传输的消息数(等于num
  • 失败:返回负值错误码,或已成功传输的消息数(小于num

struct i2c_msg结构

struct i2c_msg {__u16 addr;     /* 从设备地址 */__u16 flags;    /* 标志位(如I2C_M_RD表示读操作) */__u16 len;      /* 消息长度 */__u8 *buf;      /* 数据缓冲区 */
};
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/fs.h>       
#include <linux/miscdevice.h> // 包含miscdevice相关定义
#include <linux/uaccess.h>/* 寄存器命令 */
#define AGS10_CMD_READ_TVOC    0x00    // 读取TVOC值
#define AGS10_CMD_CALIBRATE    0x01    // 校准命令
#define AGS10_CMD_READ_VERSION 0x11    // 读取固件版本
#define AGS10_CMD_RESISTANCE  0x20    // 读取阻值#define AGS10_IOC_MAGIC  'a'/* 定义命令 */
#define AGS10_CMD_GET_TVOC    _IOR(AGS10_IOC_MAGIC, 1, u16)  // 读取TVOC值
#define AGS10_CMD_CALIBRATE   _IO(AGS10_IOC_MAGIC, 2)         // 触发校准struct ags10_data {struct i2c_client *client;struct mutex lock;struct miscdevice miscdev;u8 firmware_version;bool initialized;
};static int ags10_i2c_write(struct i2c_client *client, u8 cmd, u8 *data, int len)
{int ret;u8 buf[len + 1];memcpy(buf + 1, data, len);/* 发送命令 */buf[0] = cmd;ret = i2c_master_send(client, buf, len + 1);if (ret != 1) {dev_err(&client->dev, "Failed to send command: %d\n", ret);return ret;}return 0;
}/* 发送命令并读取响应 */
static int ags10_send_command(struct i2c_client *client, u8 cmd, u8 *data, int len)
{int ret;u8 buf[16];u8 addr = client->addr;/* 发送命令 */struct i2c_msg msgs[] = {[0] = {.addr = addr,.flags = 0,.len = sizeof(u8),.buf = &addr,},[1] = {.addr = addr,.flags = 0,.len = sizeof(u8),.buf = &cmd,},};ret = i2c_transfer(client->adapter, msgs, 2);printk(KERN_INFO "ags10_send_command ret = %d, addr = %x, cmd = %x", ret, addr, cmd);/*buf[0] = cmd;ret = i2c_master_send(client, buf, 1);if (ret != 1) {dev_err(&client->dev, "Failed to send command: %d\n", ret);return ret;}*//* 等待传感器响应 */msleep(10);/* 读取响应 */if (data && len > 0) {ret = i2c_master_recv(client, data, len);if (ret != len) {dev_err(&client->dev, "Failed to read response: %d\n", ret);return ret;}}return 0;
}/* 计算CRC校验 */
static u8 ags10_calculate_crc(u8 *data, int len)
{u8 crc = 0xFF;int i, j;for (i = 0; i < len; i++) {crc ^= data[i];for (j = 0; j < 8; j++) {if (crc & 0x80) {crc = (crc << 1) ^ 0x31;} else {crc <<= 1;}}}return crc;
}/* 读取TVOC值 (单位: ppb) */
static int ags10_read_tvoc(struct ags10_data *data, u16 *tvoc)
{int ret;u8 buf[5];  // 5字节缓冲区: [STATUS][DATA_H][DATA_M][DATA_L][CRC]u32 raw_value;mutex_lock(&data->lock);/* 发送读取TVOC命令并接收4字节数据 */ret = ags10_send_command(data->client, AGS10_CMD_READ_TVOC, buf, 5);if (ret) {mutex_unlock(&data->lock);return ret;}int i;for(i = 0; i < 5; i++){printk(KERN_INFO "ags10_read_tvoc[%d] = 0x%x", i, buf[i]);}/* 验证CRC (校验前3个数据字节) */if (buf[4] != ags10_calculate_crc(&buf[0], 4)) {dev_err(&data->client->dev, "TVOC CRC check failed: 0x%02X vs 0x%02X\n",buf[4], ags10_calculate_crc(&buf[0], 4));mutex_unlock(&data->lock);return -EIO;}/* 计算TVOC值 (24位原始值转换为ppb) */raw_value = ((u32)buf[1] << 16) | ((u32)buf[2] << 8) | buf[3];printk(KERN_INFO "ags10_read_tvoc raw_value = 0x%x", raw_value);*tvoc = (raw_value);mutex_unlock(&data->lock);return 0;
}//零点恢复校准
static int ags10_reset_calibration(struct ags10_data *data)
{	int ret;u8 buf[5] = {0x00, 0x0C, 0xFF, 0xFF, 0x81};mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_reset_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校准需要约30msreturn 0;}/*以当前阻值为零点校准*/
static int ags10_current_resistance_calibration(struct ags10_data *data)
{	int ret;u8 buf[5] = {0x00, 0x0C, 0x00, 0x00, 0xAC};mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_current_resistance_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校准需要约30msreturn 0;}/*以raw为零点校准*/
static int ags10_calibration(struct ags10_data *data, uint16_t raw)
{	int ret;u8 buf[5] = {0x00, 0x0C, (raw >> 8) & 0xFF, (raw >> 0) & 0xFF, };buf[4] = ags10_calculate_crc(buf, 4);mutex_lock(&data->lock);ret = ags10_i2c_write(data->client, AGS10_CMD_CALIBRATE, buf, 5);if (ret) {dev_err(&data->client->dev, "ags10_calibration failed\n");return ret;}mutex_unlock(&data->lock);msleep(30);  // 校准需要约30msreturn 0;}/* 读取固件版本 */
static int ags10_read_version(struct ags10_data *data)
{int ret;u8 buf[5]; //0-2:[Reserved][Version][CRC]mutex_lock(&data->lock);/* 发送读取版本命令 */ret = ags10_send_command(data->client, AGS10_CMD_READ_VERSION, buf, 5);if (ret) {mutex_unlock(&data->lock);return ret;}int i;for(i = 0; i < 5; i++){printk(KERN_INFO "ags10_read_version[%d] = 0x%x", i, buf[i]);}/* 验证CRC */if (buf[4] != ags10_calculate_crc(&buf[0], 4)) {dev_err(&data->client->dev, "CRC check failed\n");mutex_unlock(&data->lock);return -EIO;}data->firmware_version = buf[3];dev_info(&data->client->dev, "Firmware version: %d\n", data->firmware_version);mutex_unlock(&data->lock);return 0;
}/* 文件操作: 读取 */
static ssize_t ags10_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{struct ags10_data *data = filp->private_data;u16 tvoc;int ret;size_t len;if (count < 4)return -EINVAL;/* 读取TVOC值 */ret = ags10_read_tvoc(data, &tvoc);if (ret)return ret;/* 复制到用户空间 */if (copy_to_user(buf, &tvoc, sizeof(u16)))return -EFAULT;return len;
}/* 文件操作: ioctl */
static long ags10_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct ags10_data *data = filp->private_data;int ret;u16 tvoc;switch (cmd) {case AGS10_CMD_READ_TVOC:/* 读取TVOC值 */ret = ags10_read_tvoc(data, &tvoc);if (ret)return ret;/* 复制到用户空间 */if (copy_to_user((u16*)arg, &tvoc, sizeof(u16)))return -EFAULT;return 0;case AGS10_CMD_CALIBRATE:/* 发送校准命令 */ret = ags10_send_command(data->client, AGS10_CMD_CALIBRATE, NULL, 0);if (ret)return ret;return 0;default:return -ENOTTY;}
}/* 文件操作表 */
static const struct file_operations ags10_fops = {.read = ags10_read,.unlocked_ioctl = ags10_ioctl,.llseek = no_llseek,
};/* 探测函数 */
static int ags10_probe(struct i2c_client *client, const struct i2c_device_id *id)
{struct ags10_data *data;int ret;/* 检查设备是否支持 */if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {dev_err(&client->dev, "I2C functionality not supported\n");return -ENODEV;}dev_err(&client->dev, "ags10 I2C functionality supported\n");/* 分配并初始化驱动数据结构 */data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);if (!data) {dev_err(&client->dev, "Failed to allocate memory\n");return -ENOMEM;}data->client = client;mutex_init(&data->lock);i2c_set_clientdata(client, data);/* 初始化misc设备 */data->miscdev.minor = MISC_DYNAMIC_MINOR;data->miscdev.name = "ags10";data->miscdev.fops = &ags10_fops;data->miscdev.parent = &client->dev;ret = misc_register(&data->miscdev);if (ret) {dev_err(&client->dev, "Failed to register misc device\n");return ret;}/* 读取固件版本 */ret = ags10_read_version(data);if (ret) {dev_err(&client->dev, "Failed to read firmware version\n");misc_deregister(&data->miscdev);return ret;}u16 tvoc;ags10_read_tvoc(data, &tvoc);printk(KERN_INFO "ags10_read_tvoc tvoc = %d", tvoc);data->initialized = true;dev_info(&client->dev, "AGS10 TVOC sensor initialized\n");return 0;
}/* 移除函数 */
static int ags10_remove(struct i2c_client *client)
{printk(KERN_INFO "AGS10 TVOC sensor remove");struct ags10_data *data = i2c_get_clientdata(client);if (data->initialized) {misc_deregister(&data->miscdev);data->initialized = false;}return 0;
}/* 设备ID表 */
static const struct i2c_device_id ags10_id_table[] = {{ "ags10", 0 },{},
};
MODULE_DEVICE_TABLE(i2c, ags10_id_table);/* OF匹配表 */
static const struct of_device_id ags10_of_match[] = {{ .compatible = "aosong,ags10" },{},
};
MODULE_DEVICE_TABLE(of, ags10_of_match);/* I2C驱动结构体 */
static struct i2c_driver ags10_driver = {.driver = {.name = "ags10",.owner = THIS_MODULE,.of_match_table = ags10_of_match,},.probe = ags10_probe,.remove = ags10_remove,.id_table = ags10_id_table,
};module_i2c_driver(ags10_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR("cmy");
MODULE_DESCRIPTION("AGS10 TVOC Sensor Driver");
MODULE_VERSION("1.0");

五、调试与验证

将编译好的驱动文件拷贝到开发板进行测试:
在这里插入图片描述
也可以通过i2cdetect 、i2cget、i2cset等命令进行调试。

六、总结

本文详细介绍了 I2C 总线协议的工作原理,并展示了如何在 RK3568 平台上开发 AGS10 空气质量传感器的 Linux 驱动。通过深入理解 I2C 协议和 Linux 内核 I2C 子系统,我们实现了一个完整的驱动程序,包括设备初始化、数据读取和用户接口。

http://www.dtcms.com/wzjs/43527.html

相关文章:

  • 拼多多网站的类型凡科建站代理
  • wordpress在线代码编辑南昌seo服务
  • wordpress数据库修改登陆密码忘记谷歌seo新规则
  • 在菲做平台网站aso网站
  • wordpress下载收费上海seo推广公司
  • 广州交通站场建设管理中心网站国内真正的永久免费砖石
  • 怎么免费给网站做收录百度快照在哪里
  • 蝶山网站建设石家庄学院
  • 温州建设局网站首页竞价推广哪家公司好
  • 培训网站模板百度广告联盟app下载官网
  • 网站是哪个公司做的百度权重查询
  • 徐州网站建设培训班关键词com
  • 张家界住房和城乡建设局网站专业网页设计和网站制作公司
  • cpa单页网站怎么做杭州seo软件
  • 有哪些可以做1元夺宝的网站湖北网站设计
  • 同步网站内容怎么做seo快速排名优化方法
  • 网站服务内容怎么写中国网站排名查询
  • 闸北做网站公司网络营销的成功案例有哪些
  • 纯html静态网站竞价托管收费标准
  • 在日常网站建设中宣传积极网站制作出名的公司
  • 钢板防护罩做网站深圳做网站的公司
  • 制作收款网站微信推广引流加精准客户
  • 快速网站推广工具长沙关键词优化新报价
  • 自己做短视频网站找谁做百度关键词排名
  • 做游戏的av迅雷下载网站百度搜索排名优化
  • 广东电子商务网站建设价格seo什么职位
  • 网站建设几个税点教育机构在线咨询
  • 网站建设最流行语言百度定位店铺位置怎么设置
  • 做名片哪个网站最好搜索引擎优化seo专员
  • 国外做鞋子的网站吗seo点击排名源码