STM32中使用MMA7660重力加速度传感器



最近在项目中要用到飞思卡尔的MMA7660这一款传感器,我在STM32中使用的是模拟I2C来读写它的寄存器,闲话不多说,代码如下:

1、IO引脚配置和模拟I2C的方法

/******************** (C) COPYRIGHT 2015 ASTO **************************
 @* 文件名  :mma7660.c
 @* 描述    :飞思卡尔的MMA7660系列重力加速度传感器         
 @* 开发平台:STM32F103CBT6系列处理器
 @* 通信方式:I2C
 @* 硬件连接: ------------------------------
 *           | PB1  		: 中断引脚		|
 *           | PB10 		: SCL数据线		|
 *           | PB11 		: SDA数据线		|
 *            ------------------------------
 @* 库版本  :ST3.5.0
 @* 开发者  :POWER
************************************************************************/

#include "stm32f10x.h"
#include "mma7660.h"
#include "delay.h"


/*
 *=========================================================
 * 函数功能:MMA7660中断向量表配置
 * 参数:	 无
 *       
 * 函数返回值:无   
 *=========================================================   
 */
static void MMA7660_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	/* Enable the EXTI1 Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = MMA7660_INT_IRQ; //中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =  1;  //抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//次优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //通道中断使能
	NVIC_Init(&NVIC_InitStructure);//初始化中断
}

/*
 *=========================================================
 * 函数功能:MMA7660中断线配置
 * 参数:	 无
 *       
 * 函数返回值:无   
 *=========================================================   
 */
static void MMA7660_ExtiInit(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	MMA7660_NVIC_Config();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	  
	//配置MMA7660模块发生相应的事件后中断配置
	GPIO_EXTILineConfig(MMA7660_INT_PORT_SRC, MMA7660_INT_SOURCE);	
	EXTI_InitStructure.EXTI_Line = MMA7660_INT_LINE;	//中断线
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//使用中断方式触发模式(另外还有事件方式触发模式)
	EXTI_InitStructure.EXTI_Trigger = MMA7660_INT_MODE; //中断信号触发边沿
	EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断线使能
	EXTI_Init(&EXTI_InitStructure); //初始化中断 
}

/*
 **********************************************************
 *
 * IIC总线模拟程序
 *
 **********************************************************
 */

/*
 *=========================================================
 * 函数功能:MMA7660端口状态配置
 * 参数:	 无
 *       
 * 函数返回值:无   
 *=========================================================   
 */
void MMA7660_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	//中断引脚配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;			
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING;  	// 浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);				 	// 选择B端口
	
	//SCL数据线配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;			
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;		  	// 普通推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 	// 最高输出速率50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);				 	// 选择B端口
	
	//SDA数据线配置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 ;			
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_OD;		  	// 开漏输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 	// 最高输出速率50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);				 	// 选择B端口
	
	MMA7660_ExtiInit();	 //中断配置
	
	MMA7660_Begin(); 	//MMA7660寄存器配置
}


/*
 *=========================================================
 * 函数功能:MMA7660的SDA数据线配置,这里作为输出用
 * 参数:	 无
 *       
 * 函数返回值:无   
 *=========================================================   
 */
void MMA_SDA_IOOUT(void)
{ 
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 ;			
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_OD;		  	// 开漏输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 	// 最高输出速率50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);				 		// 选择B端口
}


/*
 *=========================================================
 * 函数功能:MMA7660的SDA数据线配置,这里作为输入用
 * 参数:	 无
 *       
 * 函数返回值:无   
 *=========================================================   
 */
void MMA_SDA_IOIN(void)
{ 
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 ;			
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING;  // 浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);				 	// 选择B端口
}


/*
 *=========================================================
 * 函数功能:IIC总线初始化信号
 * 参数:无
 * 函数返回值:无 
 * SDA    ---
 *           |________
 * SCL ----------
 *               |____  
 *=========================================================   
 */
void I2C_Start(void)
{
	MMA7660_SCL_H;
	MMA7660_SDA_H;
	Delayus(1);
	MMA7660_SDA_L;
	Delayus(1);  
}
 

