OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13591|回复: 13

MPU6000的SPI数据读取问题

[复制链接]

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
发表于 2014-4-2 21:38:33 | 显示全部楼层 |阅读模式
由于使用I2C读取MPU6000的数据速率有限,所以想用SPI来读取数据,但是调了两天SPI一直没调通,贴出源码请大神指教。
首先关于MPU6000的SPI描述我就没有看的很明白,一直没弄清楚其数据位是要求8位还是16位,两种数据位均尝试了也没有成功,下面是MPU6000中关于SPI的描述。


因为观察MPU6000的寄存器都是8位的,所以首先我是按照8位的数据格式来做的,SPI1的初始化程序如下:

//SPI1速度设置函数
//SpeedSet:0~7
//SPI速度=fAPB2/2^(SpeedSet+1)
//APB2时钟一般为72Mhz
void SPI1_SetSpeed(u8 SpeedSet)
{
SPI1->CR1|=0<<6; //关闭SPI设备
SpeedSet&=0X07; //限制范围
SPI1->CR1&=0XFFC7; 
SPI1->CR1|=SpeedSet<<3; //设置SPI1速度 
SPI1->CR1|=0<<7; //MSBfirst 
SPI1->CR1|=1<<6; //SPI设备使能  
//SPI1 读写8bit
//TxData:要写入的8bit
//返回值:读取到的8bit
u8 SPI1_ReadWriteByte(u8 TxData)
{
u16 retry=0;
// SPI_CS=0;//使能SPI1  
while((SPI1->SR&1<<1)==0) //等待发送区空
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}  
SPI1->DR=TxData;   //发送8个bit 
retry=0;
// delay_us(1);
while((SPI1->SR&1<<0)==0) //等待接收完8个bit  
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}      
return SPI1->DR;           //返回收到的数据
// SPI_CS=1;//关闭SPI1    
}
 
//以下是SPI模块的初始化代码,配置成主机模式,访问IMU  
//SPI口初始化
//这里针是对SPI1的初始化
void SPI1_Init(void)
{  
RCC->APB2ENR|=1<<2;   //PORTA时钟使能  
RCC->APB2ENR|=1<<12;   //SPI1时钟使能 
//这里只针对SPI口初始化
GPIOA->CRL&=0X0000FFFF; 
GPIOA->CRL|=0XBBB30000; //PA5/6/7复用,功能转化为SPI,PA4为推免输出,用于软件片选    
GPIOA->ODR|=0X7<<5;   //PA5/6/7上拉
GPIOA->ODR|=1<<4;       //PA4初始化为高电平,从设备没有使能


SPI1->CR1|=0<<10; //全双工模式
SPI1->CR1|=1<<9; //软件nss管理
SPI1->CR1|=1<<8;   //SSI设置为高电平,关闭SPI1

SPI1->CR1|=1<<2; //SPI主机
SPI1->CR1&=~(1<<11);    //8bit数据格式
SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
SPI1->CR1|=1<<0; //数据采样从第一个时间边沿开始,CPHA=1  
//对SPI1属于APB2的外设.时钟频率最大为72M.
SPI1->CR1|=0x6<<3; //Fsck=Fpclk1/128
SPI1->CR1|=0<<7; //MSBfirst   
SPI1->CR1|=1<<6; //SPI设备使能
 
}   

然后最初的想法是通过读取MPU6000的I2C地址寄存器,读出地址并通过串口输出,如果地址读出正常说明与MPU6000连接正常,读取地址的程序如下:

                SPI_CS=0;
s=SPI1_ReadWriteByte(MPU6050_RA_WHO_AM_I|0x80);   //读取ID
SPI_CS=1;
printf("\r\n%d\r\n",s);

但是串口输出的一直都是初始化的s值0
然后我又尝试采用16位数据格式,16位数据格式的初始化程序就是将8位修改为16位,I2C的ID读取函数如下:

SPI_CS=0;
s=SPI1_ReadWriteByte((MPU6050_RA_WHO_AM_I|0x80)<<8);   //读取ID
SPI_CS=1;
printf("\r\n%d\r\n",s);

但是依然输出都是0
其中:
#define SPI_CS  Aout(4)   //SPI片选信号

