oled stm32的spi


 其實各種協議是很重要的,這篇文章就當做我對spi協議的一個整理吧。

必要的spi簡介:

https://www.cnblogs.com/zengsf/p/7221207.html?utm_source=itdadao&utm_medium=referral

 

 

前幾天在網上看到一段關於oled的程序

不過那段程序是用的io口模擬spi來控制oled模塊的

我在想stm32本身就有spi為何要用io口來模擬spi協議呢

所以就想自己試着寫一寫。

首先第一部分是關於stm32的spi引腳:

http://www.eeworld.com.cn/mcu/2015/0615/article_20333.html

SPI1->CS      ------ PA4

SPI1->CLK    ------ PA5 
SPI1->MISO  ------ PA6
SPI1->MOSI  ------ PA7

SPI2->CS      ------ PB12
SPI2->CLK    ------ PB13 
SPI2->MISO  ------ PB14 
SPI2->MOSI  ------ PB15

SPI3->CS      ------ PA15  
SPI3->CLK    ------ PB3 
SPI3->MISO  ------ PB4 
SPI3->MOSI  ------ PB5

對於SPI ,需要打開相關RCC時鍾
主模式下
CLK 配置成復用推挽輸出
MOSI 配置成復用推挽輸出
MISO 配置成富哦那個或帶上拉輸入
CS若采用硬件則配置成推挽輸出,若采用軟件模式,則采用普通IO推挽輸出即可。
 
根據上面的提示,不如我們就選用spi1吧
http://blog.sina.com.cn/s/blog_66513d610102wv3p.html
知道了引腳,然后我們開始用庫函數去配置spi:
spi1的SCLK,MISO,MOSI分別是PA5,PA6,PA7引腳,這幾個引腳配置成GPIO_Mode_AF_PP即復用推挽輸出。
如果是單主單從,CS引腳可以不配置,都設置成軟件模式即可。

 引腳配置好了,我們下面進行spi模式的配置。下面的圖片僅供參考,具體問題還需具體分析。spi的極性和相位為4中,我們還需要根據實際情況去查看。

配置好了之后,我們就開始寫應用了,也就是收發函數,收發函數把數據通過配置好的底層發出去。

對於應用函數,我們應該設置好形參,形參主要是用來保存協議來往的數據的。

這個協議的收發函數有兩種(因為這個協議是雙工的):讀寫分開的函數,讀寫一起的。

讀寫分開的函數:

 

void SPI_Ecah_Buffer_Send(u8* pBuffer, u16 NumByteToRead) //發送

{

       for(int i = 0; i < NumByteToRead; i++)

       {

              SPI_Conmunication_SendByte(*pBuffer);

              pBuffer++;

       }

}

 

void SPI_Buffer_Receive(u8* pBuffer, u16 NumByteToRead) //接收

{

       while (NumByteToRead--)

       {     

              *pBuffer = SPI_Conmunication_SendByte (Dummy_Byte);

              pBuffer++;

       }

}

 
 
還有一種是讀寫一體的

void SPI_Ecah_Buffer_Send(u8* str , u8* pBuffer, u16 NumByteToRead)

{

       for(int i = 0; i < NumByteToRead; i++)

       {

              *str = SPI_Conmunication_SendByte(*pBuffer);

              pBuffer++;

              str++;

       }

}

 
 
好了到了這里之后,我們基本上已經把所有的框架寫好了,來整理一下用到的庫函數
這些函數都是stm32的庫里給我的API接口,我們配置好底層之后,就可以用這些函數去編寫自己的應用了。
SPI_Cmd(SPI2,ENABLE);//使能SPI外設
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); //發送數據函數
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;//接收數據函數
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)//判斷數據是否傳輸完成
 
 
之后我們應該在上面的框架里補充和修正一些細節。
 我們最終的目的還是想讓stm32的spi驅動oled,關於oled的細節
https://www.cnblogs.com/wp2312139418/p/5988713.html
上面文章真的很詳細。
 

OLED引腳介紹: 這個是oled模塊上的幾個引腳。我們要把它和spi對應起來。

CS:OLED片選信號

RST:OLED復位端口

DC: 命令/數據選擇端口(0:讀寫命令, 1: 讀寫數據)

SCLK(D0):串口時鍾線

SDIN(D1): 串口數據線
 
 
stm32與OLED屏接口的引腳介紹:

CS————GPIOD3;    spi的片選

RST————GPIOD4;    復位(spi里沒有)

DC—————GPIOD5;   表示寫數據還是命令。(spi里沒有)

D0——————GPIOD6; spi時鍾線

D1——————GPIOD7;   spi MOSI,代表oled從這里接收數據,假設單片機是主機,oled屏是從機。

上面接線,藍色是我推出來的。
 
我們先分析一下上面網友的模擬spi的程序:
不知道為什么,我寫到這里的時候,腦子里竟然是老師講課時的情景,
告訴我,spi有四種模式。我們可以從下面的程序中發現oled適用於哪一種模式。
 