/*
 *=========================================================
 * 函数功能:IIC总线停止信号
 * 参数:无
 * 函数返回值:无 
 * SDA        ---------
 *      ______|
 * SCL   ---------
 *                |___
 *=========================================================   
 */
void I2C_Stop(void)
{
	MMA7660_SCL_H;
	MMA7660_SDA_L;
	Delayus(1);
	MMA7660_SDA_H;
	Delayus(1);
}


/*
 *=========================================================
 * 函数功能:接收由从机向主机发起的ACK信号。
 * 参数:	 ACKBIT
 *          
 * 函数返回值:MMA_ERROR/MMA_OK   
 *=========================================================   
 */
uint8_t I2C_SlaveAck(void)
{
	uint8_t ts=0;
	MMA7660_SCL_L;
	MMA7660_SDA_H;
	
	MMA_SDA_IOIN();					//SDA设为输入
	Delayus(1);
	MMA7660_SCL_H;
	
	while(MMA7660_SDA_D!=0) {
		ts++;
		if(ts>200) {
			MMA_SDA_IOOUT();			//SDA设为输出
			MMA7660_SCL_L;
			return MMA_ERROR;			//返回错误	
		}
	}
	MMA7660_SCL_L;
	MMA_SDA_IOOUT();					//SDA设为输出
	//MMA7660_SDA_H;
	Delayus(1);
	return MMA_OK;					//返回错误	  
}


/*
 *=========================================================
 * 函数功能:IIC写一个字节数据
 * 参数: 	 a:需要写入的一个字节数据
 * 函数返回值:无
 *=========================================================   
 */
void I2C_WriteByte(uint8_t a) 
{
	uint8_t i; 
	for(i=0; i<8; i++)
	{	  	
    	MMA7660_SCL_L;
		if((a&0x80)!=0) MMA7660_SDA_H;
    	else MMA7660_SDA_L;
    	a <<= 1;
		Delayus(1);
		MMA7660_SCL_H;
    	Delayus(1);
	}
	   
	MMA7660_SCL_L;  
	if(I2C_SlaveAck()==MMA_ERROR) {		//等待从机的ACK信号
		return ;
	}
}


/*
 *=========================================================
 * 函数功能:IIC读一个字节数据
 * 参数:无
 * 函数返回值:返回读出的一个字节数据
 *=========================================================   
 */
uint8_t I2C_ReadByte(void)
{
	uint8_t a =0;
	uint8_t i;
	MMA_SDA_IOIN();					//SDA设为输入	
	for(i=0; i<8; i++) {
 		a <<= 1;  
		MMA7660_SCL_H;
		Delayus(1);
		if(MMA7660_SDA_D==1) a |= 0x01;
		Delayus(1);
		MMA7660_SCL_L;
	  	Delayus(2);	   
	}
	return a;
}


2、MMA相关的代码

/*
 **********************************************************
 *
 * MMA7660相关函数
 *
 **********************************************************
 */
/*
 *=========================================================
 * 函数功能:写MAA7660寄存器
 * 参数:     
 *       Regs_Addr - 寄存器地址
 *       Regs_Data - 寄存器值
 * 函数返回值:
 *=========================================================   
 */
void MMA7660_WriteReg(uint8_t Regs_Addr,uint8_t Regs_Data) 
{  
	I2C_Start();
	I2C_WriteByte(MMA7660_DEV_WRITE); 	//先写Slave地址,并配置成写模式
	I2C_WriteByte(Regs_Addr);    		//写寄存器地址
	I2C_WriteByte(Regs_Data);    		//写寄存器内容
	I2C_Stop();                  		//结束本段IIC进程
}


/*
 *=========================================================
 * 函数功能:读MAA7660单字节
 * 参数
 *       Regs_Addr - 寄存器地址
 * 函数返回值:寄存器值
 *=========================================================   
 */
uint8_t MMA7660_ReadReg(uint8_t Regs_Addr) 
{
	uint8_t ret;
	
	I2C_Start();
	
	I2C_WriteByte(MMA7660_DEV_WRITE); 	//先写Slave地址,并配置成写模式
	I2C_WriteByte(Regs_Addr);    		//写寄存器地址
	
	I2C_Start();
	I2C_WriteByte(MMA7660_DEV_READ);  	//写Slave地址,并配置成读模式
	ret=I2C_ReadByte();					//从传感器中读出数据
	I2C_SlaveAck();
	I2C_Stop();                  		//结束本段IIC进程 
	
	return ret;

} 


