基于STM32单片机模块练习——在使用MPU6050时遇到的令人头疼的问题

在使用MPU6050时遇到的令人头疼的问题

1.整个程序在一开始运行就卡死在启动文件

在这里插入图片描述
首先看一下,Target设置选项下的Use MicroLIB选项是不是选上勾了。
如果这个设置也解决不了问题,那么你需要检查一下程序里,是否写了printf函数的接口函数。因为MPU6050里面有在这里插入图片描述
用到了这个函数,如果你没写这个函数的接口函数,就会导致系统卡死在系统文件里。
printf函数的接口函数

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

2.while循环里的条件明明不满足了,程序却一致卡死在此循环里

检查一下,判断条件里的变量的类型是否正确。另外,如果这个变量在中断服务函数里面需要改变值,那么在定义这个变量的语句前应该加上关键字
volatile
volatile的具体描述参考

3.MPU6050在执行mpu_dmp_init()函数时,一直出现错误,且错误在run_self_test()

1)首先,看一下是不是因为你在程序初始化的时候,没有把MPU6050水平放置,至于为什么要水平放置呢?
因为在run_self_test()函数里面有一个mpu_run_self_test(gyro, accel)函数,这个函数上面有一个注释特别重要:

This function must be called with the device either face-up or face-down
 *  (z-axis is parallel to gravity).此函数必须在设备面朝上或面朝下时调用(z轴与重力平行)

2)如果照着1)的方法还是解决不了这个问题,那么请你检查一下run_self_test函数里面的具体内容是否和下面的一模一样:

//MPU6050自测试
//返回值:0,正常
//    其他,失败
u8 run_self_test(void)
{
	int result;
	//char test_packet[4] = {0};
	long gyro[3], accel[3]; 
	result = mpu_run_self_test(gyro, accel);
	if (result == 0x3) //这个地方要的别注意,有的例程会把0X3错误的写为0X7
	{
		/* Test passed. We can trust the gyro data here, so let's push it down
		* to the DMP.
		*/
		float sens;
		unsigned short accel_sens;
		mpu_get_gyro_sens(&sens);
		gyro[0] = (long)(gyro[0] * sens);
		gyro[1] = (long)(gyro[1] * sens);
		gyro[2] = (long)(gyro[2] * sens);
		dmp_set_gyro_bias(gyro);
		mpu_get_accel_sens(&accel_sens);
		accel[0] *= accel_sens;
		accel[1] *= accel_sens;
		accel[2] *= accel_sens;
		dmp_set_accel_bias(accel);
		return 0;
	}else return 1;
}

4.mpu_dmp_get_data(&pitch,&roll,&yaw)函数的返回值不正确(一直不是0)

MPU6050读不出来数据
如果参考以上这篇文章还是无法帮助解决问题,那么不妨试一下,把模拟iic的这部分代码换一下,也许可能就是因为iic这部分程序不正确。
模拟IIC的代码:

#include "mpuiic.h"
#include "./systick/bsp_SysTick.h"
#define Soft_I2C_SDA 		  GPIO_Pin_3
#define Soft_I2C_SCL 		  GPIO_Pin_4
#define Soft_I2C_PORT     GPIOB
#define MPU6050_GPIO_CLK  RCC_APB2Periph_GPIOB
//IO方向设置  ---PB11
#define MPU_SDA_IN()  {Soft_I2C_PORT ->CRL &= 0XFFFF0FFF;Soft_I2C_PORT ->CRL |= 8<<12;}       //上拉/下拉 输入模式
#define MPU_SDA_OUT() {Soft_I2C_PORT ->CRL &= 0XFFFF0FFF;Soft_I2C_PORT ->CRL |= 7<<12;}		//开漏输出  输出模式

/* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
#if 1	/* 条件编译: 1 选择GPIO的库函数实现IO读写 */
	#define MPU6050_I2C_SCL_1()  GPIO_SetBits(Soft_I2C_PORT, Soft_I2C_SCL)		/* SCL = 1 */
	#define MPU6050_I2C_SCL_0()  GPIO_ResetBits(Soft_I2C_PORT, Soft_I2C_SCL)		/* SCL = 0 */
	
	#define MPU6050_I2C_SDA_1()  GPIO_SetBits(Soft_I2C_PORT, Soft_I2C_SDA)		/* SDA = 1 */
	#define MPU6050_I2C_SDA_0()  GPIO_ResetBits(Soft_I2C_PORT, Soft_I2C_SDA)		/* SDA = 0 */
	
	#define MPU6050_I2C_SDA_READ()  GPIO_ReadInputDataBit(Soft_I2C_PORT, Soft_I2C_SDA)	/* 读SDA口线状态 */
#else	/* 这个分支选择直接寄存器操作实现IO读写 */
    /* 注意:如下写法,在IAR最高级别优化时,会被编译器错误优化 */
	#define MPU6050_I2C_SCL_1()  Soft_I2C_PORT->BSRR = Soft_I2C_SCL				/* SCL = 1 */
	#define MPU6050_I2C_SCL_0()  Soft_I2C_PORT->BRR = Soft_I2C_SCL				/* SCL = 0 */
	
	#define MPU6050_I2C_SDA_1()  Soft_I2C_PORT->BSRR = Soft_I2C_SDA				/* SDA = 1 */
	#define MPU6050_I2C_SDA_0()  Soft_I2C_PORT->BRR = Soft_I2C_SDA				/* SDA = 0 */
	
	#define MPU6050_I2C_SDA_READ()  ((Soft_I2C_PORT->IDR & Soft_I2C_SDA) != 0)	/* 读SDA口线状态 */
#endif

