ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

硬件SPI和软件模拟SPI在配置方面的一点区别

硬件SPI和软件模拟SPI在配置方面的一点区别 一 硬件SPI和软件SPI顾名思义这种方式是硬件层面的需要开启并使用单片机里面的SPI外设IO口要复用到外设由外设来控制电平翻转软件模拟就可以随便选择IO口进行配置需要手动控制电平翻转硬件接线我使用的是外接Flash模块无论是硬件还是软件接线都使用的是相同的IO口对应关系A4-CSA5-SCK时钟线A6-MISO-D0A7-MOSI-D1 接线口诀主机MOSI接从机DI 主机 MISO接从机DO二 配置GPIO配置IO文字描述配置GPIO口把CS SCK MOSI配置为推挽输出把MISO配置为浮空输入默认CS高电平抬起不选中状态硬件版本void W25Q_SPI_Init(void){GPIO_InitTypeDef GPIO_InitStruct;SPI_InitTypeDef SPI_InitStruct;// 开启时钟GPIOA、SPI1SPI1属于APB2RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);// PA5 SCK、PA7 MOSI复用推挽输出 AF_PPGPIO_InitStruct.GPIO_Pin SPI_SCK_PIN | SPI_MOSI_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(SPI_GPIO_PORT, GPIO_InitStruct);// PA6 MISO浮空输入GPIO_InitStruct.GPIO_Pin SPI_MISO_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(SPI_GPIO_PORT, GPIO_InitStruct);// PA4 CS普通推挽输出GPIO_InitStruct.GPIO_Pin FLASH_CS_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(FLASH_CS_PORT, GPIO_InitStruct);FLASH_CS_H(); // 默认片选拉高不选中Flash// SPI配置SPI_InitStruct.SPI_Direction SPI_Direction_2Lines_FullDuplex;SPI_InitStruct.SPI_Mode SPI_Mode_Master;SPI_InitStruct.SPI_DataSize SPI_DataSize_8b;SPI_InitStruct.SPI_CPOL SPI_CPOL_Low; // CPOL0 空闲SCK低SPI_InitStruct.SPI_CPHA SPI_CPHA_1Edge; // CPHA0 第一个边沿采样Mode0SPI_InitStruct.SPI_NSS SPI_NSS_Soft; // 软件管理片选SPI_InitStruct.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_4; //72M/418MSPI_InitStruct.SPI_FirstBit SPI_FirstBit_MSB; //高位先发Flash强制要求SPI_InitStruct.SPI_CRCPolynomial 7;SPI_Init(SPI1, SPI_InitStruct); //硬件SPI必须调用SPI_InitSPI_Cmd(SPI1, ENABLE); //使能SPI外设}软件模拟版本//软件模拟SPI初始化void W25Q_SPI_Init(void){GPIO_InitTypeDef GPIO_InitStruct;// 只开启GPIOA时钟删掉SPI1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// SCK PA5、MOSI PA7推挽输出GPIO_InitStruct.GPIO_Pin SPI_SCK_PIN | SPI_MOSI_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(SPI_GPIO_PORT, GPIO_InitStruct);// MISO PA6浮空输入GPIO_InitStruct.GPIO_Pin SPI_MISO_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(SPI_GPIO_PORT, GPIO_InitStruct);// CS PA4推挽输出GPIO_InitStruct.GPIO_Pin FLASH_CS_PIN;GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(FLASH_CS_PORT, GPIO_InitStruct);FLASH_CS_H(); // 默认片选拉高}三 收发字节函数的区别收发字节文字描述发送一字节数据函数有返回值因为是全双工 有发送就有接收要发送的数据作为函数参数传入通过循环从最高位开始发送数据每次都要提取出最高位数据进行发送然后发送数据左移一位选择模式0 就是上升沿采样SCK输出高电平保持不变读取MISO电平进行或操作拼接接收电平数据SCK输出低电平 停止采样保持一段时间后进行下一轮数据的发送和读取硬件版本uint8_t SPI_RW_Byte(uint8_t txDat){//等待发送缓冲区为空while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) RESET);SPI_I2S_SendData(SPI1, txDat);//等待接收完成while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) RESET);return SPI_I2S_ReceiveData(SPI1);}软件模拟版本uint8_t SPI_RW_Byte(uint8_t txdata){uint8_t i;uint8_t rxData 0;for(i 0;i8;i){if(txdata 0x80){GPIO_SetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);}else{GPIO_ResetBits(SPI_GPIO_PORT, SPI_MOSI_PIN);}txdata 1;GPIO_SetBits(SPI_GPIO_PORT, SPI_SCK_PIN);delay_us(2);//延时函数可以去掉 我加上是为了健壮性rxData 1;if(GPIO_ReadInputDataBit(SPI_GPIO_PORT, SPI_MISO_PIN)){rxData | 0x01;}GPIO_ResetBits(SPI_GPIO_PORT, SPI_SCK_PIN);delay_us(2);//同理为了健壮性}return rxData;}这个SPI手写时序虽然最开始也是参照AI和现成代码写出来的但是我会一行一行的理解然后独立参照datasheet写出来刚开始接触的时候确实感觉很难但现在感觉好一点了
返回列表