完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
目标:
实现spi的Master端。 这篇文章讲的非常直观易懂,看完就明白了。 1、首先配置口线,串口用来输入和打印,四个io口用来模拟spi,原本准备在一个单片机上同时模拟主从,但貌似不太可行,这种模拟的方式都是阻塞的。 2、proteus连接口线,放spi调试器和示波器,本来准备放个逻辑分析仪,但既然有spi调试器,用起来更方便,就没弄逻辑分析仪。 3、打开cubemx生成的工程,首先修改 main.h,加入口线的控制函数: /* Private defines -----------------------------------------------------------*/ #define MASTER_CLK_Pin GPIO_PIN_1 #define MASTER_CLK_GPIO_Port GPIOC #define MOSI_Pin GPIO_PIN_2 #define MOSI_GPIO_Port GPIOC #define MISO_Pin GPIO_PIN_3 #define MISO_GPIO_Port GPIOC #define CS_Pin GPIO_PIN_4 #define CS_GPIO_Port GPIOC /* USER CODE BEGIN Private defines */ #define SCLK_SET_H HAL_GPIO_WritePin(MASTER_CLK_GPIO_Port, MASTER_CLK_Pin, GPIO_PIN_SET) #define SCLK_SET_L HAL_GPIO_WritePin(MASTER_CLK_GPIO_Port, MASTER_CLK_Pin, GPIO_PIN_RESET) #define MOSI_SET_H HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET) #define MOSI_SET_L HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET) #define MISO_READ HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin) #define CS_H HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) #define CS_L HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) uint8_t SPI_RW_BYTE_MODE0(uint8_t data); uint8_t SPI_RW_BYTE_MODE1(uint8_t data); uint8_t SPI_RW_BYTE_MODE2(uint8_t data); uint8_t SPI_RW_BYTE_MODE3(uint8_t data); void SPI_WRITE_BUF_MODE0(uint8_t *pData,int len); void SPI_WRITE_BUF_MODE1(uint8_t *pData,int len); void SPI_WRITE_BUF_MODE2(uint8_t *pData,int len); void SPI_WRITE_BUF_MODE3(uint8_t *pData,int len); 4、在主函数中,实现四种模式的单字节收发函数: 在实现函数之前,请了解spi协议的时序,以及四种模式,本文侧重仿真测试,不做具体原理讲解: CPOL = 0 时,时钟在逻辑 0 处空闲: MODE0: CPOL = 0,CPHA = 0,数据会在 SCK的 上升沿采样,下降沿变化。 MODE1: CPOL = 0,CPHA = 1,数据会在 SCK的 下降沿采样,上升沿变化。 CPOL = 1时,时钟在逻辑高电平处空闲: MODE2: CPOL = 1,CPHA = 0,数据会在 SCK的 下降沿采样,上升沿变化。 MODE3: CPOL = 1,CPHA = 1,数据会在 SCK的 上升沿采样,下降沿变化。 /*MODE0: CPOL = 0,CPHA = 0,数据会在 SCK的 上升沿采样,下降沿变化。 /* MODE0: CPOL = 0,CPHA = 0,数据会在 SCK的 上升沿采样,下降沿变化。 sck: -------- -------- | | | | --- ------- mosi: ---------- | | --------------- miso: ---------- | | --------------- */ uint8_t SPI_RW_BYTE_MODE0(uint8_t data) { uint8_t i; uint8_t output=0; SCLK_SET_H; SPIDelay; CS_L; SPIDelay; for(i=0;i<8;i++) { SCLK_SET_L; SPI_SEND_BIT(data); //下降沿发送 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 SCLK_SET_H; SPI_READ_BIT(output);//上升沿采样,注意,必须先准备好数据,再才升上升沿,否则会出现第一个包不正确的情况。 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 } SCLK_SET_L; SPIDelay; CS_H; SPIDelay; return output; } /* MODE1: CPOL = 0,CPHA = 1,数据会在 SCK的 下降沿采样,上升沿变化。 sck: -------- ------- | | | --- ------- mosi: --- ------- |_____________| miso: --- ------- |_____________| */ uint8_t SPI_RW_BYTE_MODE1(uint8_t data) { uint8_t i; uint8_t output=0; SCLK_SET_L; SPIDelay; CS_L; SPIDelay; for(i=0;i<8;i++) { SCLK_SET_H; SPI_SEND_BIT(data); //上升沿发送 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 SCLK_SET_L; SPI_READ_BIT(output);//下降沿采样 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 } SCLK_SET_L; SPIDelay; CS_H; SPIDelay; return output; } /* MODE2: CPOL = 1,CPHA = 0,数据会在 SCK的 下降沿采样,上升沿变化。 sck: --- -------- | | | -------- --- mosi: --------- | ---------- miso: --------- | ---------- */ uint8_t SPI_RW_BYTE_MODE2(uint8_t data) { uint8_t i; uint8_t output=0; SCLK_SET_L; SPIDelay; CS_L; SPIDelay; for(i=0;i<8;i++) { SCLK_SET_H; SPI_SEND_BIT(data); //上升沿发送 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 SCLK_SET_L; SPI_READ_BIT(output);//下降沿采样 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 } SCLK_SET_H; SPIDelay; CS_H; SPIDelay; return output; } /* MODE3: CPOL = 1,CPHA = 1,数据会在 SCK的 上升沿采样,下降沿变化。 sck: --- -------- | | | -------- --- mosi: --- --- | | --------------- miso: --- --- | | --------------- */ uint8_t SPI_RW_BYTE_MODE3(uint8_t data) { uint8_t i; uint8_t output=0; SCLK_SET_H; SPIDelay; CS_L; SPIDelay; for(i=0;i<8;i++) { SCLK_SET_L; SPI_SEND_BIT(data); //下降沿发送 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 SCLK_SET_H; SPI_READ_BIT(output); //上升沿采样 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 } SCLK_SET_H; SPIDelay; CS_H; SPIDelay; return output; } 5、修改串口测试程序,用于发送spi命令: switch(aRxBuffer){ case 'a': ret=SPI_RW_BYTE_MODE0(0x0a); snprintf(( char *)output,sizeof(output),"mode0,ret=0x%02xrn",ret); len = strlen(output); break; case 'b': ret=SPI_RW_BYTE_MODE1(0x0b); snprintf(( char *)output,sizeof(output),"mode1,ret=0x%02xrn",ret); len = strlen(output); break; case 'c': ret=SPI_RW_BYTE_MODE2(0x0c); snprintf(( char *)output,sizeof(output),"mode2,ret=0x%02xrn",ret); len = strlen(output); break; case 'd': ret=SPI_RW_BYTE_MODE3(0x0d); snprintf(( char *)output,sizeof(output),"mode3,ret=0x%02xrn",ret); len = strlen(output); break; case 'e': SPI_WRITE_BUF_MODE0(buf,sizeof(buf)); goto END; case 'f': SPI_WRITE_BUF_MODE1(buf,sizeof(buf)); goto END; case 'g': SPI_WRITE_BUF_MODE2(buf,sizeof(buf)); goto END; case 'h': SPI_WRITE_BUF_MODE3(buf,sizeof(buf)); goto END; default: snprintf(( char *)output,sizeof(output),"no supported commandrn"); len = strlen(output); break; } 6、仿真测试结果: 7、可以双击spi访问器件,修改极性和相位,分别测试四种模式: 8、在上述工程基础上,加上buffer写入的方式: void SPI_WRITE_BUF_MODE0(uint8_t *pData,int len) { int i,j; uint8_t data = 0; SCLK_SET_H; SPIDelay; CS_L; SPIDelay; for(i=0;i for(j=0;j<8;j++) { SCLK_SET_L; SPI_SEND_BIT(data); //下降沿发送 SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 SCLK_SET_H; SPIDelay; //每次时钟变化之前,进行delay,确保数据稳定,对方有足够的采样时间 } } SCLK_SET_L; SPIDelay; CS_H; SPIDelay; } 9、压力测试结果: 256个字节确认收到无误! 以上是整个实验过程,相关代码和仿真设计,请到如下地址下载(没积分也是苦恼,为了能下点东西,象征性收取1个积分,请见谅!): |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1771 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1070 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1936浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
729浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
569浏览 3评论
594浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
552浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:46 , Processed in 0.723562 second(s), Total 46, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号