STM32-SPI

STM32- SPI

1. SPI概述

1.1 SPI概念

SPI(Serial Peripheral Interface,串行外围设备接口),是一种高速的、全双工、同步的通信总线,有四根通信线:

SCK(Serial Clock):时钟信号,由主设备产生

MOSI(Master Output/ Slave Input):主机数据输出,从机输入

MISO(Master Input Slave Output):主机数据输入,从机输出

SS(Slave Select):从机片选信号,由主机产生

在这里插入图片描述

特点:① 总线上允许连接多个能作主机的设备,但在任一时刻只允许有一个设备作为主机。② 总线的时钟线 SCK 由主机控制。

1.2 SPI工作原理

在这里插入图片描述

  • 字节交换:主机的串行移位寄存器通过 MOSI 信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过 MISO 信号线返回给主机,(高位先行)。
  • 数据采集(移入数据):在SCK下降沿或上升沿(看具体配置)时,主机移出的高位通过MOSI信号线传到从机的地位,从机的低位通过MISO信号线传到主机地位。每个时钟周期传输一位。
  • 波特率发送器:产出时钟信号,由主机产生。

1.3 SPI时序

  • 起始条件:SS从高电平切换到低电平
  • 终止条件:SS从低电平切换到高电平
  • 从机在被选中的状态中,SS 要始终保持为低电平

1.4 工作模式

  • CPOL/CKP(Clock Polarity,时钟极性):时钟信号在空闲状态下的电平。当CPOL=1,时钟信号为高电平;当CPOL = 0,时钟空闲状态为低电平 。
  • CPHA/ CKE(Clock Phase,时钟相位):数据的采样时刻。当CPHA = 0 时,在时钟信号的第一个边沿进行数据采样;当CPHA =1 时,在时钟信号的第二个边沿进行数据采样。
工作模式CPOLSPHASCK空闲电平采样边沿采样时刻
0(00)00上升沿第一个边沿
1(01)01下降沿第二个边沿
2(10)10下降沿第一个边沿
3(11)11上升沿第二个边沿

工作模式0:空闲状态的时钟信号为低电平,且在第一个边沿时刻进行数据移入,所以只能是上升沿移入数据(从空闲低电平转为高电平),在第二个边沿移出数据。

工作模式1:空闲状态的时钟信号为低电平,且在第二个边沿时刻进行数据移入,所以只能是下降沿移入数据(第二个边沿只能是下降了),第一个边沿移出数据。

工作模式2:空闲状态的时钟信号为高电平,且在第一个边沿时刻进行数据移入,所以只能是下降沿移入数据(从空闲高电平转为低电平),第二个边沿移出数据。

工作模式3:空闲状态的时钟信号为高电平,且在第二个边沿时刻进行数据移入,所以只能是上升沿移入数据(第二个边沿只能是上升了),第一个边沿移出数据。

2 代码配置

软件SPI代码设置

// 看引脚定义图
void MySPI_W_SS(uint8_t Value)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)Value);
}
void MySPI_W_SCK(uint8_t Value)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)Value);
}
void MySPI_W_MOSI(uint8_t Value)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)Value);
}
uint8_t MySPI_R_MISO_Byte(void)
{
	return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);
}
void MySPI_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//主机输出引脚位推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//主机输入引脚为上拉输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	MySPI_W_SS(1);
	MySPI_W_SCK(0);
	
}
void MySPI_Start(void)
{
	MySPI_W_SS(0);
}
void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}
uint8_t MySPI_SwapData(uint8_t ReturnData)//模式0,有点类似与I2C的接受字节取高位
{
	uint8_t i,ReceiveData = 0x00;
	for(i=0;i<8;i++)
	{
		MySPI_W_MOSI(ReturnData & (0x80 >> i));//取特定位
		MySPI_W_SCK(1);
		if(MySPI_R_MISO_Byte() == 1){ReceiveData |= (0x80 >> i);}//高位先行
		MySPI_W_SCK(0);
	}
	return ReceiveData;
}

硬件SPI初始化

 
void MySPI_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//主机输出引脚位推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//主机输入引脚为上拉输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128;
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;//第一个边沿开始采样,CPHA=0
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;//设置SCK空闲低电平
	SPI_InitStructure.SPI_CRCPolynomial=7;
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8为数据帧
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双线全双工
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//设置设备为主机
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);
	
	MySPI_W_SS(1);//默认设置SCK为高电平,不选择为从机
 
}

uint8_t MySPI_SwapData(uint8_t ReturnData)//模式0
{
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) != SET);//TXE会在写入数据后自动清除
	SPI_I2S_SendData(SPI1,ReturnData);//数据转移到移位寄存器
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);//RXNE会在读取数据后自动清除
	return SPI_I2S_ReceiveData(SPI1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值