(学习记录)使用HAL库 STM32CubeMX——spi(DMA)配置OLED

news2024/10/1 17:38:29

(学习总结)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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2166375.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

element 输入框文字+对应签进行长度 和 的判断

输入文字长度 指定标签的长度 &#xff08;判断长度并提示&#xff09; <div style"position: relative;" classchangyongyu><el-input type"textarea" :autosize"{ minRows: 8, maxRows: 8 }" style"margin-bottom:10px;"…

【React】useEffect

1. 基本介绍 概念 语法 副作用函数依赖项数组&#xff08;空数组时&#xff0c;只会在组件渲染完毕后执行一次副作用函数&#xff09; 2. 使用 import { useEffect, useState } from reactfunction App() {const [value, setValue] useState(0)useEffect(() > {console…

docker-图形化工具-portainer的使用

文章目录 1、安装和启动2、设置登陆密码3、dashboard 上述对容器和镜像的管理都是基于docker客户端的命令来完成&#xff0c;不太方便。为了方便的对docker中的一些对象(镜像、容器、数据卷…)来进行管理&#xff0c;可以使用Portainer来完成。Portainer是一个可视化的容器镜像…

Spring Boot 学习之路 -- Service 层

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精…

如何帮助我们改造升级原有架构——基于TDengine 平台

一、简介 TDengine 核心是一款高性能、集群开源、云原生的时序数据库&#xff08;Time Series Database&#xff0c;TSDB&#xff09;&#xff0c;专为物联网IoT平台、工业互联网、电力、IT 运维等场景设计并优化&#xff0c;具有极强的弹性伸缩能力。同时它还带有内建的缓存、…

AI可信度标准与框架

AI 可信度被定义为&#xff1a;无论从技术层面还是社会层面&#xff0c;AI 在执行任务时均能够赢得用户的信任和接受的程度。具体地&#xff0c;一个高可信度的 AI 应包含两个组成部分&#xff0c;这些组成部分应贯穿于系统的整个生命周期&#xff1a; &#xff08;一&#xff…

数据结构 ——— C语言实现动态顺序表

目录 顺序表的概念 顺序表的结构&#xff08;静态顺序表和动态顺序表&#xff09; 1. 静态顺序表&#xff1a;使用固定长度的数组存储元素 2. 动态顺序表&#xff1a;使用动态开辟的数组存储元素 为什么选择实现动态顺序表 静态顺序表的缺点&#xff1a; 动态顺序表的优点…

读构建可扩展分布式系统:方法与实践15可扩展系统的基本要素

1. 可扩展系统的基本要素 1.1. 分布式系统在本质上就是复杂的&#xff0c;你必须考虑多种故障模式&#xff0c;并设计应对所有可能发生的情况的处理方式 1.2. 大规模应用程序需要协调大量的硬件和软件组件&#xff0c;共同实现低延迟和高吞吐量的能力 1.3. 面临的挑战是将所…

入门Django

Django Django 简介URL组成部分详解第一个Django项目创建一个Django项目运行Django项目项目结构介绍project和app的关系 URL与视图函数的映射URL的两种传参方式在URL中携带参数 path函数url路由模块化url反转 Django 简介 Django 是一个高级的 Python Web 框架&#xff0c;用于…

书生白嫖A100活动之——OpenCompass

内容来源&#xff1a;Tutorial/opencompass/readme.md at camp2 InternLM/Tutorial GitHub 概览 在 OpenCompass 中评估一个模型通常包括以下几个阶段&#xff1a;配置 -> 推理 -> 评估 -> 可视化。 配置&#xff1a;这是整个工作流的起点。您需要配置整个评估过…

HTML中的表单(超详细)

一、表单 1.语法 <!-- action&#xff1a;提交的地方 method&#xff1a;提交的方式&#xff08;get会显示&#xff0c;post不会&#xff09; --> <form action"#" method"get"><p>名字&#xff1a;<input name"name" ty…

【Geoserver使用】SRS处理选项

文章目录 前言一、Geoserver的三种SRS处理二、对Bounding Boxes计算的影响总结 前言 今天来看看Geoserver中发布图层时的坐标参考处理这一项。根据Geoserver官方文档&#xff0c;坐标参考系统 (CRS) 定义了地理参考空间数据与地球表面实际位置的关系。CRS 是更通用的模型&…

3. 轴指令(omron 机器自动化控制器)——>MC_MoveFeed

机器自动化控制器——第三章 轴指令 8 MC_MoveFeed变量▶输入变量▶输出变量▶输入输出变量 功能说明▶指令详情▶时序图▶重启运动指令▶多重启动运动指令▶异常 示例程序▶参数设定▶动作示例▶梯形图▶结构文本(ST) MC_MoveFeed 指定自外部输入的中断输入发生位置起的移动距…

2024免费录屏软件的宝藏功能与实用技巧

在手机上操作很多时候为了记录方便都直接截图或者录屏&#xff0c;其实电脑也一样。现在面向电脑的录屏工具纷繁复杂&#xff0c;很容易让我们挑花了眼。今天这篇文章我将介绍几款免费的录屏软件为大家提供参考。 1.福昕录屏大师 链接达达&#xff1a;www.foxitsoftware.cn/R…

深入探索 RUM 与全链路追踪:优化数字体验的利器

作者&#xff1a;梅光辉&#xff08;重彦&#xff09; 背景介绍 随着可观测技术的持续演进&#xff0c;多数企业已广泛采用 APM、Tracing 及 Logging 解决方案&#xff0c;以此强化业务监控能力&#xff0c;尤其在互联网行业&#xff0c;产品的体验直接关系着用户的口碑&…

使用Crawler实例进行网页内容抓取

网页内容抓取的背景 随着互联网的快速发展&#xff0c;网页上的信息量日益庞大。如何从海量的网页中快速、准确地抓取所需信息&#xff0c;成为了一个技术挑战。网页内容抓取技术通过自动化的方式&#xff0c;模拟用户浏览网页的过程&#xff0c;获取网页上的文本、图片、链接…

mybatisplus介绍以及使用(上)

目录 一、概念 1、什么是mybatisplus 2、为什么要使用mybatisplus 二、mybatisplus的使用 1、安装 2、常用注解 3、条件构造器 一、概念 1、什么是mybatisplus MyBatis-Plus&#xff08;简称MP&#xff09;是一个基于MyBatis的增强框架&#xff0c;旨在简化开发、提高…

学习C语言(20)

在这段没有更新的时间作者大一开学了&#xff0c;军训期间一直比较忙没时间学习&#xff0c;9月23号结束了为期十四天的军训&#xff0c;今天开始重新更学习C语言的博客 整理今天的学习内容 1.浮点数在内存中的储存 浮点数包括float&#xff0c;double&#xff0c;long doub…

vue实现左侧数据拖拽到右侧区域,且左侧数据保留且左侧数据不能互相拖拽改变顺序

一、案例效果 二、案例代码 封装左侧抽屉 DrawerSearch.vue <template><div><mtd-form :model"formDrawerSearch" ref"formCustom" inline><mtd-form-item><mtd-inputtype"text"v-model"formDrawerSearch.hos…

美团一面:给定两棵二叉树 `A` 和 `B`,判断 `B` 是否是 `A` 的子结构?

目录标题 问题描述思路分析代码解释详细步骤复杂度分析 问题描述 给定两棵二叉树 A 和 B&#xff0c;判断 B 是否是 A 的子结构。所谓子结构是指 B 中任意节点在 A 中存在相同的结构和节点值。 例子1&#xff1a; 输入&#xff1a;tree1 [1,7,5], tree2 [6,1] 输出&#…