本文共 8068 字,大约阅读时间需要 26 分钟。

IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。
I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。IIC总线如图所示:

IIC总线时序图
HaaS1000中自带了两路I2C,只支持主模式,最高1.4Mbps接口。两路I2C管脚也是复用的,都是通过IO的fuction选择出来的。
当前的EDU的默认配置为:
|   引脚名  |         GPIO  |         说明  |      
|   I2C_M0_SCL  |         GPIO_P2_0  |         i2C0的SCL  |      
|   I2C_M0_SDA  |         GPIO_P2_1  |         i2C0的SDA  |      
|   I2C_M1_SCL  |         GPIO_P0_2  |         I2C1的SCL  |      
|   I2C_M1_SDA  |         GPIO_P0_3  |         I2C1的SDA  |      
HaaS EDU K1中只用到的了I2C1, 即(GPIO_P0_2,GPIO_P0_3)。
AliOS Things对于不同底层驱动的i2c操作实现,统一封装成本文所述hal I2c接口。 hal相关头文件位于目录:include/aos/hal。hal相关实现位于具体的mcu目录下,如:platform/mcu/haas1000/hal/。
|   hal_i2c_init  |         初始化指定I2C端口  |      
|   hal_i2c_master_send  |         master模式下从指定的I2C端口发送数据  |      
|   hal_i2c_master_recv  |         master模式下从指定的I2C端口接收数据  |      
|   hal_i2c_slave_send  |         slave模式下从指定的I2C端口发送数据  |      
|   hal_i2c_slave_recv  |         slave模式下从指定的I2C端口接收数据  |      
|   hal_i2c_mem_write  |         mem模式(读写I2C存储器)下从指定的I2C端口发送数据  |      
|   hal_i2c_mem_read  |         mem模式(读写I2C存储器)下从指定的I2C端口接收数据  |      
|   hal_i2c_finalize  |         关闭指定I2C端口  |      
请参考
#define I2C_MODE_MASTER 1 /* i2c communication is master mode */#define I2C_MODE_SLAVE 2 /* i2c communication is slave mode */#define I2C_MEM_ADDR_SIZE_8BIT 1 /* i2c memory address size 8bit */#define I2C_MEM_ADDR_SIZE_16BIT 2 /* i2c memory address size 16bit *//* * Specifies one of the standard I2C bus bit rates for I2C communication */#define I2C_BUS_BIT_RATES_100K 100000#define I2C_BUS_BIT_RATES_400K 400000#define I2C_BUS_BIT_RATES_3400K 3400000#define I2C_HAL_ADDRESS_WIDTH_7BIT 0#define I2C_HAL_ADDRESS_WIDTH_10BIT 1
i2c_dev_t
typedef struct {    uint8_t      port;   /* i2c port */    i2c_config_t config; /* i2c config */    void        *priv;   /* priv data */} i2c_dev_t;   
i2c_config_t
typedef struct {    uint32_t address_width;    uint32_t freq;    uint8_t  mode;    uint16_t dev_addr;} i2c_config_t;   
初始化指定I2C端口
函数原型
int32_t hal_i2c_init(i2c_dev_t *i2c)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述,定义需要初始化的I2C参数  |         用户自定义一个i2c_dev_t结构体  |      
返回值
返回成功或失败, 返回0表示I2C初始化成功,非0表示失败
调用示例
#define Si7006_ADDRESS 0x40 i2c_dev.port = 1; i2c_dev.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT; i2c_dev.config.freq = I2C_BUS_BIT_RATES_400K; i2c_dev.config.mode = I2C_MODE_MASTER; i2c_dev.config.dev_addr = Si7006_ADDRESS; hal_i2c_init(&i2c_dev);
master模式下从指定的I2C端口发送数据
函数原型
int32_t hal_i2c_master_send(i2c_dev_t *i2c, uint16_t dev_addr, const uint8_t *data, uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   uint16_t dev_addr  |         入参  |         目标设备地址  |         0x50  |      
|   const uint8_t *data  |         入参  |         指向发送缓冲区的数据指针  |         char pdata_send[10]  |      
|   uint16_t size  |         入参  |         要发送的数据字节数  |         10  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示I2C数据发送成功,非0表示失败
调用示例
char pdata_send[10] = {0};#define I2C2_SLAVE_ADDR  0x50ret = hal_i2c_master_send(&i2c_dev_master,I2C2_SLAVE_ADDR,pdata_send,10,50);   
master模式下从指定的I2C端口接收数据
函数原型
int32_t hal_i2c_master_recv(i2c_dev_t *i2c, uint16_t dev_addr, uint8_t *data,uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   uint16_t dev_addr  |         入参  |         目标设备地址  |         0x50  |      
|   uint8_t *data  |         入参  |         指向接收缓冲区的数据指针  |         char pdata_recv[10]  |      
|   uint16_t size  |         入参  |         期望接收的数据字节数  |         10  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示成功接收size个数据,非0表示失败
调用示例
char pdata_recv[10] = {0};#define I2C2_SLAVE_ADDR  0x50ret = hal_i2c_master_recv(&i2c_dev_master,I2C2_SLAVE_ADDR,pdata_recv,10,50);   
slave模式下从指定的I2C端口发送数据
函数原型
int32_t hal_i2c_slave_send(i2c_dev_t *i2c, const uint8_t *data, uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   const uint8_t *data  |         入参  |         指向发送缓冲区的数据指针  |         char pdata_send[10]  |      
|   uint16_t size  |         入参  |         要发送的数据字节数  |         10  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示成功发送size个数据,非0表示失败
调用示例
char pdata_send[10] = {0};ret = hal_i2c_slave_send(&i2c_dev_slave,pdata_send,10,50);   
slave模式下从指定的I2C端口接收数据
函数原型
int32_t hal_i2c_slave_recv(i2c_dev_t *i2c, uint8_t *data, uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   uint8_t *data  |         入参  |         指向要接收数据的数据指针  |         char pdata_recv[10]  |      
|   uint16_t size  |         入参  |         要接收的数据字节数  |         10  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示成功接收size个数据,非0表示失败
调用示例
char pdata_recv[10] = {0};ret = hal_i2c_slave_recv(&i2c_dev_slave,pdata_recv,10,50);   
向指定的设备内存写数据
函数原型
int32_t hal_i2c_mem_write(i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_addr_size, const uint8_t *data, uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   uint16_t dev_addr  |         入参  |         目标设备地址  |         0x50  |      
|   uint16_t mem_addr  |         入参  |         内部内存地址  |         0x20  |      
|   uint16_t mem_addr_size  |         入参  |         内部内存地址大小  |         1  |      
|   const uint8_t *data  |         入参  |         指向要发送数据的数据指针  |         char pdata[10]  |      
|   uint16_t size  |         入参  |         要发送的数据字节数  |         1  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示成功发送size个数据,非0表示失败
调用示例
char pdata[10] = {0};ret = hal_i2c_mem_write(&i2c_dev_master,0x50,0x20,1,pdata,1,50);   
从指定的设备内存读数据
函数原型
int32_t hal_i2c_mem_read(i2c_dev_t *i2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_addr_size, uint8_t *data, uint16_t size, uint32_t timeout)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
|   uint16_t dev_addr  |         入参  |         目标设备地址  |         0x50  |      
|   uint16_t mem_addr  |         入参  |         内部内存地址  |         0x20  |      
|   uint16_t mem_addr_size  |         入参  |         内部内存地址大小  |         1  |      
|   uint8_t *data  |         入参  |         指向接收缓冲区的数据指针  |         char pdata[10]  |      
|   uint16_t size  |         入参  |         要接收的数据字节数  |         1  |      
|   uint32_t timeout  |         入参  |         超时时间(单位ms),如果希望一直等待设置为HAL_WAIT_FOREVER  |         50  |      
返回值
返回成功或失败, 返回0表示成功接收size个数据,非0表示失败
调用示例
char pdata[10] = {0};ret = hal_i2c_mem_read(&i2c_dev_master,0x50,0x20,1,pdata,1,50);   
关闭指定I2C端口
函数原型
int32_t hal_i2c_finalize(i2c_dev_t *i2c)
参数
|   i2c_dev_t *i2c  |         入参  |         I2C设备描述  |         使用hal_i2c_init传入参数  |      
返回值
类型:int 返回成功或失败, 返回0表示I2C关闭成功,非0表示失败。
调用示例
ret = hal_i2c_finalize(&i2c_dev_master);
HaaS EDU K1上自带了多个传感器,均为I2C方式访问,这里我们选取温湿度SI7006的测试代码用来介绍I2C是如何运作的。
本章用到的硬件电路在开发板上默认是已经连接好了的,默认的I2C地址为0x40。原理图如下:

EDU K1上 SI7006部分原理图
驱动代码位于platform/board/haaseduk1/drivers/i2c.c
I2C部分测试代码位于 application/example/edu_demo/mfg_test/sensors_test.c
获取ID
si7006_getID(id_buf);if (id_buf[4] == Si7006_TAG){    LOGI("si7006_test", "READ Si7006 Chip OK");}   uint8_t si7006_getVer(void){    uint8_t reg[2]  = {Si7006_READ_Firmware_Revision_0,Si7006_READ_Firmware_Revision_1};    uint8_t version = 0;    hal_i2c_master_send(&i2c_dev, i2c_dev.config.dev_addr, reg, 2, 1000);    aos_msleep(30);    hal_i2c_master_recv(&i2c_dev, i2c_dev.config.dev_addr, &version, 1, 1000);    //LOGI("APP", "ver:0x%2x \n",version);    return version;}   获取版本号
uint8_t ver = si7006_getVer();LOGI("si7006_test", "si7006_version %x\n", ver);if(ver != 0x20){    goto _failed;}   获取温湿度值
si7006_getTempHumidity(&Humidity, &Temp);LOGI("si7006_test", "Temp :%f Humidity : %f\n", Temp, Humidity);if((Humidity > 300.0 || Humidity < -100.0) || (Temp > 200.0 || Temp < -50.0)){    goto _failed;}   打开edu_demo的产测开关
application/example/edu_demo/Config.in
在该文件中修改编译选项,将default n改为y,从而打开EDK_DEMO_FACTORY_TEST_ENABLIE开关。
config EDK_DEMO_FACTORY_TEST_ENABLIE bool "enable factory test function" default y
加入Demo到启动代码
application/example/edu_demo/app_entry.c
函数application_start中注释掉menu_init(); 添加sensors_test(0);,0代表SI7006的测试。
//menu_init(); sensors_test(0);
使用命令行方式进行编译
aos make distcleanaos make edu_demo@haaseduk1 -c configaos make
命令行方式
aos upload
图形界面方式
详见 第4.3.3章节-使用GUI工具烧录部分。
************************************************************************************** SI7006 Test ***************************** How to test: ***************************************************************************************************************************************************************************** ===SI7006 test start=======Result : SI7006 test PASS !!! ===
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

更多技术与解决方案介绍,请访问阿里云AIoT首页
转载地址:http://rwnu.baihongyu.com/