简介: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工程模板、外设模板、模块模板下载地址: