rt-thread是什么?

RT-Thread 是一个集实时操作系统(RTOS)内核、中间件组件和开发者社区于一体的技术平台,组件完整丰富、高度可伸缩、简易开发、超低功耗、高安全性的物联网操作系统。RT-Thread 拥有良好的软件生态,支持市面上所有主流的编译工具如 GCC、Keil、IAR 等,工具链完善、友好,支持各类标准接口,如 POSIX、CMSIS、C++应用环境、Javascript 执行环境等,方便开发者移植各类应用程序。商用支持所有主流MCU架构,如 ARM Cortex-M/R/A, MIPS, X86, Xtensa, C-Sky, RISC-V,几乎支持市场上所有主流的 MCU 和 Wi-Fi 芯片。

小飞哥结缘RT_Thread是去年参加全连接大赛,获得了个优秀奖,参赛项目是无线重力感应遥控小车,项目完整资料已经开源,小伙伴们可以自行获取,话不多说,开淦!

IIC通讯协议简介

I2C(Inter Integrated Circuit)总线是 PHILIPS 公司开发的一种半双工、双向二线制同步串行总线。I2C 总线传输数据时只需两根信号线,一根是双向数据线 SDA(serial data),另一根是双向时钟线 SCL(serial clock)。SPI 总线有两根线分别用于主从设备之间接收数据和发送数据,而 I2C 总线只使用一根线进行数据收发。

I2C 和 SPI 一样以主从的方式工作,不同于 SPI 一主多从的结构,它允许同时有多个主设备存在,每个连接到总线上的器件都有唯一的地址,主设备启动数据传输并产生时钟信号,从设备被主设备寻址,同一时刻只允许有一个主设备。如下图所示:

如下图所示为 I2C 总线主要的数据传输格式:

当总线空闲时,SDA 和 SCL 都处于高电平状态,当主机要和某个从机通讯时,会先发送一个开始条件,然后发送从机地址和读写控制位,接下来传输数据(主机发送或者接收数据),数据传输结束时主机会发送停止条件。传输的每个字节为8位,高位在前,低位在后。数据传输过程中的不同名词详解如下所示:

  • 开始条件:

SCL 为高电平时,主机将 SDA 拉低,表示数据传输即将开始,老规矩,还是波形说话,下面的波形就是对开始条件最好的描述:

  • 从机地址:

主机发送的第一个字节为从机地址,高 7 位为地址,最低位为 R/W 读写控制位,1 表示读操作,0 表示写操作。一般从机地址有 7 位地址模式和 10 位地址模式两种,如果是 10 位地址模式,第一个字节的头 7 位 是 11110XX 的组合,其中最后两位(XX)是 10 位地址的两个最高位,第二个字节为 10 位从机地址的剩下8位,如下图所示:

  • 应答信号:

每传输完成一个字节的数据,接收方就需要回复一个 ACK(acknowledge)。写数据时由从机发送 ACK,读数据时由主机发送 ACK。当主机读到最后一个字节数据时,可发送 NACK(Not acknowledge)然后跟停止条件。

  • 数据:

从机地址发送完后可能会发送一些指令,依从机而定,然后开始传输数据,由主机或者从机发送,每个数据为 8 位,数据的字节数没有限制。

  • 重复开始条件:

在一次通信过程中,主机可能需要和不同的从机传输数据或者需要切换读写操作时,主机可以再发送一个开始条件。

  • 停止条件:

在 SDA 为低电平时,主机将 SCL 拉高并保持高电平,然后在将 SDA 拉高,表示传输结束。

以上就是IIC协议的基本原理,看起来比较简单,实现起来也不难,MCU有硬件IIC的可以使用硬件IIC,没有的话,使用IO模拟即可。

RT-Thread IIC设备驱动使用

习惯于MCU BSP驱动开发的玩家来说,初识RT_Thread的设备驱动可能有点蒙,原因在于RT_thread代码结构大多是面向对象的,类linux风格,学习过linux开发的小伙伴来看rt-thread一定会倍感亲切的...

接下来就以IIC设备驱动代码来看,如何使用rt-thread的IIC驱动

访问IIC设备

一般情况下 MCU 的 I2C 器件都是作为主机和从机通讯,在 RT-Thread 中将 I2C 主机虚拟为 I2C总线设备,I2C 从机通过 I2C 设备接口和 I2C 总线通讯,相关接口如下所示:

函数 描述
rt_device_find() 根据 I2C 总线设备名称查找设备获取设备句柄
rt_i2c_transfer() 传输数据

查找IIC设备

在使用 I2C 总线设备前需要据 I2C 总线设备名称获取设备句柄,进而才可以操作 I2C 总线设备,查找设备函数如下所示:

rt_device_t rt_device_find(const char* name);

参数 描述
name 根据 I2C 总线设备名称查找设备获取设备句柄
返回 ——
设备句柄 查找到对应设备将返回相应的设备句柄
RT_NULL 没有找到相应的设备对象

如何使用呢,以下面要做的RGB颜色识别传感器为例,参数“name”实际上就是我们要用到的IIC设备名称

#define RGBSensor_I2C_BUS_NAME      "i2c3"  /* 传感器连接的I2C总线设备名称 */
static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */static void rgbSensor_init(const char *name)
{/* 查找I2C总线设备,获取I2C总线设备句柄 */i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);if (i2c_bus == RT_NULL){rt_kprintf("can't find %s device failed!\n", name);}else{rt_kprintf("find %s device success!\n", name);rt_pin_mode(sensor_ledpin, PIN_MODE_OUTPUT);begin();}
}

数据传输

获取到 I2C 总线设备句柄就可以使用 rt_i2c_transfer() 进行数据传输。函数原型如下所示:

rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,struct rt_i2c_msg         msgs[],rt_uint32_t               num);
参数 描述
bus I2C 总线设备句柄
msgs[] 待传输的消息数组指针
num 消息数组的元素个数
返回 --
消息数组的元素个数 成功
错误码 失败

和 SPI 总线的自定义传输接口一样,I2C 总线的自定义传输接口传输的数据也是以一个消息为单位。参数 msgs[] 指向待传输的消息数组,用户可以自定义每条消息的内容,实现 I2C 总线所支持的 2 种不同的数据传输模式。如果主设备需要发送重复开始条件,则需要发送 2 个消息。

关于IIC通讯所有到的地址、读写控制、数据长度、数据等参数封装在一个结构体中:

struct rt_i2c_msg
{rt_uint16_t addr;    /* 从机地址 */rt_uint16_t flags;   /* 读、写标志等 */rt_uint16_t len;     /* 读写数据字节数 */rt_uint8_t  *buf;    /* 读写数据缓冲区指针 */
}
  • 注意:

此函数会调用 rt_mutex_take(), 不能在中断服务程序里面调用,会导致 assertion 报错。

关于IIC的主要函数原型如上面,底层的东西就不需要关心了,有没有一种很方便(不知所措)的感觉,回想起以前自己编写的,起始信号、停止信号、超时判断,一点一点都要自己动手,简直了...但是初学者学学编写逻辑也挺好的,慢慢转向面向对象也挺好...

RGB颜色识别传感器实战

上面介绍了rtt IIC设备驱动的基本使用,小伙伴们是不是还有点迷糊,下面来实战,如何使用

颜色传感器简介

小飞哥在某宝买的,¥6,IIC通讯接口,板子虽小,还挺精致,原理图还是不错的,可以参考参考

红框中的双向电平转换电路是一个不错的低成本转换电路,完全可以借鉴应用到自己的产品中

  • 接口说明

  • 通讯协议

更多的传感器信息,请查看传感器datasheet

代码编写

  • 硬件连接

  • rt-Thread studio配置

新建工程就不说了,小飞哥前面的文章有讲到过,采用模拟IIC,来看看如何配置组件,我选择的是IIC3,随自己心意就好,配置比较简单,配置完保存即可

经过上面章节的介绍,对rtt iic设备的使用有了一些简单的了解,下面来具体使用,先来看初始化过程

  • 1、查找IIC设备是否注册

static void rgbSensor_init(const char *name)
{/* 查找I2C总线设备,获取I2C总线设备句柄 */i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);if (i2c_bus == RT_NULL){rt_kprintf("can't find %s device failed!\n", name);}else{rt_kprintf("find %s device success!\n", name);rt_pin_mode(sensor_ledpin, PIN_MODE_OUTPUT);begin();}
}

