STM8L的硬件SPI1共有三個主要引腳,分別是MOSI,MISO,SCK。NSS引腳只有在SMT8L作為從設備時,才有用,用于判斷是否被選擇與SPI主設備通信。本文選取NRF24L01作為SPI從設備,STM8L作為主設備,進行SPI讀寫功能測試。

下圖是淘寶上可以買到的最常見的NRF24L01模塊引腳圖,可以看到除了MOSI,MISO,SCK,三個和SPI1硬件有關(guān)的引腳外,還有CE,CSN,IRQ這三個引腳,這三個引腳用STM8L的普通IO驅(qū)動即可.

從下圖可以看到,CSN為芯片的使能引腳,讀寫寄存器時CSN必須為低電平.CE配合的內(nèi)部配置寄存器,決定NRF24L01狀態(tài).

本例中,STM8L作為SPI主設備,在STM8L用戶手冊關(guān)于SPI作為主設備的詳細配置流程如下圖.

本文只是簡單的測試SPI的讀寫功能,通過標志位等待實現(xiàn)硬件SPI讀寫單個字節(jié).沒有使用中斷和DMA功能.
注意:向NRF24L01寫數(shù)據(jù)時,需要在寄存器地址加上0x20,用于指示下一字節(jié)發(fā)送的數(shù)據(jù)是寫入這個寄存器的.
下圖是實際調(diào)試結(jié)果截圖,查看NRF24L01的數(shù)據(jù)手冊,可以知道0x00,0x01,0x02這三個寄存器的復位值分別為0x08,0x3F,0x03.由于0x00這個寄存器中的數(shù)據(jù)被我改寫過了,所以這里顯示改寫值0x55.

