3线SPI程序编写

文章目录

概要

        SPI(Serial Peripheral Interface)是一种用于串行数据传输的通信协议,通常用于在数字集成电路之间进行通信。3线SPI是SPI协议的一种变种,它使用了三根线(或信号线)来进行通信,包括主设备的片选(NCS)、输入输出(SDIO)和时钟线(SCLK)。这种协议通常用于资源受限的系统或需要节省引脚的应用中。

3线SPI的优点之一是它只需要少量的引脚就能完成通信,这对于资源受限的嵌入式系统非常有用。然而,由于只有一个双向数据线,因此无法同时进行全双工通信,这意味着主设备和从设备不能同时发送和接收数据,通信效率可能会受到一定影响。

SPI初始化代码

SPI_Init函数中,首先对GPIO进行了初始化设置,包括SCLK(时钟信号)、NCS(片选信号)和IRO(输入/输出信号)还有IRON芯片的中断脚配置。然而mxs_reg_write和mxs_reg_read函数分别用于向特定寄存器写入数据和从特定寄存器读取数据。在这两个函数中,使用了mixo_hal_spi_write和mixo_hal_spi_read函数进行SPI数据传输。mixo_hal_spi_write和mixo_hal_spi_read函数分别用于SPI的数据写入和读取操作。这里主要涉及到了SPI的时钟信号和数据信号的控制。delay_us函数用于实现微秒级的延迟,这在处理SPI通信时可能会用到。SPI_Set_SDIO_Input和SPI_Set_SDIO_Output函数用于配置SDIO引脚为输入或输出模式。SDIO通常用于SPI接口中的数据线。

#include "header.h"





   

void SPI_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
                               
    SPI_SCLK_GPIO_CLK_ENABLE();                                 
//    SPI_NCS_GPIO_CLK_ENABLE();
    SPI_IRO_GPIO_CLK_ENABLE();
    

    
    GPIO_InitStruct.Pin = SPI_SCLK_PIN;                    
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;            
    GPIO_InitStruct.Pull = GPIO_NOPULL;                    
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;          
    HAL_GPIO_Init(SPI_SCLK_GPIO_PORT, &GPIO_InitStruct);  
//    HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_SET);
    
//    GPIO_InitStruct.Pin = SPI_NCS_PIN;                     
//    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;            
//    GPIO_InitStruct.Pull = GPIO_NOPULL;                    
//    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;           
//    HAL_GPIO_Init(SPI_NCS_GPIO_PORT, &GPIO_InitStruct); 
//    HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_RESET);

    GPIO_InitStruct.Pin = SPI_IRO_PIN;                     
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;            
    GPIO_InitStruct.Pull = GPIO_PULLUP;                    
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;           
    HAL_GPIO_Init(SPI_IRO_GPIO_PORT, &GPIO_InitStruct); 
    
}
 
void mxs_reg_write(uint8_t regAddr, uint8_t regData)
{
    regAddr |= 0x80;

    mixo_hal_spi_write(regAddr);
    
    delay_us(10);
        
    mixo_hal_spi_write(regData);
    
    delay_us(20);

}

void mxs_reg_read(uint8_t regAddr, uint8_t* regData)
{
    regAddr &= 0x7F;  

    mixo_hal_spi_write(regAddr);

    delay_us(10);
    
    mixo_hal_spi_read(regData);
    
    delay_us(20);
}


void mixo_hal_spi_write(uint8_t data) 
{
    
    SPI_Set_SDIO_Output();
    
    for (int j = 0; j < 8; j++) 
    {
        SPI_SCLK_LOW();
        if ((data & 0x80) != 0)
        {
            SPI_SDIO_HIGH();
        }
        else
        {
            SPI_SDIO_LOW();
        }
        data <<= 1;
        delay_us(10);
        SPI_SCLK_HIGH();            
        delay_us(10);
    }
}


void mixo_hal_spi_read(uint8_t* buffer) 
{
    //uint8_t i = 0;
    uint8_t tmp = 0;
    SPI_Set_SDIO_Input();
    for (int j = 0; j < 8; j++) 
    {
        tmp <<= 1;
        
        SPI_SCLK_LOW();
        delay_us(10);

        if (HAL_GPIO_ReadPin(SPI_SDIO_GPIO_PORT, SPI_SDIO_PIN))
        {
            tmp |= 1;
        }
        else
        {
            tmp |= 0;
        }
        SPI_SCLK_HIGH();
        delay_us(10);
    } 
    *buffer = tmp;
}



void delay_us(int us) 
{ 
    unsigned t1, t2, delta, sysclk; sysclk = 24;
	t1 = SysTick->VAL;
    
    while (1) 
    { 
        t2 = SysTick->VAL; 
        delta = t2 < t1 ? (t1 - t2) : (SysTick->LOAD - t2 + t1) ; 
        if (delta >= us * sysclk) 
        break; 
    }
}


void SPI_Set_SDIO_Input(void) 
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    
    SPI_SDIO_GPIO_CLK_ENABLE();
    
    GPIO_InitStruct.Pin = SPI_SDIO_PIN;                    
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;            
    GPIO_InitStruct.Pull = GPIO_NOPULL;                     
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;          
    HAL_GPIO_Init(SPI_SDIO_GPIO_PORT, &GPIO_InitStruct); 
}

void SPI_Set_SDIO_Output(void) 
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    
    SPI_SDIO_GPIO_CLK_ENABLE();
    
    GPIO_InitStruct.Pin = SPI_SDIO_PIN;                    
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;            
    GPIO_InitStruct.Pull = GPIO_NOPULL;                     
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;          
    HAL_GPIO_Init(SPI_SDIO_GPIO_PORT, &GPIO_InitStruct); 
}


SPI.h

#ifndef __SPI_H
#define __SPI_H	 
#include "stdint.h"




#define SPI_SDIO_PIN                         GPIO_PIN_1
#define SPI_SDIO_GPIO_PORT                   GPIOA
#define SPI_SDIO_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOA_CLK_ENABLE()

#define SPI_SCLK_PIN                         GPIO_PIN_0
#define SPI_SCLK_GPIO_PORT                   GPIOB
#define SPI_SCLK_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOB_CLK_ENABLE()

//#define SPI_NCS_PIN                         GPIO_PIN_1
//#define SPI_NCS_GPIO_PORT                   GPIOC
//#define SPI_NCS_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOC_CLK_ENABLE()

#define SPI_IRO_PIN                         GPIO_PIN_7
#define SPI_IRO_GPIO_PORT                   GPIOB
#define SPI_IRO_GPIO_CLK_ENABLE()           __HAL_RCC_GPIOB_CLK_ENABLE()


#define SPI_SDIO_HIGH()     HAL_GPIO_WritePin(SPI_SDIO_GPIO_PORT,SPI_SDIO_PIN,GPIO_PIN_SET)
#define SPI_SDIO_LOW()      HAL_GPIO_WritePin(SPI_SDIO_GPIO_PORT,SPI_SDIO_PIN,GPIO_PIN_RESET)

#define SPI_SCLK_HIGH()     HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_SET)
#define SPI_SCLK_LOW()      HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_RESET)

#define SPI_NCS_HIGH()     HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_SET)
#define SPI_NCS_LOW()      HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_RESET)




void SPI_Init(void);//初始化
void mxs_reg_write(uint8_t regAddr, uint8_t regData);
void mxs_reg_read(uint8_t regAddr, uint8_t* regData);
void mixo_hal_spi_write(uint8_t data); 
void mixo_hal_spi_read(uint8_t* buffer); 
void SPI_Delay(uint32_t us);
void SPI_Set_SDIO_Input(void);
void SPI_Set_SDIO_Output(void);	
void delay_us(int us);


#endif

小结

3线SPI严格来说并不是SPI协议,因为只有SDIO进行数据传输而已,所以只是半双工传输, mxs_reg_write和mxs_reg_read里面分别有一个将最高位至1和0操作,这要根据使用的芯片手册提供的方法去配置。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ESP32的SPI驱动程序编写步骤如下: 1. 引入SPI.h库文件 ```c++ #include <SPI.h> ``` 2. 定义SPI线的引脚 ```c++ #define SCK 18 // 定义时钟引脚 #define MISO 19 // 定义数据输入引脚 #define MOSI 23 // 定义数据输出引脚 #define SS 5 // 定义从机选择引脚 ``` 3. 初始化SPI线 ```c++ SPI.begin(SCK, MISO, MOSI, SS); // 初始化SPI线 ``` 4. 设置SPI线属性 ```c++ SPI.setClockDivider(SPI_CLOCK_DIV8); // 设置时钟分频系数 SPI.setDataMode(SPI_MODE0); // 设置数据传输模式 SPI.setBitOrder(MSBFIRST); // 设置数据位顺序 ``` 5. 发送数据到从机 ```c++ SPI.transfer(data); // 发送数据到从机 ``` 6. 从从机接收数据 ```c++ byte data = SPI.transfer(0x00); // 从从机接收数据 ``` 完整的代码示例: ```c++ #include <SPI.h> #define SCK 18 #define MISO 19 #define MOSI 23 #define SS 5 void setup() { Serial.begin(9600); SPI.begin(SCK, MISO, MOSI, SS); SPI.setClockDivider(SPI_CLOCK_DIV8); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); } void loop() { byte data = 0x55; digitalWrite(SS, LOW); // 选择从机 SPI.transfer(data); // 发送数据到从机 digitalWrite(SS, HIGH); // 取消选择从机 digitalWrite(SS, LOW); // 选择从机 byte receive_data = SPI.transfer(0x00); // 从从机接收数据 digitalWrite(SS, HIGH); // 取消选择从机 Serial.print("Send data: "); Serial.print(data, HEX); Serial.print(" Receive data: "); Serial.println(receive_data, HEX); delay(1000); } ``` 以上是一个简单的SPI驱动程序示例,可以根据实际需要进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值