SPI_CS是片选信号
请熟悉的大神帮忙看下,SPI的程序中哪里有问题?为什么一直都无法和MPU6000正常通讯?
不胜感激!!!!!!!!!
附上小弟的原始程序!







新建文件夹.zip

451.62 KB, 下载次数: 1072

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
 楼主| 发表于 2014-4-2 21:39:32 | 显示全部楼层
自己顶一下,求指导!!!!!!!!!!!!!!!!!!!!!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165537
金钱
165537
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-4-2 23:08:08 | 显示全部楼层
帮顶
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
 楼主| 发表于 2014-4-3 08:45:43 | 显示全部楼层
没有人用过MPU6000吗?怎么会……
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-4-3 09:32:25 | 显示全部楼层
回复【楼主位】剑侠蜀山:
---------------------------------
你的SPI1初始化有问题

仔细看下《STM32中文参考手册_V10.pdf》第486页  23.5.1  SPI控制寄存器1(SPI_CR1)

这个寄存器各位的描述再说吧
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
 楼主| 发表于 2014-4-3 10:52:50 | 显示全部楼层
回复【5楼】Badu_Space:
---------------------------------
初始化有问题?请问有什么问题呀?我查了国外的MPU6000的SPI读写程序,SPI应该初始化为8位数据类型,CPOL和CPHA都是1,MSB在前,我设置的时钟是72/128MHz,有问题么?
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-4-3 12:12:33 | 显示全部楼层
回复【6楼】剑侠蜀山:
---------------------------------
SPI_CR1这个寄存器

可以参考一下原子哥的例程。

SPI1->CR1&=~(1<<11);这一句直接SPI1->CR1|=0<<11;即可,没必要这么麻烦,一不小心就将其他位给改变了





现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
 楼主| 发表于 2014-4-3 18:10:52 | 显示全部楼层
回复【7楼】Badu_Space:
---------------------------------
那我直接用:“SPI1->CR1&=0XF7FF;”吧,"<<"运算符左移的时候右端自动填0,不是吗?"0<<11"移位后不就是“0000 0000 0000 0000”,与原寄存器中的值进行“|”操作能改变什么呀?这不是无用操作吗?如果本身“SPI1->CR1”的第11位为0,那就依然是8位数据格式,那如果是1,这个操作改变不了什么呀?我看这段代码的时候就感觉有点问题。请解答,谢谢!
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-1-11
在线时间
1 小时
 楼主| 发表于 2014-4-3 18:21:07 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
问下原子哥,SPI协议,定义为全双工通信,8位数据格式,MSB在前,寄存器地址为8位,最高位为0,如果主机想要从从机读出寄存器数据,第一个时钟周期输入读/写+七位寄存器地址,那从机返回的数据是和主机输入时间相同的第一个时钟周期,还是再从主机向从机输出一个无用数据,在这第二个时钟周期才有数据返回呢?全双工不是应该输入输出同时进行的吗?但是我用示波器测量发现数据是在第二个时钟周期才输出的,请问这个是怎么回事呢?谢谢喽
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165537
金钱
165537
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-4-3 23:54:15 | 显示全部楼层
回复【9楼】剑侠蜀山:
---------------------------------
全双工是指STM32的SPI可以支持全双工,但是外设器件,不一定支持全双工啊,所以你发送基本是先发地址,后收数据的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2012-8-20
在线时间
1 小时
发表于 2014-4-27 16:11:57 | 显示全部楼层
回复【楼主位】剑侠蜀山:
---------------------------------
请问楼主解决了问题没有?至少16个时钟才可以读到数据。
回复 支持 反对

使用道具 举报

3

主题

9

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2016-7-28
在线时间
13 小时
发表于 2016-10-11 20:51:14 | 显示全部楼层
我也有这种问题,请问楼主解决了吗?
回复 支持 反对

使用道具 举报

16

主题

105

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
374
金钱
374
注册时间
2016-4-4
在线时间
54 小时
发表于 2016-10-19 16:13:40 | 显示全部楼层
楼主解决没有 我能读到数据 但是读出来好像不太对
回复 支持 反对

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
146
金钱
146
注册时间
2017-12-4
在线时间
24 小时
发表于 2018-1-26 19:43:35 | 显示全部楼层
同遇到这种问题,想读出WHO AM I 寄出去你的数据一直是00,楼主现在解决了吗
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-14 05:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表