OpenEdv-开源电子网

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

STM32 SPI通信,主机接收从机数据移位问题

[复制链接]

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
发表于 2020-11-4 15:02:54 | 显示全部楼层 |阅读模式
3金钱
我用F103作为主机,F407作为从机,从机采用SPI中断接收,主机第一次发送数据时,收到的第一个字节为0,第二次发送数据时,第一个字节为上一次发送数据的最后一个字节。如下图所示:
路过的朋友还望帮忙看看,谢谢!


主从机SPI配置函数、main函数及中断函数如下所示:
主机:
int main(void)
{   
        int i, key;
        int sum=0;
        /* 上电初始化 */
        LED_Init();
        delay_init();                                                                      //延时函数初始化
        bsp_SPI2_Init();                  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
        uart_init(115200);                                                                  //串口初始化为115200
        KEY_Init();                                                                                //按键初始化
        printf("start\n");       
        printf("%d \n",SPI2->SR);       
        while(1)
        {
                key = KEY_Scan(0);               
                if(key==KEY0_PRES)                //KEY0按下
                {
                        CS0 = 0;                       
                        while (ucTxIdx < BufferSize)
                        {
                                /* 等待发送缓冲区为空 */
                                while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
                                SPI_I2S_SendData(SPI2, ucSPI2_Buffer_Tx[ucTxIdx++] + cnt);                        // ucSPI2_Buffer_Tx[BufferSize] = { 0x06, 0x07, 0x08, 0x09 };                                       
                                /* 等待接收缓冲区非空 */
                                while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
                                ucSPI2_Buffer_Rx[ucRxIdx++] = SPI_I2S_ReceiveData(SPI2);
                        }                       
                        ucTxIdx=0;
                        ucRxIdx=0;                       
                        delay_us(10);
                        CS0 = 1;                                               
                        printf("F103发送数据为:");
                        for(i=0; i<BufferSize; i++)
                                printf("%d ",ucSPI2_Buffer_Tx + cnt);
                        printf("\n");               
                        printf("接收数据为:\n");
                        for(i=0; i<BufferSize; i++)
                        {
                                printf("%d ",ucSPI2_Buffer_Rx);
                        }
                        printf("\n");               
                        cnt++;                       
                }                                       
        }               
}


void bsp_SPI2_Init(void)
{
        /* 定义SPI结构体变量 */
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
               
        /* SPI的IO口和SPI外设打开时钟 */
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOB, ENABLE );
        RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE);               
       
        /* SPI的CLK口设置 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 ;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                                         
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        /* SPI的MISO口设置 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                                           
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        /* SPI的MOSI口设置 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                                           
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);       
                                                       
        //把PB12作为CS0
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;                                 
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //IO口速度为50MHz
        GPIO_Init(GPIOB, &GPIO_InitStructure);                                         //根据设定参数初始化GPIOB.12
                                                                                       
        /* SPI的基本配置 */
        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_Low;                                                          // 串行同步时钟的空闲状态为高电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                                  // 串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                         // NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制       
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 定义波特率预分频的值:波特率预分频值为256
        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);                                                                                                   // 使能SPI2外设
        LED0 = 0;
}


从机:
int main(void)
{
        u8 key,cnt=0;
        int i=0;
        u8 res;
        int sum=0;
        delay_init(168);                                                                   //初始化延时函数
        uart_init(115200);                                                                //初始化串口波特率为115200
        LED_Init();                                                                                //初始化LED
        KEY_Init();                                                                         //按键初始化  
        SPI1_Init();                                                                        //SPI1初始化
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        //设置系统中断优先级分组2                                        
        printf("start\n");
        while(1)
        {
                delay_ms(1000);
                key = KEY_Scan(0);               
                printf("F403发送数据为:");
                for(i=0; i<BufferSize; i++)
                        printf("%d ",ucSPI1_Buffer_Tx);       
                printf("\n");
                printf("接收数据为:\n");
                for(i=0; i<BufferSize; i++)
                {
                        printf("%d  ",ucSPI1_Buffer_Rx);                       
                        sum = sum + ucSPI1_Buffer_Rx;                       
                }
                printf("\n");
                printf("sum = %d \n",sum);
                printf("ss = %d \n",ss);
                sum=0;                                                                                                                       
        }                  
}


void SPI1_Init(void)
{         
        SPI_InitTypeDef  SPI_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        /* 开启时钟 */
        RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);

        /* 设置引脚复用 */
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

        /* 配置引脚: SCK */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
        GPIO_Init(GPIOA, &GPIO_InitStructure);       
       
        /* 配置引脚: MISO */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
        GPIO_Init(GPIOA, &GPIO_InitStructure);       
       
        /* 配置引脚: MOSI */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
        GPIO_Init(GPIOA, &GPIO_InitStructure);
               
        /* 配置引脚: NSS */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;  
        GPIO_Init(GPIOA, &GPIO_InitStructure);       
       
        //SPI1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2 ;                        //抢占优先级2
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;                                        //子优先级2
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                                                //根据指定的参数初始化NVIC寄存器       
       
        SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);               

        /* SPI配置:从模式、全双工 */
        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_Low;                                                                  // 串行同步时钟的空闲状态为高电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                                          // 串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;                                                                 // NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制       
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        // 定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                                // 指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;                                                                  // CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);                                                                            // 根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器       
       
        /* SPI1使能 */
        SPI_Cmd(SPI1, ENABLE);
}   


void SPI1_IRQHandler(void)
{                
        SPI1->DR = ucSPI1_Buffer_Tx[cntc];                                    //ucSPI1_Buffer_Tx[BufferSize] = { 0x01, 0x02, 0x03, 0x04};
        while( SPI1->SR & 0x1 )
        {                       
                ucSPI1_Buffer_Rx[cntc] = SPI1->DR;                       
        }               
        cntc++;
        ss++;               
        if(cntc>=BufferSize)
        {
                cntc = 0;
        }       
        LED0= !LED0;
}



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

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
 楼主| 发表于 2020-11-4 15:05:38 | 显示全部楼层
图没了,串口打印的数据直接复制粘贴来:

[15:04:44.890] F103发送数据为:6 7 8 9
[15:04:44.890] 接收数据为:
[15:04:44.890] 0 1 2 3
[15:04:44.890]
[15:04:46.746] F103发送数据为:7 8 9 10
[15:04:46.746] 接收数据为:
[15:04:46.750] 4 1 2 3
[15:04:46.750]
回复

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
 楼主| 发表于 2020-11-6 15:48:53 | 显示全部楼层
啊别沉求解答~
回复

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
 楼主| 发表于 2020-11-6 17:00:31 | 显示全部楼层
为什么从机中断接收和发送给主机,主机收到的数据会错位呢
回复

使用道具 举报

0

主题

25

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2020-5-7
在线时间
6 小时
发表于 2020-11-7 09:29:04 | 显示全部楼层
666666666666666666666666
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-11-7 10:39:30 | 显示全部楼层
青灰009 发表于 2020-11-6 17:00
为什么从机中断接收和发送给主机,主机收到的数据会错位呢

一样的现象,可能水平有限,之前写的spi主从也是会错位,问题是错位了会一直错下去没法纠正过来
主从机cs引脚外部按需求上下拉能好点,你可以试试
回复

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
 楼主| 发表于 2020-11-10 17:15:48 | 显示全部楼层
nashui_sx 发表于 2020-11-7 10:39
一样的现象,可能水平有限,之前写的spi主从也是会错位,问题是错位了会一直错下去没法纠正过来
主从机c ...

每一次SPI收到的数据,第一个字节都是上一轮SPI通信的最后一个字节
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2020-11-10 18:17:36 | 显示全部楼层
青灰009 发表于 2020-11-10 17:15
每一次SPI收到的数据,第一个字节都是上一轮SPI通信的最后一个字节

你这种直接错位应该是代码问题,位错位就难搞了
回复

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
71
金钱
71
注册时间
2020-10-27
在线时间
19 小时
 楼主| 发表于 2020-11-11 14:52:29 | 显示全部楼层
nashui_sx 发表于 2020-11-10 18:17
你这种直接错位应该是代码问题,位错位就难搞了

真是技术不到位,查了几天都不知问题,最后只能主从机都加个冗余位...
回复

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2020-11-15 12:30:44 | 显示全部楼层
  CS0 = 0;               
  SPI2->DR;       
  while (ucTxIdx < BufferSize)

加上红色这一句试试吧
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-4-29 23:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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