单片机学习小组
直播中

石胜厚

8年用户 1136经验值
私信 关注

SPI协议的知识点大合集,绝对实用

SPI协议的知识点大合集,绝对实用

回帖(1)

任迎新

2022-2-17 10:35:03
1. 需要的资源



  • 普通IO口

2. 基本知识点


  • SPI是什么:SPI是Serial Peripheral Interface的缩写,串行外围设备接口。是一种告诉的,全双工,同步的通信总线。
  • SPI接口四条通讯线:


    • MISO 主设备数据输入,从设备数据输出。
    • MOSI 主设备数据输出,从设备数据输入。
    • SCLK 时钟信号,由主设备产生。
    • CS 从设备片选信号。由主设备控制。


  • 支持在同一个协议总线上,挂在一个主设备多个从设备。
  • 外设的读操作和写操作是可以同时进行的,也可以分开。
  • SPI四种工作模式:


    • 时钟极性(CPOL),是指SPI通讯设备处于空闲状态时,SCK信号线的电平信号(即SPI通讯开始前,CS片选信号为高时,SCLK的状态)。CPOL=0,SCLK为低;CPOL=1,SCLK为高
    • 时钟相位(CPHA),是指数据的采样的时刻,当CPHA=0时,数据线上的信号将会在SCK时钟线的“奇数边沿”被采样;当CPHA=1时,数据线上的信号将会在SCK时钟线的“偶数边沿”被采样


  • CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,在第一个边沿(上升沿)读取数据,在第二个边沿(下降沿)发送数据。 注意:因为在第一个边沿就会读取数据,所以在第一个边沿到来之前就要把第一位数据输出出来并保持稳定。





  • CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,在第一个边沿(下降沿)读取数据,在第二个边沿(上升沿)发送数据。 注意:因为在第一个边沿就会读取数据,所以在第一个边沿到来之前就要把第一位数据输出出来并保持稳定。





  • CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,在第一个边沿(上升沿)发送数据,在第二个边沿(下降沿)读取数据。





  • CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,在第一个边沿(下降沿)发送数据,在第二个边沿(上升沿)读取数据。





  • 注意:数据的读取和发送时序并不是针对主设备或者从设备,而是同时进行的,就是说在主设备读取数据的同时,从设备也是出于读取设备的状态。


3. 定义结构体
typedef struct _SPI_CONFIG_t
{
        unsigned int Delay;
       
        unsigned char (*MISO_STA)(void);        //获取MISO的IO状态
        void (*MOSI_IO_HIGH)(void);                        //MOSI的IO设置成高
        void (*MOSI_IO_LOW)(void);                        //MOSI的IO设置成低
        void (*CS_IO_HIGH)(void);                        //CS的IO设置成高
        void (*CS_IO_LOW)(void);                        //CS的IO设置成低
        void (*CLK_IO_HIGH)(void);                        //CLK的IO设置成高
        void (*CLK_IO_LOW)(void);                        //CLK的IO设置成低
       
}SPI_CONFIG_t;


4. 函数功能
void _SPI_Delay(unsigned int n)
{
        unsigned int t;
        t=n;       
        while(t--);
}




#if SPI_CPOL==0 && SPI_CPHA==0


/*
*********************************************************************************************************
*        函 数 名: CS_Enable
*        形    参: spi
*        返 回 值: 无
*        功能说明: 片选使能
*********************************************************************************************************
*/
void CS_Enable(SPI_CONFIG_t spi)
{
        spi.CLK_IO_LOW();
        _SPI_Delay(spi.Delay);
       
        spi.CS_IO_LOW();
        _SPI_Delay(spi.Delay);
}


/*
*********************************************************************************************************
*        函 数 名: CS_Disable
*        形    参: spi
*        返 回 值: 无
*        功能说明: 片选失能
*********************************************************************************************************
*/
void CS_Disable(SPI_CONFIG_t spi)
{
        spi.CS_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CLK_IO_LOW();
        _SPI_Delay(spi.Delay);
}


