程序员开发实例大全宝库

网站首页 > 编程文章 正文

心仪M7--STM32F769I-DISCO评测-SPI通讯

zazugpt 2024-08-27 23:53:28 编程文章 18 ℃ 0 评论

本次我们介绍 SPI通讯。

基础:

有关串行外设接口SPI (Serial Peripheral Interface)的资料很多,这里只作简单的说明。

我们知道所有数字信号的核心就是0、1(低高)及其随时间变化,SPI的关键词是主从(main/slave)、SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)、模式mode,主从(main/slave)确定谁是通讯时钟、片选的控制发起方,SDI(数据输入MISO)、SDO(数据输出MOSI)配合时钟SCLK(时钟)串行变化代表数据的串行传输。模式mode则代表SDI(数据输入)、SDO(数据输出)和时钟SCLK(时钟)的状态关系以确定数据在什么时侯写出传送、什么时侯读取采样获得。 其中,规划SPI通讯的重点是模式mode:即未通讯时时钟空闲状态是0还是1(称作时钟极性CPOL, Clock polarity)、从空闲idle状态跳到活动active态还是从活动active态跳回空闲状态时采样数据对应0还是1(称作时钟相位CPHA, clock phase)。确定了这个模式和时钟频率,主从方才能以统一步调节奏协调通讯。   (我们知道数字信号总共有四种状态:高、低两个level,低跳高、高跳低两个边沿edge,通常我们用edge做触发用,level做保持稳定用,至于和时间的配合就是频率、占空比什么的了,线上的顺序排列、线间的排列就构成二进制编码和数据了,于是就什么都可以用二进制干了)

于是,总共有四种模式,如图示:

CPOL和CPHA合起来的二进制码就是SPI传输模式mode,如下表

Mode CPOLCPHA
000
101
210
311

最多需要4线实现全双工,每加加一线可增加一套进行分时使用,最少则需要两线单向专用和演示。

SPI是理解数字通讯的极好例子,初学者用软件实现一下SPI,会大大提高自己对数字线含义的理解。

其实,SPI/I2C/UART/QSPI/USB/SATA/等等所有串行都有相似之处,指示高速通讯需要解决干扰问题,对比学习一通百通,甚至都可以扩展到并行总线去了。好了,SPI的基础就说到这里了。

STM32F769I-DISCO的SPI通讯

STM32F769I-DISCO通过Arduino 接口的CN9提供了SPI2,

例子为

C:\Keil\ARM\Pack\Keil\STM32F7xx_DFP\2.8.0\Projects\STM32F769I-Discovery\Examples\SPI\SPI_FullDuplex_ComDMA  通过SPI用两个STM32F769I-DISCO板间做全双工DMA通讯。

STM32746G-Discovery板还有两个例子

SPI_FullDuplex_ComIT     中断方式通讯

SPI_FullDuplex_ComPolling    查询方式通讯

STM32F767ZI-Nucleo板还有更多例子。

这些可做为我们的起点,方便学习。

规划

1) 这里使用SPI_FullDuplex_ComDMA例子, STM32F769I-DISCO板本身SPI2做主设备、DMA方式,这里用我手头有的GD32 Colibri-F207ZE的SPI1做从设备,它的MPU和ST的类似,用查询方式。

2) 例子中只是通过用户键触发,通过比较发送和接受的内容是否一样,以及LED灯的状态,判断是否正常或出错。我们这板子有显示屏,怎么那么能不用呢! 所以和前文类似,要修改实现屏幕显示,用于判断通讯是否成功。

程序解析:

大部分情况下,任何独立任务编程的步骤是 1) 配置准备;2) 执行并判断监控(中断或查询,标志设置检查,完成);3)后续处理结束,标志复位,回等待某触发信号状态,等待下一次2)、3)循环。即是复杂任务也是找出分出这样的基本循环处理单元,它们再通过各种标志相关。即是操作系统也是这样基于标志+计数+中断构成的。