编译完,不出意外的话,应该会出现以下,恭喜你,完成了第一步...

接下来是对传感器的读写操作,先来封装两个读写寄存器函数

/* 写传感器寄存器 */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint32_t *data)
{rt_uint8_t buf[3];struct rt_i2c_msg msgs;rt_uint32_t buf_size = 1;buf[0] = TCS34725_COMMAND_BIT | reg;                   //cmdif (data != RT_NULL){buf[1] = data[0];buf[2] = data[1];buf_size = 3;}msgs.addr = TCS34725_ADDRESS;msgs.flags = RT_I2C_WR;msgs.buf = buf;msgs.len = buf_size;/* 调用I2C设备接口传输数据 */if (rt_i2c_transfer(bus, &msgs, 1) == 1){return RT_EOK;}else{return -RT_ERROR;}
}
/* 读传感器寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus,rt_uint8_t reg,rt_uint8_t len, rt_uint8_t *buf)
{struct rt_i2c_msg msgs;write_reg(i2c_bus,reg, RT_NULL);msgs.addr = TCS34725_ADDRESS;msgs.flags = RT_I2C_RD;msgs.buf = buf;msgs.len = len;/* 调用I2C设备接口传输数据 */if (rt_i2c_transfer(bus, &msgs, 1) == 1){return RT_EOK;}else{return -RT_ERROR;}
}

接下来先来确认模块是不是连接成功,进行读ID操作,这也是确认MCU和模组连接的常用方法先来读ID试试,需要注意下,型号不同,器件ID有区别,小飞哥被坑了好一会才想起来查手册...所以大家一定要先看手册,看一些关键信息,避免因手册没看浪费时间

/**************************************************************************/
/*!Initializes I2C and configures the sensor (call this function beforedoing anything else)
*/
/**************************************************************************/
rt_uint8_t begin(void)
{rt_uint8_t sensor_id = 0;/* Make sure we're actually connected */read_regs(i2c_bus,TCS34725_ID,1,&sensor_id);if ((sensor_id != 0x4d) && (sensor_id != 0x10)){rt_kprintf("find sensor failed!\n");return 0;}rt_kprintf("sensor ID is:%0x!\n",sensor_id);rt_kprintf("find sensor success!\n");/* Set default integration time and gain */RT_setIntegrationTime(TCS34725_INTEGRATIONTIME_50MS);RT_setGain(TCS34725_GAIN_1X);/* Note: by default, the device is in power down mode on bootup */RT_enable();return 1;
}

顺利的话,是没问题的,设备连接OK的

获取原始数据,根据下图中的RGBC寄存器地址读取数据即可

/******************************************************************************** @brief TCS34725获取各个通道数据** @return 1 - 转换完成,数据可用*         0 - 转换未完成,数据不可用
*******************************************************************************/
rt_uint8_t RT_getRawData (COLOR_RGBC *rgbc)
{rt_uint8_t data[2] = {0};rt_uint8_t status = TCS34725_STATUS_AVALID;read_regs(i2c_bus,TCS34725_STATUS,1,&status);if(status & TCS34725_STATUS_AVALID){read_regs(i2c_bus,TCS34725_CDATAL,2,data);rgbc->c = (data[1]<<8)|data[0];read_regs(i2c_bus,TCS34725_RDATAL,2,data);rgbc->r = (data[1]<<8)|data[0];read_regs(i2c_bus,TCS34725_GDATAL,2,data);rgbc->g = (data[1]<<8)|data[0];read_regs(i2c_bus,TCS34725_BDATAL,2,data);rgbc->b = (data[1]<<8)|data[0];return 1;}return 0;
}

如果感觉获取的颜色值跟实际差别很大,可以调节积分时间和增益倍数两个参数

实验结果

用windows画板调的颜色为红色255,0,0,实际识别出来的是200,56,40左右

实际效果会有点偏差,小伙伴们可以自己调调试试,能不能得到比较好的结果

绿色

颜色实际有些偏淡

蓝色

源码获取

欢迎添加小飞哥好友,公众号后台回复“RGB”即可获取源码,欢迎加入群聊,获得更多有趣的设计哦

