打印
[STM32F1]

关于STM32的SPI从机配置

[复制链接]
7318|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
我做SPI通讯,用STM32做从机,把主机发过来的数据返回给主机,但是数据一直不正确,不是0xff就是0x00。
以下是我的从机配置,各位前辈帮忙分析下呗,这是我第一次接触STM32的,困难重重啊。

void SPI1_conf(void)

        SPI_InitTypeDef  SPI_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        SPI_Cmd(SPI2, DISABLE);


        //从模式
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI_Direction_1Line_Rx;//
        SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
        //SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
        SPI_InitStructure.SPI_CRCPolynomial = 7;
        SPI_Init(SPI1, &SPI_InitStructure);
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        //SPI_Cmd(SPI1, ENABLE);
       
        SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
        //SPI_I2S_ClearITPendingBit(SPI1, SPI_I2S_IT_RXNE);

        //SPI2_ReadWriteByte(0xff);//启动传输



void SPI_GPIO_Configuration(void)

        GPIO_InitTypeDef GPIO_InitStructure;       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE);         //GPIOA/SPI1 时钟使能


        //从模式
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;        //sck mosi
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//miso
        //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);

        GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);



main里面在while做了如下操作

        SPI_Cmd(SPI1, ENABLE);
        if((SPI_ReadByte())!= 0)
        {
                SPI_SendByte(SPI1->DR);
        }
        SPI_Cmd(SPI1, DISABLE);


/******************************************/读
uc8 SPI_ReadByte(void)
{
        while((SPI1->SR & SPI_I2S_FLAG_TXE)==(uc16)RESET);
        SPI1->DR = 0xFF;

        while((SPI1->SR & SPI_I2S_FLAG_RXNE)==(uc16)RESET);
        return SPI1->DR;
}

/******************************************/发
u8 SPI_SendByte(u8 byte)  
{  
    /* Loop while DR register in not emplty */  
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);  

    /* Send byte through the SPI2 peripheral */  
    SPI_I2S_SendData(SPI1, byte);  

    /* Wait to receive a byte */  
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);  

    /* Return the byte read from the SPI bus */  
    return SPI_I2S_ReceiveData(SPI1);  
}  



以上是我代码里关于SPI的所有操作了,求前辈帮忙分析分析是不是哪里不对了。

沙发
蝙蝠侠|  楼主 | 2017-3-29 10:16 | 只看该作者
我单独在while里只留一个SPI_I2S_SendData(SPI1,0xa9); 也没发出任何东西。。。。
真的是配置的问题吗?

使用特权

评论回复
板凳
aozima| | 2017-3-29 10:47 | 只看该作者
本帖最后由 aozima 于 2017-3-29 11:02 编辑

从机必然是DMA,先把数据准备好在DMA里面,然后由主机来取。
最好配合中断线和状态线。

附件是我用STM32的SPI从机做一个应用,你可以参考一下SPI的时序及通讯方式。
SPI 接口硬件时序及协议.pdf (514.7 KB)

使用特权

评论回复
地板
feelhyq| | 2017-3-29 12:10 | 只看该作者
aozima 发表于 2017-3-29 10:47
从机必然是DMA,先把数据准备好在DMA里面,然后由主机来取。
最好配合中断线和状态线。

从机不一定非要是DMA噢,只要保证主机读取从机的数据完整性就可以了,保证从机给主机数据的完整性可以通过软件上指定握手协议解决,也可以利用硬件本身的开关特点。

使用特权

评论回复
5
蝙蝠侠|  楼主 | 2017-3-29 14:49 | 只看该作者
void SPI1_ReadByte(void)         //读取数据
{        
        u8 retry=0;
        //Write_data(0X08);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)   //检查指定的SPI标志位设置与否:接受缓存非空标志位
        {
                retry++;
                if(retry>200)
                {
                        Write_data(0x08);
                        return ;
                }
        }
        Write_data(0xa9);
        return ;
        //return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据                    
}

接收不了的原因好像出在这里,结果一直在发送 0x08
也就是说在  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)  一直在这里return了。

有遇到过这种情况的前辈吗?这是什么原因啊? SPI_I2S_GetFlagStatus 这个函数是做什么用的?

使用特权

评论回复
6
蝙蝠侠|  楼主 | 2017-3-29 14:50 | 只看该作者
feelhyq 发表于 2017-3-29 12:10
从机不一定非要是DMA噢,只要保证主机读取从机的数据完整性就可以了,保证从机给主机数据的完整性可以通 ...

你好 我把我读取数据的代码贴出来了,方便帮我找找哪里出问题了吗?
非常感谢!

使用特权

评论回复
7
gyh974| | 2017-3-29 15:07 | 只看该作者
SCK空闲状态是低电平吗?还有使能了中断接收,主程序里又是查询方式!!

使用特权

评论回复
8
蝙蝠侠|  楼主 | 2017-3-29 16:24 | 只看该作者
gyh974 发表于 2017-3-29 15:07
SCK空闲状态是低电平吗?还有使能了中断接收,主程序里又是查询方式!!

不好意思啊 T.T ........
我对中断接收和查询方式一点都不清楚诶。。。。
SCK空闲状态是低电平的没错。

使用特权

评论回复
9
gyh974| | 2017-3-29 16:43 | 只看该作者
进入接收后一定要读取SPI的接收寄存器:比如 retry = SPI1->DR;//清除RXNE

使用特权

评论回复
10
蝙蝠侠|  楼主 | 2017-3-29 16:50 | 只看该作者
gyh974 发表于 2017-3-29 16:43
进入接收后一定要读取SPI的接收寄存器:比如 retry = SPI1->DR;//清除RXNE

u8 SPI1_ReadByte(void)         //读取数据
{        
        u8 retry=0;
        //Write_data(0X08);
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET)   //检查指定的SPI标志位设置与否:接受缓存非空标志位
        //while(((SPI1->SR)&(1<<0))==0)
        {
                retry++;
                if(retry>200)
                {
                        //Write_data(0x08);
                        return 0x00;
                }
        }
        //Write_data(0x10);
        //return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
        return SPI1->DR;
}

这样子可以不?

使用特权

评论回复
11
pixhw| | 2017-3-29 21:25 | 只看该作者
测量IO的信号了吗

使用特权

评论回复
12
pixhw| | 2017-3-29 21:33 | 只看该作者
楼主使用模拟SPI试试。

使用特权

评论回复
13
footis| | 2017-3-29 21:46 | 只看该作者
先把中断所有相关语句全部屏蔽,然后再调试找问题。

使用特权

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

本版积分规则

9

主题

51

帖子

0

粉丝