(学习总结)STM32CubeMX HAL库教程 学习笔记撰写心得

(学习总结)STM32CubeMX HAL库教程 学习笔记撰写心得icon-default.png?t=O83Ahttps://blog.csdn.net/Wang2869902214/article/details/142435481

使用HAL库 STM32CubeMX——spi配置

使用硬件spi驱动7针1.3寸的OLED显示屏

时钟配置

(学习记录)使用 STM32CubeMX——配置时钟(入门)icon-default.png?t=O83Ahttps://blog.csdn.net/Wang2869902214/article/details/142423522

硬件SPI配置

①:在 "Pinout & Configuration" 输出与配置 页面下

②:点击需要配置的硬件spi(图中使用spi1)

③:选择需要使用的SPI通信模式,分别有如下:

  1. Transmit Only Master
    • 仅作为主设备发送数据,不接收数据。这种模式适用于只需要向从设备发送数据而不需要接收反馈的应用场景。
  2. Disable
    • 禁用SPI通信,不配置SPI外设。
  3. Full-Duplex Master
    • 作为主设备,支持全双工通信,即同时发送和接收数据。这是最常用的模式之一,适用于需要双向通信的应用场景。
  4. Full-Duplex Slave
    • 作为从设备,支持全双工通信。在这种模式下,SPI外设等待主设备发起通信,并同时发送和接收数据。
  5. Half-Duplex Master
    • 作为主设备,支持半双工通信,即在同一时间只能发送或接收数据,不能同时进行。这种模式较少使用,因为全双工提供了更高的通信效率。
  6. Half-Duplex Slave
    • 作为从设备,支持半双工通信。与Half-Duplex Master类似,但在从设备端实现。
  7. Receive Only Master
    • 仅作为主设备接收数据,不发送数据。这种模式适用于只需要从从设备接收数据的应用场景。
  8. Receive Only Slave
    • 仅作为从设备接收数据,不发送数据。与Receive Only Master相对应,在从设备端实现。
  9. Transmit Only Slave
    • 仅作为从设备发送数据,不接收数据。这种模式较为少见,因为通常从设备需要根据主设备的要求进行响应。

这里还可以选择是否使用硬件片选,大多情况下还是软件片选使用的比较多,不仅不影响速度,配置还灵活,所以这里选择不使用:"Disable"

然后就是上面说的模式选择:这里我们采用的是spi OLED显示屏,这个只需要我们STM32作为主机,发送数据到从机OLED上,不需要接收数据,所以选择"Transmit Only Master"

④:Parameter Settings  参数设置

1.Basic Parameters(基本参数)

  1. Frame Format(帧格式)

    • Motorola:这指的是SPI帧格式遵循Motorola的标准。SPI协议最初由Motorola定义,因此在许多文档和硬件中,这种帧格式被称为“Motorola SPI”。它定义了数据位如何在总线上传输,包括数据位的方向和时序。

  2. Data Size(数据大小)

    • 8 Bits:每个SPI帧包含8位数据。这是SPI通信中最常用的数据大小,适用于大多数应用场景。

  3. First Bit(首字节)

    • MSB First:数据以最高有效位(MSB)开始传输。这意味着在传输过程中,每个字节的最高位首先被发送和接收。另一种选择是LSB First(最低有效位首先),但在许多应用中,MSB First更为常见。

2.Clock Parameters(时钟参数)

  1. Prescaler (for Baud Rate)(预分频器(用于波特率))

    • 4:这是SPI时钟频率的预分频值。SPI时钟频率由系统时钟通过预分频器分频得到。预分频值越小,SPI时钟频率越高。具体的SPI时钟频率还取决于系统时钟频率和其他时钟配置参数。

  2. Baud Rate(波特率)

    • 18.0 MBits/s:这是SPI通信的波特率,即每秒传输的比特数。在预分频器为4的情况下,系统时钟需要足够高以支持这一波特率。波特率决定了SPI通信的速度。

  3. Clock Polarity (CPOL)(时钟极性)

    • LOW:当SPI设备处于空闲状态时,SCK时钟线的电平为低电平。时钟极性定义了时钟信号在空闲状态时的电平状态。CPOL=0表示空闲状态为低电平,CPOL=1表示空闲状态为高电平。

  4. Clock Phase (CPHA)(时钟相位)

    • 1 Edge:数据在SCK时钟线的第二个跳变沿(上升沿或下降沿,取决于CPOL)被采样。时钟相位决定了数据采样的时机。CPHA=0表示在第一个跳变沿采样,CPHA=1表示在第二个跳变沿采样。

