STM32固件学习记录

本文深入探讨了STM32固件开发的关键知识点,包括结构体与联合体的区别、静态变量的作用、PWM函数设置技巧、USART配置、GPIO输出模式、差分放大电路原理以及TTL与RS232电平转换等,旨在帮助读者全面掌握STM32开发的理论与实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、计算机基础

1、结构体和联合体的区别

结构体(struct)和联合体(union)的区别_结构体和联合体的区别-优快云博客

重要区别:结构体(struct)的成员各自拥有自己的内存地址;而联合体(union)只有一个内存地址,用于分配给所有成员共同使用。

优缺点:struct比union更占用内存。

疑问:应用场景未知。struct的优点未知。

2、结构体和类的区别

一文讲明白C++中的结构体Struct和类Class的区别以及使用场景_结构体和类-优快云博客

重要区别:结构体(struct)的成员是公共的,在结构体外部可以直接访问;类(class)的成员函数是私有的,在类外不可以直接访问,必须通过调用公共成员函数进行访问

应用场景:struct适合不需要对成员进行变化操作的,只需要简单存储数据;而class更适合用于对成员频繁进行变换操作,实现复杂的操作。

3、数据结构命名格式

C中int8_t、int16_t、int32_t、int64_t、uint8_t、size_t、ssize_t区别-优快云博客

int8_t中的t为type或者typedef的意义,用于表示该变量是在typedef下定义的,不是一种新的数据类型。由于不同平台的int拥有不同的字长,这样可以用于区分。

4、字符和整数的区别

C语言字符型char和整型int的关系和示例_c语言char和int-优快云博客

字符就是0-255整数范围内对ASCII码表的映射,具体如下博客所示。

char字符对应ASCII码表0-255(全)_char字符对应的ascii码值-优快云博客

因此char定义一个8位的字符时,其本质仍是整数,但用ASCII码的形式形成了字符串。

例如:

//正确例子
char a[]="abc"
char a[4]="abc"

//错误例子
char a[3]="abc"

由于char类型需要一个空字符(\0)结尾,所以需要空出至少一个字符。

//指针定义字符串
char* a='abc'
printf("%s\n",a)

//输出结果
abc

用指针即可存储字符串。但是a理论上应该是地址,*a才是数据,上代码展示的结果为a输出数据,是因为printf函数的原因吗?

还有string定义字符串,还不太了解。

字符串和字符在变量上的区别

//三种定义的方式
uint8_t test[5]={0,1,2,3,4};            //数值
uint8_t sectest[]="01234";              //字符串
uint8_t trdtest[]={'0','1','2','3','4'};//字符

数值就是直接使用ASCⅡ码。

字符串是使用字符“1”对应的ASCⅡ码,即49。

字符串结尾会有\0作结尾,所以sizeof取其长度后会比可见的长度多1。

5、常见变量的字节数,字节与字的关系

[c++]-uint8_t,uint16_t,uint32_t,uint64_t代表含义及其标准定义_c++ uint-优快云博客

char字符类型占1个字节,int整形占4个字节,float浮点型占4个字节

long类型的字节数,代表了处理器的位数。(32位机是4个字节,64位机是8个字节,但具体还有待测试)C语言中char、short、int、long各占多少字节_int short long字节-优快云博客

/* There is some amount of overlap with <sys/types.h> as known by inet code */
#ifndef __int8_t_defined
# define __int8_t_defined
typedef signed char             int8_t;
typedef short int               int16_t;
typedef int                     int32_t;
# if __WORDSIZE == 64
typedef long int                int64_t;
# else
__extension__
typedef long long int           int64_t;
# endif
# endif

/* Unsigned.  */
typedef unsigned char           uint8_t;
typedef unsigned short int      uint16_t;
#ifndef __uint32_t_defined
typedef unsigned int            uint32_t;
# define __uint32_t_defined
#endif
#if __WORDSIZE == 64
typedef unsigned long int       uint64_t;
#else
__extension__
typedef unsigned long long int  uint64_t;
#endif

常用的uint8_t实际上是unsigned char,无符号字符0-255。

u8,u16,u32代表的是位数,即8位、16位、32位

数组所占字节按照数组中的元素对应的数据类型来计算。

对字(Word)、半字(Half-Word)、字节(Byte)的概念说明_half word-优快云博客

字的位数有系统决定,32位系统一个字即32位(4个字节),半字就是16位(2个字节)。

6、static静态变量

C语言:关键字---static(声明静态变量)_static声明-优快云博客

一般加了static、extern来修饰的即为声明,其他都为定义。

C语言中声明和定义详解_c语言表的定义和申明-优快云博客

上博客说,除了extern都是定义?

普通局部变量

存放在进程的栈空间,若不显式赋值其初始值随机,在函数结束时该变量使用完毕便会被释放。

static局部变量

存放在进程的静态数据区,即使不显式赋值其初始值也为0,且在函数结束时仍旧保持该值不变(即下次不会再重新赋值)。

普通全局变量

定义在函数外部,在其他文件中可以使用extern声明后使用,其他文件无法再使用该变量名。

static全局变量

只能在本文件中使用,在其他文件中可以有与他同名的变量,互不影响。

static函数

与static全局变量类似,只能在声明该函数的文件中使用,其他文件可以用同名函数,互不影响。

应用

使用static可以保证不同文件之间不会因为变量名而发生错误。

7、常量

和宏定义作比较~~~~~~~~~~~~~~~~~~~~~~~~~~

8、#if、#endif、#elif、#else、#ifndef(#ifdef) 

预处理条件判断的经典三种用法 #if #ifndef #elif #endif - 孤独的二进制 - 每天5分钟 带你走近Arduino开发板的神奇世界_哔哩哔哩_bilibili

本质上是宏定义的使用,这些条件都是为了配合#define使用

1、由于各个头文件之间会交叉引用,加上如下判断代码,便可以在创建一次h文件后不再创建多次。

//sys.h文件
#ifndef  __SYS_H
#define  __SYS_H
*****
#endif

//key.h文件
#ifndef  __KEY_H
#define  __KEY_H
#include "sys.h"
#endif

//main文件
#include "sys.h"
#include "key.h"

2、用于整体项目的参数变换

#define STM32
//#define ESP32

#if STM32
  ****
#elif ESP32
  ****
#else
  ****
#endif

3、用于debug模式(和2同理)

#define DEBUG 1
//#define DEBUG 0

#if DEBUG 
  printf("debug info")
#endif

9、c文件和h文件

一般约定俗称,在头文件声明函数等,在c文件中定义函数等。

h和c文件关系的链接怎么形成?

不同.c文件的函数如何相互调用_两个.c文件如何相互调用-优快云博客

10、内存地址所占字节

每个内存空间由8bit组成,即1个byte;并且每个内存空间对应各自的一个地址(物理地址)。

(44 封私信 / 81 条消息) 为什么计算机被设计为每个内存地址对应8个位(1个字节),而不是更多的位(比如16个位、32个位)? - 知乎 (zhihu.com)

一个内存空间8位是最终确定下来的,为了达成某种目的。

物理地址:存储空间本身的地址

逻辑地址(虚拟地址):代码中为了方便表示,如指针变量的地址?

从计算机底层认识指针!深入理解C语言指针!_哔哩哔哩_bilibili

cpu缓存(SRAM):由触发器构成,1位数据就需要很多门电路,1个门电路需要好几个晶体管

内存条(DRAM):1位数据只需要1个晶体管,通过电容充放电来存储

终于!有人讲懂了DRAM和SRAM!-电子工程专辑 (eet-china.com)

DRAM:dynamic random access memory,动态顾名思义,电容充放电动态过程。

