STM32HAL库学习笔记

GPIO

GPIO引脚分布

彩色引脚具有特定的功能,用户无法通过编程来控制它们

VDD接电源正极VSS接地

VBAT用来接备用电池,STM32通常使用纽扣电池作为芯片的备用电源,当主电源断电之后,备用电池可以继续为芯片的Backup-Domain供电,所以芯片的一部分功能仍然可以正常运转

NRST是芯片的复位引脚,一般我们会在这个引脚上接一枚按钮,按下这个按钮,芯片复位

BOOT0启动模式选择,通过这个引脚选择芯片的启动模式

剩下蓝灰色的引脚都是普通IO引脚,这些引脚都是可编程的,给这些引脚分组,按照字母命名组号,GPIOA GPIOB GPIOC GPIOD4个组,每组最多有16个引脚,编号从0开始

IO复用和复用功能重映射

IO复用:同一个IO引脚具备多个不同的功能,既可以被用户直接编程,也可以给芯片上的其他模块使用

以PA9为例,向其写0,输出低电平;向其写1,输出高电平,这种直接控制引脚的方式叫做通用功能。

USART1是芯片内部的串口模块,通过PA9向外发送数据,比如想通过USART1发送数字100,那么我们把100写入到USART1,然后它就会通过PA9发送一段特定的波形从而把数据发送出去,此时PA9被USART1托管了,这时就不能直接控制PA9输出高电平和低电平了,我们把这种使用IO的方式叫做复用功能。

复用功能重映射:一般单个引脚可以同时兼具多种复用功能,复用功能重映射就是把冲突的复用功能移动到备用引脚上去

定时器1和串口1都是芯片内部的模块,它们所占用的引脚有一些是重复的,如果我们想同时使用定时器1和串口1,可以把USART1重映射到PB6和PB7

芯片上给大多数模块都留有一组或多组备用引脚,USART1的备用引脚在PB6和PB7

4种输出模式

这两个MOS管可以等效为一对开关

推挽模式下,如果向IO写0,那么P-MOS关断,N-MOS 导通,IO引脚通过下方的N-MOS与下方的低电压VSS相连,引脚上输出的就是低电压

IO最大输出速度

把电压升高所消耗的时间称为上升时间,把电压降落所消耗的时间称为下降时间,中间输出有效电平的时间称为保持时间,加快电压的切换速度,发现上升沿和下降沿的斜坡越靠越近,中间的保持时间越来越短,如果再加快切换速度,会发现上升沿和下降沿完全重合,此时已经不能输出有效的高低电压了。如果使用更快的上升时间和下降时间,也就是让两个斜坡更陡,这样就可以继续输出有效的高低电压了。可以看出,上升时间和下降时间限制了IO的最大输出速度,上升时间和下降时间越短,最大输出速度就越大。

三种模式下IO的最大输出速度

2MHZ------每秒钟切换200万次 10MHZ-----每秒钟切换1000万次

50MHZ-----每秒钟切换5000万次(注:M,即百万,10^6)

实际编程过程中,如何选择最大输出速度?原则是选取满足要求的最小值,过快的上升沿和下降沿会增加芯片损耗,同时会使数字信号的带宽增加,从而对电路板上的其他元器件产生电磁干扰。

1>使用单片机的IO引脚去驱动发光二极管,因为人眼能够分辨的闪烁频率大概是每秒钟10次,所以驱动发光二极管的频率也不宜太高,一般不会超过1000HZ,所以选择低速,也就是最大2MHZ的输出速度

2>英飞凌的TLE5012B是一款GMR编码器,它使用SPI总线跟单片机进行通信,官通标称的最大通信速率是8Mbps(b:bit比特,ps:per second每秒,描述数据传输的快慢),所以选择中速,也就是最大10MHZ的输出速度

3>单片机上有一个USB2.0的全速接口,它的通信速率是12Mbbps,所以只能选择高速

闪灯实验

使用单片机的IO引脚去驱动板载的LED和一颗外接的LED

