打印
[STM32F1]

硬件SPI

[复制链接]
55|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jimmhu|  楼主 | 2025-1-30 15:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. STM32 SPI
1.1 STM32的SPI接口
SPI可以设置为主、从两种模式,并且支持全双工模式,而配置为主、从模式或软件、硬件NSS,在操作上有很大的区别。由于一个项目需求,笔者对STM32的硬件模式和主从模式进行了一些研究,走了很多弯路,也查询了很多资料,现在终于调通了,因此写一篇文章记录调试心得,以及很多需要注意的地方。
本文主要探讨主模式和从模式NSS硬件和软件管理。
2. SPI Master 初始化及测试
2.1 硬件NSS模式
以下是初始化代码
/************打开时钟*************/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);  
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;        //SPI_MOSI
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
//         SPI_Cmd(SPI1, ENABLE);                        //先不打开SPI
        SPI_SSOutputCmd(SPI1, ENABLE);                   //SPI的NSS引脚控制开启
}
SPI配置为主模式,采用硬件NSS有几点需要注意,若采用硬件NSS,一定要把NSS引脚输出设置为GPIO_Mode_AF_PP,否则程序无法正确控制。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

①NSS引脚修改为GPIO_Mode_Out_PP
   /************引脚配置*************/            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  //SPI_NSS            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;            GPIO_Init(GPIOA, &GPIO_InitStructure);            GPIO_SetBits(GPIOA,GPIO_Pin_4);
int main()
{
            u8 SPI_TX=10,SPI_RX=0;                 //
            SPI1_Configuration();                                //spi初始化
            while(1)          
            {
                       SPI_Cmd(SPI1,ENABLE);                 //启动SPI
                      
/**************向从设备发送一个字节*************/
       while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
                       SPI_I2S_SendData(SPI1,SPI_TX);       
                  
/**************保存将接收到的数据*************/
                        while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET);
                        SPI_RX = SPI_I2S_ReceiveData(SPI1);
                  
                        SPI_Cmd(SPI1,DISABLE);                 //关闭SPI
                    
                        SPI_TX++;                        //发送的值+1
        delay_100ms(10);                //延时1秒
                        if(SPI_TX>50)                {SPI_TX=10;}
            }
    }
  **效果测试**
上图是刚刚的代码运行的效果,用逻辑分析仪抓取的SPI波形。
从设备设置的是收到什么就会返回什么,由于SPI的特性是在发送的同时接收数据,且从设备不能主动向主设备发送数据,因此在发送新数据的时候才能收到上此次发送的旧数据。2.3.2 软件NSS模式
while(1)   
{    GPIO_ResetBits(GPIOA,GPIO_Pin_4);                 //拉低CS                /**************向从设备发送一个字节*************/                    while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);                    SPI_I2S_SendData(SPI1,SPI_TX);                            GPIO_SetBits(GPIOA,GPIO_Pin_4);                 //拉高CS   **效果测试**
软件NSS模式下,SPI是常开的,读写数据的时候需要人为控制CS引脚
可以看到CS线在最后一个CLK脉冲发送完成后就立即拉高了,和硬件模式有一点区别

如果去掉这两个函数会怎样呢?
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET);
while(1)   
{
   GPIO_ResetBits(GPIOA,GPIO_Pin_4);                 //拉低CS
                /**************向从设备发送一个字节*************/
  SPI_I2S_SendData(SPI1,SPI_TX);       
  delay_us(2);                        //延时2微秒
  GPIO_SetBits(GPIOA,GPIO_Pin_4);                 //拉高CS
**效果测试**
SPI-NSS-SOFT-TX2
可以看到,程序似乎没有按照预想顺序进行,延时函数好像没有在SPI_I2S_ReceiveData()结束后才执行。这也是使用硬件SPI常犯的错误,因为在使用硬件SPI时,外设在进行数据读写的时候是不占用内核时间的,内核把数据丢给外设寄存器就完事了,内核只需要等待外设返回结束标志位,刚才屏蔽掉的两个函数就是在等待外设返回结束标志,而这个等待时间其实也可以做很多事情。经过测试,内核对外设的操作只用了大概0.4uS。

使用特权

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

本版积分规则

20

主题

3590

帖子

4

粉丝