TCS34725 颜色传感器设备驱动程序
一、概述
以前的传感器是用过中断的方式进行计数的,现在已经有 I2C 通行的颜色传感器,不在需要我们像之前那样,通过计数的方式获取数据,直接通过I2C读取即可。当然有通过串口的方式获取采集数据的,串口使用就比较简单了,此笔记只针对 I2C 通信的模块。
我在某宝上随意购买了一个 TCS34725 的颜色采集模块,发现厂家提供的是 Arduino 的案例,还是用 C++ 编写的,我相信有的小伙伴还没接触过 C++ ,这里我将程序改为 C 语言编写,有需要的小伙伴可以收藏一下,
注意: 此笔记中的驱动程序不单纯针对莫一块 MCU,在 ESP32、stm32、arm中都可以使用的,甚至单片机也可稍微修改一下进行使用。
二、TCS34725 使用说明
TCS34725 多数提供的说明文档都是英文版的,英语不要的小伙伴,就有点慌了,不要怕,结合我这里的描述,相信你也能看明白是怎么回事了,下面我会把需要注意的重点进行记录分析。
传感器接线
这个就比较简单了,相信能看到这篇笔记的小伙伴应该都没问题的,引脚如下图所示:
设备地址
设备寄存器
对于 TCS34725 编程需要注意的就上面三点内容,有这些知识点后,就可以编程了,现在是不是发现,没学过英文也可以完成 TCS34725 传感器的使用。
注意:如果不明白我为啥把说明书中这三个重点拿出的小伙伴,可能是对 I2C 原理还不怎么掌握,建议先去补充一下,然后再回来看就比较清晰了,这里我就不帖链接了,网上有很多。
三、TCS34725 驱动编程
还是老规矩,编程肯定要先配置,然后再使用,这个就不用说了,那么在 TCS34725 传感器中,使用之前主要有五个流程,分别是:读取设备识别号 → 设置集成时间 → 设置增益倍数 → 启动传感器 → 获取采集数据,分析如下所示。
可操作的寄存器地址
在编写程序之前,先了解有哪些寄存器可以操作的,如下所示:#define TCS34725_address (0x29) // 设备地址
#define TCS34725_COMMAND_BIT (0x80) // 命令字节 /* TCS34725传感器配置寄存器 */
#define TCS34725_ENABLE (0x00) // 启用传感器
#define TCS34725_ATIME (0x01) // 集成时间
#define TCS34725_WTIME (0x03) // R / W 等待时间
#define TCS34725_AILTL (0x04) // 清除通道下限中断阈值
#define TCS34725_AILTH (0x05)
#define TCS34725_AIHTL (0x06) // 清除通道上限中断阈值
#define TCS34725_AIHTH (0x07) // 配置寄存器
#define TCS34725_PERS (0x0C) // 中断永久性过滤器
#define TCS34725_CONFIG (0x0C) // 中断永久性过滤器
#define TCS34725_CONTROL (0x0F) // 增益倍数
#define TCS34725_ID (0x12) // 设备识别号 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
#define TCS34725_STATUS (0x13) // 设备状态
#define TCS34725_CDATAL (0x14) // 光照强度低字节
#define TCS34725_CDATAH (0x15) // 光照强度高字节
#define TCS34725_RDATAL (0x16) // 红色数据低字节
#define TCS34725_RDATAH (0x17)
#define TCS34725_GDATAL (0x18) // 绿色数据低字节
#define TCS34725_GDATAH (0x19)
#define TCS34725_BDATAL (0x1A) // 蓝色数据低字节
#define TCS34725_BDATAH (0x1B)命令寄存器
这个命令寄存器的作用图中有详细描述,如下图所示:
注意:看不懂没关系,只需要记住在进行寄存器操作时,都将寄存器地址或上一个 0x80 即可。
TCS34725 与 I2C 驱动的接口函数如下
/**
* @brief 通过I2C驱动提供的API进行对接,作用是将一个8位数据写入对应的寄存器中
*
* @param reg_addr 寄存机地址
* @param write_data 需要写入的寄存机数据
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_write8(uint8_t reg_addr, uint8_t write_data)
{
return esp32_i2c_write8(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, write_data);
} /**
* @brief 通过I2C驱动提供的API进行对接,作用是读取一个8位的数据
*
* @param reg_addr 寄存器地址
* @param read_data 数据存放地址
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_read8(uint8_t reg_addr, uint8_t* read_data)
{
return esp32_i2c_read8(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, read_data);
} /**
* @brief 通过I2C驱动提供的API进行对接,作用是读取一个16位的数据
*
* @param reg_addr 寄存器地址
* @param read_data 数据存放地址
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_read16(uint8_t reg_addr, uint16_t* read_data)
{
return esp32_i2c_read16(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, read_data);
}注意:
- 从程序中可以看出我在对每个寄存器操作前都或上了一个 0x80
- 我使用的 MCU 是 ESP32,所以这里对接的是 ESP32 的 I2C 接口函数,根据自己的需要进行更改即可。
- 需要了解 ESP 中 I2C 驱动的可以参考我之间我笔记:ESP32 I2C 总线主模式通信程序
读取设备识别号
为什么需要做这步操作了,原因很简单,可以快速验证接线和 I2C 驱动是否正常,这样在完成后面操作是,可以排除这两个麻烦的问题导致的,不然很多小伙伴发现获取不了传感器数据就直接懵逼了。
读取设备识别号的寄存器是 0x12 ,读取成功后会返回 0x44 或 0x4D,0x44 表示传感器是 TCS34721/TCS34725, 0x4D 表示传感器是 TCS34723/TCS34727,程序如下所示:/**
* @brief 返回设备类型
*
* @return uint8_t 设备识别号 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
*/
uint8_t get_tcs34725_type(void)
{
uint8_t data = 0;
tcs34725_read8(TCS34725_ID, &data);
return data;
}
判断设备是否正确
/* 1.获取TCS34725型号 */
uint8_t tcs34725_type = get_tcs34725_type();
ESP_LOGI(TAG, "device type is : %x ", tcs34725_type);
if (!((tcs34725_type == 0x44) && (tcs34725_type == 0x4D)))
{
ESP_LOGI(TAG, "Wrong device type!!!!!!!!!");
return -1;
}
设置集成时间
集成时间的寄存器地址是 0x01,不同的集成时间对应的采集范围和采样时间不同,计算方式是:最大RGBC计数 = (256 - cycles) × 1024,集成时间 ≈ (256 - 255) × 2.4ms,其中 cycles 是写入 0x01 寄存器中的值。比如向 0x01 寄存器中写入 0xFF ,则最大RGBC计数 = (256 - 255) × 1024 = 1024,且集成时间 ≈ (256 - 255) × 2.4ms = 2.4ms 也就是说此时采集的颜色值的范围是 0 ~ 1024,需要等待的采样时间为2.4ms,下面是常用的几种设置参数,可以根据自己的需要进行添加
/* 集成时间配置参数
* 最大RGBC计数 = (256 - cycles) × 1024
* 集成时间 ≈ (256 - cycles) × 2.4ms */
typedef enum
{
TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, // 2.4ms - 1 cycles - Max Count: 1024
TCS34725_INTEGRATIONTIME_24MS = 0xF6, // 24ms - 10 cycles - Max Count: 10240
TCS34725_INTEGRATIONTIME_50MS = 0xEC, // 50ms - 20 cycles - Max Count: 20480
TCS34725_INTEGRATIONTIME_101MS = 0xD5, // 101ms - 42 cycles - Max Count: 43008
TCS34725_INTEGRATIONTIME_154MS = 0xC0, // 154ms - 64 cycles - Max Count: 65535
TCS34725_INTEGRATIONTIME_700MS = 0x00 // 700ms - 256 cycles - Max Count: 65535
}
tcs34725_integration_time_t;
注意:
- 不同的集成时间,需要的采样时间不同,如果读取的时间间隔小于采样时间,那获取的颜色值都是0。
- 当设置的 cycles 小于 0xC0 后,需要的采样时间和采集范围不在增加。
设置程序如下所示:
/**
* @brief 设置集成时间
*
* @param integration_time 集成时间
* @return uint8_t 无错误时返回 0
*/
uint8_t set_tcs34725_integration_time(tcs34725_integration_time_t integration_time)
{
_tcs34725_config.integration_time = integration_time;
return tcs34725_write8(TCS34725_ATIME, integration_time);
}
增益倍数
增益倍数的寄存器地址是 0x0F,我不知道 TCS34725 内部的实现原理是什么,不过可以简单的从字面意思,类似将采集的值直接乘以一个倍数,作用是提高采集的敏感度,可以设置的增益倍数是:1、4、16、60。如下所示:/* 增益倍数 */
typedef enum
{
TCS34725_GAIN_1X = 0x00, // 1X增益
TCS34725_GAIN_4X = 0x01, // 4X增益
TCS34725_GAIN_16X = 0x02, // 16X增益
TCS34725_GAIN_60X = 0x03 // 60X增益
}
tcs34725_gain_t;
注意:不论设置的增益倍数是多少,采集的数据不会超过集成时间中设置的最大值
设置程序如下所示:
/**
* @brief 设置增益倍数
*
* @param gain 增益倍数
* @return uint8_t 无错误时返回 0
*/
uint8_t set_tcs34725_gain(tcs34725_gain_t gain)
{
_tcs34725_config.gain = gain;
return tcs34725_write8(TCS34725_CONTROL, gain);
}
启动 TCS34725 设备
启动设置的寄存器地址是 0x00,启动分中断启动和常规启动,具体的设置值如下所示:/* 启动传感器 */
#define TCS34725_ENABLE_AIEN (0x10) // RGBC中断使能
#define TCS34725_ENABLE_WEN (0x08) // 等待启用:写1激活等待计时器,写0禁用等待计时器
#define TCS34725_ENABLE_AEN (0x02) // RGBC启用:写1激活RGBC,写0禁用RGBC
#define TCS34725_ENABLE_PON (0x01) // 通电:写入1激活内部振荡器,0禁用内部振荡器
程序如下所示:
/**
* @brief 启动 tcs34725 设备
*
* @param interrupt_start 是否开启中断启动方式
* @return uint8_t 无错误时返回 0
*/
uint8_t tcs34725_start(bool interrupt_start)
{
int err = 0;
if (tcs34725_state)
{
return -1;
} err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_PON);
err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); /* 判断是否开启中断启动 */
if (interrupt_start)
{
_tcs34725_config.interrupt_start = interrupt_start;
err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_AIEN);
} tcs34725_state = true;
return err;
}
采集数据
采集数据获取的寄存器是:0x14 ~ 0x1B ,这里需要主要的是数据的高低位是反的,所以采集完成后需要交换一下高低位数据,如下所示:esp_err_t esp32_i2c_read16(uint8_t dev_addr, uint8_t reg_addr, uint16_t* read_data)
{
#if defined(CODE_SIMPLIFY)
uint8_t buf[2];
esp_err_t err = 0;
err = i2c_write(dev_addr, ®_addr, 1);
err = i2c_read(dev_addr, buf, 2);
*read_data = buf[1] << 8 | buf[0];
return err;
#else
return i2c_read16(dev_addr, reg_addr, read_data);
#endif
}
TCS34725 传感器数据的获取程序如下所示:
/**
* @brief 获取RGBC的值
*
* @param colour_r 数据存放地址
* @param colour_g 数据存放地址
* @param colour_b 数据存放地址
* @param colour_c 数据存放地址
* @return uint8_t 无错误时返回 0
*/
uint8_t get_tcs34725_rgbc(uint16_t *colour_r, uint16_t *colour_g, uint16_t *colour_b, uint16_t *colour_c)
{
uint8_t err = 0;
err = tcs34725_read16(TCS34725_RDATAL, colour_r);
err = tcs34725_read16(TCS34725_GDATAL, colour_g);
err = tcs34725_read16(TCS34725_BDATAL, colour_b);
err = tcs34725_read16(TCS34725_CDATAL, colour_c);
return err;
}
停止 TCS34725 设备
停止是设置的寄存器和启动是一样的,都是 0x00,程序如下所示:/**
* @brief 停止 tcs34725 设备
*
* @return uint8_t 无错误时返回 0
*/
uint8_t tcs34725_stop(void)
{
uint8_t err = 0;
uint8_t data = 0;
err = tcs34725_read8(TCS34725_ENABLE, &data);
err = tcs34725_write8(TCS34725_ENABLE, data & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN)); /* 通过中断启动后时,需要关闭中断设置 */
if (_tcs34725_config.interrupt_start)
{
err = tcs34725_write8(TCS34725_ENABLE, data & ~TCS34725_ENABLE_AIEN);
} tcs34725_state = false;
return err;
}
范围计算和白平衡
这里的范围计算和白平衡调节就多种多样了,可以采集完成后根据自己的需要完成。
这里提供一个简单的思想,因为颜色的范围是 0 ~ 255,所以首先将自己的设置的范围换算到 0 ~ 25,然后再进行一个简单的白平衡校准即可。
四、TCS34725驱动程序
头文件
/**
* @file tcs34725.h
*
*/
#ifndef _TCS34725_H_
#define _TCS34725_H_
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdlib.h>
#include <stdbool.h>
/*********************
* DEFINES
*********************/
#define TCS34725_address (0x29) // 设备地址
#define TCS34725_COMMAND_BIT (0x80) // 命令字节
/* TCS34725传感器配置寄存器 */
#define TCS34725_ENABLE (0x00) // 启用传感器
#define TCS34725_ATIME (0x01) // 集成时间
#define TCS34725_WTIME (0x03) // R / W 等待时间
#define TCS34725_AILTL (0x04) // 清除通道下限中断阈值
#define TCS34725_AILTH (0x05)
#define TCS34725_AIHTL (0x06) // 清除通道上限中断阈值
#define TCS34725_AIHTH (0x07) // 配置寄存器
#define TCS34725_PERS (0x0C) // 中断永久性过滤器
#define TCS34725_CONFIG (0x0C) // 中断永久性过滤器
#define TCS34725_CONTROL (0x0F) // 增益倍数
#define TCS34725_ID (0x12) // 设备识别号 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
#define TCS34725_STATUS (0x13) // 设备状态
#define TCS34725_CDATAL (0x14) // 光照强度低字节
#define TCS34725_CDATAH (0x15) // 光照强度高字节
#define TCS34725_RDATAL (0x16) // 红色数据低字节
#define TCS34725_RDATAH (0x17)
#define TCS34725_GDATAL (0x18) // 绿色数据低字节
#define TCS34725_GDATAH (0x19)
#define TCS34725_BDATAL (0x1A) // 蓝色数据低字节
#define TCS34725_BDATAH (0x1B)
/* 启动传感器 */
#define TCS34725_ENABLE_AIEN (0x10) // RGBC中断使能
#define TCS34725_ENABLE_WEN (0x08) // 等待启用:写1激活等待计时器,写0禁用等待计时器
#define TCS34725_ENABLE_AEN (0x02) // RGBC启用:写1激活RGBC,写0禁用RGBC
#define TCS34725_ENABLE_PON (0x01) // 通电:写入1激活内部振荡器,0禁用内部振荡器
/**********************
* TYPEDEFS
**********************/
/* 集成时间配置参数
* 最大RGBC计数 = (256 - cycles) × 1024
* 集成时间 ≈ (256 - cycles) × 2.4ms */
typedef enum
{
TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, // 2.4ms - 1 cycles - Max Count: 1024
TCS34725_INTEGRATIONTIME_24MS = 0xF6, // 24ms - 10 cycles - Max Count: 10240
TCS34725_INTEGRATIONTIME_50MS = 0xEC, // 50ms - 20 cycles - Max Count: 20480
TCS34725_INTEGRATIONTIME_101MS = 0xD5, // 101ms - 42 cycles - Max Count: 43008
TCS34725_INTEGRATIONTIME_154MS = 0xC0, // 154ms - 64 cycles - Max Count: 65535
TCS34725_INTEGRATIONTIME_700MS = 0x00 // 700ms - 256 cycles - Max Count: 65535
}
tcs34725_integration_time_t;
/* 增益倍数 */
typedef enum
{
TCS34725_GAIN_1X = 0x00, // 1X增益
TCS34725_GAIN_4X = 0x01, // 4X增益
TCS34725_GAIN_16X = 0x02, // 16X增益
TCS34725_GAIN_60X = 0x03 // 60X增益
}
tcs34725_gain_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
struct tcs34725_config
{
char name[20];
bool interrupt_start;
tcs34725_integration_time_t integration_time;
tcs34725_gain_t gain;
}tcs34725_config_t;
uint8_t tcs34725_start(bool interrupt_start);
uint8_t tcs34725_stop(void);
uint8_t get_tcs34725_type(void);
uint8_t set_tcs34725_integration_time(tcs34725_integration_time_t integration_time);
uint8_t set_tcs34725_gain(tcs34725_gain_t gain);
uint8_t get_tcs34725_rgbc(uint16_t *colour_r, uint16_t *colour_g, uint16_t *colour_b, uint16_t *colour_c);
tcs34725_integration_time_t get_tcs34725_integration_time(void);
tcs34725_gain_t get_tcs34725_gain(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _TCS34725_H_ */
程序源码
#include "tcs34725.h"
#include "esp32_i2c_drive.h"
/***************************************************************
文件名 : tcs34725.c
作者 : jiaozhu
版本 : V1.0
描述 : tcs34725 传感器驱动文件。
其他 : 无
日志 : 初版 V1.0 2022/12/30
***************************************************************/
/* TCS34725设备启动状态 */
static bool tcs34725_state = false;
/* 设备默认配置参数 */
struct tcs34725_config _tcs34725_config =
{
.name = "TCS34725",
.interrupt_start = false,
};
/**
* @brief 通过I2C驱动提供的API进行对接,作用是将一个8位数据写入对应的寄存器中
*
* @param reg_addr 寄存机地址
* @param write_data 需要写入的寄存机数据
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_write8(uint8_t reg_addr, uint8_t write_data)
{
return esp32_i2c_write8(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, write_data);
}
/**
* @brief 通过I2C驱动提供的API进行对接,作用是读取一个8位的数据
*
* @param reg_addr 寄存器地址
* @param read_data 数据存放地址
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_read8(uint8_t reg_addr, uint8_t* read_data)
{
return esp32_i2c_read8(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, read_data);
}
/**
* @brief 通过I2C驱动提供的API进行对接,作用是读取一个16位的数据
*
* @param reg_addr 寄存器地址
* @param read_data 数据存放地址
* @return uint8_t 无错误时返回 0
*/
static uint8_t tcs34725_read16(uint8_t reg_addr, uint16_t* read_data)
{
return esp32_i2c_read16(TCS34725_address, TCS34725_COMMAND_BIT | reg_addr, read_data);
}
/**
* @brief 启动 tcs34725 设备
*
* @param interrupt_start 是否开启中断启动方式
* @return uint8_t 无错误时返回 0
*/
uint8_t tcs34725_start(bool interrupt_start)
{
int err = 0;
if (tcs34725_state)
{
return -1;
}
err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_PON);
err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
/* 判断是否开启中断启动 */
if (interrupt_start)
{
_tcs34725_config.interrupt_start = interrupt_start;
err = tcs34725_write8(TCS34725_ENABLE, TCS34725_ENABLE_AIEN);
}
tcs34725_state = true;
return err;
}
/**
* @brief 停止 tcs34725 设备
*
* @return uint8_t 无错误时返回 0
*/
uint8_t tcs34725_stop(void)
{
uint8_t err = 0;
uint8_t data = 0;
err = tcs34725_read8(TCS34725_ENABLE, &data);
err = tcs34725_write8(TCS34725_ENABLE, data & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
/* 通过中断启动后时,需要关闭中断设置 */
if (_tcs34725_config.interrupt_start)
{
err = tcs34725_write8(TCS34725_ENABLE, data & ~TCS34725_ENABLE_AIEN);
}
tcs34725_state = false;
return err;
}
/**
* @brief 返回设备类型
*
* @return uint8_t 设备识别号 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727
*/
uint8_t get_tcs34725_type(void)
{
uint8_t data = 0;
tcs34725_read8(TCS34725_ID, &data);
return data;
}
/**
* @brief 设置集成时间
*
* @param integration_time 集成时间
* @return uint8_t 无错误时返回 0
*/
uint8_t set_tcs34725_integration_time(tcs34725_integration_time_t integration_time)
{
_tcs34725_config.integration_time = integration_time;
return tcs34725_write8(TCS34725_ATIME, integration_time);
}
/**
* @brief 获取设置的集成时间
*
* @return tcs34725_integration_time_t
*/
tcs34725_integration_time_t get_tcs34725_integration_time(void)
{
return _tcs34725_config.integration_time;
}
/**
* @brief 设置增益倍数
*
* @param gain 增益倍数
* @return uint8_t 无错误时返回 0
*/
uint8_t set_tcs34725_gain(tcs34725_gain_t gain)
{
_tcs34725_config.gain = gain;
return tcs34725_write8(TCS34725_CONTROL, gain);
}
/**
* @brief 获取设置的增益倍数
*
* @return tcs34725_gain_t
*/
tcs34725_gain_t get_tcs34725_gain(void)
{
return _tcs34725_config.gain;
}
/**
* @brief 获取RGBC的值
*
* @param colour_r 数据存放地址
* @param colour_g 数据存放地址
* @param colour_b 数据存放地址
* @param colour_c 数据存放地址
* @return uint8_t 无错误时返回 0
*/
uint8_t get_tcs34725_rgbc(uint16_t *colour_r, uint16_t *colour_g, uint16_t *colour_b, uint16_t *colour_c)
{
uint8_t err = 0;
err = tcs34725_read16(TCS34725_RDATAL, colour_r);
err = tcs34725_read16(TCS34725_GDATAL, colour_g);
err = tcs34725_read16(TCS34725_BDATAL, colour_b);
err = tcs34725_read16(TCS34725_CDATAL, colour_c);
return err;
}
注意:到此笔记也结束了,上面程序还有不完善的地方,只能自行更改了。当然上面的程序也是可以直接只用的,但是程序只供学习使用,有什么为题概不负责。最后有写得不好的地方,望各位大佬多多指教。
TCS34725 颜色传感器设备驱动程序的更多相关文章
- 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)
截图 描述: l STM32 HAL库编程 l 使用模拟IIC通信,方便程序移植 l Python界面编写,蘑菇头的帽子是什么颜色 l STM32 HAL库串口通信 l Python界面使用 ...
- 嵌入式Linux设备驱动程序:用户空间中的设备驱动程序
嵌入式Linux设备驱动程序:用户空间中的设备驱动程序 Embedded Linux device drivers: Device drivers in user space Interfacing ...
- LCD设备驱动程序
LCD是Liquid Crystal Display的简称,也就是经常所说的液晶显示器 LCD能够支持彩色图像的显示和视频的播放,是一种非常重要的输出设备 Framebuffer 是Linux系统 ...
- linux设备驱动程序--在用户空间注册文件接口
linux字符设备驱动程序--创建设备节点 基于4.14内核,运行在beagleBone green 在上一讲中,我们写了第一个linux设备驱动程序--hello_world,在驱动程序中,我们什么 ...
- linux设备驱动程序--hello-world
linux字符设备驱动程序--hello_world 基于4.14内核, beagleBone green平台 PC端的设备驱动程序 有过电脑使用经验的人都知道,当我们将外部硬件设备比如鼠标键盘插入到 ...
- linux设备驱动程序-i2c(0)-i2c设备驱动源码实现
(基于4.14内核版本) 为了梳理清楚linux内核中的i2c实现框架,从本文开始,博主将分几个章节分别解析i2c总线在linux内核中的形成过程.匹配过程.以及设备驱动程序源码实现. 在介绍linu ...
- linux设备驱动程序--串行通信驱动框架分析
linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...
- 嵌入式Linux驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入
字符设备驱动程序 应用程序是调用C库中的open read write等函数.而为了操作硬件,所以引入了驱动模块. 构建一个简单的驱动,有一下步骤. 1. 创建file_operations 2. 申 ...
- YL-64 颜色传感器
TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAOS TCS3200RGB感应芯片和4个白光LED灯,TCS3200能在一定的范围内检测和测量几乎所有的可见光.它适合于色度计测量应用领域 ...
- 装系统提示缺少所需的CD/DVD驱动器设备驱动程序
昨晚用ultraISO和win7 旗舰版(ultimate)的镜像做了个启动U盘,插在自己新电脑上安装过程中提示“缺少所需的CD/DVD驱动器设备驱动程序”,用网上的很多办法都不行,最后找官网的客服问 ...
随机推荐
- SDOI2017树点染色
题目链接 发现1操作很像lct中的access,然后它每次染的又是一个新颜色,因此同一个颜色就在同一颗splay里了,且一个点到根的权值val[i]也就是到根路径上虚边的个数,然后看access时会对 ...
- Vue中使用Switch开关用来控制商品的上架与下架情况、同时根据数据库商品的状态反应到前台、前台修改商品状态保存到数据库
一般后台对商品的信息管理.包含商品的上架与下架.为了提高用户的体验.将商品上下架的操作做成开关的形式.同时后台数据库中保存的商品状态能够根据开关状态改变. 1.效果展示 这种效果:== 当开关是开启状 ...
- SQL分层查询
数据中可能存在层次关系,本文章主要介绍查询这种关系的实例.会大量使用递归式 CTE. Emps 表中 EName 员工和 MGR 上级之间的关系如下: 每个上级也同样是员工,主管和员工之间为父子关系. ...
- 一次 Java log4j2 漏洞导致的生产问题
一.问题 近期生产在提交了微信小程序审核后(后面会讲到),总会出现一些生产告警,而且持续时间较长.我们查看一些工具和系统相关的,发现把我们的 gateway 差不多打死了. 有一些现象. 网关有很多接 ...
- 基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2
基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2 Video Capture&Display IP for V4L2 在主机端视频设备内核驱动V4L2 的控制和调度下,Vi ...
- python中的字符串学习
# 1.字符串的下标(索引) # 取字符串中的子串 print('1.字符串的下标(索引)') str1 = 'PYTHON' print(str1[0]) print(str1[-4]) # 2.字 ...
- Python基础之模块:7、项目开发流程和项目需求分析及软件开发目录
一.项目开发流程 1.项目需求分析 明确项目具体功能: 明确到底要写什么东西,实现什么功能,在这个阶段的具体要询问项目经理和客户的需求 参与人员: 产品经理.架构师.开发经理 技术人员主要职责: 引导 ...
- java学习之socket编程
0x00前言和思维导图 Socks实际上是什么:实际上是提供了精彩通信的端口,在通信之前双方都必须要创造一个端点才能通信,其实感觉socket跟计算机的三次握手有些相似,分为三个步骤: (1)服务器监 ...
- 万字干货_JDK动态代理及其源码解析 拿捏了
目录 代理模式 静态代理 静态代理和动态代理的区别?什么是静态.动态? 静态代理的使用步骤 示例 静态代理的缺陷 解决静态代理的缺陷的思路 JDK动态代理 JDK 动态代理类使用步骤 示例 底层原理 ...
- K8s如何启用cgroup2支持?
什么是 cgroup ️Reference: control groups(控制组),通常被称为cgroup,是Linux内核的一项功能.它允许将进程组织成分层的组,然后限制和监控各种资源的使用. 内 ...