/*
*********************************************************************************************************
*        函 数 名: SPI_WriteByte
*        形    参: spi; dat:写入的数据
*        返 回 值: 无
*        功能说明: spi写入一个字节的时序
*********************************************************************************************************
*/
void SPI_WriteByte(SPI_CONFIG_t spi, unsigned char dat)
{
        unsigned char i=0;
       
        for(i=0;i<8;i++)
        {
                if(dat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
        }
}


/*
*********************************************************************************************************
*        函 数 名: SPI_ReadByte
*        形    参: spi;
*        返 回 值: spi读一个字节
*        功能说明: spi读一个字节的时序
*********************************************************************************************************
*/
unsigned char SPI_ReadByte(SPI_CONFIG_t spi)
{
        unsigned char i=0,dat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                if(spi.MISO_STA())
                        dat |= 0x01;
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
        }
       
        return dat;
}


/*
*********************************************************************************************************
*        函 数 名: SPI_WRByte
*        形    参: spi; wdat:写入的数据
*        返 回 值: spi读一个字节
*        功能说明: spi同时读写一个字节的时序
*********************************************************************************************************
*/
unsigned char SPI_WRByte(SPI_CONFIG_t spi, unsigned char wdat)
{
        unsigned char i=0,rdat=0;
       
        for(i=0;i<8;i++)
        {
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                wdat<<=1;
                               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                rdat<<=1;
               
                if(spi.MISO_STA())
                        rdat |= 0x01;
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
        }
       
        return rdat;       
}


#endif


#if SPI_CPOL==1 && SPI_CPHA==0


void CS_Enable(SPI_CONFIG_t spi)
{
        spi.CLK_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CS_IO_LOW();
        _SPI_Delay(spi.Delay);
}


void CS_Disable(SPI_CONFIG_t spi)
{
        spi.CS_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CLK_IO_HIGH();
        _SPI_Delay(spi.Delay);
}


void SPI_WriteByte(SPI_CONFIG_t spi, unsigned char dat)
{
        unsigned char i=0;
       
        for(i=0;i<8;i++)
        {
                if(dat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
        }
}


unsigned char SPI_ReadByte(SPI_CONFIG_t spi)
{
        unsigned char i=0,dat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                if(spi.MISO_STA())
                        dat |= 0x01;
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
        }
       
        return dat;
}


unsigned char SPI_WRByte(SPI_CONFIG_t spi, unsigned char wdat)
{
        unsigned char i=0,rdat=0;
       
        for(i=0;i<8;i++)
        {
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                wdat<<=1;
                               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                rdat<<=1;
               
                if(spi.MISO_STA())
                        rdat |= 0x01;
                _SPI_Delay(spi.Delay);               
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
        }
       
        return rdat;       
}




#endif




#if SPI_CPOL==0 && SPI_CPHA==1


void CS_Enable(SPI_CONFIG_t spi)
{
        spi.CLK_IO_LOW();
        _SPI_Delay(spi.Delay);
       
        spi.CS_IO_LOW();
        _SPI_Delay(spi.Delay);
}


void CS_Disable(SPI_CONFIG_t spi)
{
        spi.CS_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CLK_IO_LOW();
        _SPI_Delay(spi.Delay);
}


void SPI_WriteByte(unsigned char dat)
{
        unsigned char i=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
                       
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
        }
}


unsigned char SPI_ReadByte(void)
{
        unsigned char i=0,dat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                if(MISO_STA)
                        dat |= 0x01;
                _SPI_Delay(spi.Delay);
        }
}


unsigned char SPI_WRByte(unsigned char wdat)
{
        unsigned char i=0,rdat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                rdat<<=1;
               
                if(MISO_STA)
                        rdat |= 0x01;
                _SPI_Delay(spi.Delay);
        }       
}




#endif


#if SPI_CPOL==1 && SPI_CPHA==1


void CS_Enable(SPI_CONFIG_t spi)
{
        spi.CLK_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CS_IO_LOW();
        _SPI_Delay(spi.Delay);
}


void CS_Disable(SPI_CONFIG_t spi)
{
        spi.CS_IO_HIGH();
        _SPI_Delay(spi.Delay);
       
        spi.CLK_IO_HIGH();
        _SPI_Delay(spi.Delay);
}


void SPI_WriteByte(unsigned char dat)
{
        unsigned char i=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
                       
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
        }
}


