This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

读取加速度传感器时的SPI时序问题

背景信息:

A使用的芯片  TM4C123GH6PMI

B 硬件环境    TM4C123G Launchpad

C 软件环境    TivaWare_C_Series-2.1.0.12573

D其它        CCS6.0.1   加速度传感器为mpu6500

    使用SSI0模块

   ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK);    //PA2功能配置为SSI0CLK,时钟线
   ROM_GPIOPinConfigure(GPIO_PA3_SSI0FSS);    //PA3功能配置为SSI0FSS,片选线
   ROM_GPIOPinConfigure(GPIO_PA5_SSI0TX);     //PA5功能配置为SSI0TX,数据发送线
   ROM_GPIOPinConfigure(GPIO_PA4_SSI0RX);       //PA4功能配置为SSI0RX,数据接收线

第一次弄这种与外接传感器通信读取数据的,很多地方不太明白,请大家多多帮助!

问题1: 用示波器观察PA5引脚的数据发送情况,发现接和不接传感器时波形不同?图一为不接传感器。图二为接上传感器后,在时钟空闲时仍存在数据变换,但是都是一些无用的数据,应该没有影响的吧?

 这个是不接传感器时的图像。

 这个是连接上传感器的图像。

 这个是时钟与片选图像。

问题2:SPI_Write_register和SPI_Read_register这两个函数中我分别对引入的参数WriteReg做了如下操作:WriteReg+=0x80;和WriteReg&=0x7F;目的是按照SPI的要求在进行写操作时把第一个字节的首位变为1,读操作的时候把第一个字节的首位变为0。请问这样的做法是否正确?

//往MPU6500的寄存器写入
uint8_t SPI_Write_register(uint8_t WriteReg,uint8_t Value)//WriteReg要写的寄存器地址,Value要写的寄存器值
{
    uint8_t status;
    WriteReg+=0x80;
//    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,0);
    status=SPI_RW(WriteReg);
    SPI_RW(Value);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_PIN_3);
    return(status);
}
//读取MPU6500指定寄存器的值
uint8_t SPI_Read_register(uint8_t WriteReg)
{
    uint8_t status;
    WriteReg&=0x7F;
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,0);
    //status=SPI_RW(WriteReg);
    SPI_RW(WriteReg);
    status=SPI_RW(0);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_PIN_3);
    return(status);
}

 

问题3:用示波器观察PA4引脚的数据接收情况,发现一直处于低电平,既读出的数据一直为零。是不是我对mpu6500的寄存器的写操作没有成功,使得mpu6500没有被成功配置造成的?

下面是我的代码:

//----------------------------------------------------------------------------
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/ssi.h"
#include "driverlib/pin_map.h"
#include "driverlib/adc.h"
#include "mpu6500.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
//----------------------------------------------------------------------------
unsigned char BUF[10];       //接收数据缓存区
short T_X,T_Y,T_Z,T_T;		 //X,Y,Z轴,温度

void delay()
{
	unsigned int counter = 0;
	while(counter < 10000){
		counter++;
	}
}

//-------------------------------------------------------------------------------------------
// @brief SSI模块使能,并且设置相关端口初始状态
// @param none
// @return none
//		 _______________
//				        |
//			PA2(SSI0Clk)|-->***	时钟信号端
//	TIVA	PA3(SSI0Fss)|-->SYNC	帧信号端
//			PA5(SSI0Tx) |-->SDIN	SSI数据发送端(LM4F120->DAC8802)
//			PA4(SSI0Rx) |-->SDOUT
//		________________|
//
//-------------------------------------------------------------------------------------------
void ssi_en()
{
	uint32_t ui32Data;
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);			//使能外设SSI0模块
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);		//使能SSI0使用的外设GPIOA

    //SSI0端口功能使能
    ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK);					//PA2功能配置为SSI0CLK,时钟线
    ROM_GPIOPinConfigure(GPIO_PA3_SSI0FSS);					//PA3功能配置为SSI0FSS,帧信号
    ROM_GPIOPinConfigure(GPIO_PA5_SSI0TX);					//PA5功能配置为SSI0TX,数据发送线
    ROM_GPIOPinConfigure(GPIO_PA4_SSI0RX);                  //PA4功能配置为SSI0RX,数据发送线



    ROM_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_2|GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);	//配置PA2,PA3,PA4,PA5供外设SSI0使用

    ROM_SSIConfigSetExpClk(SSI0_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 1000000, 8);	//端口模式:1MHZ,8位数据

    ROM_SSIEnable(SSI0_BASE);				//使能SSI
    while(SSIDataGetNonBlocking(SSI0_BASE, &ui32Data)){};//清除缓冲区的数据,确保读到的数据时正确的。
}


/*unsigned char ssi_send_2_dac8802(unsigned long val)
{
	if(val > 16384) return 0;
    ROM_SSIDataPut(SSI0_BASE, DAC_AB + val);	//发数据+
    while(ROM_SSIBusy(SSI0_BASE));				//等待发送完成

    //数据发送结束时,LDAC线需要一个电平的跳变(H->L->H)
	ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0);
	delay();
	ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2);
	delay();
    return 1;
}*/
//**********************************************************************
//
uint8_t SPI_RW(uint8_t value)
{
    uint32_t ui32Data;
    uint8_t ui8Data;

    SSIDataPut(SSI0_BASE,value);

    while (ROM_SSIBusy(SSI0_BASE))
    {

    }


    ROM_SSIDataGet(SSI0_BASE, &ui32Data);
    ui8Data = ui32Data & 0xff;
    return(ui8Data);
}
//********************************************************************

