访问I2C设备(比如eeprom),我知道的有三总方法:
(一)i2c-dev操作I2C设备:不用添加设备驱动,用户直接在应用层完成对具体I2C 设备的驱动工作。
(二)sysfs操作I2C设备:需添加设备驱动,通过sys展示出来的文件操作设备(比如/sys/devices/platform/s3c2440-i2c/i2c-0/0-0050/eeprom)
(三)设备节点操作i2C设备:添加设备驱动,为设备驱动创建设备节点,从/dev访问I2C设备(比如/dev/eeprom)
原文链接:https://blog.csdn.net/wuxiwang/article/details/140118183
一 OLED 12880(SH1107)
模组链接:https://item.taobao.com/item.htm?spm=a1z09.2.0.0.512d2e8dkifnvI&id=674600863020&_u=tom5bln21f7
模组资料:https://pan.baidu.com/s/17XWkG6xXvj94V_DfXcro8Q 1217
内核支持fb_sh1106.c,所以这里尝试按照去改fb_sh1106.c去适配fb_sh1107.c。
1.1 sh1106和sh1107的区别?
支持的分辨率不一样。
2.1 模块原理图
2.2 供电
5v供电。
2.3 接线
模块引脚 | F1C200S |
---|---|
VCC | 5V |
GND | GND |
SDA | TWI0_SDA/PD0 |
SCL | TWI0_SCK/PD12 |
2.4 测试
sh1107_app.sh
i2cset -y 0 0x3c 0x00 0xAE
i2cset -y 0 0x3c 0x00 0xDC
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0x20
i2cset -y 0 0x3c 0x00 0x81
i2cset -y 0 0x3c 0x00 0x80
i2cset -y 0 0x3c 0x00 0xA0
i2cset -y 0 0x3c 0x00 0xA4
i2cset -y 0 0x3c 0x00 0xA6
i2cset -y 0 0x3c 0x00 0xC0
i2cset -y 0 0x3c 0x00 0xA8
i2cset -y 0 0x3c 0x00 0x7F
i2cset -y 0 0x3c 0x00 0xD5
i2cset -y 0 0x3c 0x00 0x50
i2cset -y 0 0x3c 0x00 0xD3
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0xDB
i2cset -y 0 0x3c 0x00 0x37
i2cset -y 0 0x3c 0x00 0xD9
i2cset -y 0 0x3c 0x00 0x22
i2cset -y 0 0x3c 0x00 0xaf
# 清屏
for i in {0..15}
do
v=$((0xb0+i))
i2cset -y 0 0x3c 0x00 $v
i2cset -y 0 0x3c 0x00 0x11
i2cset -y 0 0x3c 0x00 0x08
for i in {0..79}
do
i2cset -y 0 0x3c 0x40 0xff
done
done
# 黑屏
for i in {0..15}
do
v=$((0xb0+i))
i2cset -y 0 0x3c 0x00 $v
i2cset -y 0 0x3c 0x00 0x11
i2cset -y 0 0x3c 0x00 0x08
for i in {0..79}
do
i2cset -y 0 0x3c 0x40 0x00
done
done
二 温湿度传感器(SHT35)
内核已持支持的hwmon设备,查看https://www.kernel.org/doc/html/latest/hwmon/index.html
linux内核已自带的sht3x驱动,但是该驱动不支持设备树。
2.1 模块供电
2.2 硬件接线
模块引脚 | F1C200S |
---|---|
VCC | 3.3V |
GND | GND |
SDA | TWI0_SDA/PD0 |
SCL | TWI0_SCK/PD12 |
2.3 内核配置
2.4 设备树
与之前保持一致。支持i2c0。
2.5 驱动
内核自带驱动增加调试代码。
vim driver/hwmon/sht3x.c
static int sht3x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......
// 在驱动匹配成功之后,会打印
printk("sht3x_probe\r\n");
}
编译
sudo cp driver/hwmon/sht3x.ko /media/wang/rootfs/lib/modules/5.4.99
2.6 设备信息
sht35_device.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
static struct i2c_board_info sht3x_i2c_board_info __initdata = {
I2C_BOARD_INFO("sht3x", 0x44),
};
static int __init sht3x_init(void)
{
int ret = 0;
struct i2c_adapter *adapter;
printk("sht3x_init\r\n");
adapter = i2c_get_adapter(0);
i2c_new_client_device(adapter, &sht3x_i2c_board_info);
return ret;
}
static void __exit sht3x_exit(void)
{
}
module_init(sht3x_init);
module_exit(sht3x_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wangxinchen");
Makefile
ifneq ($(KERNELRELEASE),)
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
obj-m := sht35_device.o
else
PWD:= $(shell pwd)
KDIR := /home/wang/workplace/code/linux-5.4.99
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
rm -rf .*.cmd *.o *.mod.c .tmp_versions *.mod *.symvers *.order
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions *.mod *.symvers *.order
endif
编译
make
sudo cp sht35_device.ko /media/wang/rootfs/lib/modules/5.4.99
2.7 测试
insmod /lib/modules/5.4.99/sht35_device.ko
insmod /lib/modules/5.4.99/sht3x.ko
ls /sys/class/hwmon/
ls /sys/class/hwmon/hwmon0
cat /sys/class/hwmon/hwmon0/temp1_input
cat /sys/class/hwmon/hwmon0/humidity1_input
2.8 应用程序
sht35_app.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
FILE *temp_file, *humi_file;
int temperature, humidity;
char buf[64];
while(1){
temp_file = fopen("/sys/class/hwmon/hwmon0/temp1_input", "r");
if (temp_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
humi_file = fopen("/sys/class/hwmon/hwmon0/humidity1_input", "r");
if (temp_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
// 读取温度值
if (fgets(buf, sizeof(buf), temp_file) != NULL) {
temperature = atoi(buf);
printf("Temperature: %.3f C ", (float)temperature / 1000); // 温度通常以毫摄氏度为单位
}
// 读取湿度
if (fgets(buf, sizeof(buf), humi_file) != NULL) {
humidity = atoi(buf);
printf("Humidity: %.3f C\n", (float)humidity / 1000); // 温度通常以毫摄氏度为单位
}
fclose(temp_file);
fclose(humi_file);
//sleep(1);
usleep(100000); //100ms
}
return EXIT_SUCCESS;
}
需要放在移植的debian系统下编译。
gcc sht35_app.c -o sht35_app
导入开发板测试
创建I2C设备:
echo sht3x 0x44 > /sys/bus/i2c/devices/i2c-0/new_device
加载驱动
insmod /lib/modules/5.4.99/sht3x.ko
测试程序
./sht35_app
删除I2C设备:
echo 0x44 > /sys/bus/i2c/devices/i2c-0/delete_device
2.9 参考
https://blog.csdn.net/u014754841/article/details/132580947
https://blog.csdn.net/lihui126/article/details/45723017
三 气体传感器(SGP30)
3.1 供电
3.2 模块原理图
3.3 接线
模块 | F1C200S |
---|---|
VCC | 3.3V |
GND | GND |
SDA | TWI0_SDA/PD0 |
SCL | TWI0_SCK/PD12 |
3.4 内核配置
3.5 设备树
gas@58 {
compatible = "sensirion,sgp30";
reg = <0x58>;
status = "okay";
};
3.6 驱动
编译成模块,手动加载便于调试。
内核自带驱动使用了IIO子系统。
IIO 驱动框架提供了 sysfs 接口,因此加载成功以后我们可以在用户空间访问对应的 sysfs 目录项,进入目录“/sys/bus/iio/devices/”目录里面,此目录下都是 IIO 框架设备。
GP30主要是对空气质量进行检测,TVOC是一项重要指标,指总可挥发有机物气体。一般我们可以用它来反映甲醛的浓度!
SGP30气体传感器使用了MOS技术和电化学技术来检测VOC分子的浓度,并使用红外线吸收技术来检测CO2浓度。
sudo cp drivers/iio/chemical/sgp30.ko /media/wang/rootfs/lib/modules/5.4.99/
3.7 测试
insmod /lib/modules/5.4.99/sgp30.ko
驱动加载成功,在目录/sys/bus/iio/devices下可看到设备
ls /sys/bus/iio/devices
cat /sys/bus/iio/devices/iio\:device0/in_concentration_co2_input
cat /sys/bus/iio/devices/iio\:device0/in_concentration_voc_input
单位换算
在SGP30的测量中,二氧化碳(CO2)的浓度单位是ppm(parts per million),而挥发性有机化合物(VOC)的浓度单位是ppb(parts per billion)。
二氧化碳浓度标准:多少PPM对人体有危害?
PPM: 气体浓度的100万分之一。※1%=10000ppm
PPB: 气体浓度的10亿分之一。※1ppm=1000ppb
这里读出来的结果:
0.000756 转换为 PPM --> 0.000756*1000000 = 756PPM
0.000000120 转换为 PPB --> 0.000000120*1000000000 = 120PPB = 0.12PPM
PPB转换为mg/L的公式是:1 ppb = 1 μg/L = 0.001 mg/L。
PPM转换为mg/L的公式是:1 ppm = 1 mg/L。
在室内空气中,VOC检测值的正常范围根据国家相关标准,一般在0-500μg/m³之间。
https://teesing.com/en/tools/ppm-mg3-converter
VOC 应小于0.5mg/m³(0.155 ppm)
二氧化碳浓度含量与人体的生理反应:
1、350~450ppm,同一般室外环境;
2、350~1000ppm,空气清新,呼吸顺畅;
3、1000~2000ppm,感觉空气浑浊,并开始觉得昏昏欲睡。
3.8 应用程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
加载驱动
insmod /lib/modules/5.4.99/sgp30.ko
匹配成功目录/sys/bus/iio/devices下会有设备。
VOC 应小于0.5mg/m³(0.155 ppm)
*/
int main() {
FILE *voc_file, *co2_file;
float voc_raw, co2_raw;
char buf[64];
while(1){
voc_file = fopen("/sys/bus/iio/devices/iio\:device0/in_concentration_voc_input", "r");
if (voc_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
co2_file = fopen("/sys/bus/iio/devices/iio\:device0/in_concentration_co2_input", "r");
if (co2_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
if (fgets(buf, sizeof(buf), voc_file) != NULL) {
voc_raw = atof(buf)*1000000000; // 单位PPB
}
if (fgets(buf, sizeof(buf), co2_file) != NULL) {
co2_raw = atof(buf)*1000000; // 单位PPM
}
// 1PPM=1000PPB
// 1PPB=1/1000PPM
// voc Molecular Weight 78.9516 g/mol
// 0.0409 x (ppm) x 78.9516 = 69.652
printf("voc_mg:%.2f mg/m³ co2_ppm: %d\r\n", voc_raw/1000*0.0409*78.9516, (int)(co2_raw));
fclose(voc_file);
fclose(co2_file);
//sleep(1);
usleep(100000); //100ms
}
return EXIT_SUCCESS;
}
四 加速度传感器(ADXL345)
4.1 模块原理图
支持I2C和SPI通信,是靠什么判断的?
4.2 供电
模块是5v供电,内部转3.3v。
4.3 接线
模块引脚 | F1C200S |
---|---|
VCC50 | 5V |
GND | GND |
SDA | TWI0_SDA/PD0 |
SCL | TWI0_SCK/PD12 |
4.4 配置内核
4.5 驱动
内核自带驱动,使用IIO子系统。IIO子系统参考正点原子Linux文档。
sudo cp drivers/iio/accel/adxl345_core.ko /media/wang/rootfs/lib/modules/5.4.99/
sudo cp drivers/iio/accel/adxl345_i2c.ko /media/wang/rootfs/lib/modules/5.4.99/
4.6 设备树
accelerometer@53 {
compatible = "adi,adxl345";
reg = <0x53>;
status = "okay";
};
4.7 测试
IIO 驱动框架提供了 sysfs 接口,因此加载成功以后我们可以在用户空间访问对应的 sysfs 目录项,进入目录“/sys/bus/iio/devices/”目录里面,此目录下都是 IIO 框架设备。
insmod /lib/modules/5.4.99/adxl345_core.ko
insmod /lib/modules/5.4.99/adxl345_i2c.ko
驱动加载成功,在目录/sys/bus/iio/devices下可看到设备
ls /sys/bus/iio/devices
cat /sys/bus/iio/devices/iio\:device0/in_accel_scale
cat /sys/bus/iio/devices/iio\:device0/in_accel_x_raw
cat /sys/bus/iio/devices/iio\:device0/in_accel_y_raw
cat /sys/bus/iio/devices/iio\:device0/in_accel_z_raw
4.8 应用程序
如果不用设备树,可以
echo adxl345 0x53> /sys/bus/i2c/devices/i2c-0/new_device
adxl345_app.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
加载驱动
insmod adxl345_core.ko
insmod adxl345_i2c.ko
匹配成功目录/sys/bus/iio/devices下会有设备。
*/
int main() {
FILE *accel_scale_file, *accel_x_raw_file, *accel_y_raw_file, *accel_z_raw_file;
int accel_x_raw, accel_y_raw, accel_z_raw;
float accel_scale;
char buf[64];
while(1){
accel_scale_file = fopen("/sys/bus/iio/devices/iio\:device0/in_accel_scale", "r");
if (accel_scale_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
accel_x_raw_file = fopen("/sys/bus/iio/devices/iio\:device0/in_accel_x_raw", "r");
if (accel_x_raw_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
accel_y_raw_file = fopen("/sys/bus/iio/devices/iio\:device0/in_accel_y_raw", "r");
if (accel_y_raw_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
accel_z_raw_file = fopen("/sys/bus/iio/devices/iio\:device0/in_accel_z_raw", "r");
if (accel_z_raw_file == NULL) {
perror("Error opening file");
return EXIT_FAILURE;
}
if (fgets(buf, sizeof(buf), accel_scale_file) != NULL) {
accel_scale = atof(buf);
//printf("accel_scale: %f ", accel_scale);
}
if (fgets(buf, sizeof(buf), accel_x_raw_file) != NULL) {
accel_x_raw = atoi(buf);
//printf("accel_x_raw: %d ", accel_x_raw);
}
if (fgets(buf, sizeof(buf), accel_y_raw_file) != NULL) {
accel_y_raw = atoi(buf);
//printf("accel_y_raw: %d ", accel_y_raw);
}
if (fgets(buf, sizeof(buf), accel_z_raw_file) != NULL) {
accel_z_raw = atoi(buf);
//printf("accel_z_raw: %d\n", accel_z_raw);
}
printf("accel x:%.2f y:%.2f z:%.2f\r\n", accel_scale*accel_x_raw, accel_scale*accel_y_raw, accel_scale*accel_z_raw);
fclose(accel_scale_file);
fclose(accel_x_raw_file);
fclose(accel_y_raw_file);
fclose(accel_z_raw_file);
//sleep(1);
usleep(100000); //100ms
}
return EXIT_SUCCESS;
}
执行结果
gcc adxl345_app.c -o adxl345_app
root@wangpi:/home/wxc# ./adxl345_app
accel x:0.34 y:-8.04 z:-3.87
accel x:0.31 y:-8.08 z:-4.02
accel x:0.31 y:-8.08 z:-4.02
accel x:0.27 y:-8.08 z:-3.98
accel x:0.34 y:-8.04 z:-3.98
accel x:0.31 y:-8.04 z:-3.98
accel x:0.31 y:-8.08 z:-3.98
accel x:0.31 y:-8.08 z:-3.98
4.9 问题
accel_scale 为什么是0.0383???
在驱动源码adxl345_core.c中查到答案。
/*
* In full-resolution mode, scale factor is maintained at ~4 mg/LSB
* in all g ranges.
*
* At +/- 16g with 13-bit resolution, scale is computed as:
* (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
*/
static const int adxl345_uscale = 38300;
4.10 libiio库
sudo apt install libiio-dev
未完成。
4.11 参考
【【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81】的IIO章节。
五、SSD1306
5.1 模组链接
5.2 模组原理图
5.3 供电
3.3v供电。
5.4 接线
模块引脚 | F1C200S |
---|---|
VCC | 3.3V |
GND | GND |
SDA | TWI0_SDA/PD0 |
SCL | TWI0_SCK/PD12 |
5.5 测试
SSD1306_app.sh
i2cset -y 0 0x3c 0x00 0xAE
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0x10
i2cset -y 0 0x3c 0x00 0x40
i2cset -y 0 0x3c 0x00 0x81
i2cset -y 0 0x3c 0x00 0xCF
i2cset -y 0 0x3c 0x00 0xA1
i2cset -y 0 0x3c 0x00 0xC8
i2cset -y 0 0x3c 0x00 0xA6
i2cset -y 0 0x3c 0x00 0xA8
i2cset -y 0 0x3c 0x00 0x3f
i2cset -y 0 0x3c 0x00 0xD3
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0xd5
i2cset -y 0 0x3c 0x00 0x80
i2cset -y 0 0x3c 0x00 0xD9
i2cset -y 0 0x3c 0x00 0xF1
i2cset -y 0 0x3c 0x00 0xDA
i2cset -y 0 0x3c 0x00 0x12
i2cset -y 0 0x3c 0x00 0xDB
i2cset -y 0 0x3c 0x00 0x40
i2cset -y 0 0x3c 0x00 0x20
i2cset -y 0 0x3c 0x00 0x02
i2cset -y 0 0x3c 0x00 0x8D
i2cset -y 0 0x3c 0x00 0x14
i2cset -y 0 0x3c 0x00 0xA4
i2cset -y 0 0x3c 0x00 0xA6
i2cset -y 0 0x3c 0x00 0xAF
# 清屏
for i in {0..7}
do
echo $i
v=$((0xb0+i))
i2cset -y 0 0x3c 0x00 $v
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0x10
for i in {0..127}
do
i2cset -y 0 0x3c 0x40 0xff
done
done
# 黑屏
for i in {0..7}
do
echo $i
v=$((0xb0+i))
i2cset -y 0 0x3c 0x00 $v
i2cset -y 0 0x3c 0x00 0x00
i2cset -y 0 0x3c 0x00 0x10
for i in {0..127}
do
i2cset -y 0 0x3c 0x40 0x00
done
done
5.6 内核配置
5.7 设备树
ssd1306: oled@3c {
compatible = "solomon,ssd1306fb-i2c";
reg = <0x3c>;
reset-gpios=<&pio 4 12 GPIO_ACTIVE_LOW>;
solomon,height = <64>;
solomon,width = <128>;
solomon,page-offset = <0>;
solomon,com-lrremap;
solomon,com-invdir;
//solomon,com-offset = <32>;
status = "okay";
};
5.8 驱动
使用drivers/video/fbdev/ssd1307fb.c
5.9 测试
insmod /lib/modules/5.4.99/ssd1307fb.ko