stm32 基础
GPIO工作原理
八种输入输出模式:
GPIO_Mode_AIN 模拟输入
GPIO_Mode_IN_FLOATING 浮空输入
特点是 引脚内部没有上拉或下拉电阻,引脚的电平状态完全由外部电路决定。如果外部没有明确的电平信号,引脚可能会处于一个不确定的状态(即“浮空”状态)。
比如在使能USART通信时,接收信号的引脚就要设置为浮空输入。
I/O的电平状态是不确定的,完全由外部输入决定
GPIO_Mode_IPD 下拉输入
很好理解,接地,在空闲状态下是低电平。
GPIO_Mode_IPU 上拉输入
接VCC,空闲时为高电平,比如在配置UART的RX引脚时就可以设置为上拉输入。
GPIO_Mode_Out_OD 开漏输出
- 结构:开漏输出由一个MOSFET(场效应管)构成,其漏极(Drain)作为输出引脚,源极(Source)接地。
- 工作原理:
- 当MOSFET导通时,输出引脚被拉低(低电平,0V)。
- 当MOSFET截止时,输出引脚处于高阻态(无电流输出),需要通过外部上拉电阻将电平拉高(高电平,如3.3V或5V)。
不同于推挽输出可以主动输出高、低电平,他只能主动输出低电平。
GPIO_Mode_Out_PP 推挽输出
- 信号来源:引脚信号直接来自 GPIO 外设(即由软件控制)。
- 工作原理:
- 输出高电平时,上拉 MOS 管导通,引脚输出高电平(VDD)。
- 输出低电平时,下拉 MOS 管导通,引脚输出低电平(GND)。
- 特点:
- 可以主动驱动高电平和低电平。
- 输出能力强,适合驱动负载(如 LED、继电器等)。
- 不能同时输出高电平和低电平,因此不适合直接连接两个输出引脚。
- 应用场景:
- 驱动外部设备(如 LED、蜂鸣器等)。
- 作为普通数字信号输出。
GPIO_Mode_AF_OD 复用开漏输出
复用的意思是芯片内置的某个模块比如I2C的SCL和SDA接口接在了某个GPIO的引脚上。重映射是指通过配置寄存器或硬件机制,将某些外设功能或引脚重新分配到其他物理引脚上的功能。
GPIO_Mode_AF_PP 复用推挽输出
- 信号来源:引脚信号来自外设(如 USART、SPI、I2C 等),而不是直接来自 GPIO 外设。
- 工作原理:
- 与推挽输出类似,上拉和下拉 MOS 管交替导通,但信号由外设控制。
- 输出高电平时,上拉 MOS 管导通,引脚输出高电平(VDD)。
- 输出低电平时,下拉 MOS 管导通,引脚输出低电平(GND)。
- 特点:
- 信号由外设控制,软件无法直接控制引脚状态。
- 输出能力强,适合驱动负载。
- 用于外设的专用功能。
- 应用场景:
- 外设通信(如 USART 的 TX 引脚、SPI 的 MOSI 引脚等)。
- 需要外设控制信号输出的场景。
STM32F103ZET6芯片为144脚芯片,包括7个通用目的的输入/输出口(GPIO)组,分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOG,同时每组GPIO口组有16个GPIO口。通常简略称为PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中x为0-15。
寄存器(register)
有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址等。
比如,引脚的高低电平数据(1或0)就放在不同的寄存器里,通过地址,可以访问到不同的寄存器。指令、地址寄存器与数据寄存器类似,用来保存当前正在执行的一条指令和CPU当前所访问的主存单元的地址。
STM32的寄存器(如GPIO、定时器、中断控制器等)在断电后会丢失其状态,上电后寄存器的值是随机的(未定义的)。STM32的Flash闪存是非易失性存储器,断电后Flash中存储的代码和数据不会丢失。上电后,CPU会从Flash中读取代码并执行。在程序执行过程中,代码会对寄存器进行初始化。
当我们使用寄存器的方式点亮LED灯时,需要进行的操作:
- 使能GPIO时钟
- 配置GPIO模式
- 控制GPIO输出
AHB时钟通常直接由系统时钟(SYSCLK)提供。用于连接高性能外设,如CPU、DMA、SRAM、FLASH等。
APB1时钟由AHB时钟经过分频器(APB1预分频器)得到,TIM2、TIM3、TIM4(定时器)
USART2、USART3(串口)
I2C1、I2C2(I2C接口)
SPI2(SPI接口)
PWR(电源控制)
CAN(控制器局域网)
APB2的时钟频率通常较高(最大频率与AHB时钟相同),GPIOA、GPIOB、GPIOC等(GPIO端口)
TIM1(定时器)
USART1(串口)
SPI1(SPI接口)
ADC1、ADC2(模数转换器)
EXTI(外部中断)
USART通信
单工是指数据传输仅能沿一个方向,不能实现反方向传输,如校园广播。半双工是指数据传输可以沿着两个方向,但是需要分时进行,如对讲机。全双工是指数据可以同时进行双向传输,日常的打电话属于这种情形。同步通信要求通信双方共用同一时钟信号,在总线上保持统一的时序和周期完成信息传输。
优点:可以实现高速率、大容量的数据传输,以及点对多点传输。缺点:要求发送时钟和接收
时钟保持严格同步,收发双方时钟允许的误差较小,同时硬件复杂。异步通信不需要时钟信号,而是在数据信号中加入开始位和停止位等一些同步信号,以便使接收端能够正确地将每一个字符接收下来,某些通信中还需要双方约定传输速率。
优点:没有时钟信号硬件简单,双方时钟可允许一定误差。缺点:通信速率较低,只适用点对点传输。
串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232、RS-422 和 RS-485 等
波特率,比如9600表示1s发送9600位byte启动位固定为低电平,停止位固定为高电平串口的空闲状态是高电平硬件数据流控CTS、RTS(了解)设置不同的停止位(1、1.5、2)
串口中断时每次中断处理一字节数据:
- 串口每接收到一个字节数据,就会触发一次中断,进入该中断服务程序。
- 在中断中,读取接收到的字节数据,并根据协议规则(
0x0D 0x0A
结尾)判断是否完成一帧数据的接收。每个字节可以表示一个数值范围(0x00 到 0xFF,即 0 到 255)。
0x0D 是 ASCII 字符中的 回车符(Carriage Return, CR)。0x0A 是 ASCII 字符中的 换行符(Line Feed, LF)。
时钟
代码解释
typedef
的作用
typedef
是 C/C++ 中的一个关键字,用于为已有的数据类型定义一个新的别名。- 通过
typedef
,可以让代码更简洁、易读,或者方便后续修改数据类型。
1 | //在stdint.h中有如下定义 |
#ifdef
和 #if
是预处理指令,用于条件编译。它们的作用是根据条件决定是否编译某段代码。
core_cm3.h函数中:
1 |
SysTick_Type是定义的时钟寄存器的结构体,
1 |
SysTick_BASE指向时钟外设的物理地址
I2C协议
软件模拟
主要使用I2C一主多从的模式(也有多主多从模式,多主机仲裁),同步半双工,两根通信线:SCL、SDA,带数据应答,从机权力较小只能被动读取时钟线,并且不能主动发起对数据线的控制。
- SCL和SDA都设置为开漏输出模式,并接了上拉电阻(阻值一般4.7kΩ左右)
- SCL设置为开漏主要是因为有多主机的模式,若没有也可以设置为推挽输出
时序控制(时序是怎么定义的):
起始条件:SCL在高电平期间,SDA从高电平到低电平的变化(下降沿)
终止条件:SCL在高电平时,SDA上升沿
发送数据:主机在SCL低电平时,将数据加载到SDA上(高低电平),加载完毕后恢复SCL高电平,方便从机在上升沿获取SDA的状态即数据。这样即发送一位数据,重复八次即发送一个字节。
接收数据:模式与发送数据一样,由从机进行数据加载,主机在SCL高电平时读取数据。SCL高电平时不允许SDA状态发生变化。主机在设置为接收模式时,需要释放对SDA的控制。
应答设置:发送方发送八位数数据(一个字节)后,释放控制权,切换为读取,由接收方收到数据后发送SDA低电平表示收到数据。
设备地址:每种芯片出厂时都会被分配七位数的地址,比如MPU6050是1101000,若相同则可以改变最后的几位的高低电平,模块上最后几位可以通过接线控制高低电平,后面一位为读写位,最后一位为应答位。
注意⚠️:示波器中左边的波形时间上早于右边的波形
发送数据的流程大概为:
激活起始条件,紧跟7位地址和1位读写位,读写位为0表示主机要进行写操作,1表示主机要接收特定从机的数据。而后是从机的一位应答位。当主机切换为读模式时,返回从机当前地址指针指向的地址的值(当前地址读),但是可以通过在读取地址前设置指定地址写来读取想要的地址(指定地址读)
硬件实现
STM32芯片内部有硬件直接实现应答、收发等功能。
有7位地址(起始+7位从机地址+应答+数据1+应答+…这是I2C的规定,后面的数据可以由厂商自己定义,比如mpu6050是数据位首先是寄存器的地址,再是从指定寄存器地址开始写入数据)和10位地址(起始位后两个字节都是寻址11110标志位+两位地址+1位读写位+后一字节地址)两种模式,主要使用7位
数据寄存器(DR)
状态寄存器(SR):EV5(读:SR1向DR写入数据清除)、EV6、EV7
移位寄存器(SR1)
由数据寄存器发送数据给移位寄存器,再由移位寄存器发送数据。
流程:
1、开启时钟,既要开启I2C的硬件时钟,也要开启对应GPIO的时钟
2、设置引脚模式,为复用开漏,引脚控制交给硬件I2C。
3、初始化I2C,当高于100khz时会有高低电平的占空比的设置,由于上升比较缓慢,所以需要将低电平的时间设置的长一些
4、I2C_Cmd()启用I2C
5、写入起始位,并调用函数读取状态寄存器的事件状态
6、叫唤从机,并设置为发送模式 ,通过EV6事件判断从机是否应答
7、发送寄存器地址和数据,并且分别检查状态
8、最后一个字节发送后,需要检查EV8_2
如果是接收的话,就需要先设置为发送模式,并且指定接收寄存器地址再设置为接收模式,此外还需要设置应答。
在接收状态时,若一直没有出现想要的结果就会程序卡死,因此设置退出,指定数进行递减,到0函数异常退出
缺点
由于开漏输出的弱上拉,导致通信频率受到上拉波形的限制,主流的最大为400khz
SPI通信
全双工的同步串行通信协议,仅支持一主多从
SPI通信使用以下4根信号线:
- MOSI(Master Out Slave In):主设备发送数据,从设备接收数据。
- MISO(Master In Slave Out):从设备发送数据,主设备接收数据。
- SCLK(Serial Clock):主设备提供的时钟信号,用于同步数据传输。
- SS/CS(Slave Select/Chip Select):主设备用于选择从设备的信号(低电平有效)。
为避免多MISO高电平在冲突,SPI规定只有在ss选中时才允许该外设MISO设置为高,其他状态为高阻态(即为断开状态)
移位寄存器
波特率发生器(时钟)
在每一个上升时钟沿进行移位输出,主机的输出到MOSI上,从机输出到MISO上。
在下降沿进行移位输入,主机的数据输入到从机的移位寄存器的低位,从机的数据输入到主机的移位寄存器的低位。
当我们不需要一方的数据时,不需要方发送0x00或者0xFF。
起始条件为:ss从高电平切换到低电平
终止条件:ss从低电平切换到高电平
通过CPOL和CPHA的0或1两种状态设置四种模式,CPOL不同状态区别在于SCl的电平取反,CPHA不同状态区别在于数据移入移出的时机,,我们主要掌握模式0,即SCK第一个边沿移入数据,第二个边沿移出数据。
第一个字节为指令码(芯片数据手册会有具体说明)比如是要读数据还是写数据,后面为数据
时钟:对于stm32f1,SPI1使用APB2的时钟(72MHz),但需要进行(2、4、8、16、32、64、128、256)分频,
写程序时需要重点关注两个标志位:发送缓冲器空闲标志位(TXE)和接收缓冲器非空标志位(RXNE)
代码流程:
1、开启SPI和GPIO时钟
2、配置对应的GPIO口,SS的GPIO设置为推挽输出,SCL和MOSI配置为复用推挽输出,MISO配置为上拉输入。
3、通过结构体对SPI初始化
4、通过SPI_Cmd()函数使能SPI
5、设置默认给ss输出高电平,即默认不选中从机
6、查看TXE标志位是否为1,为1时发送数据
7、检查RXNE标志位是否为1,为1时接收保存数据
传感器
姿态传感器
有六轴(加速度、陀螺仪的x、y、z)、九轴(+磁力计的x、y、z)、十轴(+气压计测高度)。
融合数据用于确定姿态的欧拉角(俯仰、偏航、横滚)。
根据加速度计的加速度值,可以测量出静态时物体的姿态。
陀螺仪是可以直接测量物体运动的角度,但是MPU6050的陀螺仪只能测量角速度,但是可以通过对角速度进行积分得到角度,由于噪声(尤其是静止时)导致角度会发生偏移。MPU6050还内置了温度传感器,但它只支持I2C通信。
在与MPU6050通信时,需要先写入唤醒模块,解除睡眠模式,使用I2C通信进行读时需要先起始条件(叫mpu6050),再使用写模式的指定某个寄存器,然后再重新起始
存储外设
W25Q64存储8MB的数据,并且掉电不丢失,存储介质是Flash闪存,像我们电脑的硬盘、U盘都属于flash闪存,(SRAM、DRAM属于易失性存储器),原理图中引脚上方一条横线表示低电平有效。
芯片内划分block、sector(1个block16个sector)和page(1个sector16个page,256字节)
芯片写入数据只能由1改写为0,不能0改写为1,所以要覆盖原先的内容时需要先进行擦除,只能按sector擦除,且连续写入时一次最多写入256字节,多了会覆盖前面(由于页缓存区的缘故),写入操作结束后,芯片进入忙状态,不进行新的读写
Buck电路
核心器件:开关管(S)、电感(L)、电容(C)、二极管(D)
开关管:可以导通和关断电流,常见的开关管有三极管、MOSFET、IGBT等
电感:可以将电能转换成磁能储存起来,也能将磁能转换为电能再次释放
(1)电感在进行储能和释能转换时,电感的正负极会发生反向
(2)流经电感的电流不能突变,只能逐步变大或变小
电容:具备存放电的功能,电容器两端电压高于外部电路电压时放电,反之充电,充放电不会发生正负极的反向
二极管:具有正负极特性,电流只能单向流过,只有正极与正极相接才可流过电流,否则无法流过。
注:D也可以是MOS管,MOS的压降损耗比二极管要小,二极管D也可以是其他快恢复或者肖特基二极管,导通压降更小的,损耗也小。Q和D是是一个同步整流,Q开D关、或者Q关D开。
boost电路
ADC、DAC
ADC 是 Analog-to-Digital Converter(模数转换器)的缩写,它是将模拟信号转换为数字信号的关键硬件模块。
基本原理
- 模拟信号:连续变化的信号(如电压、电流)。
- 数字信号:离散的信号(如二进制数值)。
- ADC 通过采样和量化,将模拟信号转换为数字信号。
stm32F1的ADC采用12位逐次逼近型ADC,1us转换时间(最快1MHz),输入电压范围:0-3.3,转换范围:0-4095。
规则通道:可选多个通道同时进行ADC转换,但需要配合DMA使用,防止数据被覆盖
注入通道:可直接使用四个同时进行ADC转换
模式:
1、单次转换,非扫描模式
2、单次转换,扫描模式(需要用到DMA)
3、连续转换,扫描模式
数据对齐:包括左对齐和右对齐两种,可以降低分辨率,比如将12位的分辨率变为8位
DAC为数字信号转换为模拟信号,主要应用于波形发生器、音频解码芯片(比如使用PWM控制电机、呼吸灯就可以理解为DAC)
静态局部变量
存储位置:
- 如果静态局部变量被初始化,则存储在
.data
段(已初始化数据段)。 - 如果未初始化,则存储在
.bss
段(未初始化数据段)。
1. .data 段
定义:
.data
段用于存储已初始化的全局变量和静态变量。- 这些变量在程序编译时被明确赋予了初始值。
特点:
- 存储在 RAM 中。
- 初始值存储在 Flash/ROM 中,程序启动时会被复制到 RAM。
- 占用 Flash/ROM 和 RAM 空间。
2. .bss 段
定义:
.bss
段用于存储未初始化的全局变量和静态变量。- 这些变量在程序编译时没有初始值。
特点:
- 存储在 RAM 中。
- 不占用 Flash/ROM 空间(因为没有初始值)。
- 程序启动时,
.bss
段会被清零。