SRAM:static random access memory,静态,由电路瞬间响应。

RAM、SRAM、DRAM、SDRAM、DDRSDRAM等之间的区别_运行内存和内存那个是srm-优快云博客

单片机的内存地址:

        sram(RAM):SRAM存储原理-优快云博客

        flash(ROM):深入了解存储系统之闪存 (Flash Memory) - 知乎 (zhihu.com)

        

单片机的内存空间包括几部分:

        1、CODE

        2、SRAM

        3、外设

STM32深入系列01——内存简述(Flash和SRAM)_stm32内存-优快云博客

11、 寄存器

STM32中的32代表:CPU位数=CPU中寄存器的位数=数据宽度=CPU能够一次并行处理的数据宽度

CPU位数、操作系统位数、指令集、寄存器位数、机器字长等_操作系统位数和机器字长-优快云博客

例如,STM32F103中USART的DR(数据寄存器)、SR(状态寄存器),这两者都为16位寄存器,而SR的各个位代表了各种控制,DR的低8位存储数据(高8位硬件强制置零)。

寄存器由D触发器(不确定)构成,1个D触发器代表一位,多个D触发器组成寄存器便是一个多位的寄存器。

数字电路基础:理解寄存器工作原理与设计-优快云博客

12、CPU

CPU组成:运算器(ALU)、控制器(CU)、寄存器、缓存(cache)、总线和接口等。

CPU工作方式:CPU的基本工作是执行存储的指令序列,即程序,程序的执行过程实际上是不断地取出指令、分析指令、执行指令的过程。

CPU 工作原理(附详细图解)_cpu工作原理-优快云博客

CPU运行效率的决定因素:核心数、主频、寄存器位数、缓存容量等

什么是CPU?CPU的性能指标是什么?_决定cpu性能的主要指标-优快云博客

CPU指令集:指令集是连接CPU和操作系统的桥梁:

                      CPU——指令集(机器语言,实现CPU基本功能)——操作系统HAL库

【计算机基础】-详解CPU位数、操作系统位数、编译器位数_cpu的位数-优快云博客

二、固件代码部分

1、模块化编写思路

将每个要实现的功能模块放置到各自的C文件当中,形成函数形式,并且设定好全局变量。main文件里调用各功能函数即可。

2、keil调试

Keil5软件使用-进阶调试篇_keil调试教程-优快云博客

1)追踪变量watch1、watch2中,全局变量可以一直监视,局部变量只能在函数中监视,static变量无法监视。

寄存器窗口internal-mode的模块:thread表示在任务中,handle表示在中断中。

2)程序卡死后进行debug测试:debug-run-进入卡死状态-stop-查看命令停止位置(PC位置)-怀疑跑飞-观察call stack。(可能存在跑飞现象,停止后仍不显示黄色命令指针)

3)Keil优化等级影响局部变量查看,默认level3最简化,会在debug时无法查看局部变量;level0时最复杂,可以debug查看局部变量。

3、STM32CubeIDE

4、HAL库使用

1、DMA配置

HAL_ADC_Start_DMA(&hadc1,(u32*)ADC_Value,Channel);

该函数为DMA方式调用ADC采集数据时的函数,相比查询和中断两种方式,编写起来最为简单。

注意其中ADC_Value为数据缓存区,输入的必须是地址(一般输入为数组时,其数组名便为地址;为变量时,需要加上&来取地址),

Channel即为开启的ADC通道数(多通道依次排序,单通道则是同一个值做循环),同时决定了其与缓存区放置的个数。一般常用:Channel数=ADC通道数