/*
 *=========================================================
 * 函数功能:读MAA7660加速度输出
 * 参数  :
 *       Regs_Addr - 加速度寄存器地址
 * 函数返回值:加速度值
 *=========================================================   
 */
uint8_t MMA7660_GetResult(uint8_t Regs_Addr) 
{
   uint8_t ret;
   
   // 等待转换完成并取出值   
   ret=MMA7660_ReadReg(Regs_Addr);

   while(ret&0x40) {
   		ret=MMA7660_ReadReg(Regs_Addr);	//数据更新,重新读
   }
 
   return ret;
}


/*
 *=========================================================
 * 函数功能:MAA7660寄存器配置,决定MMA7660工作方式
 * 参数  :
 *       
 * 函数返回值:无
 *=========================================================   
 */
void MMA7660_Begin(void)
{
	MMA7660_WriteReg(MMA7660_MODE,0x00);			//standby mode	//首先必须进入standby模式才能更改寄存器
	MMA7660_WriteReg(MMA7660_SPCNT,0x00);			//No Sleep Count
	MMA7660_WriteReg(MMA7660_INTSU,0xE3);//0xE0 will be OK //original value: 0x03			//Configure GINT Interrupt
	MMA7660_WriteReg(MMA7660_PDET,0xE0); //orginal value: 0xE0			//No tap detection enabled
	MMA7660_WriteReg(MMA7660_SR,0x02); //orginal value: 0x34				//8 samples/s,TILT debounce filter=2
	MMA7660_WriteReg(MMA7660_PD,0x00);	//original value: 0x00			//No tap detection debounce count enabled
	MMA7660_WriteReg(MMA7660_MODE,0x41);//original value: 0x41			//Active Mode,INT= push-pull and active low	
}


3、头文件定义

#ifndef _MMA7660_H_
#define _MMA7660_H_

//硬件定义
#define MM_INT  	GPIO_Pin_1		//	PB1
#define MM_SCL  	GPIO_Pin_10		//	PB10
#define MM_SDA  	GPIO_Pin_11		//	PB11

/*
 **********************************************************
 *
 * 中断线配置,低电平触发
 *
 **********************************************************
 */
#define		MMA7660_INT_GPIO_SRC		GPIOB					//外设组
#define		MMA7660_INT_PORT_SRC    	GPIO_PortSourceGPIOB	//中断引脚组
#define		MMA7660_INT_IRQ       		EXTI1_IRQn				//中断号
#define		MMA7660_INT_SOURCE   		GPIO_PinSource1			//中断源  	
#define		MMA7660_INT_LINE		    EXTI_Line1				//中断线
#define		MMA7660_INT_MODE      		EXTI_Trigger_Falling	//中断触发方式

/*
 **********************************************************
 *
 * 相关宏定义
 *
 **********************************************************
 */
//==========模拟IIC==================//
#define MMA_ERROR			0
#define MMA_OK				1
#define I2C_NOACK			0
#define I2C_ACK				1
#define MMA7660_SDA			GPIO_Pin_10		//	PB10 //IIC数据线接口
#define MMA7660_SCL			GPIO_Pin_11		//	PB11 //IIC时钟线接口
#define MMA7660_INT			GPIO_Pin_1		//	PB1  //中断线接口 

#define	MMA7660_INT_D	GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)	//PB1读数据

#define	MMA7660_SDA_D	GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)	//PB11读数据
#define	MMA7660_SDA_H   GPIO_SetBits(GPIOB, GPIO_Pin_11)	 // PB11 高电平
#define	MMA7660_SDA_L   GPIO_ResetBits(GPIOB, GPIO_Pin_11)	 // PB11 低电平
						
#define	MMA7660_SCL_H   GPIO_SetBits(GPIOB, GPIO_Pin_10)	 // PB10 高电平
#define	MMA7660_SCL_L   GPIO_ResetBits(GPIOB, GPIO_Pin_10)	 // PB10 低电平


//==========MMA7660 寄存器地址==================//
#define MMA7660_XOUT  0x00   // 6-bit output value X 
#define MMA7660_YOUT  0x01   // 6-bit output value Y 
#define MMA7660_ZOUT  0x02   // 6-bit output value Z
#define MMA7660_TILT  0x03   // Tilt Status 
#define MMA7660_SRST  0x04   // Sampling Rate Status
#define MMA7660_SPCNT 0x05   // Sleep Count
#define MMA7660_INTSU 0x06   // Interrupt Setup
#define MMA7660_MODE  0x07   // Mode
#define MMA7660_SR    0x08   // Auto-Wake/Sleep and 
                      		 // Portrait/Landscape samples 
                      		 // per seconds and Debounce Filter
#define MMA7660_PDET  0x09   // Tap Detection
#define MMA7660_PD    0x0A   // Tap Debounce Count


//=========MMA7660 功能参数==================//
#define MMA7660_DEV_ADDR   0x4C //Normally,can range 0x08 to 0xEF
#define MMA7660_DEV_WRITE  MMA7660_DEV_ADDR<<1 | 0x00
#define MMA7660_DEV_READ   MMA7660_DEV_ADDR<<1 | 0x01


/*
 **********************************************************
 *
 * 全局函数声明
 *
 **********************************************************
 */
void MMA7660_Init(void);								//SCL,INT端口输出配置
void MMA_SDA_IOOUT(void);								//SDA端口配置为输出
void MMA_SDA_IOIN(void);								//SDA端口配置为输入
void I2C_Start(void);									//开始信号
void I2C_Stop(void);									//结束信号
uint8_t I2C_SlaveAck(void);						//应答信号
void I2C_WriteByte(uint8_t a);					//写一字节
uint8_t I2C_ReadByte(void);						//读一字节
void MMA7660_WriteReg(uint8_t Regs_Addr,uint8_t Regs_Data); //写寄存器
uint8_t MMA7660_ReadReg(uint8_t Regs_Addr);	//读寄存器
uint8_t MMA7660_GetResult(uint8_t Regs_Addr); //读加速度
void MMA7660_Begin(void);								  //开始传送前的寄存器值设置


/*
 **********************************************************
 *
 * 全局定义
 *
 **********************************************************
 */


#endif /* _MMA7660_H_ */



4、中断处理函数

#if MMA7660_EN > 0u
#include "mma7660.h"
/*******************************************************************************
* Function Name  : EXTI1_IRQHandler
* Description    : This function handles External lines 1 interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void EXTI1_IRQHandler(void)
{
	OSIntEnter(); 	 //用于统计中断的嵌套层数,对嵌套层数+1,请注意:这适用于有内核参与的中断
	
	if(EXTI_GetITStatus(MMA7660_INT_LINE) != RESET) //如果检测到状态位置位
	{		
		EXTI_ClearITPendingBit(MMA7660_INT_LINE); 	//清除中断标志位
		
		//发送信号量给相应的MMA7660任务控制块
		if (!GPIO_ReadInputDataBit(MMA7660_INT_GPIO_SRC, GPIO_Pin_1)) {	//如果读取到的是低电平,则表明产生了重力传感器事件
			OS_ERR err;
			
			MMA7660_ReadReg(MMA7660_TILT);//读取TILT寄存器,清除中断,以便下次再进入中断			
			
			//使用发送信号量的方式
			//第二个参数:1. OS_OPT_POST_NONE表明在发布任务信号量之后调用任务调度程序
			//			  2. OS_OPT_POST_NO_SCHED则OSTaskSemPost后不会调用调度程序
			OSTaskSemPost(&MMA7660_TCB,
					  	  OS_OPT_POST_NONE,
					  	  &err);	
		}	
	}
	
	OSIntExit();//对嵌套层数减1,在退出中断前启动任务调度(适用于有u/COS-III内核参与的中断)
}
#endif


5、主函数调用

在main函数中调用如下代码即可:

	#if MMA7660_EN > 0u			/* MMA7660重力传感器初始化 */
		MMA7660_Init();	
	#endif





你可能感兴趣的:(嵌入式开发,STM32)