unsigned char SPI_ReadByte(void)
{
        unsigned char i=0,dat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                dat<<=1;
               
                if(MISO_STA)
                        dat |= 0x01;
                _SPI_Delay(spi.Delay);
        }
}


unsigned char SPI_WRByte(unsigned char wdat)
{
        unsigned char i=0,rdat=0;
       
        for(i=0;i<8;i++)
        {
                spi.CLK_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                if(wdat&0x80)
                        spi.MOSI_IO_HIGH();
                else
                        spi.MOSI_IO_LOW();
                _SPI_Delay(spi.Delay);
               
                spi.CLK_IO_HIGH();
                _SPI_Delay(spi.Delay);
               
                rdat<<=1;
               
                if(MISO_STA)
                        rdat |= 0x01;
                _SPI_Delay(spi.Delay);
        }       
}




#endif




/*
*********************************************************************************************************
*        函 数 名: SPI_WriteOneData
*        形    参: spi; wdat:写入的数据
*        返 回 值: 无
*        功能说明: spi写入一个字节
*********************************************************************************************************
*/
void SPI_WriteOneData(SPI_CONFIG_t spi, unsigned char wdat)
{       
        CS_Enable(spi);
       
        SPI_WriteByte(spi,wdat);
               
        CS_Disable(spi);
}


/*
*********************************************************************************************************
*        函 数 名: SPI_ReadOneData
*        形    参: spi;
*        返 回 值: 读取一个字节
*        功能说明: spi读取一个字节
*********************************************************************************************************
*/
unsigned char SPI_ReadOneData(SPI_CONFIG_t spi)
{
        unsigned char rdat=0;
       
        CS_Enable(spi);
       
        rdat = SPI_ReadByte(spi);
               
        CS_Disable(spi);
       
        return rdat;
}


/*
*********************************************************************************************************
*        函 数 名: SPI_WROneData
*        形    参: spi; wdat:写入的数据
*        返 回 值: spi读一个字节
*        功能说明: spi同时读写一个字节
*********************************************************************************************************
*/
unsigned char SPI_WROneData(SPI_CONFIG_t spi, unsigned char wdat)
{
        unsigned char rdat=0;
       
        CS_Enable(spi);
       
        rdat = SPI_WRByte(spi,wdat);
               
        CS_Disable(spi);
       
        return rdat;
}


/*
*********************************************************************************************************
*        函 数 名: SPI_Write_Buf
*        形    参: spi; wdat:写入的数据; len:读取写入字节数
*        返 回 值: 无
*        功能说明: spi写多个字节
*********************************************************************************************************
*/
void SPI_Write_Buf(SPI_CONFIG_t spi, unsigned char* wdat, unsigned char len)
{
        unsigned char i=0;
       
        CS_Enable(spi);
       
        for(i=0;i                 SPI_WriteByte(spi,wdat);
               
        CS_Disable(spi);
}




/*
*********************************************************************************************************
*        函 数 名: SPI_Read_Buf
*        形    参: spi;  rdat:读取的数据; len:读取字节数
*        返 回 值: 无
*        功能说明: spi读多个字节
*********************************************************************************************************
*/
void SPI_Read_Buf(SPI_CONFIG_t spi, unsigned char* rdat, unsigned char len)
{
        unsigned char i=0;
       
        CS_Enable(spi);
       
        for(i=0;i                 rdat = SPI_ReadByte(spi);
               
        CS_Disable(spi);
}




/*
*********************************************************************************************************
*        函 数 名: SPI_WR_Buf
*        形    参: spi; wdat:写入的数据; rdat:读取的数据; len:读取写入字节数
*        返 回 值: 无
*        功能说明: spi同时读写多个字节
*********************************************************************************************************
*/
void SPI_WR_Buf(SPI_CONFIG_t spi, unsigned char* wdat,unsigned char* rdat, unsigned char len)
{
        unsigned char i=0;
       
        CS_Enable(spi);
       
        for(i=0;i                 rdat = SPI_WRByte(spi,wdat);
               
        CS_Disable(spi);
}
举报

更多回帖

×
20
完善资料,
赚取积分