3.Advanced Parameters(高级参数)

  1. CRC Calculation(CRC计算)

    • Disabled:禁用CRC(循环冗余校验)计算。CRC是一种用于检测数据传输或存储过程中错误的方法。在某些应用中,为了提高数据传输的可靠性,可以启用CRC计算。但在此配置中,CRC计算被禁用。

  2. NSS Signal Type(NSS信号类型)

    • Software:NSS(从设备选择)信号由软件控制。这意味着SPI外设的NSS引脚不被用作硬件NSS信号,而是可以通过软件来模拟NSS信号的功能。这提供了更大的灵活性,允许在软件层面控制从设备的选择和释放。

NVIC Settings:

  • SPI1 global interrupt:当启用此中断时,如果SPI1通信过程中发生某些事件(如传输完成、错误等),处理器将暂停当前正在执行的任务,并跳转到预定义的中断服务程序(ISR)去处理这些事件。这对于需要实时响应SPI通信状态变化的应用尤为重要。

DMA Settings:

对于SPI1在主机仅发送模式下的DMA设置,具体参数如下:

  • SPI1 TX:这表示DMA通道被配置为处理SPI1的发送(TX)操作。

  • DMA1 Channel 3:DMA通道的选择。STM32微控制器通常包含多个DMA控制器,每个控制器有多个通道。在这个例子中,选择了DMA1控制器的第3个通道来处理SPI1的发送数据。

  • Memory To Peripheral:数据传输方向。这表明数据将从内存传输到外设(SPI1),即从CPU管理的内存区域读取数据,然后通过SPI1接口发送给外部设备。

  • LOW:DMA通道优先级。DMA控制器可以管理多个通道,每个通道可以有不同的优先级。在这个例子中,DMA1 Channel 3被配置为低优先级。这意味着如果有多个DMA通道同时请求总线控制权,优先级更高的通道将首先获得访问权。

添加其他的OLED控制引脚



这里就添加OLED需要的其他的几个控制引脚(全部配置输出模式),再给上用户标签,分别如下:
OLED CS  :OLED片选引脚

OLED RES :OLED复位引脚

OLED D/C :OLED数据和命令引脚

OLED SCLK:OLED spi时钟引脚

OLED SDIN:OLED spi数据引脚

移植江科大OLED 7针SPI代码

江协科技资料下载

1.修改头文件

由于本教程是HAL库,所以标准库的一些头文件不适用

改为:

只需留下一个main.h

然后在main.h文件中添加所需要的头文件

/* USER CODE BEGIN Includes */

/*****C语言库******/

#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
/*****C语言库******/

/*****STM32CubeMX生成的库******/
#include "spi.h"
/*****STM32CubeMX生成的库******/

/*****keil5拓展库******/

/*****keil5拓展库******/

/*****自己的硬件库******/
#include "OLED.h"
/*****自己的硬件库******/


/* USER CODE END Includes */

2.修改传输数据引脚

这些引脚改为在STM32CubeMX中配置的对应的引脚,除了数据和时钟引脚,因为这个我们已经使用硬件spi了,cubeMX已经帮我们处理好了

只用保留这三个:


/**
  * 函    数:OLED写RES高低电平
  * 参    数:要写入RES的电平值,范围:0/1
  * 返 回 值:无
  * 说    明:当上层函数需要写RES时,此函数会被调用
  *           用户需要根据参数传入的值,将RES置为高电平或者低电平
  *           当参数传入0时,置RES为低电平,当参数传入1时,置RES为高电平
  */
void OLED_W_RES(uint8_t BitValue)
{
	/*根据BitValue的值,将RES置高电平或者低电平*/
	HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, (GPIO_PinState)BitValue);
}

/**
  * 函    数:OLED写DC高低电平
  * 参    数:要写入DC的电平值,范围:0/1
  * 返 回 值:无
  * 说    明:当上层函数需要写DC时,此函数会被调用
  *           用户需要根据参数传入的值,将DC置为高电平或者低电平
  *           当参数传入0时,置DC为低电平,当参数传入1时,置DC为高电平
  */
void OLED_W_DC(uint8_t BitValue)
{
	/*根据BitValue的值,将DC置高电平或者低电平*/
	HAL_GPIO_WritePin(OLED_D_C_GPIO_Port, OLED_D_C_Pin, (GPIO_PinState)BitValue);
}

/**
  * 函    数:OLED写CS高低电平
  * 参    数:要写入CS的电平值,范围:0/1
  * 返 回 值:无
  * 说    明:当上层函数需要写CS时,此函数会被调用
  *           用户需要根据参数传入的值,将CS置为高电平或者低电平
  *           当参数传入0时,置CS为低电平,当参数传入1时,置CS为高电平
  */
void OLED_W_CS(uint8_t BitValue)
{
	/*根据BitValue的值,将CS置高电平或者低电平*/
	HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, (GPIO_PinState)BitValue);
}

因为CubeMX已经帮我们初始化了引脚,所以我们可以直接删除这些蓝色的部分

3.修改传输数据函数

还是因为我们配置了硬件spi,直接使用HAL库中spi的发送数据函数

删除:

下方的函数里面的内容需要修改一下:

更改为:

/**
  * 函    数:OLED写命令
  * 参    数:Command 要写入的命令值,范围:0x00~0xFF
  * 返 回 值:无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_W_CS(0);					//拉低CS,开始通信
	OLED_W_DC(0);					//拉低DC,表示即将发送命令
	HAL_SPI_Transmit(&hspi1, &Command, sizeof(Command), 0xFF);		//写入指定命令
	OLED_W_CS(1);					//拉高CS,结束通信
}

/**
  * 函    数:OLED写数据
  * 参    数:Data 要写入数据的起始地址
  * 参    数:Count 要写入数据的数量
  * 返 回 值:无
  */
void OLED_WriteData(uint8_t *Data, uint8_t Count)
{	
	OLED_W_CS(0);					//拉低CS,开始通信
	OLED_W_DC(1);					//拉高DC,表示即将发送数据
	HAL_SPI_Transmit(&hspi1, Data, Count, 0xFF);		//写入指定命令
	OLED_W_CS(1);					//拉高CS,结束通信
}

4.编译

编译时可能会报错,需要在魔术棒中的:C/C++中

添加:--no-multibyte-chars

显示

运行这三句话

	OLED_Init();        //OLED初始化
	OLED_Printf(0, 0, 6, "Hello World!");  //写入缓存
	OLED_Update();       //更新屏幕

由于我的显示屏是1.3寸OLED,这里需要X += 2; 否则显示屏右边会出现异常百条

配合DMA使用

开启spi的发送DMA

注意:这里必须要把发送和接收的DMA都打开,才能使用DMA,所以目前只能配置为全双工

将发送函数改为:

/**
  * 函    数:OLED写命令
  * 参    数:Command 要写入的命令值,范围:0x00~0xFF
  * 返 回 值:无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_W_CS(0);					//拉低CS,开始通信
	OLED_W_DC(0);					//拉低DC,表示即将发送命令
	HAL_SPI_Transmit_DMA(&hspi1, &Command, sizeof(Command));		//写入指定命令
	OLED_W_CS(1);					//拉高CS,结束通信
}

/**
  * 函    数:OLED写数据
  * 参    数:Data 要写入数据的起始地址
  * 参    数:Count 要写入数据的数量
  * 返 回 值:无
  */
void OLED_WriteData(uint8_t *Data, uint8_t Count)
{	
	OLED_W_CS(0);					//拉低CS,开始通信
	OLED_W_DC(1);					//拉高DC,表示即将发送数据
	HAL_SPI_Transmit_DMA(&hspi1, Data, Count);		//写入指定命令
	OLED_W_CS(1);					//拉高CS,结束通信
}

 运行这三句话

	OLED_Init();        //OLED初始化
	OLED_Printf(0, 0, 6, "Hello World!");  //写入缓存
	OLED_Update();       //更新屏幕

文章结尾

本节内容配置spi和DMA驱动OLED就结束了

下一节内容:配置硬件iic

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