您现在的位置是:首页 >技术杂谈 >SPI通讯网站首页技术杂谈

SPI通讯

哆啦哆小魔仙 2023-05-25 20:00:02
简介SPI通讯

1、介绍

SPI是高速、全双工、同步的通信总线。

SPI应用于存储芯片、AD转换器及LCD中。

同步、异步区别:是否有时钟线,例如SPI、I2C是同步通信,需要用到时钟线,串口是异步通信,没有时钟线。

SPI通信需要四根线:MISO MOSI SCLK(时钟) CS(片选)

 

MISO和MOSI有没有容易搞混的小伙伴,直接看英文记忆。

例如:MISO 英文全称为 Master input slave output,缩写MISO,主机输入从机输出。

2、时序

2、1如何配置LA2016显示波形

以之前开源项目里的触摸屏工程为例,那个工程触摸屏驱动是厂家写好的,把程序上传单片机,连接屏幕,看一下波形。

在LA2016波形仪器上选择四个通道,依次为MISO MOSI SCLK(时钟) CS(片选)。

 

连接四个通道至单片机的对应引脚,点击软件LA2016等待触发,点击屏幕触发,波形如下(没有设置):

 

调试了好久,都没有得到MISO MOSI 两个数据线上的波形,原因:

没有设置LA2016软件关于CPOL和CPHA!!!!!

这里CPOL和CPHA需要找到程序,看程序里是如何编写的,在LA2016波形显示软件上进行对应设置。

找到程序关于SPI初始化部分的函数,如下:

void SPI2_Init(void)    
{
    SPI_InitTypeDef  SPI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
     
    //配置SPI2管脚
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
​
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_Init(GPIOB, &GPIO_InitStructure);  
    
    //SPI2配置选项
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 ,ENABLE);
       
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(SPI2, &SPI_InitStructure);
​
    //使能SPI2
    SPI_Cmd(SPI2, ENABLE);   
}

****时钟极性******

  1. CPOL = 0:时钟空闲IDLE为低电平 0;

  2. CPOL= 1:时钟空闲IDLE为高电平1;

    ****时钟相位******

    1. CPHA= 0:在时钟信号SCK的第一个跳变沿采样;

    2. CPHA= 1:在时钟信号SCK的第二个跳变沿采样;

看程序得知,CPOL =0;CPHA=1,软件上对应配置如下:

 

连接调试仪器与单片机对应引脚,上电,LA2016软件点击等待触发,触摸屏幕产生SPI通信,正确波形如下:

 

 注意:片选信号下降沿触发有效!

选取一小块波形,我们来看下通讯流程:

 

 流程:

1、主设备发起信号,将CS片选信号拉低。

2、主设备发送时钟信号,告诉从设备进行读数据写数据下降沿有效(图中的波形,有的是上升沿)。

3、主设备将要发送的数据发送到数据缓存区,缓存区通过移位寄存器、串行移位寄存器通过MOSI信号线一位一位发送出去,同时MISO将接收到的数据通过移位寄存器一位一位的移到接收缓存区。

4、从机通过自己的通过MISO线将内容发送出去,MOSI接收。

2、2实战看波形

找到正点原子HAL库SPI例子的代码,直接在上面改main函数。

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/NORFLASH/norflash.h"
#include "./BSP/SPI/spi.h"
​
int main(void)
{
    uint8_t key;
    uint16_t i = 0;
    uint8_t rec_data = 0;
    
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    usmart_dev.init(72);                /* 初始化USMART */
    led_init();                         /* 初始化LED */
    lcd_init();                         /* 初始化LCD */
    key_init();                         /* 初始化按键 */
    norflash_init();
    
    while (1)
    {
        key = key_scan(0);
​
        if (key == KEY1_PRES) /* KEY1按下,写入 */
        {
            NORFLASH_CS(0);
            spi2_read_write_byte(0x06);
            NORFLASH_CS(1);
            
        }
​
    }
}
​

注意看SPI初始化!!!!

 

看程序配置CPOL和CPHA,连接LA2016时配置软件。

测试下我们在main函数中写的代码,把程序上传到单片机,并连接LA2016和单片机引脚,点击触发没看波形如下:

 

最喜欢正点原子写的这个函数,可以同时读写:

uint8_t spi2_read_write_byte(uint8_t data)
{
    uint8_t rec_data = 0;
    
    HAL_SPI_TransmitReceive(&g_spi2_handler, &data, &rec_data, 1, 1000);
    
    return rec_data;
}

测试一下读数据,用一根杜邦线把MISO和MOSI连接起来。

看波形有数据收到!

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。