模拟SPI NRF24L01模块的简单使用
软件模拟SPI
(注:默认已经充分了解SPI通信协议)
软件模拟
- 软件模拟的好处:
- 灵活性好。(你想想,平时使用硬件SPI是不是拼死拼活的找那几个复用的引脚,要是一开始就规划好还行,但是项目开发到一半,突然来一个硬件SPI,还发现引脚口全被占用,就只能很幸苦的去慢慢修改引脚或者找其他复用。)
- 适应范围广。(极端情况,试想一下要是你的单片机不支持SPI呢 <( ̄ˇ ̄)/ )
- 简单容易移植。(你瞅瞅网上开源代码~~)
- 软件模拟的坏处
- 速度稍慢。(搭配操作系统使用,通信速率~~在一定程度上~~慢于硬件SPI,毕竟人家走的总线。)
- 单片机方面标志位少。(就不会像寄存器那样标志位一大堆,查看配置是否有问题?一看逻辑分析仪,二读取模块寄存器就好)
如何软件模拟SPI (手撸代码的话)
- 时序图
众所周知,SPI常见的有四种模式,其中上图参考手册里一扒拉就出来了,对着时序图看看可以写撸代码了。 - 开始写代码
首先看看spi.h文件
/**@file spi.h
* @brief 软件模拟spi代码配置
* @details 使用IO口模拟SPI时序,进行SPI通信
* @author LOGOTAO
* @date 2021-7-15
* @version V1.0
**********************************************************************************
* @attention
* 使用该文件需要自己依据需要修改引脚口
*
**********************************************************************************
*/
#ifndef __SPI_H
#define __SPI_H
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#define SPI_SCK_PIN GPIO_PIN_5 //SPI SCK
#define SPI_SCK_GPIO_PORT GPIOA
#define SPI_MOSI_PIN GPIO_PIN_7 //SPI MOSI
#define SPI_MOSI_GPIO_PORT GPIOA
#define SPI_MISO_PIN GPIO_PIN_6 //SPI MISO
#define SPI_MISO_GPIO_PORT GPIOA
#define SPI_NSS_PIN GPIO_PIN_4 //SPI 片选线
#define SPI_NSS_GPIO_PORT GPIOA
#define SPI_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPI_MISO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPI_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPI_NSS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define MOSI_H HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_SET)
#define MOSI_L HAL_GPIO_WritePin(SPI_MOSI_GPIO_PORT, SPI_MOSI_PIN, GPIO_PIN_RESET)
#define SCK_H HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_SET)
#define SCK_L HAL_GPIO_WritePin(SPI_SCK_GPIO_PORT, SPI_SCK_PIN, GPIO_PIN_RESET)
#define READ_MISO HAL_GPIO_ReadPin(SPI_MISO_GPIO_PORT, SPI_MISO_PIN)
#define CSN_H HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_SET)
#define CSN_L HAL_GPIO_WritePin(SPI_NSS_GPIO_PORT, SPI_NSS_PIN, GPIO_PIN_RESET)
void SPI_Init(void);
uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat);
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte);
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte);
uint8_t SOFT_SPI_RW_MODE3(uint8_t write_dat);
#endif
再查看实现代码部分spi.h
/**@file spi.c
* @brief 软件模拟spi代码配置
* @details 使用IO口模拟SPI时序,进行SPI通信
* @author LOGOTAO
* @date 2021-7-15
* @version V1.0
**********************************************************************************
* @attention
* 使用该文件需要自己依据需要修改引脚口
*
**********************************************************************************
*/
#include "spi.h"
/**
*@brief 简单延迟函数
*@param 延迟时间
*@return 无
*
***/
static void delay_us(uint32_t time)
{
uint32_t i;
for(i=0;i<time;i++);
}
/**
*@brief 软件模拟SPI引脚口初始化
*@param 无
*@return 无
*
***/
void SPI_Init(void)
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
SPI_SCK_GPIO_CLK_ENABLE();
SPI_MISO_GPIO_CLK_ENABLE();
SPI_MOSI_GPIO_CLK_ENABLE();
SPI_NSS_GPIO_CLK_ENABLE();
#if 0 //配置引脚口参考宏定义,条件编译,便于折叠阅读
#define GPIO_MODE_INPUT MODE_INPUT /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP 1(MODE_PP | MODE_OUTPUT) /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD 11 (MODE_OD | MODE_OUTPUT) /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP (MODE_PP | MODE_AF) /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD (MODE_OD | MODE_AF) /*!< Alternate Function Open Drain Mode */
#define GPIO_MODE_ANALOG MODE_ANALOG /*!< Analog Mode */
#define GPIO_MODE_IT_RISING (EXTI_MODE | GPIO_MODE_IT | RISING_EDGE) /*!< External Interrupt Mode with Rising edge trigger detection */
#define GPIO_MODE_IT_FALLING (EXTI_MODE | GPIO_MODE_IT | FALLING_EDGE) /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING (EXTI_MODE | GPIO_MODE_IT | RISING_EDGE | FALLING_EDGE) /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING (EXTI_MODE | GPIO_MODE_EVT | RISING_EDGE) /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING