STM32SPI外设介绍
1、SPI通信协议
SPI通信协议是同步,全双工通信协议,四根通信线(SS、SCK、MOSI、MISO),支持总线挂载多设备。本质是交换字节,高位先行,指令码加数据的方式。
SS:片选线,低电平有效
SCK:时钟线
MOSI:主机输出从机输入
MISO:主机输入从机输出
从机未被选中时,MISO为高阻态,不输出电平
SPI时序基本单元
起始条件:SS从高电平切换到低电平
终止条件:SS从低电平切换到高电平
有四个模式
模式0:
CPOL=0:空闲状态下,SCK为低电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
模式1:
CPOL=0:空闲状态下,SCK为低电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
模式2:
CPOL=1:空闲状态下,SCK为高电平
CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据
模式3:
CPOL=1:空闲状态下,SCK为高电平
CPHA=1:SCK第一个边沿移出数据,第二个边沿移入数据
指定地址写:发送写指令,在指定地址下写数据
指定地址读:发送读指令,在指定地址下读数据
2、STM32SPI外设资源
STM32F103C8T6有两个SPI外设资源:SPI1、SPI2,SPI1_SS对应引脚配置为PA4,SPI1_SCK对应引脚配置为PA5,SPI1_MISO对应引脚配置为PA6,SPI1_MOSI对应引脚配置为PA7。SPI2_SS对应引脚配置为PB12,SPI2_SCK对应引脚配置为PB13,SPI2_MISO对应引脚配置为PB14,SPI2_MOSI对应引脚配置为PB15。可配置8/16位数据帧,高位先行/低位先行,支持多主机模型,主或从操作。
3、软件模拟SPI通信
1、配置时钟和引脚配置
软件模拟引脚任意,这里选用PA4、PA5、PA6、PA7。输出引脚为推挽输出,输入引脚为浮空或上拉。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
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);
2、函数封装,实现对通信线的电平读取写入操作
void MySPI_SS(uint8_t BitValue) //SS配置为PA4
{
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction) BitValue);
}
void MySPI_CLK(uint8_t BitValue) //SCK配置为PA5
{
GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction) BitValue);
}
void MySPI_DI(uint8_t BitValue) // MOSI配置为PA7
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction) BitValue);
}
uint8_t MySPI_DO(void) //MISO配置为PA6
{
return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);
}
3、空闲状态
SS高电平,SCK低电平,模式0
MySPI_SS(1);
MySPI_CLK(0);
4、起始条件
MySPI_SS(0);
5、终止条件
MySPI_SS(1);
6、交换字节
主机发送数据,和从机发送的数据进行交换,主机接收从机发送的数据
uint8_t i,ByteReceive=0x00;
for(i=0;i<8;i++)
{
MySPI_DI(ByteSend&(0x80>>i));
MySPI_CLK(1);
if(MySPI_DO()==1){ByteReceive|=(0x80>>i);}
MySPI_CLK(0);
}
return ByteReceive;
4、硬件SPI通信(基于标准库,STM32作为主机)
1、时钟和引脚配置
选用SPI1外设,SS软件模拟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitTypeDef 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);
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_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
2、SPI结构体配置
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128; //128分频
SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge; //第一个边沿开始采样
SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //模式0
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; //SS软件触发
SPI_Init(SPI1,&SPI_InitStructure);
3、SPI使能
起始和终止直接对SS进行操作即可
SPI_Cmd(SPI1,ENABLE);
MySPI_SS(1);
4、交换字节
TXE、RXNE标志位不需要手动清除
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==!SET); //等待TXE为1
SPI_I2S_SendData(SPI1,ByteSend);
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==!SET); //等待RXNE为1
return SPI_I2S_ReceiveData(SPI1);