除了向单片机下载程序之外,我们还可以使用ST-Link对代码进行调试,在调试之前,首先先关闭掉代码的优化,如下图

使用bootloader清除程序

如果忘记了这个步骤,芯片的调试接口将会被锁死,烧录程序时会发现烧录不进去,可以通过bootloader把里面的程序清除掉,程序被清除掉之后,单片机的调试接口将被重新打开

BOOT0接1,BOOT接0

然后点击disconnected,断开连接

4种输入模式

当IO引脚工作在输入模式下时,它的作用就是去测量外部输入信号的电压,相当于一块电压表,因此它的内阻也应当是无穷大,无穷大的电阻相当于开路,所以我们把这个位置断开,同时如果我们不接上拉电阻和下拉电阻,那么这个时候IO引脚完全悬空了,悬空的引脚就像一根天线,他会接收空间的电磁波,我们会读到随机的0和1。现在我们加入上拉电阻,同样不接外部输入信号,这时候电路由两个电阻分压,因为下面电阻的阻值是无穷大,所以它会分得整个Vdd,而上面电阻分得的电压是0V,接了上拉电阻之后,即使没有外部信号,IO引脚上也会出现一个稳定的高电压,而不再是一个随机值。

按钮实验

使用一枚按钮,去控制最小系统板上的板载LED,按下按钮时,LED点亮;松开按钮时,LED熄灭。

把IO引脚配置为输入上拉模式,按钮松开时,IO引脚悬空,此时在上拉电阻的作用下 ,IO引脚商呈现高电平,此时读到的IO引脚的值为1;当按钮按下时,IO引脚通过这条线接地,所以引脚上是低电平,此时读到的IO引脚的值为0

UART

UART

基础知识

串口是以数据帧为单位传输数据的

十进制85转化为二进制是01010101(补足8位,高位补0)

串口发送时低位先行,即10101010

一位代表传输一个高低电压所需要的时间

波特率越高,数据传输的速率就越快,注意收发双方应该选择相同的波特率

简单的数据发送实验

选择异步模式,观察右边的引脚分配图,发现CubeMX自动分配好了UART的引脚,并且CubeMX

自动配置好了引脚的参数,但是由于串口的数据接收引脚可能会意外断开,最好配置一个上拉电阻

将调试器和USB转TTL模块都接到电脑上

本次实验选择最常用的,如下

CubeMX自动帮我们生成了串口1的句柄,即huart1

设超时时间是10ms,如果数据发送在10ms内没有完成,那么发送过程就会停止,并且返回一个错误。一般不使用这个超时时间,填写HAL_MAX_DELAY表示无限期等待下去,直到发送完成为止

返回值只有返回HAL_OK才表示发送成功,其他返回值都表示发送出错


传送数据的一些解释

1>0x5A 的十进制值是:5 × 16 + 10 = 90

2>uint8_t byteArray[] = {1,2,3,4,5};

byteArray 是一个 uint8_t 数组,每个元素占 1 字节,数组长度自动推断为 5

1 个 uint8_t = 1 个字节 ,数组里每个元素正好对应 内存中的 1 个字节

HAL_UART_Transmit(&huart1, byteArray, 5, HAL_MAX_DELAY);

这里,byteArray 本质上是指向数组首元素的指针(即 &byteArray[0])。

3>char ch = 'a'; 内存中实际是:ch = 97 (0x61),串口发送0110 0001 // 97 → 'a'

实际发生的是:把数字 97 放进 1 字节的内存中,'a' 不是字符对象,它是一个 值为 97 的整数

如果char ch = 97; printf("%c\n", ch); // a,把 97 当 ASCII 码解释

printf("%d\n", ch); // 97,直接当数字 → 97

4>"Hello world" 是 字符串常量,本质是一个 以 \0 结尾的字符数组,内存结构为

H e l l o w o r l d \0,str 实际上是指向数组的首元素(即 'H')的指针。

char *str是一个 指针,指向字符串首地址,等价写法:char str[] = "Hello world";

