STM8L的硬件SPI1共有三个主要引脚,分别是MOSI,MISO,SCK。NSS引脚只有在SMT8L作为从设备时,才有用,用于判断是否被选择与SPI主设备通信。本文选取NRF24L01作为SPI从设备,STM8L作为主设备,进行SPI读写功能测试。

下图是淘宝上可以买到的最常见的NRF24L01模块引脚图,可以看到除了MOSI,MISO,SCK,三个和SPI1硬件有关的引脚外,还有CE,CSN,IRQ这三个引脚,这三个引脚用STM8L的普通IO驱动即可.

从下图可以看到,CSN为芯片的使能引脚,读写寄存器时CSN必须为低电平.CE配合的内部配置寄存器,决定NRF24L01状态.

本例中,STM8L作为SPI主设备,在STM8L用户手册关于SPI作为主设备的详细配置流程如下图.

本文只是简单的测试SPI的读写功能,通过标志位等待实现硬件SPI读写单个字节.没有使用中断和DMA功能.
注意:向NRF24L01写数据时,需要在寄存器地址加上0x20,用于指示下一字节发送的数据是写入这个寄存器的.
下图是实际调试结果截图,查看NRF24L01的数据手册,可以知道0x00,0x01,0x02这三个寄存器的复位值分别为0x08,0x3F,0x03.由于0x00这个寄存器中的数据被我改写过了,所以这里显示改写值0x55.

- /*硬件连接*
- // STM8L NRF24L01
- // PB4 --> CSN
- // PD4 --> CE
- // PB5 --> SCK
- // PB6 --> MOSI
- // PB7 <-- MISO
- /****************************************************************************************
- *开发环境:IAR for stm8 v1.40.1
- *硬件平台:STM8L-DISCOVERY
- *功能说明:通过硬件SPI等待的方法,实现对NRF24L01寄存器的读写,借助IAR软件的调试功能,查看变量的数值
- *作 者:茗风
- ****************************************************************************************/
- #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
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- 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
- //此延时函数,延时时间为130ms
- //16M/8/2=1M 一个指令周期为1us
- }
- ///******************************************************************** **********************************
- //* 功 能 :SPI基本写一个字节函数
- //* 入口参数 :address为寄存器地址
- // data为写入数据
- //* 出口参数 :无
- //* 说 明 :SPI文件提供基本的写函数,具体的器件写方式可能不同,建议使用基本函数进行封装
- //* 范 例 :无
- //******************************************************************************************************/
- 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; //读取数据,仅仅是为了清除标志位
- while(!(SPI1_SR_TXE));//等待发送寄存器为空
- SPI1_DR=data;
- while(!(SPI1_SR_TXE));
- CSN_H;
- }
- ///******************************************************************** **********************************
- //* 功 能 :SPI基本读一个字节函数
- //* 入口参数 :address为寄存器地址
- //* 出口参数 :无
- //* 说 明 :SPI文件提供基本的读函数,具体的器件读方式可能不同,建议使用基本函数进行封装
- //* 范 例 :无
- //******************************************************************************************************/
- 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));//准备读数据
- value=SPI1_DR;
- CSN_H;
- return value;
- }
- /******************************************************************************************************
- * 名 称: SPI_init()
- * 功 能:初始化SPI
- * 入口参数:无
- * 出口参数:无
- * 说 明: 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;//关闭IRQ中断
- PB_CR2_C27 =0;//关闭中断
-
-
- CLK_PCKENR1_PCKEN14=1;//打开SPI1外设时钟
-
- SPI1_CR1_SPE=0;//关闭SPI设备
- //设置串行波特率
- SPI1_CR1_BR=0;//fmaster/2=1M
-
- //配置CPOL和CPHA,定义数据传输和串行时钟间的相位关系
- SPI1_CR1_CPHA=0;//数据采样从第一个时钟边沿开始
- SPI1_CR1_CPOL=0;//空闲状态时,SCK保持低电平
-
- //定义帧格式
- SPI1_CR1_LSBFIRST=0;//先发送MSB
-
- //使能从设备管理//主模式需通过改变SSI位 来控制SPI_SEL
- SPI1_CR2_SSM=1;//禁止软件从设备
- SPI1_CR2_SSI=1;
-
- //主从设备模式选择
- SPI1_CR1_MSTR=1;//作为主设备
-
- SPI1_CR2_RXONLY=0;//全双工
- SPI1_CR2_BDM=0;//选择单向数据模式
-
- 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");
- }
- }
复制代码
|