因为网上模拟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;
else
MOSI_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通讯