STM32软件模拟SPI实现方法详解

STM32 软件模拟SPI

  • 前言
  • 关于 SPI
  • SPI 协议
  • 软件模拟实现
  • Driver_SPI.h
  • Driver_SPI.c
  • 前言

    STM32库:标准函数库
    测试环境:STM32F103系列

    关于 SPI

    SPI 协议

    SPI(Serial Peripheral Interface,串行外设接口)是由摩托罗拉(Motorola)在1980前后提出的一种全双工同步串行通信接口,它用于MCU与各种外围设备以串行方式进行通信以交换信息,通信速度最高可达25MHz以上。

    SPI接口主要应用在EEPROM、FLASH、实时时钟、网络控制器、OLED显示驱动器、AD转换器,数字信号处理器、数字信号解码器等设备之间。

    SPI通常由四条线组成,一条主设备输出与从设备输入(Master Output Slave Input,MOSI),一条主设备输入与从设备输出(Master Input Slave Output,MISO),一条时钟信号(Serial Clock,SCLK),一条从设备使能选择(Chip Select,CS)。与I²C类似,协议都比较简单,也可以使用GPIO模拟SPI时序。

    SPI和I²C对比如表所示。SPI可以同时发出和接收数据,因此SPI的理论传输速度比I²C更快。SPI通过片选引脚选择从机,一个片选一个从机,因此在多从机结构中,需要占用较多引脚,而I²C通过设备地址选择从机,只要设备地址不冲突,始终只需要两个引脚。

    软件模拟实现

    Driver_SPI.h

    #ifndef __DRIVER_SPI_H
    #define __DRIVER_SPI_H
    #include "sys.h" 
    
    
    /************************* SPI 硬件相关定义 *************************/
    
    #define         SPI_GPIOx    GPIOB
    #define         RCC_APB2Periph_GPIOx   RCC_APB2Periph_GPIOB
    #define         SPI_GPIO_CSN     GPIO_Pin_12      //片选
    #define         SPI_GPIO_SCK     GPIO_Pin_13      //时钟
    #define         SPI_GPIO_MOSO    GPIO_Pin_14      //输入
    #define         SPI_GPIO_MOSI    GPIO_Pin_15      //输出
    
    //SPI时钟
    #define 		SCK_L	GPIO_ResetBits(SPI_GPIOx , SPI_GPIO_SCK)
    #define 		SCK_H	GPIO_SetBits(SPI_GPIOx , SPI_GPIO_SCK)
     
    //SPI输入
    #define 		READ_MISO	GPIO_ReadInputDataBit(SPI_GPIOx, SPI_GPIO_MOSO)
     
    //SPI片选信号	
    #define 		CSN_L     GPIO_ResetBits(SPI_GPIOx, SPI_GPIO_CSN)
    #define 		CSN_H     GPIO_SetBits(SPI_GPIOx, SPI_GPIO_CSN)
     
    //SPI输出
    #define 		MOSI_L	GPIO_ResetBits(SPI_GPIOx , SPI_GPIO_MOSI)
    #define 		MOSI_H	GPIO_SetBits(SPI_GPIOx , SPI_GPIO_MOSI)
       
    void mySPI_Init(void);                //SPI 初始化
    u8 mySPI_ReadWriteByte(u8 TxData);    //模拟SPI读写数据函数
    
    
    #endif
    /************************* SPI 硬件相关定义结束 *************************/
    
    

    Driver_SPI.c

    #include "Driver_SPI.h"
    
    /*
    * 函数名:void Delay(vu32 nCount)
    * 输入参数:nCount 延时计数
    * 返回值:无
    * 函数作用:阻塞式软件延时
    */
    void Delay(vu32 nCount)
    {
      for(; nCount != 0; nCount--);
    }
    /*
    * 函数名:void SPI_Init(void)
    * 输入参数:
    * 返回值:无
    * 函数作用:初始化 SPI 的四根引脚
    */
    void mySPI_Init(void) 
    {
     GPIO_InitTypeDef  GPIO_InitStructure;
     	
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);	 //使能端口时钟
    
        GPIO_InitStructure.GPIO_Pin = SPI_GPIO_CSN|SPI_GPIO_SCK|SPI_GPIO_MOSI;				 //端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
        GPIO_Init(SPI_GPIOx, &GPIO_InitStructure);					 //根据设定参数初始化
        
        CSN_H;      //片选不选中
        
    	GPIO_InitStructure.GPIO_Pin = SPI_GPIO_MOSO;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //上拉输入
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(SPI_GPIOx, &GPIO_InitStructure);
        
        
    }
    /*
    * 函数名:u8 mySPI_ReadWriteByte(u8 TxData) 
    * 输入参数:TxData 待写入的数据
    * 返回值:读取到的数据
    * 函数作用:模拟SPI读写数据
    */
    u8 mySPI_ReadWriteByte(u8 TxData)                                        
    {		
    	u16 bit_ctr;
       	for(bit_ctr=0;bit_ctr<8;bit_ctr++) 
       	{
    		if(TxData & 0x80) MOSI_H; 		        
    		else MOSI_L;
    		
    		TxData = (TxData << 1);           
    		SCK_H; 
    		Delay(0xff);
    		if(READ_MISO)   TxData |= 0x01; 
    		SCK_L; 
    		Delay(0xff);           		 
       	}
        return(TxData);           		  		    
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32软件模拟SPI实现方法详解

    发表回复