STM32驱动MEMS数字型气体传感器(多个使用)

简介:STM32F103C8T6驱动MEMS数字型气体传感器(多个使用)源码介绍。

开发平台:KEIL ARM

MCU型号:STM32F103C8T6

传感器型号:精讯畅通MEMS系列数字型气体传感器

特别提示:驱动内可能使用了某些其他组件,比如delay等,在文末外设模板下载地址内有。

1积分源码下载地址在文末!!!

接口图:

使用举例:

#include <stdio.h>
#include "MEMS.h"

int main()
{
	uint16_t NH3_val, H2S_val;
	MEMS_init(IIC_MEMS_NH3); // 初始化
	MEMS_init(IIC_MEMS_H2S); // 初始化
	while(1) {
		NH3_val = MEMS_read(IIC_MEMS_NH3); // 读取
		H2S_val = MEMS_read(IIC_MEMS_H2S); // 读取
		printf("NH3 ppm:%d, H2S ppm:%d\n", NH3_val, H2S_val);
		delayMs(1000);
	}
}

驱动源码:

IICs.c

#include "IICs.h"


#define IIC_SCL_OUT_1(port, pin)		(port->BSRR = (uint32_t)pin) // 置1
#define IIC_SCL_OUT_0(port, pin)		(port->BRR = (uint32_t)pin)
#define IIC_SDA_OUT_1(port, pin)		(port->BSRR = (uint32_t)pin) // 置1
#define IIC_SDA_OUT_0(port, pin)		(port->BRR = (uint32_t)pin)
#define IIC_SDA_IN(port, pin)			((port->IDR & pin) != 0)

struct IIC_CONFIG {
	uint32_t IIC_SDA_CLK;
	GPIO_TypeDef* IIC_SDA_PORT;
	uint16_t IIC_SDA_PIN;
	uint32_t IIC_SCL_CLK;
	GPIO_TypeDef* IIC_SCL_PORT;
	uint16_t IIC_SCL_PIN;
} iic_config[] = {
	{RCC_APB2Periph_GPIOB, GPIOB, GPIO_Pin_0, RCC_APB2Periph_GPIOB, GPIOB, GPIO_Pin_1},
	{RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_6, RCC_APB2Periph_GPIOA, GPIOA, GPIO_Pin_7}
};

/**
  * @brief  IIC延时
  * @param  None
  * @retval None
  */
static void IIC_Delay(uint8_t iicNo)
{
	static uint16_t delayTime[] = {400, 400};
	uint16_t i;
	/* 
	 	下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化
  
		循环次数为10时,SCL频率 = 205KHz 
		循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 
	 	循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 
	*/
	for (i = 0; i < delayTime[iicNo]; i++);
}
/**
  * @brief  SDA输出方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_OUT(uint8_t iicNo)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(iic_config[iicNo].IIC_SDA_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin=iic_config[iicNo].IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
	GPIO_Init(iic_config[iicNo].IIC_SDA_PORT,&GPIO_InitStructure); 						
}
/**
  * @brief  SDA输入方向配置
  * @param  None
  * @retval None
  */
void Set_IIC_SDA_IN(uint8_t iicNo)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(iic_config[iicNo].IIC_SDA_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin=iic_config[iicNo].IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_Init(iic_config[iicNo].IIC_SDA_PORT,&GPIO_InitStructure);
}
/**
  * @brief  模拟IIC初始化
  * @param  None
  * @retval None
  */
void IIC_init(uint8_t iicNo)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(iic_config[iicNo].IIC_SDA_CLK | iic_config[iicNo].IIC_SCL_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin = iic_config[iicNo].IIC_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(iic_config[iicNo].IIC_SDA_PORT, &GPIO_InitStructure);	
	GPIO_InitStructure.GPIO_Pin = iic_config[iicNo].IIC_SCL_PIN;
	GPIO_Init(iic_config[iicNo].IIC_SCL_PORT, &GPIO_InitStructure);	
	IIC_stop(iicNo);
}
/**
  * @brief  模拟IIC起始信号
  * @param  None
  * @retval None
  */
