STM32 軟件模擬SPI時序驅動NRF24L01

  其實stm32本身的硬件SPI也很好用,但是還是想用軟件來模擬一下PSI的時序。
   SPI 是一種高速的,全雙工,同步串行的通信總線。SPI通信方式相當於是一個環形結構,由CSN、MISO、MOSI、SCLK四線組成,主要是在SCLK時鐘線的驅動下,進行數據轉換。
   接下來直接上程序配置:
   使用32模擬SPI時序的IO口配置,應該注意的是MISO應該選擇模擬輸入方式GPIO_Mode_IN_FLOATING。
   以下是我的初始化部分:
/*用於軟件模擬SPI IO口宏定義區*/
#define SPI_CS_PORT     GPIOB
#define SPI_CS_PIN      GPIO_Pin_11
#define SPI_CS_LOW      (SPI_CS_PORT->BRR |=SPI_CS_PIN)
#define SPI_CS_HIGH     (SPI_CS_PORT->BSRR |=SPI_CS_PIN)

#define SPI_SCK_PORT    GPIOA
#define SPI_SCK_PIN     GPIO_Pin_12
#define SPI_SCK_LOW     (SPI_SCK_PORT->BRR |=SPI_SCK_PIN)
#define SPI_SCK_HIGH    (SPI_SCK_PORT->BSRR|=SPI_SCK_PIN)

#define SPI_MISO_PORT    GPIOA
#define SPI_MISO_PIN     GPIO_Pin_8
#define SPI_MISO_LOW     (SPI_MISO_PORT->BRR |=SPI_MISO_PIN)
#define SPI_MISO_HIGH    (SPI_MISO_PORT->BSRR|=SPI_MISO_PIN)
#define SPI_MISO_READ    (SPI_MISO_PORT->IDR &SPI_MISO_PIN)

#define SPI_MOSI_PORT    GPIOA
#define SPI_MOSI_PIN     GPIO_Pin_11
#define SPI_MOSI_LOW     (SPI_MOSI_PORT->BRR |=SPI_MOSI_PIN)
#define SPI_MOSI_HIGH    (SPI_MOSI_PORT->BSRR|=SPI_MOSI_PIN)

void SPI_GPIO_Config(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);

    //CS
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Pin=SPI_CS_PIN;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(SPI_CS_PORT, &GPIO_InitStruct);
    //SCK
    GPIO_InitStruct.GPIO_Pin=SPI_SCK_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Init(SPI_SCK_PORT,&GPIO_InitStruct);
    //MISO
    GPIO_InitStruct.GPIO_Pin=SPI_MISO_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_Init(SPI_MISO_PORT,&GPIO_InitStruct);
    //MOSI
    GPIO_InitStruct.GPIO_Pin=SPI_MOSI_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_Init(SPI_MOSI_PORT,&GPIO_InitStruct);  

    SPI_CS_HIGH;
    SPI_SCK_LOW;
}

模擬SPI時序
這裏寫圖片描述

u8 SPI_RW(u8 data)
{
    u8 i;
    SPI_SCK_LOW;     //先將時鐘線拉低
    for(i=0;i<8;i++)
    {   
        if((data&0x80)==0x80)  //從高位發送
        {
            SPI_MOSI_HIGH;
        }
        else
        {
            SPI_MOSI_LOW;
        }

        SPI_SCK_HIGH;  //將時鐘線拉高,在時鐘上升沿,數據發送到從設備

        data<<=1;

        if(SPI_MISO_READ)   //讀取從設備發射的數據
        {
            data|=0x01;     
        }
        SPI_SCK_LOW;     //在下降沿數據被讀取到主機
    }

    return data;         //返回讀取到的數據
}

寫寄存器操作:`
u8 SPI_Moni_Write_Reg(u8 Reg,u8 data)
{
u8 states;

SPI_CS_LOW;  //先將CSN拉低

states=SPI_RW(Reg);  //寫入寄存器的地址,即圖中的Cn位,並讀取狀態位

SPI_RW(data);       // 要寫入的數據

SPI_CS_HIGH;

return states;   

}

讀寄存器操作:
u8 SPI_Moni_Read_Reg(u8 Reg)
{
    u8 data;

    SPI_CS_LOW;

    SPI_RW(Reg);   //先寫入寄存器的地址

    data=SPI_RW(0); //通過寫入無效數據0,將從設備上的數據擠出來

    SPI_CS_HIGH;

    return data;
}
接下來就是寫緩衝區、讀緩衝區函數 了:
u8 SPI_Moni_Write_Buf(u8 Reg,u8 *Buf,u8 len)
{
    u8 states;

    SPI_CS_LOW;

    states=SPI_RW(Reg);

    while(len>0)
    {
        SPI_RW(*Buf);
        Buf++;
        len--;
    }
    SPI_CS_HIGH;

    return states;
}

u8 SPI_Moni_Read_Buf(u8 Reg,u8 *Buf,u8 len)
{
    u8 states;

    SPI_CS_LOW;

    states=SPI_RW(Reg);

    while(len>0)
    {
        *Buf=SPI_RW(0);
        Buf++;
        len--;
    }

    SPI_CS_HIGH;

    return states;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章