//********************************************************************
//往MPU6500的寄存器写入
uint8_t SPI_Write_register(uint8_t WriteReg,uint8_t Value)//WriteReg要写的寄存器地址,Value要写的寄存器值
{
    uint8_t status;
    WriteReg+=0x80;
//    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,0);
    status=SPI_RW(WriteReg);
    SPI_RW(Value);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_PIN_3);
    return(status);
}
//**********************************************************************

//读取MPU6500指定寄存器的值
uint8_t SPI_Read_register(uint8_t WriteReg)
{
    uint8_t status;
    WriteReg&=0x7F;
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,0);
    //status=SPI_RW(WriteReg);
    SPI_RW(WriteReg);
    status=SPI_RW(0);
    GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_PIN_3);
    return(status);
}

//初始化MPU9250,根据需要请参考pdf进行修改************************
void Init_MPU9250(void)
{

	SPI_Write_register(PWR_MGMT_1, 0x00);	//解除休眠状态
	SPI_Write_register(SMPLRT_DIV, 0x07);
	SPI_Write_register(CONFIG, 0x06);
	SPI_Write_register(GYRO_CONFIG, 0x18);
	SPI_Write_register(ACCEL_CONFIG, 0x19);

 

}
//******读取MPU9250数据****************************************
void READ_MPU9250_ACCEL(void)
{

   BUF[0]=SPI_Read_register(ACCEL_XOUT_L);
   BUF[1]=SPI_Read_register(ACCEL_XOUT_H);
   T_X=	(BUF[1]<<8)|BUF[0];
 //  T_X/=164; 						   //读取计算X轴数据

   BUF[2]=SPI_Read_register(ACCEL_YOUT_L);
   BUF[3]=SPI_Read_register(ACCEL_YOUT_H);
   T_Y=	(BUF[3]<<8)|BUF[2];
 //  T_Y/=164; 						   //读取计算Y轴数据
   BUF[4]=SPI_Read_register(ACCEL_ZOUT_L);
   BUF[5]=SPI_Read_register(ACCEL_ZOUT_H);
   T_Z=	(BUF[5]<<8)|BUF[4];
  // T_Z/=164; 					       //读取计算Z轴数据



}

void READ_MPU9250_GYRO(void)
{

   BUF[0]=SPI_Read_register(GYRO_XOUT_L);
   BUF[1]=SPI_Read_register(GYRO_XOUT_H);
   T_X=	(BUF[1]<<8)|BUF[0];
   T_X/=16.4; 						   //读取计算X轴数据

   BUF[2]=SPI_Read_register(GYRO_YOUT_L);
   BUF[3]=SPI_Read_register(GYRO_YOUT_H);
   T_Y=	(BUF[3]<<8)|BUF[2];
   T_Y/=16.4; 						   //读取计算Y轴数据
   BUF[4]=SPI_Read_register(GYRO_ZOUT_L);
   BUF[5]=SPI_Read_register(GYRO_ZOUT_H);
   T_Z=	(BUF[5]<<8)|BUF[4];
   T_Z/=16.4; 					       //读取计算Z轴数据


  // BUF[6]=Single_Read(GYRO_ADDRESS,TEMP_OUT_L);
  // BUF[7]=Single_Read(GYRO_ADDRESS,TEMP_OUT_H);
  // T_T=(BUF[7]<<8)|BUF[6];
  // T_T = 35+ ((double) (T_T + 13200)) / 280;// 读取计算出温度
}

/*
void READ_MPU9250_MAG(void)
{
   Single_Write(GYRO_ADDRESS,0x37,0x02);//turn on Bypass Mode
   Delayms(10);
   Single_Write(MAG_ADDRESS,0x0A,0x01);
   Delayms(10);
   BUF[0]=Single_Read (MAG_ADDRESS,MAG_XOUT_L);
   BUF[1]=Single_Read (MAG_ADDRESS,MAG_XOUT_H);
   T_X=(BUF[1]<<8)|BUF[0];

   BUF[2]=Single_Read(MAG_ADDRESS,MAG_YOUT_L);
   BUF[3]=Single_Read(MAG_ADDRESS,MAG_YOUT_H);
   T_Y=	(BUF[3]<<8)|BUF[2];
   						   //读取计算Y轴数据

   BUF[4]=Single_Read(MAG_ADDRESS,MAG_ZOUT_L);
   BUF[5]=Single_Read(MAG_ADDRESS,MAG_ZOUT_H);
   T_Z=	(BUF[5]<<8)|BUF[4];
 					       //读取计算Z轴数据
}*/
void check(void)
{
	
	BUF[9]=SPI_Read_register(WHO_AM_I);
}
  • 那个不接从机的时候的数据应该不对呀。你看看那个发出去的波形,是你需要的格式和数据波形吗?看不出有什么问题

  • 感谢您的回复!

    发出去的波形我检查过是我想要的格式和数据。

    //*************************************************************************
    //读取MPU6500指定寄存器的值
    uint8_t SPI_Read_register(uint8_t WriteReg)
    {
        uint8_t status;
        WriteReg&=0x7F;
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3);
        GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,0);
        //status=SPI_RW(WriteReg);
        SPI_RW(WriteReg);
        status=SPI_RW(0);
        GPIOPinWrite(GPIO_PORTA_BASE,GPIO_PIN_3,GPIO_PIN_3);
        return(status);
    }

    第一个字节为做了与运算后的寄存器地址,第二个字节为0代表读操作。

    我检查过传感器是完好的,因为用I2C通信的时候能正确地读取出从机中寄存器的值。

    我还想请问一下,我这一步的作法是否正确?这是我参考SPI协议后加上的,但是在网络上没看到其他人的代码中有做这一步。而且我尝试把这一步骤去掉,但读数还是一直为0.

    WriteReg&=0x7F;
  • 不知道你找到问题了没有,以前一直没有操作过SPI,都是用的IO模拟,向你学习下经验