1、概述
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总线时序图
2、资源介绍
HaaS1000中自带了两路I2C,主模式最高1.4Mbps接口。两路I2C管脚也是复用的,都是通过IO的fuction选择出来的。当前的HaaS EDU K1的默认配置为:
引脚名 |
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),HaaS EDU K1上所有的传感器都是接在I2C1,每个传感器的地址是不同的。
3、HAL接口介绍
AliOS Things对于不同底层驱动的i2c操作实现,统一封装成本文所述hal I2c接口。 hal相关头文件位于目录:include/aos/hal。hal相关实现位于具体的mcu目录下,如:platform/mcu/haas1000/hal/。
3.1、API列表
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端口 |
3.2、API详情
3.2.1、相关宏定义
-
#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
3.2.2、相关结数据结构
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;
3.2.3、hal_i2c_init
初始化指定I2C端口
函数原型
int32_t hal_i2c_init(i2c_dev_t *i2c)
参数
i2c_dev_t *i2c |
入参 |
I2C设备描述,定义需要初始化的I2C参数 |
用户自定义一个i2c_dev_t结构体 |
返回值
返回成功或失败, 返回0表示I2C初始化成功,非0表示失败
调用示例
-
#define I2C1_PORT_NUM 1
-
-
#define I2C2_PORT_NUM 2
-
-
#define I2C2_SLAVE_ADDR 0x50
-
-
/* define dev master */
-
-
i2c_dev_t i2c_dev_master;
-
-
i2c_dev_t i2c_dev_slave;
-
-
/* i2c port set */
-
-
i2c_dev_master.port = I2C1_PORT_NUM;
-
-
/* i2c attr config */
-
-
i2c_dev_master.config.mode = I2C_MODE_MASTER;
-
-
i2c_dev_master.config.freq = I2C_BUS_BIT_RATES_3400K;
-
-
i2c_dev_master.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT;
-
-
i2c_dev_slave.port = I2C2_PORT_NUM;
-
-
/* i2c attr config */
-
-
i2c_dev_slave.config.mode = I2C_MODE_SLAVE;
-
-
i2c_dev_slave.config.freq = I2C_BUS_BIT_RATES_3400K;
-
-
i2c_dev_slave.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT;
-
-
i2c_dev_slave.config.dev_addr = I2C2_SLAVE_ADDR;
-
-
/* init master i2c with the given settings */
-
-
ret = hal_i2c_init(&i2c_dev_master);
-
-
/* init slave i2c with the given settings */
-
-
ret = hal_i2c_init(&i2c_dev_slave);
3.2.4、hal_i2c_master_send
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 0x50
-
-
ret = hal_i
2c_master_send(&i
2c_dev_master,I
2C
2_SLAVE_ADDR,pdata_send,
10,
50);
-
3.2.5、hal_i2c_master_recv
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 0x50
-
-
ret = hal_i
2c_master_recv(&i
2c_dev_master,I
2C
2_SLAVE_ADDR,pdata_recv,
10,
50);
3.2.6、hal_i2c_slave_send
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_i
2c_slave_send(&i
2c_dev_slave,pdata_send,
10,
50);
3.2.7、hal_i2c_slave_recv
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_i
2c_slave_recv(&i
2c_dev_slave,pdata_recv,
10,
50);
3.2.8、hal_i2c_mem_write
向指定的设备内存写数据
函数原型
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_i
2c_mem_write(&i
2c_dev_master,
0x
50,
0x
20,
1,pdata,
1,
50);
3.2.9、hal_i2c_mem_read
从指定的设备内存读数据
函数原型
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_i
2c_mem_read(&i
2c_dev_master,
0x
50,
0x
20,
1,pdata,
1,
50);
3.2.10、hal_i2c_finalize
关闭指定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);
4、案例介绍
HaaS EDU K1上自带了多个传感器,均为I2C方式访问,这里我们选取温湿度SI7006的测试代码用来介绍I2C是如何运作的。
4.1、硬件实现
硬件电路在开发板上默认是已经连接好了的,默认的I2C地址为0x40。。原理图如下:
EDU SI7006部分原理图
4.2、软件设计
驱动代码位于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");
-
-
}
IIC驱动代码
-
void si7006_init(void)
-
{
-
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);
-
}
-
-
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;
-
}
4.3、编译与下载
4.3.1、代码准备
打开edu_demo的产测开关
application/example/edu_demo/Config.in
在该文件中修改编译选项,打开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();
-
//menu_init();
-
-
sensors_test();
4.3.2、编译
如下使用命令行方式
-
aos
make distclean
-
-
aos
make edu_demo@haaseduk1 -c config
-
-
aos
make
-
4.3.3、烧录
- 命令行方式
aos upload
- 图形界面方式
详见haaS EDU k1 快速开始 第4.3.3章节-使用GUI工具烧录部分。
开发者技术支持
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号
更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/
转载:https://blog.csdn.net/HaaSTech/article/details/114677894