RT-Thread学习笔记|TCS34725 RGB 颜色识别传感器详解相关推荐

  1. Halcon 学习笔记八:颜色识别

    Halcon 学习笔记八:颜色识别 一.图像处理需要的知识 二.图像处理的预处理和分割过程 二.颜色识别的方法 三.例子一 四.例子二 五.例子三 一.图像处理需要的知识 1.图像处理基础(rgb(h ...

  2. 【相机标定与三维重建原理及实现】学习笔记1——相机模型数学推导详解

    目录 前言 一.小孔成像模型 二.坐标系的变换 1.世界坐标系到相机坐标系的变换(刚体变换)[xw^→xc^\boldsymbol {\hat{x_{w}}}\rightarrow \boldsymb ...

  3. SNMP学习笔记之SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  4. 吴恩达深度学习笔记(114)-RNN梯度消失问题详解

    https://www.toutiao.com/a6652968074712449550/ 2019-02-10 14:34:53 循环神经网络的梯度消失(Vanishing gradients wi ...

  5. Pillow库学习笔记之Image.convert去底色详解

    目的 需要提取出图中的数字,但是图中数字受到两种背景色的影响,因此需要先将其去掉. 实现 方法一(直接对数组操作) 首先按照官网示例看看图片的基本信息. from PIL import Image i ...

  6. 【STM32学习笔记】(1)—— STM32详解

    什么是STM32 STM32的字面含义: 1.ST-代表着意法半导体公司,即由什么公司生产. 意法半导体公司是一家SOC厂商,所谓SOC(System-on-a-Chip),根据它的中文意思可以知道& ...

  7. HTML学习笔记3:HTML基本骨架详解

    在HTML笔记1中,我简单介绍了HTML抽象的基本框架,其实,HTML的基本骨架部分还有更多内容需要了解,这一节,咱们就详细学习HTML的基本骨架. 打开sublime编辑器,输入html:xt 图1 ...

  8. [转]iOS5 ARC学习笔记:strong、weak等详解

    iOS5中加入了新知识,就是ARC,其实我并不是很喜欢它,因为习惯了自己管理内存.但是学习还是很有必要的. 在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都 ...

  9. 微信小程序开发学习笔记006--微信小程序组件详解02

    技术交流QQ群:170933152 案例7:开关选择器 案例8:各种图标 案例9:页面跳转 案例10:多媒体音视频 案例11:嵌入地图 案例12:画布:在上面可以画柱状图等等. 今天继续讲组件: 登录 ...

最新文章

  1. java 使用http2.0_【Java】okhttp3如何发送http2请求?
  2. js 浅拷贝直接赋值_js 深拷贝 vs 浅拷贝
  3. MarkDown编辑器常用语法
  4. linux播放到设备,linux - 将字节流式传输到ALSA播放设备 - 堆栈内存溢出
  5. 计算机应用基础基础系统,计算机应用基础试题库系统分析
  6. 基于JAVA+SpringMVC+Mybatis+MYSQL的校园二手自行车交易系统
  7. es 全量同步mysql_MySQL用得好好的,为什么要转ES?
  8. java速学堂,速学堂 JAVA300 第四章练习
  9. YDUI的移动端页面rem适配方案使用方法记录
  10. Composition API 监听属性
  11. oracle 10g初次使用用户名
  12. 这知道这个错误是咋回事啊?
  13. Blurring the Lines between Blockchains andDatabase Systems: the Case of Hyperledger Fabric(翻译)
  14. python中文居中对齐处理
  15. 1.1 数列极限与函数极限
  16. http://www.v2ex.com/ 技术论坛
  17. Rank-consistent Ordinal Regression for Neural Networks
  18. 深圳大学计算机图形学实验一——OpenGL绘制布布头像
  19. 5个浏览次数靠前的小程序!免费使用,请低调收藏起来!
  20. 罗技驱动默认安装位置介绍

热门文章

  1. cosh()函数以及C ++中的示例
  2. 工具栏ToolStrip
  3. 【ubuntu】开机进入initramfs,无法开机
  4. Java concurrent包中常用的类
  5. Oracle卸载详细步骤
  6. soft-nms(softnms)(pytorch实现) softer nms
  7. Terracotta 3.2.1简介 (一)
  8. 华云数据打造企业社会责任践行范本
  9. python处理通达信数据,加入BOLL通道数据,量化交易
  10. linux中grep的用法