一、 写这个移植手册的目的
9月份接手了一个新的项目,需要用到温度、湿度、和压力三个参数,并且参数值的要求比较严苛,经过一番查询发现BOSCH有一颗BME280传感器,性价比相当高,经过与供应商核对以及网络查询后最终决定使用这颗料,于是原理图、PCB图、PCB板一气呵成,但是最终在使用STM32F103驱动BME280的时候出现了问题(根本原因在于懒惰),本来觉的可以在网上找一个现成的驱动修修补补就可以用了,哪知寻遍整个网络也没有看到有人放出STM32F103直接驱动BME280的文章(相当失望,嘿嘿),最终所能查到的就只有BOSCH公司放出的官方驱动SDK(个人认为这是最好的驱动),接口需要自己根据具体的处理器实现,所以只能自力更生,潜心手写。
闲话不多说,开始写吧!
二、 IIC总线接口
BME280传感器支持IIC总线和SPI总线,由于BME280传感器的工作频率为25HZ,频率比较低,并且IIC总线相对于SPI可以节约1个处理器的IO口,所以最终确定使用IIC总线,总线时序使用模拟的方式,便于将来移植到不同的处理器上面。
硬件配置需要注意:BME280的SDO引脚直接接地,CSB引脚直接接到3.3V电源,中间不用使用任何电阻直接连接保证电平稳定性。
以前公司内部也有比较成熟的IIC总线的驱动,但是没有仔细严格分析过时序的正确性,正好利用这个机会将IIC总线的时序从头到尾捋捋。
开始:
要掌握IIC的通信协议,需要掌握以下6个通信信号:
1.起始信号
2.终止信号
3.写数据
4.读数据
5.应答信号
6.非应答信号
IIC总线写时序
IIC总线读时序
• 起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
• 应答信号
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK)
• 数据读写
一目了然吧!?参考代码如下:
/*******************************************************************************
I2C_START
*******************************************************************************/
void BMP280_I2C_START(void)
{
BMP280_I2C_SCL(1);
BMP280_I2C_SDA(1);
BMP280_I2C_DELAY(2);
BMP280_I2C_SDA(0);
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(0);
}
/*******************************************************************************
I2C_STOP
*******************************************************************************/
void BMP280_I2C_STOP(void)
{
BMP280_I2C_SCL(1);
BMP280_I2C_SDA(0);
BMP280_I2C_DELAY(2);
BMP280_I2C_SDA(1);
BMP280_I2C_DELAY(2);
}
/*******************************************************************************
I2C_WAIT_ACK
*******************************************************************************/
uint8_t BMP280_I2C_WAIT_ACK(void)
{
uint8_t Wait_cnt;
BMP280_I2C_SCL(0);
BMP280_I2C_SDA(1);
BMP280_I2C_SDA_IN();
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(1);
Wait_cnt = 255;
while(BMP280_RD_I2C_SDA != 0)
{
Wait_cnt--;
if(Wait_cnt == 0)
{
break;
}
}
BMP280_I2C_SCL(0);
BMP280_I2C_SDA_OUT();
if(Wait_cnt == 0)
{
BMP280_I2C_STOP();
}
return Wait_cnt;
}
/*******************************************************************************
I2C_ACK
*******************************************************************************/
void BMP280_I2C_ACK(void)
{
BMP280_I2C_SDA(0);
BMP280_I2C_SCL(0);
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(1);
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(0);
}
/*******************************************************************************
I2C_NOT_ACK
*******************************************************************************/
void BMP280_I2C_NOT_ACK(void)
{
BMP280_I2C_SDA(1);
BMP280_I2C_SCL(0);
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(1);
BMP280_I2C_DELAY(2);
BMP280_I2C_SCL(0);
}
/*******************************************************************************
I2C_WRITE_BYTE
*******************************************************************************/
uint8_t BMP280_I2C_WRITE_BYTE(uint8_t dat)
{
uint8_t i;
BMP280_I2C_SCL(0); //ÔÚSCLΪµÍÆÚ¼äÉèÖÃSDAΪÊä³ö
BMP280_I2C_SDA_OUT();
BMP280_I2C_SDA(0);
BMP280_I2C_DELAY(1);
for(i = 0;i < 8;i ++)
{
if(dat & 0x80)
{
BMP280_I2C_SDA(1);
}
else
{
BMP280_I2C_SDA(0);
}
dat <<= 1;
BMP280_I2C_DELAY(4);
BMP280_I2C_SCL(1);
BMP280_I2C_DELAY(8);
BMP280_I2C_SCL(0);
}
i = BMP280_I2C_WAIT_ACK();
return i;
}
/*******************************************************************************
I2C_READ_BYTE
*******************************************************************************/
uint8_t BMP280_I2C_READ_BYTE(uint8_t ack)
{
uint8_t i;
uint8_t dat=0x00;
BMP280_I2C_SCL(0);
BMP280_I2C_SDA(1);
BMP280_I2C_SDA_IN();
BMP280_I2C_DELAY(1);
for(i = 0;i < 8;i ++)
{
dat <<= 1;
BMP280_I2C_SCL(1);
BMP280_I2C_DELAY(4);
if(BMP280_RD_I2C_SDA != 0)
{
dat |= 0x01;
}
BMP280_I2C_SCL(0);
BMP280_I2C_DELAY(4);
}
BMP280_I2C_SDA_OUT();
if(ack != 0)
{
BMP280_I2C_ACK();
}
else
{
BMP280_I2C_NOT_ACK();
}
return dat;
}
三、 官方代码移植
官方代码包含以下几个文件,将文件添加到工程中
编译有一处错误,将变量的定义移到函数开头即可,很容易改,这里就不截图了,大家都懂得。
编译没有错误后,利用开始写出的IIC总线时序开始制作接口函数,接口函数有三个如下,直接贴出制作好的接口函数:
int8_t i2c_reg_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
{
uint8_t res;
res = BMP280_I2C_Write_Bytes(i2c_addr,reg_addr,reg_data,length);
if(res==1)
{
return 0;
}
else
{
return 1;
}
}
int8_t i2c_reg_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
{
uint16_t res;
res = BMP280_I2C_Read_Bytes(i2c_addr,reg_addr,reg_data,length);
if(res==length)
return 0;
else
return 1;
}
void delay_ms(uint32_t period_ms)
{
Systick_Delay(period_ms);
}
延时函数使用了滴答定时器,延时单位为ms,这个延时很灵活根据自己处理器的使用情况或者是否使用操作系统的情况灵活使用。
至此如果初始化成功,说明移植就已经成功了,接下来就可以参照BOSCH提供的例程进行数据读取了。
需要注意一点,就是在读取传感器参数的时候读取频率必须大于25HZ,否则读数会有问题。
关于BME280的滤波器等参数的设置,请参照BME280官方手册,至此STM32F103处理器驱动BME280传感器的程序移植工作完毕,如想交流可以加QQ:184006847。