完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
/* 自定义同义关键字 ——————————————————–*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus; /* 自定义参数宏 ——————————————————–*/ define BufferSize 32 /* 自定义函数宏 ——————————————————–*/ /* 自定义全局变量 ——————————————————–*/ SPI_InitTypeDef SPI_InitStructure; /* 定义 SPI 初始化结构体 */ u8 SPI1_Buffer_Tx[BufferSize] = /* 定义待 SPI1 传输数据 */ { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10, 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20 }; u8 SPI2_Buffer_Tx[BufferSize] = /* 定义待 SPI2 传输数据 */ { 0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60, 0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68, 0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70 }; u8 SPI1_Buffer_Rx[BufferSize]; /* 开辟内存空间待 SPI1 接收 */ u8 SPI2_Buffer_Rx[BufferSize]; /* 开辟内存空间待 SPI2 接收 */ u8 Tx_Idx = 0; /* 发送计数变量 */ u8 Rx_Idx = 0; /* 接收计数变量 */ vu8 k = 0 , i = 0; /* 循环计数变量 */ /* 自定义函数声明 ——————————————————–*/ void RCC_Configuration(void); void GPIO_Configuration(void); void SPI_Configuration(void); void USART_Configuration(void); /********************************************************************* * 函数名 : main * 函数描述 : main 函数 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ int main(void) { /* 设置系统时钟 */ RCC_Configuration(); /* 设置 GPIO 端口 */ GPIO_Configuration(); /* 设置 SPI */ SPI_Configuration(); /* 设置 USART */ USART_Configuration(); /* 设置 SPI2 为主机*/ SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_Init(SPI1, &SPI_InitStructure); /* 设置 SPI2 为从机*/ SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; SPI_Init(SPI2, &SPI_InitStructure); while(Tx_Idx 《 BufferSize) { /* 等待 SPI1 发送缓冲空 */ while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); /* SPI2 发送数据 */ SPI_I2S_SendData(SPI2, SPI2_Buffer_Tx[Tx_Idx]); /* SPI1 发送数据 */ SPI_I2S_SendData(SPI1, SPI1_Buffer_Tx[Tx_Idx++]); /* 等待 SPI2 接收数据完毕 */ while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); /* 读出 SPI2 接收的数据 */ SPI2_Buffer_Rx[Rx_Idx] = SPI_I2S_ReceiveData(SPI2); /* 等待 SPI1 接收数据完毕 */ while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); /* 读出 SPI1 接收的数据 */ SPI1_Buffer_Rx[Rx_Idx++] = SPI_I2S_ReceiveData(SPI1); } /* 打印试验结果信息 ---------------------------------------------------------------------------------------------*/ printf(“rnThe First transfer between the two SPI perpherals: The SPI1 Master and the SPI2 slaver. rn”); printf(“rnThe SPI1 has sended data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI1_Buffer_Tx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rnThe SPI2 has receive data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI2_Buffer_Rx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rn rn”); printf(“rnThe SPI2 has sended data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI2_Buffer_Tx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rnThe SPI1 has receive data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI1_Buffer_Rx + k)); for(i = 0 ; i 《 200 ; i ++); } /* 打印试验结果信息 ---------------------------------------------------------------------------------------------*/ Tx_Idx=0; Rx_Idx=0; for(k=0; k 《 BufferSize; k++) { *(SPI2_Buffer_Rx + k) = 0; } for(k=0; k 《 BufferSize; k++) { *(SPI1_Buffer_Rx + k) = 0; } /* 设置 SPI2 为主机*/ SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_Init(SPI2 , &SPI_InitStructure); /* 设置 SPI1 为从机*/ SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; SPI_Init(SPI1 , &SPI_InitStructure); while(Tx_Idx 《 BufferSize) { /* 等待 SPI2 发送缓冲空 */ while(SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_TXE) == RESET); /* SPI1 发送数据 */ SPI_I2S_SendData(SPI1 , SPI1_Buffer_Tx[Tx_Idx]); /* SPI2 发送数据 */ SPI_I2S_SendData(SPI2 , SPI2_Buffer_Tx[Tx_Idx++]); /* 等待 SPI1 接收数据完毕 */ while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); /* 读出 SPI1 接收的数据 */ SPI1_Buffer_Rx[Rx_Idx] = SPI_I2S_ReceiveData(SPI1); /* 等待 SPI2 接收数据完毕 */ while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); /* 读出 SPI2 接收的数据 */ SPI2_Buffer_Rx[Rx_Idx++] = SPI_I2S_ReceiveData(SPI2); } /* 打印试验结果信息 ---------------------------------------------------------------------------------------------*/ printf(“rn rnThe Second transfer between the two SPI perpherals: The SPI2 Master and the SPI1 slaver. rn”); printf(“rnThe SPI2 has sended data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI2_Buffer_Tx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rnThe SPI1 has receive data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI1_Buffer_Rx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rn rn”); printf(“rnThe SPI1 has sended data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI1_Buffer_Tx + k)); for(i = 0 ; i 《 200 ; i ++); } printf(“rnThe SPI2 has receive data below: rn”); for(k = 0; k 《 BufferSize ; k ++) { printf(“%0.2d r” , *(SPI2_Buffer_Rx + k)); for(i = 0 ; i 《 200 ; i ++); } /* 打印试验结果信息 ---------------------------------------------------------------------------------------------*/ while(1); } /********************************************************************* * 函数名 : RCC_Configuration * 函数描述 : 设置系统各部分时钟 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ void RCC_Configuration(void) { /* 定义枚举类型变量 HSEStartUpStatus */ ErrorStatus HSEStartUpStatus; /* 复位系统时钟设置 */ RCC_DeInit(); /* 开启 HSE */ RCC_HSEConfig(RCC_HSE_ON); /* 等待 HSE 起振并稳定 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* 判断 HSE 起是否振成功,是则进入if()内部 */ if(HSEStartUpStatus == SUCCESS) { /* 选择 HCLK(AHB)时钟源为SYSCLK 1分频 */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* 选择 PCLK2 时钟源为 HCLK(AHB) 1分频 */ RCC_PCLK2Config(RCC_HCLK_Div1); /* 选择 PCLK1 时钟源为 HCLK(AHB) 2分频 */ RCC_PCLK1Config(RCC_HCLK_Div2); /* 设置 FLASH 延时周期数为2 */ FLASH_SetLatency(FLASH_Latency_2); /* 使能 FLASH 预取缓存 */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* 使能 PLL */ RCC_PLLCmd(ENABLE); /* 等待 PLL 输出稳定 */ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 选择 SYSCLK 时钟源为 PLL */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 等待 PLL 成为 SYSCLK 时钟源 */ while(RCC_GetSYSCLKSource() != 0x08); } /* 打开 SPI2 时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); /* 打开 GPIOA,GPIOB,USART1 和 SPI1 时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1 |RCC_APB2Periph_SPI1, ENABLE); } /********************************************************************* * 函数名 : GPIO_Configuration * 函数描述 : 设置各GPIO端口功能 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ void GPIO_Configuration(void) { /* 定义 GPIO 初始化结构体 GPIO_InitStructure */ /* 设置 SPI1 引脚: SCK, MISO 和 MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); /* 设置 SPI2 引脚: SCK, MISO 和 MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOB, &GPIO_InitStructure); /* 设置 USART1 的Tx脚(PA.9)为第二功能推挽输出功能 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA , &GPIO_InitStructure); /* 设置 USART1 的Rx脚(PA.10)为浮空输入脚 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA , &GPIO_InitStructure); } /********************************************************************* * 函数名 : SPI_Configuration * 函数描述 : 设置 SPI 参数 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ void SPI_Configuration(void) { /* * SPI 设置为双线双向全双工 * SPI 发送接收 8 位帧结构 * 时钟悬空低 * 数据捕获于第二个时钟沿 * 内部 NSS 信号由 SSI 位控制 * 波特率预分频值为 4 * 数据传输从 LSB 位开始 * 用于 CRC 值计算的多项式 */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; SPI_InitStructure.SPI_CRCPolynomial = 7; /* 使能 SPI1 */ SPI_Cmd(SPI1, ENABLE); /* 使能 SPI2 */ SPI_Cmd(SPI2, ENABLE); } /********************************************************************* * 函数名 : USART_Configuration * 函数描述 : 设置USART1 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ void USART_Configuration(void) { /* 定义 USART 初始化结构体 USART_InitStructure */ USART_InitTypeDef USART_InitStructure; /* 波特率为115200bps; * 8位数据长度; * 1个停止位,无校验; * 禁用硬件流控制; * 禁止USART时钟; * 时钟极性低; * 在第2个边沿捕获数据 * 最后一位数据的时钟脉冲不从 SCLK 输出; */ USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No ; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1 , &USART_InitStructure); /* 使能 USART1 */ USART_Cmd(USART1 , ENABLE); } /********************************************************************* * 函数名 : fputc * 函数描述 : 将printf函数重定位到USATR1 * 输入参数 : 无 * 输出结果 : 无 * 返回值 : 无 *********************************************************************/ int fputc(int ch, FILE *f) { USART_SendData(USART1, (u8) ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; } 注意事项: 1、SPI设备在通信时,时钟由SPI主设备提供。因此,当SPI接口配置成从机模式时,对其频率进行设置的参数其实是无意义的。 2、若使用硬件CS模式,则需要加入对CS引脚的GPIO配置。 3、程序中遵循“先配置设置,后开启设备”的原则,即将设备配置完毕再行启用设备,在改动设备参数之前先行禁用设备。这个原则对绝大部分硬件平台上的设备仍然是适用的。 4、程序中使用了C语言的标准库函数memset来清零数组,对移植性要求不高的代码设计里,使用这个的库函数可以轻易减少大量代码,同时不会损失太多效率,建议读者灵活运用。 5、程序中将SPI设备的时钟分频数设置为4,并在前文计算出了此参数下各自的sclk频率。 但不要尝试将分频数设置为2,因为此时SPI1的SCLK频率将达到36MHZ——这已经和SPI2设备所能接受的SCLK最高频率持平,这样可能会影响SPI通信的稳定性。读者在以后无论使用任何硬件的设备,同样要考虑这样的问题,在正式应用中尽量不要逼近器件的极限承受能力(比如对CPU进行超频)。 6、在有2个spi接口的stm32版本里,spi2和spi3的部引脚和JTAG接口引脚存在复用的情况。当stm32复位后这些引脚会保持在JTAG功能模式中。这样无论是调试或非调试期间spi2和spi3接口都无法使用,可以采用如下解决方法: 一、在调试期间使用SWD接口调试; 二、在正式应用后将JTAG关闭; 三、将spi2、spi3或JTAG引脚重映射至其他口。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1659 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1571 浏览 1 评论
998 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
695 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1617 浏览 2 评论
1877浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
663浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
529浏览 3评论
548浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
517浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-29 23:20 , Processed in 0.951192 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号