本着学习一门技术就掌握一门技术的态度,我打算把我自己的学习经历记录下来,对我的学习也会很有帮助
对于协议的学习,我发现通过gpio口模拟协议的方式,能让我们对协议的理解更加通透。
一、SPI协议简介
1、需要几根线:SPI是由SCK、MOSI、MISO、CS
及时钟、数据(主出从入线、从出主入线)、片选三种线组成,有很多时候数据线只需要一条,因为从机可能不需要返回数据。
2、传输位数:通常SPI的传输位数是8位,但是由于从机设备类目多可能会有9位或者别的数据长度。
3、传输的数据类型:通常分为命令和数据,所以有9位之分,通常最高位为区分位。
二、 SPI的优缺点
2.1 优点
1):支持全双工通信
2):通信简单
3):数据传输速率快
** **2.2 缺点
没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据
可靠性上有一定的缺陷。
三、配置SPI的重要参数
3.1、参数解释
- CPOL:总线空闲时的电平高低
- CPHA:在一个时钟周期里,是第一个跳变沿还是第二个跳变沿读取数据(0,1)
- MSB:高位在前还是低位在前
3.2、在qubemx里的设置
- **FIFOThreshold **: 这可能指的是FIFO(First In, First Out)的阈值设置,当FIFO中的数据达到某个特定的水平时,触发某些动作(如中断或数据发送)。
- TXCRCInitializationPattern AllZeroPattern: 通常是指发送方CRC(Cyclic Redundancy Check)初始化的模式。AllZeroPattern意味着在开始进行CRC计算之前,CRC寄存器被初始化为全0的模式。
- RXCRCInitializationPattern AllZeroPattern: 这与TXCRCInitializationPattern相似,但适用于接收方。接收方CRC也被设置为在开始进行CRC校验之前初始化为全0。
- NSSPolarity NSSPolarityLow: 在SPI通信中,NSS(或CS/SS)的极性设置决定了外设被选中时NSS引脚的电平状态。NSSPolarityLow意味着当NSS引脚为低电平时,外设被选中。
- MasterSSIdleness 00Cycle: 这可能指的是在SPI通信中,主设备在释放NSS信号后需要保持空闲状态的周期数。00Cycle可能意味着没有额外的空闲周期。
- MasterInterDataIdleness 00Cycle: 类似于MasterSSIdleness,这可能指的是主设备在连续数据传输之间需要保持空闲状态的周期数。
- MasterReceiverAutoSusp Disable: 这个设置可能与自动暂停接收数据的功能有关。Disable意味着这个功能被关闭,也就是说接收器不会在特定条件下自动暂停接收数据。
- MasterKeepIOState MasterKeepIOStateDisable: 这可能指控制SPI主设备的I/O状态是否保持不变。MasterKeepIOStateDisable意味着主设备不会在传输结束后保持I/O引脚的状态。
- OSwap Disabled: 这可能是指一个选项,用于在特定的硬件配置中交换某些操作的顺序。Disabled意味着这种操作交换没有被激活。
四、实际举例数据
1、一桢完整数据
五、通过gpio口模拟spi通讯
1、代码
// 假设以下宏定义了对应的GPIO操作
#define CSB_LOW() HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_RESET)
#define CSB_HIGH() HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_SET)
#define SCLB_LOW() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET)
#define SCLB_HIGH() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET)
#define SDI_LOW() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_RESET)
#define SDI_HIGH() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_SET)
#define LCD_RESET_LOW() HAL_GPIO_WritePin(GPIOH, GPIO_PIN_8, GPIO_PIN_RESET) // RESET置低
#define LCD_RESET_HIGH() HAL_GPIO_WritePin(GPIOH, GPIO_PIN_8, GPIO_PIN_SET) // RESET置高
void SPI_SendData(uint8_t cmd)//数据传输函数
{
for (uint8_t i = 0; i < 8; i++)
{
if(cmd&0x80) SDI_HIGH();//通过与命令读取最高位,如果为1则拉高数据线电平
else SDI_LOW();如果为0则拉高数据线电平
cmd<<= 1;//操作完一位以后,整个左移一位最高位舍弃
SCLB_LOW();//_nop_(); _nop_();_nop_();_nop_();
__nop();//通过执行空语句实现跳变沿更加清晰
SCLB_HIGH();//_nop_();_nop_();_nop_();_nop_();
}
}
void LCD_WriteCommand(uint8_t cmd) {
CSB_LOW(); // 激活LCD
SDI_LOW(); // 如果是0,则设置数据线低电平
//上面两行是数据线(命令或数据区分)准备阶段
SCLB_LOW(); // 拉低时钟
__nop();
SCLB_HIGH(); // 拉高时钟以采样数据
//数据准备好以后通过上面两行产生跳变沿
//前面发送的数据是命令或数据的区分线
SPI_SendData(cmd);//发送实际的8位数据
CSB_HIGH(); // 取消LCD激活
}
void LCD_WriteData(uint8_t data) {
CSB_LOW(); // 激活LCD
SDI_HIGH(); // 如果是0,则设置数据线低电平
SCLB_LOW(); // 拉低时钟
__nop();
SCLB_HIGH(); // 拉高时钟以采样数据
SPI_SendData(data);
CSB_HIGH(); // 取消LCD激活
}