练习要求:
通过I2C分别实现与芯片si7006(获取湿度、温度)和芯片ap3216(获取环境光照强度)的通讯;
1、运行效果
2、分析ap3216如何获取光照强度
2.1、需要操作的寄存器
通过分析手册,需要操作以下寄存器:
0x00:系统配置
0x0C:环境光低位
0x0D:环境光高位
2.2、配置system寄存器为获取环境光模式
只监测环境光,因此,只需要配置成 0x01 (画红框的目的,一开始的目标是同时测量环境光、红外和物体接近, IGNORE!)
2.3、读取环境光
一次环境光的数据由两个寄存器构成(高、低位)
3、代码
3.1、main.c
#include "si7006.h"
#include "ap3216.h"
int main()
{
unsigned short hum;
short tem;
unsigned short als;
i2c_init(); // i2c初始化
si7006_init(); // 进行si7006初始化
ap3216_init();
while (1)
{
// 读取温度和湿度
hum = si7006_read_hum();
hum = 125 * hum / 65536 - 6; // 数据的处理
tem = si7006_read_tem();
tem = tem * 175.72 / 65536 - 46.85;
printf("tem=%d hum=%d\n\r", tem, hum);
// 读取光照
als = ap3216_read_als();
printf("als=[%d]\n\r", als);
delay_ms(1000);
}
return 0;
}
3.2、ap3216.c
#include "ap3216.h"
#include "delay.h"
void ap3216_init()
{
i2c_init();
//1、设置模式
//1.1、选iic地址 0x1E:写
i2c_start();
i2c_write_byte((0x1E << 1) | 0);
i2c_wait_ack();
// 2、设置配置寄存器地址 0x00
i2c_write_byte((0x00 << 1) | 0);
i2c_wait_ack();
// 3、配置为0x01:只读环境光
i2c_write_byte(0x01);
i2c_wait_ack();
i2c_stop();
}
unsigned short ap3216_read_als()//ambient light sensor
{
//1、读取高8位 寄存器地址 0x0D
//1.1、设置要读取的寄存器
i2c_start();
i2c_write_byte((0x1E<<1)|0);
i2c_wait_ack();
i2c_write_byte(0x0D);
i2c_wait_ack();
//1.2、从寄存器读数据
i2c_start();
i2c_write_byte((0x1E<<1)|1);
i2c_wait_ack();
char als_high=i2c_read_byte(1);
i2c_stop();
//2、读取低8位 寄存器地址 0x0C
//2.1、设置要读取的寄存器
i2c_start();
i2c_write_byte((0x1E<<1)|0);
i2c_wait_ack();
i2c_write_byte(0x0C);
i2c_wait_ack();
//2.2、从寄存器读数据
i2c_start();
i2c_write_byte((0x1E<<1)|1);
i2c_wait_ack();
char als_low=i2c_read_byte(1);
i2c_stop();
//
//printf("als_high=[%d], als_low=[%d]\n\r", als_high, als_low);
return (als_high<<8)|als_low;
}
3.3、si7006.c
#include "si7006.h"
//芯片初始化
void si7006_init()
{
i2c_start();
i2c_write_byte(0X40<<1|0);
i2c_wait_ack();
i2c_write_byte(0XE6);
i2c_wait_ack();
i2c_write_byte(0X3A);
i2c_wait_ack();
i2c_stop();
}
//读取温度函数封装
short si7006_read_tem()
{
short tem;
char tem1,tem2;
i2c_start();//主机发起起始信号
i2c_write_byte(0X40<<1|0);
i2c_wait_ack();
i2c_write_byte(0XE3);
i2c_wait_ack();
i2c_start();//主机发起重复起始信号
i2c_write_byte(0X40<<1|1);
i2c_wait_ack();
delay_ms(100);//给从机测量时间
tem1=i2c_read_byte(0);//读取温度的高8位,回应应答信号
tem2=i2c_read_byte(1);//读取低八位,回应非应答信号
i2c_stop();
//获取完整温度
tem=tem1<<8|tem2;
return tem;
}
//读取湿度函数封装
unsigned short si7006_read_hum()
{
unsigned short hum;
unsigned char hum1,hum2;
i2c_start();//主机发起起始信号
i2c_write_byte(0X40<<1|0);
i2c_wait_ack();
i2c_write_byte(0XE5);
i2c_wait_ack();
i2c_start();//主机发起重复起始信号
i2c_write_byte(0X40<<1|1);
i2c_wait_ack();
delay_ms(100);//给从机测量时间
hum1=i2c_read_byte(0);//读取温度的高8位,回应应答信号
hum2=i2c_read_byte(1);//读取低八位,回应非应答信号
i2c_stop();
//获取完整温度
hum=hum1<<8|hum2;
return hum;
}
4、小结
笔者在写si7006.c时,同时犯了以上两个错误,通过和示例代码比较,总结出以下两点:
- start后面必须要跟I2C地址+操作位(读/写);
- 除了上一点,后面操作的所有寄存器都不需要进行移位操作和读取操作的配置了。
此外,还有一个疑问:
- 是否在配置系统寄存器之前,都需要先进行软件复位(基于ap3216);
- 手册中有描述,进行测量时需要一定的时间,问题是,我如何知道应该延迟多久,以及,如果读取间隔过短,读取两次,我很有可能其实读到的同一次测量的数据。后续可以研究,是否可以结合中断,来解决这个问题。