STM32F103ZET6+IIC+SGP30气体传感
为了加深对IIC协议的理解和应用,接下来,使用STM32驱动SGP30气体传感传感器
准备IIC协议
用的还是之前的那些代码,只是把GPIO引脚口改了一下而已~~~
1、声明GPIO和IIC初始化
void SGP30_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SGP30_SCL_GPIO_CLK | SGP30_SDA_GPIO_SDA, ENABLE);
GPIO_InitStructure.GPIO_Pin = SGP30_SCL_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SGP30_SCL_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
2、IIC数据线的输出模式
因为在IIC数据线输出数据前,需要将数据线设置为输出模式才行
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
3、IIC数据线的输入模式
同样在IIC数据线输入数据前,需要将数据线设置为输入模式才行
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
4、IIC起始信号
void SGP30_IIC_Start(void)
{
SDA_OUT();
SGP30_SDA = 1;
SGP30_SCL = 1;
delay_us(20);
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 0;
}
5、IIC停止信号
void SGP30_IIC_Stop(void)
{
SDA_OUT();
SGP30_SCL = 0;
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 1;
SGP30_SDA = 1;
delay_us(20);
}
6、IIC等待应答信号
返回值:1,接收应答失败;0,接收应答成功。
u8 SGP30_IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA_IN();
SGP30_SDA = 1;
delay_us(10);
SGP30_SCL = 1;
delay_us(10);
while(SGP30_SDA_READ())
{
ucErrTime++;
if(ucErrTime > 250)
{
SGP30_IIC_Stop();
return 1;
}
}
SGP30_SCL = 0;
return 0;
}
7、IIC产生应答信号
void SGP30_IIC_Ack(void)
{
SGP30_SCL = 0;
SDA_OUT();
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
}
8、IIC不产生应答信号
void SGP30_IIC_NAck(void)
{
SGP30_SCL = 0;
SDA_OUT();
SGP30_SDA = 1;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
}
9、IIC发送一个字节
返回从机有无应答,1,有应答;0,无应答。
void SGP30_IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
SGP30_SCL = 0;
for(t = 0; t < 8; t++)
{
if((txd & 0x80) >> 7)
SGP30_SDA = 1;
else
SGP30_SDA = 0;
txd <<= 1;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
delay_us(20);
}
delay_us(20);
}
10、IIC读取一个字节
读取字节时,ask=1,产生应答;ask=0,不产生应答
u16 SGP30_IIC_Read_Byte(u8 ack)
{
u8 i;
u16 receive = 0;
SDA_IN();
for(i = 0; i < 8; i++ )
{
SGP30_SCL = 0;
delay_us(20);
SGP30_SCL = 1;
receive <<= 1;
if(SGP30_SDA_READ())
receive++;
delay_us(20);
}
if (!ack)
SGP30_IIC_NAck();
else
SGP30_IIC_Ack();
return receive;
}
气体传感器的驱动过程
驱动代码如下:
void SGP30_Init(void)
{
SGP30_GPIO_Init();
SGP30_Write(0x20, 0x03);
// SGP30_ad_write(0x20,0x61);
// SGP30_ad_write(0x01,0x00);
}
void SGP30_Write(u8 a, u8 b)
{
SGP30_IIC_Start();
SGP30_IIC_Send_Byte(SGP30_write); //发送器件地址+写指令
SGP30_IIC_Wait_Ack();
SGP30_IIC_Send_Byte(a); //发送控制字节
SGP30_IIC_Wait_Ack();
SGP30_IIC_Send_Byte(b);
SGP30_IIC_Wait_Ack();
SGP30_IIC_Stop();
delay_ms(100);
}
u32 SGP30_Read(void)
{
u32 dat;
u8 crc;
SGP30_IIC_Start();
SGP30_IIC_Send_Byte(SGP30_read); //发送器件地址+读指令
SGP30_IIC_Wait_Ack();
dat = SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
crc = SGP30_IIC_Read_Byte(1);
crc = crc;
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(0);
SGP30_IIC_Stop();
return(dat);
}
在之前的USART工程上,新建两个文件,一个是SGP30.h文件,另一个是SGP30.c文件
SGP30.h文件的代码如下:
#ifndef __HX711_H
#define __HX711_H
#include "sys.h"
#include "delay.h"
#define SGP30_SCL PEout(7)
#define SGP30_SDA PEout(8)
// GPIO 引脚宏定义
#define SGP30_SCL_GPIO_CLK RCC_APB2Periph_GPIOE
#define SGP30_SCL_GPIO_PORT GPIOE
#define SGP30_SCL_GPIO_PIN GPIO_Pin_7
#define SGP30_SDA_GPIO_SDA RCC_APB2Periph_GPIOE
#define SGP30_SDA_GPIO_PORT GPIOE
#define SGP30_SDA_GPIO_PIN GPIO_Pin_8
#define SGP30_SDA_READ() GPIO_ReadInputDataBit(SGP30_SDA_GPIO_PORT, SGP30_SDA_GPIO_PIN)
#define SGP30_read 0xb1 //SGP30的读地址
#define SGP30_write 0xb0 //SGP30的写地址
void SGP30_IIC_Start(void);
void SGP30_IIC_Stop(void);
void SGP30_IIC_Send_Byte(u8 txd);
u16 SGP30_IIC_Read_Byte(unsigned char ack);
u8 SGP30_IIC_Wait_Ack(void);
void SGP30_IIC_Ack(void);
void SGP30_IIC_NAck(void);
void SGP30_IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 SGP30_IIC_Read_One_Byte(u8 daddr,u8 addr);
void SGP30_Init(void);
void SGP30_Write(u8 a, u8 b);
u32 SGP30_Read(void);
#endif
SGP30.c文件的代码如下:
#include "SGP30.h"
void SGP30_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(SGP30_SCL_GPIO_CLK | SGP30_SDA_GPIO_SDA, ENABLE);
GPIO_InitStructure.GPIO_Pin = SGP30_SCL_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SGP30_SCL_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}
void SGP30_IIC_Start(void)
{
SDA_OUT();
SGP30_SDA = 1;
SGP30_SCL = 1;
delay_us(20);
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 0;
}
void SGP30_IIC_Stop(void)
{
SDA_OUT();
SGP30_SCL = 0;
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 1;
SGP30_SDA = 1;
delay_us(20);
}
u8 SGP30_IIC_Wait_Ack(void)
{
u8 ucErrTime = 0;
SDA_IN();
SGP30_SDA = 1;
delay_us(10);
SGP30_SCL = 1;
delay_us(10);
while(SGP30_SDA_READ())
{
ucErrTime++;
if(ucErrTime > 250)
{
SGP30_IIC_Stop();
return 1;
}
}
SGP30_SCL = 0;
return 0;
}
void SGP30_IIC_Ack(void)
{
SGP30_SCL = 0;
SDA_OUT();
SGP30_SDA = 0;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
}
void SGP30_IIC_NAck(void)
{
SGP30_SCL = 0;
SDA_OUT();
SGP30_SDA = 1;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
}
void SGP30_IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
SGP30_SCL = 0;
for(t = 0; t < 8; t++)
{
if((txd & 0x80) >> 7)
SGP30_SDA = 1;
else
SGP30_SDA = 0;
txd <<= 1;
delay_us(20);
SGP30_SCL = 1;
delay_us(20);
SGP30_SCL = 0;
delay_us(20);
}
delay_us(20);
}
u16 SGP30_IIC_Read_Byte(u8 ack)
{
u8 i;
u16 receive = 0;
SDA_IN();
for(i = 0; i < 8; i++ )
{
SGP30_SCL = 0;
delay_us(20);
SGP30_SCL = 1;
receive <<= 1;
if(SGP30_SDA_READ())
receive++;
delay_us(20);
}
if (!ack)
SGP30_IIC_NAck();
else
SGP30_IIC_Ack();
return receive;
}
void SGP30_Init(void)
{
SGP30_GPIO_Init();
SGP30_Write(0x20, 0x03);
// SGP30_ad_write(0x20,0x61);
// SGP30_ad_write(0x01,0x00);
}
void SGP30_Write(u8 a, u8 b)
{
SGP30_IIC_Start();
SGP30_IIC_Send_Byte(SGP30_write);
SGP30_IIC_Wait_Ack();
SGP30_IIC_Send_Byte(a);
SGP30_IIC_Wait_Ack();
SGP30_IIC_Send_Byte(b);
SGP30_IIC_Wait_Ack();
SGP30_IIC_Stop();
delay_ms(100);
}
u32 SGP30_Read(void)
{
u32 dat;
u8 crc;
SGP30_IIC_Start();
SGP30_IIC_Send_Byte(SGP30_read);
SGP30_IIC_Wait_Ack();
dat = SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
crc = SGP30_IIC_Read_Byte(1);
crc = crc;
dat <<= 8;
dat += SGP30_IIC_Read_Byte(1);
dat <<= 8;
dat += SGP30_IIC_Read_Byte(0);
SGP30_IIC_Stop();
return(dat);
}
main.c文件的代码如下:
#include "stm32f10x.h"
#include <stdio.h>
#include "delay.h"
#include "led.h"
#include "USART_Init_Config.h"
#include "SGP30.h"
int main(void)
{
u32 CO2Data, TVOCData; //定义CO2浓度变量与TVOC浓度变量
u32 sgp30_dat; //定义SGP30读取到的数据
delay_init(); //延时函数初始化
LED_Init(); //LED初始化
USART_Init_Config(); //串口初始化
SGP30_Init(); //SGP30初始化
delay_ms(100);
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read(); //读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16; //获取CO2的值
TVOCData = sgp30_dat & 0x0000ffff; //获取TVOC的值
while(CO2Data == 400 && TVOCData == 0)
{
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read(); //读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16; //获取CO2的值
TVOCData = sgp30_dat & 0x0000ffff; //获取TVOC的值
printf("正在检测中......");
delay_ms(500);
}
while(1)
{
SGP30_Write(0x20,0x08);
sgp30_dat = SGP30_Read(); //读取SGP30的值
CO2Data = (sgp30_dat & 0xffff0000) >> 16; //获取CO2的值
TVOCData = sgp30_dat & 0x0000ffff; //获取TVOC的值
printf("CO2浓度为:%0.2d\r\nTVOC浓度为:%0.2d\r\n",CO2Data,TVOCData);
delay_ms(1000);
}
}
运行效果
打开串口调试助手
完整工程下载!!!