void IIC_start(uint8_t iicNo)
{
	Set_IIC_SDA_OUT(iicNo);
	IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	IIC_SDA_OUT_0(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
}
/**
  * @brief  模拟IIC停止信号
  * @param  None
  * @retval None
  */
void IIC_stop(uint8_t iicNo)
{
	Set_IIC_SDA_OUT(iicNo);
	IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_SDA_OUT_0(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
}
/**
  * @brief  模拟IIC主机应答
  * @param  None
  * @retval None
  */
void IIC_ack(uint8_t iicNo)
{
	Set_IIC_SDA_OUT(iicNo);
	IIC_SDA_OUT_0(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
	IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);	
	IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
}
/**
  * @brief  模拟IIC主机不应答
  * @param  None
  * @retval None
  */
void IIC_noack(uint8_t iicNo)
{
	Set_IIC_SDA_OUT(iicNo);
	IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
	IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
}
/**
  * @brief  模拟IIC等待从机应答
  * @param  None
  * @retval 1: 接收应答失败 0: 接收应答成功
  */
uint8_t IIC_wait_ack(uint8_t iicNo)
{
	uint8_t rec = 0;
	Set_IIC_SDA_OUT(iicNo);
	IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_Delay(iicNo);
	Set_IIC_SDA_IN(iicNo);
	IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
	rec = IIC_SDA_IN(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
	IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
	IIC_Delay(iicNo);
	
	return rec;
}
/**
  * @brief  模拟IIC发送一个字节
  * @param  None
  * @retval None
  */
void IIC_send_byte(uint8_t iicNo, uint8_t txd)
{
	uint8_t i=0;
	Set_IIC_SDA_OUT(iicNo);
	for(i=0;i<8;i++)
	{
		if(txd&0x80) IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
		else IIC_SDA_OUT_0(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN);
		IIC_Delay(iicNo);
		IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
		IIC_Delay(iicNo); // 发送数据
		IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
		if(i == 7) IIC_SDA_OUT_1(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN); // 最后一位数据发送完要释放SDA总线
		txd <<= 1;
		IIC_Delay(iicNo);
	}
}
/**
  * @brief  模拟IIC读取一个字节
  * @param  ack: 0,读完不产生应答 1,读完产生应答
  * @retval 返回读取到的字节
  */
uint8_t IIC_read_byte(uint8_t iicNo, uint8_t ack)
{
	uint8_t i,receive=0;
	Set_IIC_SDA_IN(iicNo);
	for(i=0;i<8;i++)
	{
		receive <<= 1;
		IIC_SCL_OUT_1(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
		IIC_Delay(iicNo);
		if(IIC_SDA_IN(iic_config[iicNo].IIC_SDA_PORT, iic_config[iicNo].IIC_SDA_PIN)) receive++; // 连续读取八位
		IIC_SCL_OUT_0(iic_config[iicNo].IIC_SCL_PORT, iic_config[iicNo].IIC_SCL_PIN);
		IIC_Delay(iicNo);	
	}
	if(!ack) IIC_noack(iicNo);
	else IIC_ack(iicNo);

	return receive; // 返回读取到的字节
}

IICs.h

#ifndef __IICS_H
#define __IICS_H

#include "main.h"

typedef enum {
	IIC_MEMS_NH3 = 0,
	IIC_MEMS_H2S
} IIC_NO;

void Set_IIC_SDA_OUT(uint8_t iicNo);
void Set_IIC_SDA_IN(uint8_t iicNo);
void IIC_init(uint8_t iicNo);
void IIC_start(uint8_t iicNo);
void IIC_stop(uint8_t iicNo);
void IIC_ack(uint8_t iicNo);
void IIC_noack(uint8_t iicNo);
uint8_t IIC_wait_ack(uint8_t iicNo);
void IIC_send_byte(uint8_t iicNo, uint8_t txd);
uint8_t IIC_read_byte(uint8_t iicNo, uint8_t ack);
#endif

MEMS.c

#include "MEMS.h"
#include "IICs.h"


/**
  * @brief  MEMS数字型气体传感器IIC端口初始化
  * @param  None
  * @retval	None
  */
void MEMS_init(uint8_t iicNo)
{
	IIC_init(iicNo); // iic延时计数400
}
/**
  * @brief  读取MEMS数字型气体传感器检测浓度
  * @param  None
  * @retval 返回读取到的数据 2字节
  */
uint16_t MEMS_read(uint8_t iicNo)
{
	uint8_t recHigh = 0,recLow = 0;
	IIC_start(iicNo);
	IIC_send_byte(iicNo, MEMS_wrAddr); // slave address + write cmd
	if(IIC_wait_ack(iicNo)) {
		IIC_stop(iicNo);
		return 0xFFFF;
	}
	IIC_send_byte(iicNo, 0xA1); // read cmd
	if(IIC_wait_ack(iicNo)) {
		IIC_stop(iicNo);
		return 0xFFFE;
	}
	IIC_start(iicNo);
	IIC_send_byte(iicNo, MEMS_rdAddr); // slave address + read cmd
	if(IIC_wait_ack(iicNo)) {
		IIC_stop(iicNo);
		return 0xFFFD;
	}
	recHigh = IIC_read_byte(iicNo, 1);
	recLow = IIC_read_byte(iicNo, 0);
	IIC_stop(iicNo);
	return (uint16_t)recHigh << 8 | recLow;
}

MEMS.h 

#ifndef __MEMS_H
#define __MEMS_H

#include "main.h"

#define MEMS_wrAddr	0x54
#define MEMS_rdAddr	0x55

void MEMS_init(uint8_t iicNo);
uint16_t MEMS_read(uint8_t iicNo);

#endif

驱动下载地址:

https://download.csdn.net/download/m0_50669075/87672789

STM32工程模板、外设模板、模块模板下载地址:

stm32_template: STM32F103工程模板,外设模板,模块模板。模块模板包括:DHT11温湿度传感器,OLED屏幕,DS18B20温度传感器,DS1302时钟模块,红外测温模块,RFID模块,SIM900A短信模块,OneNET入网,ADXL345三轴传感器,离线语音识别模块,语音播报模块,甲醛传感器,PM2.5模块,SG90舵机,健康检测模块,消息队列示例,链表示例,分时调度系统示例等。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿衰0110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值