转换后的指针仍然指向相同的内存位置,但数据的类型解释变成了无符号 8 位整数,这样 HAL_UART_Transmit 就可以正确地处理这些字节数据,进行 UART 传输。

&ch 返回的是一个指向 ch 的指针,类型是 char *(即指向一个字符的指针)。强制类型转换 (uint8_t *)&ch 的目的是将 ch 的地址从 char * 转换为 uint8_t *,使得指针类型符合 HAL_UART_Transmit 函数的要求。

简单的数据接收实验

通过串口想单片机发送命令,发送字符1,板载LED点亮,发送字符0,板载LED熄灭

如果第四个参数填10,即超时时间是10ms,如果在10ms之内没有接受到足够数量的数据,那么接收就会停止并返回错误,一般不使用这个超时时间,这时参数应当填HAL_MAX_DELAY,表示超时时间是无限大,如果没有接收到足够数量的数据,就会一直等待下去

该编程接口还有一个返回值,用来返回程序执行的结果,只有返回HAL_OK才表示接收成功

dataRcvd表示接收到的数据,Rcvd是Rceived的缩写

GBK、UTF-8 和 ASCII 字符编码标准的解释

IIC

基础知识

串口可以实现一对一的数据传输,单片机有三个串口,通过串口,最多让单片机和三个外部设备连接。

如果想要连接更多设备,就需要用到总线,IIC就是一种总线,可以让单片机跟大量设备进行连接,单片机一般作为IIC总线的主机,其他设备作为从机,

SCL(Serial Clock,串行时钟线),负责传输时钟信号,即这种高低变化的方波信号,每个时钟周期传输一位,所以时钟的频率越高,传输数据的速率就越快.

SDA(Serial Data,串行数据线),负责传输数据,高电压表示1,低电压表示0。

主机和从机都有SCL和SDA引脚,需要将它们分别连接在SCL和SDA线上,IIC总线还需要两颗上拉电阻,阻值一般取4.7K,一颗接在SCL上,另一颗接在SDA上,分别对时钟线和数据线进行上拉,从机和主机的SCL和SDA引脚都应该使用开漏输出(P-MOS断开,只控制N-MOS的通断,N-MOS导通时输出低电压,N-MOS关断时,引脚悬空输出高阻抗)。

SCL和SDA两条线实现逻辑线与的原理是一样的,所以我们只分析其中的一条线。向所有的引脚都写1,开漏模式下向IO引脚写1,输出高阻抗,相当于开路,这样总线就悬空了,但是由于上拉电阻的存在,总线上的电压会被拉高,也就是输出高电压1;向任意一个引脚写0,剩下的引脚保持1,写1的引脚输出高阻抗,写0的引脚输出低电压,总线通过写0的引脚接地,虽然有上拉电阻的存在,但是它已经不起作用了,总线输出低电压0。这样就通过硬件电路实现了逻辑线与。

弱上拉,强下拉

由于IIC是总线结构,所以主机和从机会共用SCL和SDA这两条线

起始位

在数据传输开始之前,总线上处于空闲状态,由于上拉电阻的存在,所以SCL和SDA上都是高电压,此时,主机只要把SDA线拉低,就可以发送一个起始位。

寻址

在上一个阶段,我们已将发送了起始位,现在开始寻址,首先发送从机的七位地址,比如要寻址的设备是第一个从机0x78,把它的地址转换为二进制01111000,把最后一位丢掉,遇到0就发送低电压,遇到1就发送高电压,最后还要发送一个RW位用来填写数据传输的方向,R/W#=0时,代表向从机写数据,R/W#=1时,代表从从机读数据。发送完从机的地址之后,主机释放SDA线,等待从应答。从机通过把 SDA拉低来发送一个应答信号来告诉主机寻址成功,我们把这个应答信号称为ACK(Acknowlege),如果没有发送应答信号叫NAK(Not Acknowlege)。

寻址阶段NAK的原因:

地址填错,要寻址的从机不存在;要寻址的从机正忙,没来得及回复ACK;从机故障