/**********************************************
函数名称:MPU_IIC_Delay
函数功能:MPU IIC延时函数,延时2ms
函数参数:无
函数返回值:无
**********************************************/
void MPU_IIC_Delay(void)
{
	uint8_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 < 100; i++);
}


/**********************************************
函数名称:MPU_IIC_Init
函数功能:MPU IIC初始化
函数参数:无
函数返回值:无
**********************************************/
void MPU_IIC_Init(void)
{					     
  GPIO_InitTypeDef  GPIO_InitStructure;
	
  RCC_APB2PeriphClockCmd(MPU6050_GPIO_CLK|RCC_APB2Periph_AFIO,ENABLE);			//先使能外设IO PORTB时钟 
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); 	
  GPIO_InitStructure.GPIO_Pin = Soft_I2C_SCL|Soft_I2C_SDA;	  //端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; 				  //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;				  //IO口速度为50MHz
  GPIO_Init(Soft_I2C_PORT , &GPIO_InitStructure);					 					//根据设定参数初始化GPIO 
	
  GPIO_SetBits(Soft_I2C_PORT,Soft_I2C_SCL|Soft_I2C_SDA);						  //PB10,PB11 输出高	
 
}

//产生IIC起始信号
void MPU_IIC_Start(void)
{
	MPU_SDA_OUT();      //sda线输出
	MPU6050_I2C_SDA_1();	  	  
	MPU6050_I2C_SCL_1();
	MPU_IIC_Delay();
 	MPU6050_I2C_SDA_0();//START:when CLK is high,DATA change form high to low 
	MPU_IIC_Delay();
	MPU6050_I2C_SCL_0();//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void MPU_IIC_Stop(void)
{
	MPU_SDA_OUT();//sda线输出
	MPU6050_I2C_SCL_0();
	MPU6050_I2C_SDA_0();//STOP:when CLK is high DATA change form low to high
 	MPU_IIC_Delay();
	MPU6050_I2C_SCL_1();  
	MPU6050_I2C_SDA_1();//发送I2C总线结束信号
	MPU_IIC_Delay();							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 MPU_IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	MPU_SDA_IN();      //SDA设置为输入  
	MPU6050_I2C_SDA_1();MPU_IIC_Delay();	   
	MPU6050_I2C_SCL_1();MPU_IIC_Delay();	 
	while(MPU6050_I2C_SDA_READ())
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			MPU_IIC_Stop();
			return 1;
		}
	}
	MPU6050_I2C_SCL_0();//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void MPU_IIC_Ack(void)
{
	MPU6050_I2C_SCL_0();
	MPU_SDA_OUT();
	MPU6050_I2C_SDA_0();
	MPU_IIC_Delay();
	MPU6050_I2C_SCL_1();
	MPU_IIC_Delay();
	MPU6050_I2C_SCL_0();
}
//不产生ACK应答		    
void MPU_IIC_NAck(void)
{
	MPU6050_I2C_SCL_0();
	MPU_SDA_OUT();
	MPU6050_I2C_SDA_1();
	MPU_IIC_Delay();
	MPU6050_I2C_SCL_1();
	MPU_IIC_Delay();
	MPU6050_I2C_SCL_0();
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void MPU_IIC_Send_Byte(u8 _ucByte)
{                        

		uint8_t i;
        MPU_SDA_OUT(); 
	MPU6050_I2C_SCL_0();//拉低时钟开始数据传输
	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)
		{
			MPU6050_I2C_SDA_1();
		}
		else
		{
			MPU6050_I2C_SDA_0();
		}
		_ucByte <<= 1;	/* 左移一个bit */
		
		MPU6050_I2C_SCL_1();
		MPU_IIC_Delay();	
		MPU6050_I2C_SCL_0();
		MPU_IIC_Delay();
	
		
	
	}
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 MPU_IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	MPU_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        MPU6050_I2C_SCL_0(); 
        MPU_IIC_Delay();
		MPU6050_I2C_SCL_1();
        receive<<=1;
        if(MPU6050_I2C_SDA_READ())receive++;   
		MPU_IIC_Delay(); 
    }					 
    if (!ack)
        MPU_IIC_NAck();//发送nACK
    else
        MPU_IIC_Ack(); //发送ACK   
    return receive;
}



5.读取的数据成功率低(也就是说读取10次,mpu_dmp_get_data有5次都返回1,而不是0)

1.可能是 MPU_IIC_Delay()这个函数取值不恰当,可以调整一下看看效果。
2.读取MPU6050数据卡死的总结

6.容易忽视的小问题,却恰恰最致命

例如:

STM32的PB3、PB4,分别是JTAG的JTDO和NJTRST引脚,在没关闭JTAG功能之前,在程序中是配置不了这些引脚的功能的。要配置这些引脚,首先要开启AFIO时钟,然后在AFIO的设置中,释放这些引脚。具体看STM32的参考手册中有关AFIO的部分。

RCC_APB2PeriphClockCmd(MPU6050_GPIO_CLK|RCC_APB2Periph_AFIO,ENABLE);			//先使能外设IO PORTB时钟 
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); 	
/******************************************************************
 #define GPIO_Remap_SWJ_NoJTRST      ((uint32_t)0x00300100)  < Full SWJ Enabled (JTAG-DP + SW-DP) but without JTRST 
#define GPIO_Remap_SWJ_JTAGDisable  ((uint32_t)0x00300200) < JTAG-DP Disabled and SW-DP Enabled 
#define GPIO_Remap_SWJ_Disable      ((uint32_t)0x00300400) !< Full SWJ Disabled (JTAG-DP + SW-DP) 
******************************************************************/

STM32——GPIO重映射(GPIO_PinRemapConfig)

  • 16
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ღ 金龍戲水 ღ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值