1) 在原例子中要增加LCD显示支持,这次参考例子2.8.0\Projects\STM32F769I-Discovery\Examples\BSP,这个例子简洁测试了声频、视频、显示、触摸、SD卡、SDRAM等功能,要比使用RTOS的Demonstration简单多了。

2) STM32F769I-DISCO 用DMA接收发送,Colibri-F207ZE查询接收发送, Error_Handler

STM32F769I-DISCO 主要代码

intmain(void)

{

 static long x =0;

static char buffer[50];

CPU_CACHE_Enable(); /* Enable the CPU Cache */ 

HAL_Init();

SystemClock_Config();  /* Configure the system clock to 216 MHz */

/*##-1-配置 LCD ###*/

LCD_Config();

BSP_LCD_Clear(LCD_COLOR_WHITE);

BSP_LCD_SetTextColor(LCD_COLOR_RED);

BSP_LCD_SetFont(&LCD_DEFAULT_FONT);

BSP_LCD_DisplayStringAtLine(4,(uint8_t*)" By okwh ");

BSP_LCD_DisplayStringAtLine(6,(uint8_t*)" http://home.eeworld.com.cn/space-uid-328390.html ");

BSP_LCD_DisplayStringAtLine(10,(uint8_t*)" Press User-Key to continue SPI Testing..... ");

BSP_LCD_DrawRect(10,10,780,460); BSP_LCD_SetTextColor(LCD_COLOR_GREEN); BSP_LCD_DrawRect(20,20,760,440); BSP_LCD_SetTextColor(LCD_COLOR_RED);

BSP_LCD_DrawCircle(400,240,100); BSP_LCD_DrawCircle(400,240,30);

BSP_LCD_SetTextColor(LCD_COLOR_GREEN);

BSP_LCD_DrawCircle(200,240,100); BSP_LCD_DrawCircle(200,240,30);

BSP_LCD_SetTextColor(LCD_COLOR_BLUE);

BSP_LCD_DrawCircle(600,240,100); BSP_LCD_DrawCircle(600,240,30);

/*##-1-配置SPI #########*/

SpiHandle.Instance = SPI2

SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;//32;

SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;

SpiHandle.Init.CLKPhase = SPI_PHASE_2EDGE; //SPI_PHASE_1EDGE;

SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;//SPI_POLARITY_HIGH;

SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;

SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;

SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;

SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

SpiHandle.Init.CRCPolynomial = 7;

SpiHandle.Init.NSS = SPI_NSS_SOFT;

SpiHandle.Init.Mode = SPI_MODE_MASTER;

HAL_Delay(5);

if(HAL_SPI_Init(&SpiHandle) != HAL_OK)

Error_Handler();

BSP_PB_Init(BUTTON_USER,BUTTON_MODE_GPIO); //init User key

while (1)

{

while(BSP_PB_GetState(BUTTON_USER) != GPIO_PIN_SET) //等User key

HAL_Delay(1000);

while(BSP_PB_GetState(BUTTON_USER) == GPIO_PIN_SET)

HAL_Delay(1000);

BSP_LCD_Clear(LCD_COLOR_BLUE);

BSP_LCD_SetTextColor(LCD_COLOR_RED);

sprintf(&buffer[0], " Times : %lu", x);

BSP_LCD_DisplayStringAtLine(1,buffer);

BSP_LCD_DisplayStringAtLine(4," Send: ");

BSP_LCD_DisplayStringAtLine(6,aTxBuffer);

BSP_LCD_DisplayStringAtLine(8," Received :");

if(HAL_SPI_TransmitReceive_DMA(&SpiHandle,(uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE) != HAL_OK)

Error_Handler(); //DNA发收

while (wTransferState == TRANSFER_WAIT) { }

switch(wTransferState)

{

caseTRANSFER_COMPLETE :

BSP_LCD_DisplayStringAtLine(10,aRxBuffer);

if(Buffercmp((uint8_t*)aTxBuffer,(uint8_t*)aRxBuffer, BUFFERSIZE))

{

BSP_LCD_DisplayStringAtLine(12,"Failed !!!! ! LED1 twinkles ! ");

BSP_LCD_DisplayStringAtLine(18,"Press User-Key recontinue SPI Testing..... ");

Error_Handler();

}

else

{

BSP_LCD_DisplayStringAtLine(12,"All OK !");

BSP_LCD_DisplayStringAtLine(18,"Press User-Key recontinue SPI Testing..... ");

}

break;

default :

Error_Handler();

break;

}

x++;

}

}

static void Error_Handler(void)

{

BSP_LED_Init(LED1);

BSP_LED_Off(LED1);

while (BSP_PB_GetState(BUTTON_USER) != GPIO_PIN_SET) //等User key

{

BSP_LED_Toggle(LED1);

HAL_Delay(500);

}

}

Colibri-F207ZE查询接收发送 主要代码:

int main(void)

{

uint16_t x=0; uint8_t cc;

GPIO_InitPara GPIO_InitStructure;

/* Enable Peripheral clock */

RCC_APB2PeriphClock_Enable( RCC_APB2PERIPH_GPIOA | RCC_APB2PERIPH_GPIOB | RCC_APB2PERIPH_GPIOC| RCC_APB2PERIPH_AF , ENABLE);

RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_SPI1,ENABLE);

/* Configure SPI1 pins: SCK, MISO and MOSI --------------------------------PA5/6/7-*/

/* Confugure SCK and MOSI pins as Alternate Function Push Pull | GPIO_PIN_6*/

GPIO_InitStructure.GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_7 ;

GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;

GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING; //SCK MO 备用推挽

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Confugure MISO pin as Input Floating */

GPIO_InitStructure.GPIO_Pin = GPIO_PIN_6;

GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP; // //MI 浮空输入

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* SPI1 configuration */

SPI_InitStructure.SPI_TransType = SPI_TRANSTYPE_FULLDUPLEX ;

SPI_InitStructure.SPI_Mode = SPI_MODE_SLAVE; //SPI_MODE_MASTER; //从

SPI_InitStructure.SPI_FrameFormat = SPI_FRAMEFORMAT_8BIT ;

SPI_InitStructure.SPI_SCKPL = SPI_SCKPL_LOW;

SPI_InitStructure.SPI_SCKPH = SPI_SCKPH_2EDGE;

SPI_InitStructure.SPI_SWNSSEN = SPI_SWNSS_SOFT; ///NSS不用

SPI_InitStructure.SPI_PSC = SPI_PSC_16; //分频

SPI_InitStructure.SPI_FirstBit = SPI_FIRSTBIT_MSB;

SPI_InitStructure.SPI_CRCPOL = 7; //CRC

SPI_Init(SPI1, &SPI_InitStructure);

SPI_CRC_Enable(SPI1, DISABLE);

SPI_Enable(SPI1, ENABLE); /* Enable SPI1 */

/* Transfer procedure */

while (1) //查询循环收发

{

while (SPI_I2S_GetBitState(SPI1, SPI_FLAG_RBNE) == RESET) {__NOP;} //先收后发

cc = SPI_I2S_ReceiveData( SPI1 );

while (SPI_I2S_GetBitState(SPI1, SPI_FLAG_TBE) == RESET){__NOP;}

SPI_I2S_SendData(SPI1, cc);

}

}

实验结验证果:

1) STM32F769I-DISCO SPI2 和  红色板为GD32板 GD32Colibri-F207ZE 的SPI1的连接, 红黄蓝先对应 SCK/MISO/MOSI

2) 开始前画面: user key 触发,循环发收通讯。

3) 通讯乱码:

4) 通讯成功 !

至此, SPI通讯验证成功!

以上图文内容均是EEWORLD论坛网友:okwh 原创,在此感谢。

欢迎微博@EEWORLD

如果你也写过此类原创干货请关注微信公众号:EEWORLD(电子工程世界)回复“投稿”,也可将你的原创发至:bbs_service@eeworld.com.cn,一经入选,我们将帮你登上头条!

与更多行业内网友进行交流请登陆EEWORLD论坛。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表