不管是哪种原因,只要收到了NAK,就表示寻址失败

数据传输

根据上一阶段填写的RW值,数据传输有两种不同的方向

写:主机发送,从机接收 。主机首先向从机发送8个比特,也就是一个字节的数据,然后释放掉SDA线,等待从机确认接收,从机通过把SDA拉低来发送一个ACK,表示数据收到;然后主机再发送第二个字节,以此类推,每次可以发送多个字节。

读:从机发送,主机接收。读数据和写数据类似,但是方向相反,从机发送数据,主机回复ACK,每读一个字节,回复一个ACK,

停止位

在数据传输结束之后,主机需要向总线上发送一个停止位,当SCL是高电压时,向SDA上发送一个上升沿。

练习:主机向从机0x78写0x5a,0x33,然后再读一个字节

数据传输开始之前,总线上处于空闲状态;主机通过把SDA拉低来发送一个起始位,开始寻址,主机发送0x78,RW=0,表示写数据;然后主机释放SDA等待从机应答,从机0x78通过把SDA拉低来发送一个ACK,此时寻址成功;主机发送第一个字节0x5a(01011010),然后释放SDA等待从机确认接收数据,从机通过把SDA拉低,发送ACK,第一个字节传输完成;紧接着主机发送第二个字节0x33(00110011),释放SDA等待从机应答,从机发送ACK,第二个字节发送成功。两个字节都发完了,此时主机发送停止位,数据传输结束,总线重新进入空闲状态。下一步主机需要从从机读取一个字节的数据,它先发送起始位,然后发送0x78(0111100),RW=1,表示方向是读,主机释放SDA,从机发送ACK表示寻址成功,主机从从机读取一个字节的数据,然后从机释放SDA,等待主机应答,因为不想接收更多的数据,所以发送一个NAK,然后发送一个停止位,数据传输结束。

IIC以高低变化的电压来传输数据,每个时钟周期传输一位,把每秒钟传输位的数量叫做波特率,波特率越大,通信速率越快。根据通信速率的快慢IIC总线可以分成多种模式,STM32F105C8T6只支持标准模式和快速模式,也就是最大通信速度不超过400kbps

IIC总线里,主机可以通过SCL向外发送这种方波信号,即时钟信号,在快速模式下,它的占空比是可以设置的,如果没有特殊说明,我们一般选择2:1的占空比。

简单的数据收发实验

我们可以使用一块0.96寸的OLED显示屏显示字母、汉字、图像、动画等各种各样的信息。

我们一般用不到SMBus,直接选IIC

STM32既可以作为主机来连接大量的外部设备,也可以作为从机挂载在IIC总线上,当STM32作为IIC从机的时候,需要另一块单片机作为主机。STM32作从机的现象比较少见,只有在大型的项目中才会用到。当STM32作主机的时候,设置上面的参数,当STM32作从机时,设置下面的参数。

相关推荐
知南x2 小时前
【正点原子STM32MP157学习篇】A7和M4联合调试(通过STM32CubeIDE)
stm32·嵌入式硬件·学习
儒雅永缘2 小时前
Solidworks练习37-旋转、拉伸切、阵列
笔记·学习
丝斯20112 小时前
AI学习笔记整理(47)——大模型企业应用技术之提示工程
人工智能·笔记·学习
ValidationExpression2 小时前
LangChain1.0学习
学习·ai·langchain·fastapi
木木木一2 小时前
Rust学习记录--C0 总目录
开发语言·学习·rust
sjg200104142 小时前
GoFrame学习随便记2
windows·学习
qq_344115222 小时前
WinForm学习笔记一(建立项目)
笔记·学习
小呀小萝卜儿2 小时前
2026-01-14 学习记录--LLM-申请Hugging Face 访问令牌(以Meta-Llama-3.1-8B-Instruct为例)
学习·语言模型·llama
走在路上的菜鸟2 小时前
Android学Flutter学习笔记 第五节 Android视角认知Flutter(插件plugins)
android·学习·flutter