Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2C_IIC
原创征文
教程笔记
基于RoboMasterC型开发板的RT-Thread使用分享(六)i2c读取磁力计数据实验
发布于 2023-02-28 09:30:06 浏览:739
订阅该版
[tocm] 你们的年更作者回来了🥳经过了痛苦的开学考预习与考试之后,现在恢复自由身没有课程开始出来实习啦,这次文章算是带着自己复习I2C相关知识,便于在工作中使用。 ### I2C简介 ***** 不喜欢看文字的同学可以看下面这个视频做的也非常好,而且这次视频没有出错,很推荐 [4分钟看懂!I2C通讯协议 最简单的总线通讯!_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1dg4y1H773/?spm_id_from=444.41.list.card_archive.click&vd_source=a189d61cdd7d4ed6c863087f5aaff9d2) I2C 是 PHILIPS 公司开发的一种半双工、双向二线制同步串行总线。 两线制代表 I2C 只需两根信号线,一根数据线 SDA,另一根是时钟线 SCL。这个也是I2C的优势所在,虽然传输速率较慢,但是占用引脚数量少,在引脚资源紧张的芯片上就特别好用。 I2C 总线允许挂载多个主设备,但总线时钟同一时刻只能由一个主设备产生,并且要求每个连接到总线上的器件都有唯一的 I2C 地址,从设备可以被主设备寻址。那么我们想要在同一个I2C总线上使用多个主设备。 ![I2C 总线主从设备连接方式](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/device/i2c/figures/i2c1.png) **这里善于思考的同学可能就会想到如果我们想要在同一个I2C总线上并联两个一样的设备ID冲突怎么办呢?** 之后带大家看传感器的Datasheet的时候,就会发现传感器上面有一个ADDR引脚,根据它引脚电平高低会切换ID号,这样就可以避免ID冲突了。 I2C通信具有几类信号 - 开始信号S:当SCL处于高电平时,SDA从高电平拉低至低电平,代表数据传输的开始 - 结束信号P:当SCL处于高电平时,SDA从低电平拉高至高电平,代表数据传输结束 - 数据信号:数据信号每次都传输8位数据,每一位数据都在一个时钟周期内传递,当SCL处于高电平时,SDA数据线上的电平需要稳定,当SCL处于低电平的时候,SDA数据线上的电平才允许改变。 - 应答信号ACK/NACK:应答信号是主机发送8bit数据,从机对主机发送低电平,表示已经接收数据。 ![I2C 总线数据传输格式](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/device/i2c/figures/i2c2.png) 整个I2C通信过程理解成收发快递的过程,设备I2C地址理解成学校快递柜的地址,读写位代表寄出和签收快递,寄存器地址则是快递柜上的箱号,而数据便是需要寄出或者签收的快递。整个过程便是如同到学校的快递柜(从机 I2C 地址),对第几号柜箱(寄存器地址), 进行寄出或者签收快递(数据)的过程。 ### IST8310简介 **** IST8310 是一款由 ISentek 公司推出的 3 轴磁场传感器,尺寸为 3.0*3.0*1.0mm,支持快速 I2C 通信,可达 400kHz,14 位磁场数据,测量范围可达1600uT(x,y-axis)和 2500uT(z-axis), 最高 200Hz 输出频率。使用IST8310磁力计可以检测地磁场强度,用于计算磁场角度。 下图为IST8310的引脚功能表 ![screenshot_1677337322941.png](https://oss-club.rt-thread.org/uploads/20230228/32ac6e555f9e85923b67c7bb1263494a.png.webp) 此外我们可以整理等下我们会用到的GPIO引脚 | 管脚 | 功能 | | ---- | -------------------------------- | | SCL | I2C的时钟线 | | SDA | I2C的数据线 | | RSTN | IST8310的RESET,低电平重启IST8310 | | DRDY | IST8310的数据准备(data ready) | 以及我们可以看一下从机地址的设置,在这个芯片之后从机地址的设置是通过CAD0和CAD1两个引脚设置的,这样可以实现设置四个不同的地址。 ![screenshot_1677338039942.png](https://oss-club.rt-thread.org/uploads/20230228/e1ddf9703ae72a554d63c0b224d76419.png) 下面是开发板的原理图,我们可以看到下面CAD0和CAD1引脚都浮空了,根据上图可以得知,这个IST8310的从机地址为0x0E与原理图中标注的一致。 ![screenshot_1677338529004.png](https://oss-club.rt-thread.org/uploads/20230228/d7376b2a0b77343515a8819a38653cbe.png.webp) ### CubeMX配置 ********** 首先我们开始看到我们的原理图上。 ![screenshot_1677338965173.png](https://oss-club.rt-thread.org/uploads/20230228/8e2e2c99289ba51b3c3fc72be5e9cded.png.webp) ![screenshot_1677338529004.png](https://oss-club.rt-thread.org/uploads/20230228/d7376b2a0b77343515a8819a38653cbe.png.webp) ![screenshot_1677339535247.png](https://oss-club.rt-thread.org/uploads/20230228/1b70028fad7cae7750cb06a32280dbf2.png) 根据上面两个图我们可以发现这个IST8310是挂载在I2C总线上面的。 STM32上I2C3_SCL在PA8,I2C_SDA在PC9,DRDY数据准备引脚在PG3,复位RSTN引脚在PG6,接着在CubeMX进行相应的配置。 ![screenshot_1677339331341.png](https://oss-club.rt-thread.org/uploads/20230228/577fe9e2a44de8de21774403d4c42881.png.webp) ![screenshot_1677341098593.png](https://oss-club.rt-thread.org/uploads/20230228/f6999d07e6be7bad676e2cc5a770a3c4.png.webp) 之后我们可以看到我们在CubeMX中配置的东西实际上都在board文件之中,其中board.c文件里面为我们的时钟树配置,stm32f4xx_hal_msp.c里的就是我们上面设置的那些引脚配置 ![screenshot_1677375351285.png](https://oss-club.rt-thread.org/uploads/20230228/b6d326767cc19d53cfa72af6f984b35c.png) 这里就是刚刚I2C3配置的函数,为啥突然开始讲这个主要也是实习时发现大部分情况下是没有STM32可以用的,也就不能用CubeMX那么轻松的配置了,pintopin替换直接把国产芯片当作STM32使用总感觉会出问题,因此还是学习自己配置的方法。 ```c else if(hi2c->Instance==I2C3) { /* USER CODE BEGIN I2C3_MspInit 0 */ /* USER CODE END I2C3_MspInit 0 */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**I2C3 GPIO Configuration PC9 ------> I2C3_SDA PA8 ------> I2C3_SCL */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C3; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C3; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* Peripheral clock enable */ __HAL_RCC_I2C3_CLK_ENABLE(); /* USER CODE BEGIN I2C3_MspInit 1 */ /* USER CODE END I2C3_MspInit 1 */ } ``` ### 代码编写 ******** 首先在RT-Thread Settings组件中打开I2C设备驱动程序 ![screenshot_image-20230226095109787.png](https://oss-club.rt-thread.org/uploads/20230228/7e4edf34364fccc96a4da210116ab08e.png.webp) ``` menuconfig BSP_USING_I2C3 bool "Enable I2C3 BUS (software simulation)" default n select RT_USING_I2C select RT_USING_I2C_BITOPS select RT_USING_PIN if BSP_USING_I2C3 comment "Notice: PA8 --> 8; PC9 --> 41" config BSP_I2C3_SCL_PIN int "i2c1 scl pin number" default 8 config BSP_I2C3_SDA_PIN int "I2C1 sda pin number" default 41 endif ``` ![screenshot_image-20230226101351612.png](https://oss-club.rt-thread.org/uploads/20230228/d63e09502c31099257e1796add42781b.png) 配置完后我们来看一下几个重要的实现函数 i2c写入寄存器的函数 ```C rt_err_t ist8310_iic_write(rt_uint8_t write_addr, rt_uint8_t data, rt_uint32_t number) { rt_uint8_t buf[2]; buf[0] = write_addr; buf[1] = data; rt_size_t result; result = rt_i2c_master_send(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_WR, buf, 2); rt_thread_mdelay(10); if (result == 2) { rt_kprintf("IST8310 write failed,ERR is:%d\r\n", result); return -RT_ERROR; } } ``` 关于读取,写入这里引用上面推荐视频里的一幅图 ![screenshot_1677511674527.png](https://oss-club.rt-thread.org/uploads/20230228/f3a2548017bac73455746036b4a6f028.png.webp) 这里我们函数的实现也是按照这个原理,`rt_i2c_master_send`首先将设备的地址**IST8310_ADDR**,加上读写位**RT_I2C_WR**发送 之后我们定义的buf缓冲区中装着的就是我们要发送的寄存器地址**write_addr**,和要写入的数据**data**。 需要注意的是`rt_i2c_master_send`返回的是发送的消息的个数,且不包含一开始发送的设备地址**IST8310_ADDR**的。 下面的读取函数也是同理的,先发送想要读取的**read_addr**,然后利用`rt_i2c_master_recv`函数进行读取。 ```c rt_err_t ist8310_iic_read(rt_uint8_t read_addr, rt_uint32_t len, rt_uint8_t *buf) { //通知要读哪个设备的哪个内存地址的内容,(告知是需要读read_addr) rt_i2c_master_send(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_WR, &read_addr, 1); //读取到的内容存入buf rt_i2c_master_recv(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_RD, buf, len); //地址读数据 } ``` 这样看完大家应该对于i2c的通信方式更加熟悉了。 下面介绍的是读取磁力计值函数`ist8310_read_mag` ```c void ist8310_read_mag(float mag[3]) { uint8_t buf[6]; int16_t temp_ist8310_data = 0; //read the "DATAXL" register (0x03) ist8310_iic_read(0x03, 6, buf); temp_ist8310_data = (int16_t) ((buf[1] << 8) | buf[0]); mag[0] = MAG_SEN * temp_ist8310_data; temp_ist8310_data = (int16_t) ((buf[3] << 8) | buf[2]); mag[1] = MAG_SEN * temp_ist8310_data; temp_ist8310_data = (int16_t) ((buf[5] << 8) | buf[4]); mag[2] = MAG_SEN * temp_ist8310_data; } ``` ![screenshot_1677547112408.png](https://oss-club.rt-thread.org/uploads/20230228/c22d72af322fa6061dab3d23857e7707.png.webp) 我们这里对照表格就可以看到数据寄存器是从0x03开始到0x08结束的,我们使用`ist8310_iic_read`实际上虽然我们一开始只说明了读取0x03的值,但是根据消息长度的大小,它继续读取下面寄存器的值的。 最后给大家详细一下初始化函数`ist8310_init` ```c rt_uint8_t ist8310_init(const char*name) { rt_uint8_t temp[2] = { 0, 0 }; ist8310_i2c_bus = (struct rt_i2c_bus_device *) rt_device_find(name); rt_uint8_t res[2] = { 0, 0 }; rt_uint8_t writeNum = 0; if (ist8310_i2c_bus == RT_NULL) { rt_kprintf("can't find %s device!\n", name); } else { ist8310_RST_L(); rt_thread_mdelay(sleepTime); ist8310_RST_H(); rt_thread_mdelay(sleepTime); ist8310_IIC_read_single_reg(IST8310_WHO_AM_I, 1, res); if (res[0] != IST8310_WHO_AM_I_VALUE) { initialized = RT_TRUE; return IST8310_NO_SENSOR; } for (writeNum = 0; writeNum < IST8310_WRITE_REG_NUM; writeNum++) //开启中断,并且设置低电平,平均采样两次,200Hz输出频率 { ist8310_IIC_write_single_reg(ist8310_write_reg_data_error[writeNum][0], ist8310_write_reg_data_error[writeNum][1]); ist8310_delay_us(wait_time); ist8310_IIC_read_single_reg(ist8310_write_reg_data_error[writeNum][0], 1, res); ist8310_delay_us(wait_time); if (res[0] != ist8310_write_reg_data_error[writeNum][1]) { return ist8310_write_reg_data_error[writeNum][2]; } } initialized = RT_TRUE; return IST8310_NO_ERROR; } } ``` 第一个特殊点是读取WHO AM I寄存器,这里是为了确认读取的是ist8310传感器,避免ID冲突或者没有传感器导致后续的通信错误。这里WHO AM I里的值默认是10我们读取到10则说明没有问题。 ![screenshot_1677513164714.png](https://oss-club.rt-thread.org/uploads/20230228/4c9ab2c497460ab08362020b535f906c.png) 第二个特殊点就是for循环里面的那些操作,**ist8310_write_reg_data_error**这个二维数组里面的内容大家可以翻一下最后完整的`ist8310.h`代码 这里做的事情实际上是对配置寄存器进行写入配置,对应的寄存器即意义如下。大家根据下面的表格就可以计算出相应要写入的值了。 ![screenshot_1677546758253.png](https://oss-club.rt-thread.org/uploads/20230228/9d8dff704c85e1808b6b15b03eaaf8df.png.webp) ![screenshot_1677546780486.png](https://oss-club.rt-thread.org/uploads/20230228/59b8d7644e7d1fe158376c0d797852ed.png.webp) ist8310.c完整代码 ```c // // Created by Goldengrandpa on 2022/11/4. // #include "ist8310.h" rt_err_t ist8310_iic_write(rt_uint8_t write_addr, rt_uint8_t data, rt_uint32_t number) { rt_uint8_t buf[2]; buf[0] = write_addr; buf[1] = data; rt_size_t result; result = rt_i2c_master_send(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_WR, buf, 2); rt_thread_mdelay(10); if (result == 2) { rt_kprintf("IST8310 write failed,ERR is:%d\r\n", result); return -RT_ERROR; } } void ist8310_delay_us(uint16_t us) { uint32_t ticks = 0; uint32_t told = 0, tnow = 0, tcnt = 0; uint32_t reload = 0; reload = SysTick->LOAD; ticks = us * 72; told = SysTick->VAL; while (1) { tnow = SysTick->VAL; if (tnow != told) { if (tnow < told) { tcnt += told - tnow; } else { tcnt += reload - tnow + told; } told = tnow; if (tcnt >= ticks) { break; } } } } rt_err_t ist8310_iic_read(rt_uint8_t read_addr, rt_uint32_t len, rt_uint8_t *buf) { //通知要读哪个设备的哪个内存地址的内容,(告知是需要读read_addr) rt_i2c_master_send(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_WR, &read_addr, 1); //读取到的内容存入buf rt_i2c_master_recv(ist8310_i2c_bus, IST8310_ADDR, RT_I2C_RD, buf, len); //地址读数据 } rt_err_t ist8310_IIC_write_single_reg(rt_uint8_t reg, rt_uint8_t data) { rt_uint8_t buf[2]; buf[0] = reg; buf[1] = data; if (rt_i2c_master_send(ist8310_i2c_bus, IST8310_ADDR, 0, buf, 2) == 2) { return RT_EOK; } else { return -RT_ERROR; } } uint8_t ist8310_IIC_read_single_reg(rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf) { struct rt_i2c_msg msgs[2]; msgs[0].addr = IST8310_ADDR; /* 从机地址 */ msgs[0].flags = RT_I2C_WR; /* 写标志 */ msgs[0].buf = ® /* 从机寄存器地址 */ msgs[0].len = 1; /* 发送数据字节数 */ msgs[1].addr = IST8310_ADDR; /* 从机地址 */ msgs[1].flags = RT_I2C_RD; /* 读标志 */ msgs[1].buf = buf; /* 读取数据指针 */ msgs[1].len = len; /* 读取数据字节数 */ if (rt_i2c_transfer(ist8310_i2c_bus, msgs, 2) == 2) { return RT_EOK; } else { return -RT_ERROR; } } void ist8310_RST_H(void) { rt_pin_write(IST8310_RSTN_PIN_NUM, 1); } void ist8310_RST_L(void) { rt_pin_write(IST8310_RSTN_PIN_NUM, 0); } void ist8310_read_mag(float mag[3]) { uint8_t buf[6]; int16_t temp_ist8310_data = 0; //read the "DATAXL" register (0x03) ist8310_iic_read(0x03, 6, buf); temp_ist8310_data = (int16_t) ((buf[1] << 8) | buf[0]); mag[0] = MAG_SEN * temp_ist8310_data; temp_ist8310_data = (int16_t) ((buf[3] << 8) | buf[2]); mag[1] = MAG_SEN * temp_ist8310_data; temp_ist8310_data = (int16_t) ((buf[5] << 8) | buf[4]); mag[2] = MAG_SEN * temp_ist8310_data; } rt_uint8_t ist8310_init(const char*name) { rt_uint8_t temp[2] = { 0, 0 }; ist8310_i2c_bus = (struct rt_i2c_bus_device *) rt_device_find(name); rt_uint8_t res[2] = { 0, 0 }; rt_uint8_t writeNum = 0; if (ist8310_i2c_bus == RT_NULL) { rt_kprintf("can't find %s device!\n", name); } else { ist8310_RST_L(); rt_thread_mdelay(sleepTime); ist8310_RST_H(); rt_thread_mdelay(sleepTime); ist8310_IIC_read_single_reg(IST8310_WHO_AM_I, 1, res); if (res[0] != IST8310_WHO_AM_I_VALUE) { initialized = RT_TRUE; return IST8310_NO_SENSOR; } for (writeNum = 0; writeNum < IST8310_WRITE_REG_NUM; writeNum++) { ist8310_IIC_write_single_reg(ist8310_write_reg_data_error[writeNum][0], ist8310_write_reg_data_error[writeNum][1]); ist8310_delay_us(wait_time); ist8310_IIC_read_single_reg(ist8310_write_reg_data_error[writeNum][0], 1, res); ist8310_delay_us(wait_time); if (res[0] != ist8310_write_reg_data_error[writeNum][1]) { return ist8310_write_reg_data_error[writeNum][2]; } } initialized = RT_TRUE; return IST8310_NO_ERROR; } } static void i2c_ist8310_sample(int argc, char *argv[]) { rt_uint8_t buf; rt_uint8_t result=0; float msg[3] = { 0, 0, 0 }; char name[RT_NAME_MAX]; if (argc == 2) { rt_strncpy(name, argv[1], RT_NAME_MAX); } else { rt_strncpy(name, IST8310_I2C_BUS_NAME, RT_NAME_MAX); } if (!initialized) { /* 传感器初始化 */ result=ist8310_init(name); } if (initialized) { ist8310_read_mag(msg); rt_kprintf("read ist8310 sensor x:%f y:%f z:%f\n", msg[0], msg[1], msg[2]); } else { rt_kprintf("%d\n",result); rt_kprintf("initialize sensor failed!\n"); } } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(i2c_ist8310_sample, ist8310_sample); ``` ist8310.h ```c // // Created by Goldengrandpa on 2022/11/4. // #ifndef RTTHREAD_IST8310_H #define RTTHREAD_IST8310_H #include
#include
#include "board.h" #define IST8310_I2C_BUS_NAME "i2c3" /* 传感器连接的I2C总线设备名称 */ #define IST8310_ADDR 0X0E /* 从机地址 */ #define IST8310_CALIBRATION_CMD 0xE1 /* 校准命令 */ #define IST8310_NORMAL_CMD 0xA8 /* 一般命令 */ #define IST8310_GET_DATA 0xAC /* 获取数据命令 */ #define IST8310_WRITE_REG_NUM 4 #define IST8310_WHO_AM_I 0x00 //ist8310 "who am I " #define IST8310_WHO_AM_I_VALUE 0x10 //device ID #define IST8310_DATA_READY_BIT 2 #define IST8310_NO_ERROR 0x00 #define IST8310_NO_SENSOR 0x40 static const uint8_t wait_time = 150; static const uint8_t sleepTime = 50; #define IST8310_RSTN_PIN_NUM GET_PIN(G,6) #define MAG_SEN 0.3f //raw int16 data change to uT unit. 原始整型数据变成 单位ut typedef struct ist8310_real_data_t { uint8_t status; float mag[3]; } ist8310_real_data_t; //the first column:the registers of IST8310. 第一列:IST8310的寄存器 //the second column: the value to be writed to the registers.第二列:需要写入的寄存器值 //the third column: return error value.第三列:返回的错误码 static const rt_uint8_t ist8310_write_reg_data_error[IST8310_WRITE_REG_NUM][3] ={ {0x0B, 0x08, 0x01}, //enalbe interrupt and low pin polarity.开启中断,并且设置低电平 {0x41, 0x09, 0x02}, //average 2 times.平均采样两次 {0x42, 0xC0, 0x03}, //must be 0xC0. 必须是0xC0 {0x0A, 0x0B, 0x04}}; //200Hz output rate.200Hz输出频率 static struct rt_i2c_bus_device *ist8310_i2c_bus = RT_NULL; /* I2C总线设备句柄 */ static rt_bool_t initialized = RT_FALSE; /* 传感器初始化状态 */ rt_err_t ist8310_iic_write(rt_uint8_t write_addr, rt_uint8_t data, rt_uint32_t number); rt_err_t ist8310_iic_read(rt_uint8_t read_addr, rt_uint32_t len, rt_uint8_t *buf); void ist8310_read_mag(float mag[3]); static void read_mag(struct rt_i2c_bus_device *bus,float *cur_mag);/*读取磁场*/ void ist8310_RST_H(void);/*设置RSTN引脚为1*/ void ist8310_RST_L(void);/*设置RSTN引脚为0*/ void ist8310_delay_us(rt_uint16_t us); rt_err_t ist8310_IIC_write_single_reg(rt_uint8_t reg, rt_uint8_t data); rt_uint8_t ist8310_IIC_read_single_reg(rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf); static void i2c_ist8310_sample(int argc, char *argv[]); #endif //RTTHREAD_IST8310_H ``` 运行结果: ![screenshot_1677512319689.png](https://oss-club.rt-thread.org/uploads/20230228/2a9d37b3559c0f3832af6c0bec710372.png) ### 往期教程 ****** [RT-Thread-基于RoboMasterC型开发板的RT-Thread使用分享(一)RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/article/09dffc578f32d85d.html) [RT-Thread-基于RoboMasterC型开发板的RT-Thread使用分享(二)RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/article/2240be90085f3b35.html) [RT-Thread-基于RoboMasterC型开发板的RT-Thread使用分享(三)RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/article/46b79ff6792d3ec5.html) [RT-Thread-基于RoboMasterC型开发板的RT-Thread使用分享(四)按键中断实验RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/article/090525df389edfc3.html) [RT-Thread-基于RoboMasterC型开发板的RT-Thread使用分享(五)ADC测量电压实验RT-Thread问答社区 - RT-Thread](https://club.rt-thread.org/ask/article/7c6f904f158ebebf.html)
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
goldengrandpa
这家伙很懒,什么也没写!
文章
11
回答
19
被采纳
2
关注TA
发私信
相关文章
1
NXP的I2C应该比ST的好用吧
2
Use of I2C device driver
3
关于I2C 驱动问题请教
4
我如何知道这个iic的io配置和我电路设计的是一致的?
5
I2C模拟读操作失败,不知道问什么进不去读函数
6
RTT的I2C有官方文档资料没有
7
求 STM32F103 IIC 自定义IO初始化 代码
8
报一个LPC4008代码中I2C的bug
9
RTOS IIC总线使用
10
关于在RTT中使用STM32 I2C的疑问
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部