/*    SPI寫數據/命令
 *    Mode :O:寫命令   1:寫數據
 *    data :數據/命令
 *
*/
void SPI_Write(char data, int Mode)
{    
    int i = 0;
    if(Mode)                   //這個是用來區分命令,還是數據的。
    {
        OLED_DC(1);        //DC引腳輸入高,表示寫數據
    }
    else
    {
        OLED_DC(0);        //DC引腳輸入低,表示寫命令
    }
    OLED_CS(0);            //CS引腳輸入低,片選使能   這里符合spi協議,低電平是選中。
    for(i = 0; i < 8; i++)     //從這句話,我們能判斷出,這個spi協議是,8位的, spi分為8幀和16幀
    {
        OLED_D0(0);        //D0引腳輸入低
        if(data & 0x80)      //判斷傳輸的數據最高位為1還是0   從這里判斷是先傳輸高位, spi協議有先傳高位或先傳低位。
        {
            OLED_D1(1);    //D1引腳輸入高 
        }
        else
        {
            OLED_D1(0);    //D1引腳輸入低
        }
        OLED_D0(1);        //D1引腳輸入高    //先准備好數據,然后在讓時鍾有一個上升沿,也就是上升沿的時候讀取數據。
        data <<= 1;        //將數據左移一位
    }
    OLED_DC(0);            //DC引腳輸入低
    OLED_CS(1);            //CS引腳輸入高,片選失能,  //這個可能是為了防止干擾,
}
 
所以呢。我們要把io口改一下:
 
 OLED屏與stm32接口的引腳介紹:

CS————GPIOD3;    spi的片選

RST————GPIOD4;    復位(spi里沒有)

DC—————GPIOD5;   表示寫數據還是命令。(spi里沒有)

D0——————GPIOD6; spi時鍾線

D1——————GPIOD7;   spi MOSI,代表oled從這里接收數據,假設單片機是主機,oled屏是從機。
 
 把上面的一層關系,修改成下面這樣:
單片機                        ----- oled屏幕

SPI1->CS      ------ PA4----CS

SPI1->CLK    ------ PA5 ---- D0
SPI1->MISO  ------ PA6----- D1
SPI1->MOSI  ------ PA7
                             PB1----- RST
                              PB2----- DC
 
 之后,就是spi配置的修正:
也就是上面提到的這個圖片:

第一個是全雙工,其實沒有必要,因為oled屏好像不會返回數據給stm32

第二行是從機,我感覺單片機應該還是主機的好

第三個8幀,這個應該不用改

第四個,這個應該也是低電平,空閑時刻D0 ,,,,,,候選項:SPI_CPOL_High(=1)和SPI_CPOL_Low ( =0)

第五個,感覺應該是第一個跳變沿被采集,,,,,,, 候選項:SPI_CPHA_1Edge (=0) 和SPI_CPHA_2Edge(=1)

第六個,cs片選引腳為軟件模式

第七個, 這個是波特率,分頻為8,可以但是這個時鍾默認應該是36M的。

第八個,這個的確是先傳高字節

第九個,這個是CRC校驗,實際上是這個賦值是7是沒有意義的,至於為什么?

https://blog.csdn.net/kobesdu/article/details/50972273

SPI_CRCPolynomial :這是 SPI 的 CRC 校驗中的多項式,若我們使用 CRC 校驗
時,就使用這個成員的參數(多項式)來計算 CRC 的值。由於本實驗的 Flash 不支持 CRC
校驗,所以我們向這個結構體成員賦值為7 實際上是沒有意義的。
配置完這些結構體成員后,我們要調用SPI_Init() 函數把這些參數寫入寄存器中,實現
SPI 的初始化,然后調用

 
 之后我們把引腳線改一下,然后把spi配置改一下,
然后程序要改
void SPI_Write(char data, int Mode) ,這個函數我們就不再用了。
然后需要重新寫一個,用SPI_Conmunication_SendByte(*pBuffer);
這個庫函數寫一個,按照oled的操作規則寫一個應用函數,看來是協議
包含着協議呀,
 
這個我晚上回去測試一下,看看能不能用。
不過改來改去似乎沒有覺得有多么簡單,也許調用庫函數對於移植和后期的維護是很方便的吧。
 
改一下函數:
/*    SPI寫數據/命令
 *    Mode :O:寫命令   1:寫數據
 *    data :數據/命令
 *
*/
void SPI_Write(char data, int Mode)
{    
    int i = 0;
    if(Mode)                   //這個是用來區分命令,還是數據的。
    {
        OLED_DC(1);        //DC引腳輸入高,表示寫數據
    }
    else
    {
        OLED_DC(0);        //DC引腳輸入低,表示寫命令
    }
    OLED_CS(0);            //CS引腳輸入低,片選使能   這里符合spi協議,低電平是選中。
   SPI_Conmunication_SendByte(data);  //這個是協議部分,不知道這樣可以不可以。
    OLED_DC(0);            //DC引腳輸入低
    OLED_CS(1);            //CS引腳輸入高,片選失能,  //這個可能是為了防止干擾,
}
 
 
先整理一下網友的程序。
然后把我的程序改進去試一下。
 
見我的另一篇博客:oled的一套stm32實驗。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM