stm32使用hal库模拟spi模式3
因为网上模拟spi模拟的都是模式0,很少有模式3的。
模式3的时序图,在clk的下降沿切换电平状态,在上升沿采样, SCK空闲为高电平
初始化cs,clk,miso,mosi四个io。miso配置为输入,cs、clk、mosi配置为推挽输出。
HAL_GPIO_WritePin(GPIOD, spi_sck_Pin|spi_cs_Pin, GPIO_PIN_SET); //sck,cs空闲时为高GPIO_InitStruct.Pin = spi_miso_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(spi_sdo_GPIO_Port, &GPIO_InitStruct);GPIO_InitStruct.Pin = spi_mosi_Pin|spi_sck_Pin|spi_cs_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
my_spi.h
#ifndef __MY_SPI_H
#define __MY_SPI_H
#include "main.h"
#include "gpio.h"#define SCK_H HAL_GPIO_WritePin(GPIOD, spi_sck_Pin, GPIO_PIN_SET)
#define SCK_L HAL_GPIO_WritePin(GPIOD, spi_sck_Pin, GPIO_PIN_RESET)
#define MOSI_H HAL_GPIO_WritePin(GPIOD, spi_sdi_Pin, GPIO_PIN_SET)
#define MOSI_L HAL_GPIO_WritePin(GPIOD, spi_sdi_Pin, GPIO_PIN_RESET)
#define MISO HAL_GPIO_ReadPin(spi_sdo_GPIO_Port,spi_sdo_Pin)
#define CS_H HAL_GPIO_WritePin(GPIOD, spi_cs_Pin, GPIO_PIN_SET)
#define CS_L HAL_GPIO_WritePin(GPIOD, spi_cs_Pin, GPIO_PIN_RESET)uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat );void Delay5us(U8 delaycnt);#endif
my_spi.c
#include "my_spi.h"
#include "stdint.h"void delay_us(uint16_t i){uint8_t a;while(i--){for(a=6;a>0;a--); //64mhz,6大概1us}
}void Delay5us(U8 delaycnt)
{U8 i;for(i=0; i<delaycnt; i++){delay_us(5);}
}//模式3测试通过
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat )
{uint8_t i=0, read_dat=0;for( i = 0; i < 8; i++ ){SCK_L;if( write_dat & 0x80 )MOSI_H;elseMOSI_L;write_dat <<= 1;delay_us(2);SCK_H;read_dat <<= 1;if( MISO )read_dat++;delay_us(2);__nop();}return read_dat;
}/*
// CPOL = 0, CPHA = 0, MSB first
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat )
{uint8_t i, read_dat;for( i = 0; i < 8; i++ ){if( write_dat & 0x80 )MOSI_H; else MOSI_L; write_dat <<= 1;delay_us(1); SCK_H; read_dat <<= 1; if( MISO ) read_dat++; delay_us(1);SCK_L; __nop();}return read_dat;
}// CPOL=0,CPHA=1, MSB first
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte)
{uint8_t i,Temp=0;for(i=0;i<8;i++) // 循环8次{SCK_H; //拉高时钟if(byte&0x80){MOSI_H; //若最到位为高,则输出高}else {MOSI_L; //若最到位为低,则输出低}byte <<= 1; // 低一位移位到最高位delay_us(1);SCK_L; //拉低时钟Temp <<= 1; //数据左移if(MISO)Temp++; //若从从机接收到高电平,数据自加一delay_us(1);}return (Temp); //返回数据
}// CPOL=1,CPHA=0, MSB first
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte)
{uint8_t i,Temp=0;for(i=0;i<8;i++) // 循环8次{if(byte&0x80){MOSI_H; //若最到位为高,则输出高}else {MOSI_L; //若最到位为低,则输出低}byte <<= 1; // 低一位移位到最高位delay_us(1);SCK_L; //拉低时钟Temp <<= 1; //数据左移if(MISO)Temp++; //若从从机接收到高电平,数据自加一delay_us(1);SCK_H; //拉高时钟}return (Temp); //返回数据
}
*/
使用示例:
CS_L; // SPI_CS脚拉低,开始SPI通讯Delay5us(1);for (i=0; i<5; i++) {AFERxBuf[i]=SOFT_SPI_RW_MODE3(AFETxBuf[i]);}Delay5us(1);CS_H; // SPI_CS脚拉高,结束SPI通讯