SPI通信协议
SPI通信协议
- 软件SPI
全双工,一主多从,同步。
四根线:片选SS(CS),主发从收MOSI(DO),主收从收MISO(DI),时钟SCK。
一共四种模式:
CPOL | 0 | 1 |
---|---|---|
CPHA | ||
0 | 空闲状态下,SCL-低;第0个边缘移出数据(SS的下降沿);第1个边沿移入数据;第二个边沿移出数据;… | 空闲状态下,SCL-高;第0个边缘移出数据(SS的下降沿);第1个边沿移入数据;第二个边沿移出数据;… |
1 | 空闲状态下,SCL-低;;第1个边沿移出数据;第二个边沿移入数据… | 空闲状态下,SCL-高;;第1个边沿移出数据;第二个边沿移入数据… |
软件SPI
引脚初始化
// CS:
void MySPI_W_SS(u8 BitValue)
{//根据BitValue,设置SS引脚的电平GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}
// SCK
void MySPI_W_SCK(uint8_t BitValue)
{//根据BitValue,设置SCK引脚的电平GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}
//MOSI
void MySPI_W_MOSI(uint8_t BitValue)
{//根据BitValue,设置MOSI引脚的电平,BitValue要实现非0即1的特性GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}
//MISO
uint8_t MySPI_R_MISO(void)
{//读取MISO电平并返回return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}
void MySPI_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/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); //将PA4、PA5和PA7引脚初始化为推挽输出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); //将PA6引脚初始化为上拉输入/*设置默认电平*///SS默认高电平MySPI_W_SS(1);
#if mode == 0 || mode == 1//SCK默认低电平 MySPI_W_SCK(0);
#elif mode == 2 || mode == 3//SCK默认高电平 MySPI_W_SCK(1);
#endif}
协议层:
//开始
void MySPI_Start(void)
{MySPI_W_SS(0); //拉低SS,开始时序
}
//停止
void MySPI_Stop(void)
{MySPI_W_SS(1); //拉高SS,终止时序
}
交换一个字节
模式0:
SCK-空闲状态默认为零。
从第0个边沿开始移出,然后依次移入,移出
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i,ByteReceive = 0x00;//前面是开始信号,SS被拉低相当与第0个边沿for(i=0;i<8;i++) //接收一个字节 8位{MySPI_W_MOSI(ByteSend & (0x80 >> i)); //移出MySPI_W_SCK(1); //下一个边沿 开始移入//当MISO为1时,置变量指定位为1,当MISO为0时,不做处理,指定位为默认的初值0if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);} //移入MySPI_W_SCK(0); //再来一个边沿,数据切换变成移出}//返回接收到的一个字节数据return ByteReceive;
}
模式1:
SCK-空闲状态默认为零。
从第1个边沿开始移出,然后依次移入,移出.
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i,ByteReceive = 0x00;for(i=0;i<8;i++) //接收一个字节 8位{ MySPI_W_SCK(1); //第一个边沿 移出MySPI_W_MOSI(ByteSend & (0x80 >> i)); //移出MySPI_W_SCK(0); //再来一个边沿,数据切换变成移入if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);} //移入}//返回接收到的一个字节数据return ByteReceive;
}
模式2:
SCK-空闲状态默认为高。
从第0个边沿开始移除,然后依次移入,移出.
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i,ByteReceive = 0x00;//前面是开始信号,SS被拉低相当与第0个边沿for(i=0;i<8;i++) //接收一个字节 8位{MySPI_W_MOSI(ByteSend & (0x80 >> i)); //移出MySPI_W_SCK(0); //下一个边沿 开始移入//当MISO为1时,置变量指定位为1,当MISO为0时,不做处理,指定位为默认的初值0if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);} //移入MySPI_W_SCK(1); //再来一个边沿,数据切换变成移出}//返回接收到的一个字节数据return ByteReceive;
}
模式3:
SCK-空闲状态默认为零。
从第1个边沿开始移出,然后依次移入,移出.
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i,ByteReceive = 0x00;for(i=0;i<8;i++) //接收一个字节 8位{ MySPI_W_SCK(0); //第一个边沿 移出MySPI_W_MOSI(ByteSend & (0x80 >> i)); //移出MySPI_W_SCK(1); //再来一个边沿,数据切换变成移入if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);} //移入}//返回接收到的一个字节数据return ByteReceive;
}