赞
踩
为了加深对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); } }
运行效果
打开串口调试助手
完整工程下载!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。