- /*硬件連接*
- // STM8L NRF24L01
- // PB4 --> CSN
- // PD4 --> CE
- // PB5 --> SCK
- // PB6 --> MOSI
- // PB7 <-- MISO
- /****************************************************************************************
- *開發(fā)環(huán)境:IAR for stm8 v1.40.1
- *硬件平臺:STM8L-DISCOVERY
- *功能說明:通過硬件SPI等待的方法,實現(xiàn)對NRF24L01寄存器的讀寫,借助IAR軟件的調(diào)試功能,查看變量的數(shù)值
- *作 者:茗風
- ****************************************************************************************/
- #include"iostm8l152c6.h"
- #include"stdbool.h"
- #include"stdint.h"
-
- #define CSN_H PB_ODR_ODR4=1
- #define CSN_L PB_ODR_ODR4=0
- #define CE_H PD_ODR_ODR4=1
- #define CE_L PD_ODR_ODR4=0
- uint16_t VDD_Value=0;
- /******************************************************************************************************
- * 名 稱:void delay_10ms(uint8_t x_ms)
- * 功 能:延時10ms
- * 入口參數(shù):無
- * 出口參數(shù):無
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- void delay_100ms(void)
- {
- uint8_t i,j;
- for(i=0;i<255;i++)//2*255個指令周期
- for(j=0;j<255;j++);//2*255個指令周期
- //delay_10ms共消耗 x_ms*2*255+2*x_ms個指令周期
- //255*2*255+2*255=130610us=130ms
- //此延時函數(shù),延時時間為130ms
- //16M/8/2=1M 一個指令周期為1us
- }
- ///******************************************************************** **********************************
- //* 功 能 :SPI基本寫一個字節(jié)函數(shù)
- //* 入口參數(shù) :address為寄存器地址
- // data為寫入數(shù)據(jù)
- //* 出口參數(shù) :無
- //* 說 明 :SPI文件提供基本的寫函數(shù),具體的器件寫方式可能不同,建議使用基本函數(shù)進行封裝
- //* 范 例 :無
- //******************************************************************************************************/
- void SPI1_Write_REG(uint8_t address,uint8_t data)
- {
- uint8_t tmp;
- address |=0x20;
- CSN_L;
- SPI1_DR=address;//寫入需要操作的寄存器地址,
- while(!(SPI1_SR_RXNE));
- tmp=SPI1_DR; //讀取數(shù)據(jù),僅僅是為了清除標志位
- while(!(SPI1_SR_TXE));//等待發(fā)送寄存器為空
- SPI1_DR=data;
- while(!(SPI1_SR_TXE));
- CSN_H;
- }
- ///******************************************************************** **********************************
- //* 功 能 :SPI基本讀一個字節(jié)函數(shù)
- //* 入口參數(shù) :address為寄存器地址
- //* 出口參數(shù) :無
- //* 說 明 :SPI文件提供基本的讀函數(shù),具體的器件讀方式可能不同,建議使用基本函數(shù)進行封裝
- //* 范 例 :無
- //******************************************************************************************************/
- uint8_t SPI1_Read_REG(uint8_t address)
- {
- volatile uint8_t value=0;
- CSN_L;
- value=SPI1_DR;//讀一次,清除標志位
- while(!(SPI1_SR_TXE));
- SPI1_DR=address;//寫入需要操作的寄存器地址,
-
- while(!(SPI1_SR_RXNE));
- value=SPI1_DR;
-
- while(!(SPI1_SR_TXE));
- SPI1_DR=0xFF;//寫入一個無效值
-
- while(!(SPI1_SR_RXNE));//準備讀數(shù)據(jù)
- value=SPI1_DR;
- CSN_H;
- return value;
- }
- /******************************************************************************************************
- * 名 稱: SPI_init()
- * 功 能:初始化SPI
- * 入口參數(shù):無
- * 出口參數(shù):無
- * 說 明: SP1傳輸速率設置為fmaster/2=8M,主模式,
- * 范 例:無
- ******************************************************************************************************/
- void SPI_Init(void)
- {
- static uint8_t temp0=0,temp1=0,temp2=0,temp3=0;
- //輸出IO
- PD_DDR_DDR4 =1;//CE設置為輸出
- PB_DDR_DDR4 =1;//CSN設置為輸出
- PB_DDR_DDR5 =1;//SCK設置為輸出
- PB_DDR_DDR6 =1;//SIMO設置為輸出
-
- PD_CR1_C14 =1;//CE設置為推挽輸出
- PB_CR1_C14 =1;//CSN設置為推挽輸出
- PB_CR1_C15 =1;//SCK設置為推挽輸出
- PB_CR1_C16 =1;//SIMO設置為推挽輸出
-
- PB_CR2_C26 =1;//SIMO的IO輸出速率為10MHz
- PB_CR2_C25 =1;//SCK的IO輸出速率為10MHz
- PD_CR2_C24 =1;//CE的IO輸出速率為10MHz
- PB_CR2_C24 =1;//CSN的IO輸出速率為10MHz
-
- //輸入IO
- PD_DDR_DDR5 =0;//IRQ設置為輸入
- PB_DDR_DDR7 =0;//SOMI設置為輸入
-
- PD_CR1_C15 =1;//IRQ設置為帶上拉電阻輸入
- PB_CR1_C17 =1;//SOMI設置帶上拉電阻輸入
-
- PD_CR2_C25 =0;//關(guān)閉IRQ中斷
- PB_CR2_C27 =0;//關(guān)閉中斷
-
-
- CLK_PCKENR1_PCKEN14=1;//打開SPI1外設時鐘
-
- SPI1_CR1_SPE=0;//關(guān)閉SPI設備
- //設置串行波特率
- SPI1_CR1_BR=0;//fmaster/2=1M
-
- //配置CPOL和CPHA,定義數(shù)據(jù)傳輸和串行時鐘間的相位關(guān)系
- SPI1_CR1_CPHA=0;//數(shù)據(jù)采樣從第一個時鐘邊沿開始
- SPI1_CR1_CPOL=0;//空閑狀態(tài)時,SCK保持低電平
-
- //定義幀格式
- SPI1_CR1_LSBFIRST=0;//先發(fā)送MSB
-
- //使能從設備管理//主模式需通過改變SSI位 來控制SPI_SEL
- SPI1_CR2_SSM=1;//禁止軟件從設備
- SPI1_CR2_SSI=1;
-
- //主從設備模式選擇
- SPI1_CR1_MSTR=1;//作為主設備
-
- SPI1_CR2_RXONLY=0;//全雙工
- SPI1_CR2_BDM=0;//選擇單向數(shù)據(jù)模式
-
- SPI1_CR1_SPE=1;//開啟SPI設備
-
- //NRF24L01上電復位后需要100ms才能進入到掉電模式
- //配置NRF24L01之前必須要有100ms以上的延時
- delay_100ms();
- //至此NRF24L01進入到掉電模式,允許對NRF24L01寄存器進行讀寫操作
- CE_L;
- CSN_H;
- PB_DDR_DDR5=0;//SCK_L
-
- /************以下,幾個讀寫操作,是為了測試SPI讀寫功能*****************/
- temp0=SPI1_Read_REG(0x00);//
- temp1=SPI1_Read_REG(0x01);//0x3F
- temp2=SPI1_Read_REG(0x02);//0x03
-
- SPI1_Write_REG(0x00,0x38);
- temp3=SPI1_Read_REG(0x00);
- asm("nop");
- }
- void main(void)
- {
- SPI_Init();
- // asm("rim"); //enable interrupts
- while(1)
- {
- asm("wfi");
- }
- }
復制代碼
|