完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
SPI (Serial Peripheral interface)是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
今天分享下,基于STM32F103C8T6工控板上的两个SPI接口进行互相通讯,其中SPI1作为主机,SPI2作为从机。 硬件部分 1)某宝网上购买的STM32F103C8T6工控板,价格50¥左右; 2)某宝网上购买的232转USB数据线(如下图所示),价格15¥左右; 3)杜邦线若干,价格几乎为0¥。 硬件连接 由原理图(如下所示)可知,将PA5与PB13连接,PA6与PB14连接,PA7与PB15连接即可。注意:SPI与串口的连接不同,串口的RX引脚接另一个串口TX引脚,而两个SPI连接是同名字的相连! 部分代码 spi.h头文件 /** ******************************** STM32F10x ********************************* * @文件名称: spi.h * @作者名称: 闲人Ne * @摘要简述: SPI头文件 ******************************************************************************/ #ifndef __SPI_H #define __SPI_H /* 包含的头文件 ---------------------------------------------------------------*/ #include “stm32f10x.h” /* 函数申明 -------------------------------------------------------------------*/ void SPI1_Init(void); void SPI2_Init(void); u8 SPI1_ReadWriteByte(u8 TxData); u8 SPI2_ReadWriteByte(u8 TxData); #endif /* __SPI_H */ /****** Copyright (C)2021 闲人Ne. All Rights Reserved ****** END OF FILE *******/ spi.c源文件 /** ******************************** STM32F10x ********************************* * @文件名称: spi.c * @作者名称: 闲人Ne * @摘要简述: SPI头文件 ******************************************************************************/ /* 包含的头文件 ---------------------------------------------------------------*/ #include “spi.h” /************************************************** 函数名称:SPI1_Init() 函数功能:SPI1初始化函数:配置成主机模式 入口参数:无 返回参数:无 开发作者:闲人Ne ***************************************************/ void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); // GPIOA时钟使能,选择SPI1,对应PA4,PA5,PA6,PA7 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE ); // SPI1时钟使能 // 初始化GPIOA,PA5/6/7都设置复用推挽输出AF_PP GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出AF_PP GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); // PA5/6/7置高电平 // 初始化SPI函数 SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 设置SPI单向或双向的数据模式:SPI设置为双线双向全双工 SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // SPI1设为主机 SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // 针对SPI_CR1寄存器的DFF位,设置数据帧大小为8位 SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; // 针对SPI_CR1寄存器的CPOL位,串行同步时钟的空闲状态为高电平 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; // 针对SPI_CR1寄存器的CPHA位,串行同步时钟的第二个跳变沿(即上升沿)数据被采样 SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // 针对SPI_CR1寄存器的SSM位,NSS信号由软件(使用SSI位)管理 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // 针对SPI_CR1寄存器的BR位,波特率预分频值为256,最低速率 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; // 针对SPI_CR1寄存器的LSBFIRST位,数据传输从MSB位开始 SPI_InitStruct.SPI_CRCPolynomial = 7; // 针对SPI_CRCPR寄存器的CRCPOLY位,设为0x0007,为复位值 SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); // 使能SPI外设 } /************************************************** 函数名称:u8 SPI1_ReadWriteByte(u8 TxData) 函数功能:SPI1读写一个字节函数 入口参数:TxData:要写入的字节 返回参数:读取到的字节 开发作者:闲人Ne ***************************************************/ u8 SPI1_ReadWriteByte(u8 TxData) { u8 retry=0; // 检查SPI_SR寄存器的TXE位(发送缓冲为空),其值0时为非空,1时为空 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) { retry++; // 发送缓冲为空时,retry++ if(retry》200)return 0; } SPI_I2S_SendData(SPI1, TxData); // 通过外设SPI2发送一个数据 retry=0; // 检查SPI_SR寄存器的RXNE位(接收缓冲为空),其值0时为空,1时为非空 while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) { retry++; // 当接收缓冲为非空时,retry++ if(retry》200)return 0; } return SPI_I2S_ReceiveData(SPI1); // 返回通过SPIx最近接收的数据 } /************************************************** 函数名称:SPI2_Init() 函数功能:SPI2初始化函数:配置成从机模式 入口参数:无 返回参数:无 开发作者:闲人Ne ***************************************************/ void SPI2_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); // GPIOB时钟使能,选择SPI2,对应PB12,PB13,PB14,PB15 RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE ); // SPI2时钟使能 // 初始化GPIOB,PB13/14/15都设置复用推挽输出AF_PP,PB14对应MISO,最好设为带上拉输入 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出AF_PP GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); // PB13/14/15置高电平 // 初始化SPI函数 SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 设置SPI单向或双向的数据模式:SPI设置为双线双向全双工 SPI_InitStruct.SPI_Mode = SPI_Mode_Slave; // SPI2设为从机 SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // 针对SPI_CR1寄存器的DFF位,设置数据帧大小为8位 SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; // 针对SPI_CR1寄存器的CPOL位,串行同步时钟的空闲状态为高电平 SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; // 针对SPI_CR1寄存器的CPHA位,串行同步时钟的第二个跳变沿(即上升沿)数据被采样 SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; // 针对SPI_CR1寄存器的SSM位,NSS信号由软件(使用SSI位)管理 SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // 针对SPI_CR1寄存器的BR位,波特率预分频值为256,最低速率 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; // 针对SPI_CR1寄存器的LSBFIRST位,数据传输从MSB位开始 SPI_InitStruct.SPI_CRCPolynomial = 7; // 针对SPI_CRCPR寄存器的CRCPOLY位,设为0x0007,为复位值 SPI_Init(SPI2, &SPI_InitStruct); SPI_Cmd(SPI2, ENABLE); // 使能SPI外设 } /************************************************** 函数名称:u8 SPI1_ReadWriteByte(u8 TxData) 函数功能:SPI1读写一个字节函数 入口参数:TxData:要写入的字节 返回参数:读取到的字节 开发作者:闲人Ne ***************************************************/ u8 SPI2_ReadWriteByte(u8 TxData) { u8 retry=0; // 检查SPI_SR寄存器的TXE位(发送缓冲为空),其值0时为非空,1时为空 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) { retry++; // 发送缓冲为空时,retry++ if(retry》200)return 0; } SPI_I2S_SendData(SPI2, TxData); // 通过外设SPI2发送一个数据 retry=0; // 检查SPI_SR寄存器的RXNE位(接收缓冲为空),其值0时为空,1时为非空 while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) { retry++; // 当接收缓冲为非空时,retry++ if(retry》200)return 0; } return SPI_I2S_ReceiveData(SPI2); // 返回通过SPIx最近接收的数据 } /****** Copyright (C)2021 闲人Ne. All Rights Reserved ****** END OF FILE *******/ main.c主函数 /** ******************************** STM32F10x ********************************* * @文件名称: main.c * @作者名称: 闲人Ne * @库版本号: V3.5.0 * @工程版本: V1.0.0 * @开发日期: 2021年02月17日 * @摘要简述: 主函数 ******************************************************************************/ /* 包含的头文件 ---------------------------------------------------------------*/ #include “led.h” #include “spi.h” #include “serial_communication.h” #include “sys.h” #include “delay.h” #include “nvic_configuration.h” /************************************************ 函数名称:int main() 函数功能:主函数入口 入口参数:无 返回参数:int 开发作者:闲人Ne *************************************************/ u8 spi1_sand_data=0; u8 spi2_sand_data=100; u8 spi2_receive_data; u8 spi1_receive_data; int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); SPI1_Init(); SPI2_Init(); My_USART1_Init(); D1=1; while(1) { spi1_receive_data=SPI1_ReadWriteByte(spi1_sand_data); printf(“nSP1接收的数据为:%drn”,spi1_receive_data); spi2_receive_data=SPI2_ReadWriteByte(spi2_sand_data); printf(“nSP2接收的数据为:%drn”,spi2_receive_data); spi1_sand_data++; spi2_sand_data++; delay_ms(500); } } /****** Copyright (C)2021 闲人Ne. All Rights Reserved ****** END OF FILE *******/ 实验结果 实验结果完全符合逻辑,通讯成功! 经验分享 该程序可作为双芯片之间SPI通讯的参考代码。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1649 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1566 浏览 1 评论
994 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
693 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1613 浏览 2 评论
1871浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
656浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
526浏览 3评论
543浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
515浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 08:46 , Processed in 1.003723 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号