打印
[STM32F1]

关于两个STM32的SPI通信问题,真心希望得到大家帮助

[复制链接]
1676|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
blues_more|  楼主 | 2014-7-12 17:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 blues_more 于 2014-7-12 18:04 编辑

主机用SPI1,从机用SPI2。目的是主机发送一组数据,从机接受,同时从机返回一组数据,通过串口打印验证。下面是程序。
主机SPI初始
#include "stm32f10x.h"
#include "SPI_init.h"
#include "sys.h"
void SPI1_Configaration(void)
{
         GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOA, ENABLE );//PORTA时钟使能
RCC_APB2PeriphClockCmd(        RCC_APB2Periph_SPI1,  ENABLE );//SPI1时钟使能

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;         //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;         //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;         //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;         //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;         //定义波特率预分频的值:波特率预分频值为4
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}   
主机main函数
#include "stm32f10x.h"
#include "SPI_init.h"
#include "usart_init.h"
#include "delay.h"
#include "sys.h"
#define buffersize 32
u8 SPI1_buffer_TX[buffersize]=
{
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20
};
u8 SPI_buffer_RX[buffersize]={0};
u8 TX_Counter=0;
u8 RX_Counter=0;
u8 k=0;
u8 i=0;
int main(void)
{
u8 SPI1_RXNE=0;
u8 SPI1_TXE=0;
delay_init();
usart_configuration(115200);
SPI1_Configaration();
while(TX_Counter<buffersize)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); //检查指定的SPI标志位设置与否:发送缓存空标志位         
SPI_I2S_SendData(SPI1, SPI1_buffer_TX[TX_Counter]); //通过外设SPIx发送一个数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //检查指定的SPI标志位设置与否:接受缓存非空标志位            
   SPI_buffer_RX[RX_Counter]=SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
//SPI1_RXNE=SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);
//printf(" %0.2d \r ",SPI1_RXNE);
TX_Counter++;
RX_Counter++;
}
printf("\r\n SPI1 输出数据如下:\r\n");
while(i<buffersize)
{
printf(" %0.2d \r ",SPI1_buffer_TX);
i++;
}
printf("\r\n SPI1 收到数据如下:\r\n");
while(k<buffersize)
{
printf(" %0.2d \r ",SPI_buffer_RX[k]);
k++;
}
while(1);
}
从机SPI初始化
#include "stm32f10x.h"
#include "SPI_init.h"
#include "sys.h"
void SPI2_Configaration(void)
{
         GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
RCC_APB1PeriphClockCmd(        RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;         //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;         //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;         //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;         //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;         //定义波特率预分频的值:波特率预分频值为4
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

SPI_Cmd(SPI2, ENABLE); //使能SPI外设
}   
从机主函数
#include "stm32f10x.h"
#include "SPI_init.h"
#include "usart_init.h"
#include "delay.h"
#include "sys.h"
#define buffersize 32
u8 SPI2_buffer_TX[buffersize]=
{
0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,
0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,
0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70
};
u8 SPI_buffer_RX[buffersize]={0};
u8 TX_Counter=0;
u8 RX_Counter=0;
u8 k=0;
u8 i=0;
int main(void)
{
u8 SPI2_RXNE=0;
delay_init();
usart_configuration(115200);
SPI2_Configaration();
while(TX_Counter<buffersize)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //检查指定的SPI标志位设置与否:发送缓存空标志位         
SPI_I2S_SendData(SPI2, SPI2_buffer_TX[TX_Counter]); //通过外设SPIx发送一个数据
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //检查指定的SPI标志位设置与否:接受缓存非空标志位
SPI_buffer_RX[RX_Counter]=SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
TX_Counter++;
RX_Counter++;
}
printf("\r\n SPI2 输出数据如下:\r\n");
while(i<buffersize)
{
printf(" %0.2d \r ",SPI2_buffer_TX);
i++;
}
printf("\r\n SPI2 收到数据如下:\r\n");
while(k<buffersize)
{
printf(" %0.2d \r ",SPI_buffer_RX[k]);
k++;
}
while(1);
}
运行结果是主机收到一些无规律的数,从机收到的数全是0。
​顺便问一下这个过程中自己的几个疑问
1、SPI通信时,初始化是,波特率预分频到底是什么,为什么SPI1和SPI2的速度分别为72M和36M,但采用相同的预分频系数,这样两者波特率不同为什么能通信。(事实证明是可以的。)
2、对寄存器操作怎么没有效果SPI1->SR&=~(1<<1);
​3、实验中,我发现TXE位一直是1
​真心希望得到大家的帮组!!!
沙发
ar_m_cu| | 2014-7-12 17:45 | 只看该作者
SPI通信时,主机需要设置波特率,从机不需要,从机被动发送

使用特权

评论回复
板凳
mmuuss586| | 2014-7-12 18:33 | 只看该作者
SPI主从通讯没做过;
按楼上的意见改改看下;

使用特权

评论回复
地板
blues_more|  楼主 | 2014-7-12 21:01 | 只看该作者
ar_m_cu 发表于 2014-7-12 17:45
SPI通信时,主机需要设置波特率,从机不需要,从机被动发送

之前看到别人的程序都设置了波特率所以我也照做了。。。不过按照你的说法改后,确实得到了正确的结果。但是从机还好,不过主机有时候依然会得到一些错误的数据,而且得到的正确数据中总是缺少从机发送的最后一个。你觉得这是什么原因呢?

使用特权

评论回复
5
blues_more|  楼主 | 2014-7-12 21:02 | 只看该作者
mmuuss586 发表于 2014-7-12 18:33
SPI主从通讯没做过;
按楼上的意见改改看下;

恩,改过后确实得到了正确的结果。从机没问题,不过主机有时候依然会得到一些错误的数据,而且得到的正确数据中总是缺少从机发送的最后一个。

使用特权

评论回复
6
zhaoyu2005| | 2014-7-12 22:00 | 只看该作者
blues_more 发表于 2014-7-12 21:02
恩,改过后确实得到了正确的结果。从机没问题,不过主机有时候依然会得到一些错误的数据,而且得到的正确 ...

你仔细思考下spi的数据传输机制吧,尤其从机返回数据。这个东西很简单。

使用特权

评论回复
7
ar_m_cu| | 2014-7-12 23:20 | 只看该作者
blues_more 发表于 2014-7-12 21:01
之前看到别人的程序都设置了波特率所以我也照做了。。。不过按照你的说法改后,确实得到了正确的结果。但 ...

主机从从机读取数据,需要发送一个假写字节数据。SPI主从通信的原理是,主机发送一个数据,同时接收一个数据。

使用特权

评论回复
8
1400437756| | 2014-11-4 20:57 | 只看该作者
楼主你搞好了吗,可以把程序上传一下吗

使用特权

评论回复
9
cyg_lugang| | 2014-11-4 22:23 | 只看该作者
初学者,过来参观参观,学学使用SPI的方式……

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

14

主题

39

帖子

1

粉丝