打印
[应用相关]

学习STM32的SPI总线通信

[复制链接]
389|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-9-13 08:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
SPI(Serial Peripheral Interface)是一种同步的串行通信接口。在STM32中,SPI接口是一种常用的外设通信接口,可以用于与其他外设(如传感器、存储器、显示器等)进行通信。

在使用STM32的SPI接口进行通信之前,需要进行一些基本的配置设置。下面是一个使用STM32CubeMX(官方提供的图形化配置工具)进行SPI配置的案例。

#include "stm32f4xx_hal.h"

void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_SPI2_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI2_Init();

  while (1)
  {
    // 在这里进行SPI通信的操作
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void MX_SPI2_Init(void)
{
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
}

上面的代码是通过SPI2接口实现通信的配置代码。具体的配置包括时钟设置、GPIO初始化和SPI初始化等。

下面是一个使用STM32的SPI接口实现与一片OLED显示屏通信的案例。假设OLED显示屏的数据传输使用的是SPI接口。

#include "stm32f4xx_hal.h"

#define OLED_RST_Pin GPIO_PIN_0
#define OLED_RST_GPIO_Port GPIOC
#define OLED_DC_Pin GPIO_PIN_1
#define OLED_DC_GPIO_Port GPIOC
#define OLED_CS_Pin GPIO_PIN_2
#define OLED_CS_GPIO_Port GPIOC

SPI_HandleTypeDef hspi2;

void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_SPI2_Init(void);
void OLED_Init(void);
void OLED_WriteCmd(uint8_t cmd);
void OLED_WriteData(uint8_t data);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI2_Init();

  OLED_Init();

  while (1)
  {
    // 在这里进行SPI通信的操作
  }
}

void OLED_Init(void)
{
  HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_RESET);
  HAL_Delay(100);
  HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_SET);
  HAL_Delay(200);

  OLED_WriteCmd(0xAE); // 显示关闭

  OLED_WriteCmd(0xD5); // 设置时钟分频因子/振荡器频率
  OLED_WriteCmd(0x80);

  OLED_WriteCmd(0xA8); // 设置驱动路数
  OLED_WriteCmd(0x3F);

  OLED_WriteCmd(0xD3); // 设置显示偏移
  OLED_WriteCmd(0x00);

  OLED_WriteCmd(0x40); // 设置显示开始行

  OLED_WriteCmd(0x8D); // 设置电荷泵
  OLED_WriteCmd(0x14);

  OLED_WriteCmd(0x20); // 设置内存地址模式
  OLED_WriteCmd(0x00); // 水平地址模式

  OLED_WriteCmd(0xA1); // 设置段重启

  OLED_WriteCmd(0xC8); // 设置COM输出扫描方向

  OLED_WriteCmd(0xDA); // 设置COM引脚配置
  OLED_WriteCmd(0x12);

  OLED_WriteCmd(0x81); // 设置对比度控制
  OLED_WriteCmd(0xCF);

  OLED_WriteCmd(0xD9); // 设置预充电周期
  OLED_WriteCmd(0xF1);

  OLED_WriteCmd(0xDB); // 设置VCOMH电压倍率
  OLED_WriteCmd(0x40);

  OLED_WriteCmd(0xA4); // 设置全局显示开启

  OLED_WriteCmd(0xA6); // 设置显示方式

  OLED_WriteCmd(0xAF); // 显示开启
}

void OLED_WriteCmd(uint8_t cmd)
{
  HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi2, &cmd, sizeof(cmd), HAL_MAX_DELAY);
  HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_SET);
}

void OLED_WriteData(uint8_t data)
{
  HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_SET);
  HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi2, &data, sizeof(data), HAL_MAX_DELAY);
  HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_SET);
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2401_85258012/article/details/142112423

使用特权

评论回复
沙发
LEDyyds| | 2024-9-13 10:19 | 只看该作者
SPI还是很常用的

使用特权

评论回复
板凳
泡椒风爪| | 2024-9-20 23:07 | 只看该作者
代码示例展示了如何使用STM32的SPI接口与OLED显示屏进行通信,整体结构良好

使用特权

评论回复
地板
ym0sly| | 2024-9-23 18:50 | 只看该作者
可能还需要为CS、DC和RST引脚配置输出模式。

使用特权

评论回复
5
szt1993| | 2024-9-23 19:12 | 只看该作者
OLED显示屏的数据传输使用的是SPI接口速率会快很多

使用特权

评论回复
6
呈兴| | 2024-9-26 21:35 | 只看该作者
在OLED初始化过程中,适当的延时可能是必要的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15611

帖子

11

粉丝