当Channel数>ADC通道数时,例如Channel=1即只放在缓存区1(即地址指针不会增加),Channel=4即放在缓存区1,2,3,4(即地址指针会增加

调用一次,只能采集一次。

在使用单通道采集时,需要将其配置为如下图所示

Scan、Continuous、Discontinuous都需要禁用,原理尚未弄懂

DMA处的配置如上图所示,Mode设置为Circular和Normal都可以。

2、HAL_XXX_Init与HAL_XXX_MspInit的关系

HAL_XXX_Init函数中会调用到HAL_XXX_MspInit,从而可以将初始化参数配置与硬件管脚映射部分分离。

5、PWM函数设置

为了简化占空比为0-100,可以在SetCompare()函数中设置一个变量为

A=compare*period/100

将A作为最终的compare值去比较

这样便可以实现compare0-100表示占空比0-100的简化设置。

sConfigOC.Pulse该参数即初始的脉宽值,相当于Compare。

6、位置式PID与增量式PID

推导过程略过

位置式PID

u(x)=Kp*e(x)+Ki*[e(0)+e(1)+...+e(x)]*dt+Kd*[e(x)-e(x-1)]/dt

简化之后为

u(x)=Kp*e(x)+KI*[e(0)+e(1)+...+e(x)]+KD*[e(x)-e(x-1)]

即此处的KI和KD都和时间相关,dt表示单位时间间隔

增量式PID

Δu(x)=u(x)-u(x-1)=Kp*[e(x)-e(x-1)]+Ki*e(x)*dt+Kd*[e(x)-2e(x-1)+e(x-2)]/dt

简化之后为

Δu(x)=u(x)-u(x-1)=Kp*[e(x)-e(x-1)]+KI*e(x)+KD*[e(x)-2e(x-1)+e(x-2)]

u(x)=u(x-1)+Δu(x)

7、USART/UART配置

【STM32F4+CubeMX零基础快速入门】串口收发全攻略_哔哩哔哩_bilibili

正点原子教程,配置串口基本步骤

1、初始化;2、配置中断:HAL_UART_Receive_IT;3、设置中断优先级;4、编写中断服务函数;5、串口数据发送

8、宏和extern变量在头文件中的区别

宏定义的值是可以直接通过引用.h文件便可以引用

而变量要想通过头文件引用过来,必须加上extern的声明

9、SWD和JTAG

下载调试接口 SWD 和 JTAG的区别-优快云博客

SWD是ARM公司开发的协议,可以用于调试和下载;只需2个引脚。可以通过其I/O口打印调试信息?

JTAG兼容性更强,可以用于STM以外的其他芯片,而且功能更丰富。

10、操作系统

相对于操作系统而言的,就是裸机开发。

例如STM32,裸机开发其实是对硬件直接操作,编写对寄存器进行控制;

而操作系统,则是将各种封装好的API提供调用,从而不用去配置寄存器,省时省力。

PS:一般的C语言开发本身也已经封装好了各种函数,最底层的机器语言则为01代码。

11、中断配置的一般步骤

以定时器中断为例:

配置时钟——配置外设参数(定时器就是分频系数,计数值,计数模式等等)——配置中断优先级、使能中断、启动中断——编写中断服务函数(及中断回调函数)

三、硬件电路部分

1、IO口电气特性

st单片机IO口类型FT、TC是什么意思_百度知道 (baidu.com)

TC:标准3.3V

FT:5V耐压

2、推挽输出和开漏输出

开漏输出与推挽输出 - 知乎 (zhihu.com)

推挽输出:

        由一个PMOS和一个NMOS组合而成的推挽结构,低电平输入时,PMOS导通,NMOS截止,输出便被拉高(即连接VDD);当高电平输入时,NMOS导通,PMOS截止,输出便被拉低(即连接GND)。

        特点:

                能实现真正的高电平和低电平,在两种电平下都有驱动能力。

                无法线与,当用两个GPIO控制一个输出时,当一个输出高电平,另一个输出低电平时,短路,两个导通的MOS管必会因为大电流而烧毁一个。

开漏输出:

        类比于开集输出,使用单个三极管来控制信号的导通与否(B极作为控制开关);

        开漏输出使用单个MOS管来控制输出,例如NMOS,对高电平没有驱动能力(因为没有电阻形成电流?),必须上拉电阻才能真正输出高电平。

        特点:

                可以根据上拉电阻来调节电源特性,适合运用在需要调节电平的地方,开漏输出只有一个MOS管来控制接地或者高阻态,因此上拉任何电压时,控制高阻态可以输出任何电平。

                可以线与,可以多个GPIO口来控制同一个输出,只有GPIO都为1的时候才能输出1,否则为0。

GPIO推挽输出和开漏输出

GPIO推挽输出和开漏输出模式区别详解_gpio的推挽输出和开漏输出有何区别-优快云博客

当配置为推挽输出时,两个MOS管都工作;当配置为开漏输出时,只有NMOS启用。

GPIO在配置为输出时没有上拉下拉的配置

单片机通信中推挽和开漏的应用

详解:开漏输出与推挽输出 - 知乎 (zhihu.com)

总结:推挽输出更适合单线通信(SPI,UART),开漏输出更适合双向单线通信(I2C,One-Wire)。

复用推挽输出与复用开漏输出

简单而言,一般的输出模式为CPU控制寄存器写入;而复用则是由片上外设决定,相当于cpu先控制外设,外设再产生信号(如UART推挽输出),所以复用时无上下拉。

3、电压电流采样电路

同向放大电路(同向和反向的区别待分析,注重反向端负反馈的特性)

同相放大电路-通俗易懂教程 - 知乎 (zhihu.com)

定义:输入信号从同向端输入

特点:

        1、输入阻抗高(输入端高达几MΩ),意义是?

        2、输出阻抗低(输出端低至几Ω),带负载能力强。

        3、电压放大倍数,A=(R2/R3)+1

        4、输出和输入保持同相位

应用:

        1、小信号的放大:因为输入阻抗高,即使放大倍数极大也可以对信号调节。

        2、电压跟随器:将输出电压全服负反馈到反向输入端,就可以使输出电压等于输入电压。

        3、有源滤波器:在输入端串并联电容电感等,从而可以选取需要的信号频率。

电压采样

电压、电流采样电路设计以及放大倍数计算_电流采集电路-优快云博客

通过分压然后放大的形式获得Vout,然后由单片机检测该值。

为什么要用正向放大?为什么不是反向放大?

电流采样

运放电流检测采样电路电压采样电路_电流采样电路-优快云博客

低端电流采样

高端电流采样

4、差分放大电路

6.深入浅出:差分放大电路——参考《模拟电子技术基础》清华大学华成英主讲-优快云博客

简单概括,差分放大电路就是为了减小共模信号的干扰(比如对地信号有波动,那么便可以消除)。

差分放大电路芯片AD620

仪用放大器AD620的简单介绍-优快云博客

特性:高精度:40ppm最大非线性精度、低失调电压、低失调漂移

5、TTL和RS232

RS232电平和TTL电平有什么不同?如何转换? - 知乎 (zhihu.com)

TTL和RS232之间的详细对比_232 ttl-优快云博客

UART、RS232、TTL关系浅析 - 知乎 (zhihu.com)

PL2303是USB转RS232的芯片,为什么开发板上用它连接单片机串口和USB接口呢?单片机串口不是TTL电平么?_百度知道 (baidu.com)

串行通信/并行通信和UART、SPI、I2C、USB以及TTL、CMOS、RS-232、RS-485区别详细整理_串口与usb,spi通信有啥区别-优快云博客

1、TTL和RS232的电平标准范围不同,TTL一般为0-5V,而RS232为正负十几V,且RS232使用负电压表示逻辑1,正电压表示逻辑0。

2、TTL一般用于嵌入式设备,RS232(属于COM)一般用于PC级设备。

3、PL2303芯片是RS232(TTL)转USB(TTL),

        个人理解,USB是一种通信方式(USB广义上也是串行),而RS232(串口)是另一种通信方式,那么此处的转换的意思是通信方式上的转换;区分于RS232转TTL,该者为电平上的转换。此处的RS232实际意义相当于UART。

通信方式列举:串口通信(serial communication)、USB、蓝牙、以太网

逻辑电平列举:TTL、CMOS、RS232、RS485

电平和通信方式,是否无法同时做转换。

6、三极管

三极管的两个二极管朝向恰好相反。

三极管的奥秘:如何用小电流控制大电流_三极管怎么用小电流控制大电流-优快云博客

三极管的集电极反偏为什么会导通,由于三极管NPN各自层的厚度和掺杂不同。如下图所示,导致发射极的多数电子到达基极后只能与少量空穴结合,从而剩下的大量电子被集电极的高电势吸引,从而流动过去。顾名思义,发射极发射电子,集电极收集电子。

7、线性稳压器(LR)和开关稳压器(SR)

线性稳压器一般只能做压降,常见的有LDO,原理简单。

开关稳压器,也常被称为DC-DC,使用开关电路来做到升压、降压等的效果,电路设计复杂,效率高。

8、集成运放(模电视频)

还搞不懂虚短与虚断概念?虚断与虚断通俗讲解,几分钟带你搞定_虚短虚断的概念-优快云博客

运放特性:输入阻抗无穷大,当输入电压进输入端时,其电流几乎为0,称为虚断。

开环的时候工作在线性工作区:Uo=A*(Up-Un)——A为1,000,000(同向反向定义:当另一者输出为0时,Up与Uo相位一致,Un与Uo相位相反)

        比如±15V供电时,输出假设最多14V,那么在A的放大倍数下,Up-Un最大可以达到14uV才能放大,否则饱和。(而一般情况下14uV视为导通,因此一般Up=Un,称为虚短

运放组成部分:输入级(差分放大)、中间级(电压放大:共射级)、输出级(互补对称电路?)、偏置电路(提供电源)

中间级的放大倍数要求:RC要大,同时满足IC要在mA级别——此时电流源即可满足

9、PL2303USB转TTL模块调试心得

1、模块上的指示灯能有效显示是否数据有发送或者接收,从而判断问题来自上位机或者下位机。

2、当与下位机串口引脚相连时发现,发送数据后TXD指示灯不亮,可能是上下位机TXD与TXD相连的原因。

10、电源抑制比PSRR(即纹波抑制比)

关于dB计算,本身的计算的是功率系数为10,转换成电压后就便为20

dB=10lg(P1/P2)=10lg((U1/U2)^2)=20lg(U1/U2)

dB运算是log前面是10还是20_百度知道 (baidu.com)

11、MOS管

1、源极与衬底相连

2、栅极电压Ugs>0时,多子空穴被打到衬底底部,少子电子被吸到衬底顶部,从而在两个N极之间形成沟道,因此称为N沟道型;Ugs越宽,沟道的宽度越宽。

(SiO2绝缘层直接被挪开了?电场强行开辟出了沟道)

3、增强型和耗尽型:

增强型要加上Ugs>Ugsth,才能形成沟道

耗尽型自带沟道,Ugs>Ugsoff时,都是开启状态

12、电机驱动信号

步进电机通过斩波恒流驱动

斩波:就是恒定的直流通过不断开关来控制输出的电压,类似于PWM。

斩波恒流:通过PI控制算法来进行电流检测和控制稳定。

浅谈斩波恒流算法(代码解析)_哔哩哔哩_bilibili

13、FPGA

FPGA本质上是一个可以编程的数字电路器件,软件用于配置其硬件的走线、寄存器等等。

FPGA的时钟是数字电路器件中需要的时序。

CPLD与FPGA在原理上有一定差别,但都属于可编程数字电路器件。具体选型需要哪个,取决于项目情况的需要,比如FPGA可以拓展PLL、DSP等等,因此具有更高的扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值