参考:
https://www.bilibili.com/video/BV1ebwEzAE2a
嵌入式学习速成 - 札记网

一、什么是电压

在一般的理解中,电压是电池两端电势的差值,如果假设一节干电池正极电压为3.7V,负极为0V,那么这节电池的电压就为正极电压值减去负极电压值,即3.7V - 0V = 3.7V。

然而这样的假设其实并不是非常符合实际情况。例如将小灯泡分别于一节电池的正极与另一节电池的负极相连,而两节电池间则断开,实际观测到小灯泡无法工作。使用电流表测得小灯泡两端电流为0,而小灯泡本身有电阻,由 $U = I \times R$ 公式可以发现实际小灯泡两端电压相等。
因此,不是任何时候都可以假设电池正极为3.7V而电池负极为0V。

根据电压的定义,我们当然也不能认为正负分别为103.7V、100V是错误的,因为它们也符合差值为3.7V的情况。

在后文,我们把这种两节电池没有没有共同参考的情况定义为悬空
我们把接地(电压为0V)的情况使用GND来表示。

二、共地
在一般情况下,电池两端电压仅需满足差值等于电压值即可,而无法研究一节电池正极(或负极)的电压对于另一节电池的数值情况,两节电池就是两个独立的系统,互不干涉也互不观测。

如果没有共同参考,A认为的2V,B表示不知道是啥。这种情况,就是上述的悬空(开路)

而在单片机中,这并不是我们理想的情况,因此,我们将两节电池负极连接并接地(GND)。

此时,两个系统合并为一个系统。我们既能知道一节电池的电压,又能通过观测两节电池正极电压(高电平)的差值来反映两节电池的异同。

因此,为了让整个电子系统以统一参考运行,务必将所有的GND连接在一起,称为共地
如果失误没有共地,则会出现:通信失败、舵机乱动等一系列异常情况。

三、单片机最小系统

单片机最小系统由最基础的电路组件构成,只要去掉其任意一部分,该系统都不能正常运作。单片机最小系统包括:单片机芯片、时钟电路、复位电路、电源。

单片机芯片(主控芯片)
系统的核心,负责执行程序、处理信号,通常标有型号,如STM32F103C8T6。

时钟电路(晶振)
像心脏一样提供工作节拍,每震荡一次推动主控芯片的一步计算(联想到Minecraft中的游戏刻game tick)。

复位电路
使单片机一键重启,恢复到初始的稳定状态。一般为一个黑色小按钮。

电源
给单片机供电。

为了方便开发,这四个部分被集成在一块板子上,称为最小系统板

使用这块板子,再通过板上的引脚,单片机最小系统被连接到其他模块是实现各种功能。
下文围绕引脚的功能展开。

四、GPIO

GPIP意为通用输入输出(General Purpose Input/Output),它是单片机最基础的功能。可以读取引脚处的输入值或控制输出值。

输入模式

在此模式下,可以读取引脚处的输入值是高电平还是低电平。
高电平一般是单片机的工作电压,多为3.3V或5V。
低电平指代GND或0V。

输入模式最常用于按键检测,通过检测输入的电平高低来判断按键的开闭。
然而若是仅如图设计电路,会发现一个致命的问题:当按键闭合时,引脚检测到0V低电平;但是当按键断开,引脚到按键整段处于悬空状态,读取到的值既有可能是0也有可能是1。

因此,为了避免悬空的产生,我们设计使用上拉电阻下拉电阻的方法。

上拉输入
在芯片外连接1k$\Omega$~100k$\Omega$的电阻(常用4.7k$\Omega$、10k$\Omega$),再连接高电平。

此时,当按键闭合接地,由于加入电阻避免了短路,引脚处读取的值为0V低电平;当按键断开,由于形成断路。电流为0,电阻两端电压几乎相同为3.3V或5V,因此引脚处读取到高电平。我们便能通过引脚的输入值来判断按键的开闭。

下拉输入
在芯片外连接1k$\Omega$~100k$\Omega$的电阻(常用4.7k$\Omega$、10k$\Omega$),再接地

同理,当按键闭合,由于加入电阻避免了短路,且导线连接任意点电压相等,引脚输入高电平;当按键断开,电阻两端电流为0,电压几乎相等,引脚输入低电平。也可以通过输入电平的高低来判断按键的开闭。

现代芯片很多可以内部开启(或关闭)上拉/下拉电阻,无需手动在芯片外部添加。

输出模式

0和1的输出
输出模式的本质是有两个开关分别控制引脚连接到VCC(Voltage at the Common Collector,一般3.3V或5V)和GND。

连接到上方VCC时,引脚输出高电平1;
连接到下方GND时引脚输出低电平0。

这种输出方式称为推挽输出,相当于直接连接电源或接地,因此,具备一定的驱动能力,可以给元件供电。

除了推挽输出,还有另一种常见的输出方式称为开漏输出
开漏输出只使用一个开关,但是增加一个上拉电阻(也可芯片内部上拉)

当开关闭合,引脚接地,输出低电平0;当开关断开,由于电流近似为0,电阻两端电压几乎相同,引脚输出高电平1。
开漏输出只能拉低电平,而无法主动输出高电平。由于上拉电阻(1k$\Omega$~100k$\Omega$)的串联接入,使得引脚输出高电平时也几乎无法驱动元件(电压、电流过小)。

但是,开漏输出可以实现“线与”逻辑,用于多设备输出到同一根总线。

如图,若A、B、C、D四个引脚的开关均断开,输出高电平1;只要其中一个引脚开关闭合,就会拉低总线的电平,使其输出低电平0。

五、PWM:介于0和1之间的输出
只输出0和1,往往不是我们希望达到的最终结果,为了能够输出像0.666666这样的数值,我们引入了PWM。

PWM(Pulse Width Modulation)即脉冲宽度调制技术,通过改变脉冲的宽度,来模拟不同的电压值。通俗来讲,就是通过快速地切换0和1,使用1所占一个周期的比例来表示大小。

占空比 50%:
高电平 ████________████________
└─4ms─┘└─4ms─┘ 周期 8ms

占空比 80%:
高电平 ████████__████████__
└──6.4ms─┘ 周期 8ms

频率较高时,就可以近似的实现电压的调节,但本质仍然是快速的0和1的脉冲信号。

从上面的陈述我们可以发现,PWM具有两个关键性参数:频率占空比

频率($\frac{1}{周期}$):一秒钟内走过一个周期的次数。频率越快模拟信号越平稳。可以改变蜂鸣器的音调

占空比:一个脉冲周期内,高电平所占的时间与整个周期所占时间的比例。占空比越大,模拟的电压与高电平越近。可以控制LED亮度、电机转速、舵机角度等。

六、TIM定时器/计数器
前面介绍了PWM产生我想要的脉冲,例如0.6666,那么一个很自然的问题就是:如何让单片机输出我想要的脉冲呢?

一个方法是:让程序一直检查时间,达到规定时间就输出高电平1,再达到规定时间就输出低电平0,以此为周期…
这个方法有两个致命的问题:
一、PWM的频率可能会达到100khz、1Mhz甚至更高,让程序去实时地获取、比较时间、输出会极大影响PWM的精度。
二、程序在反复、实时的检查过程中,无法执行其他的程序。

为了搞清楚这个问题,我们首先要知道一个基本事实:单片机的内部设计了外设(Peripherals),这个外设在配置好后,只要有系统的时钟信号,就会根据自己的配置执行一定的功能。而主程序则可以继续执行其他的任务,也能读取外设的状态。我们在前面提到的GPIO就是外设的一种,同时,接下来提到的所有内容都是外设。

因此,我们使用称为TIM定时器/计数器(Timer/Counter) 的外设来解决这个问题。
而TIM实现PWM的关键在于进位和溢出,就像一个机械计数器,在满10后会往前进一位,在达到所能表达的最大数字9999后又会发出提醒并归零。

预分频值PSC、自动重装值ARR和比较值CCR是TIM的三个核心参数

分频器的作用是降低频率,输入PSC个脉冲,分频器就会输出1个脉冲,把频率降低到原来的$\frac{1}{PSC}$。
因此,PSC变大,输出频率变小;
PSC变小,输出频率变大。
预分频值PSC主要决定了总脉冲的频率,影响计数值上升的速度(斜率)。

自动重装值ARR可以类比为机械计数器可表示的最大数9999,当前计数值在上升达到ARR时,会归零重新开始下一个周期的上升。

比较值CCR决定了计数时溢出状态的判定,当计数值还未达到CCR,处于未溢出状态,输出高(或低)电平;当计数值超过CCR,处于溢出状态,输出低(或高)电平,如图。

通过上面的叙述,我们可以给出PSC、ARR、CCR对于PWM频率和占空比的决定公式:

PWM频率 = $\frac{主频}{(PSC+1)\times(ARR+1)}$
PWM占空比 = $\frac{CCR}{ARR+1}$

注意:此处PSC和ARR的本质也是计数器的值,而单片机中从0开始计数,因此在表示实际的份数时要“+1”,而CCR由于是人为设定的分界线,本质与意义相同,无需再加。

七、ADC
我们成功通过PWM输出了0.6666这样的信号,但在实际场景中还需读取这样的值,也即读取模拟信号。此时,我们就要用到ADC(模数转换器)

例如,在5V的单片机中,我们可以通过ADC将读取到的3.1V电压值转为2539/4095。即0111 1111 0111,满足$\frac{3.1}{5}$ $\approx$ $\frac{2539}{4095}$。

在有些单片机中,存在名为ADC_VREF的引脚,用于指定ADC的最大量程(小于等于单片机的VCC),若不接ADC_VREF,则将VCC作为ADC的最大量程。

精度\分辨率(N bit) 表示ADC的转换结果有$2^{N}$个电压台阶,位数越高,精度越高。
如12bit的精度转换结果为:2539/4095(011111110111)
8bit的精度转换结果为:158/255(10011110)

采样率/转换时间:由于ADC内部通过逐次逼近的方法来确定转换后的值,因此需要转换时间,即采样率。

另外,还有一个名为**DAC(数模转换器)**的元件,也能将数字信号输出为模拟信号,但是此处PWM可作为较初级的平替。

八、IRQ,中断请求

中断请求(Interrupt Request) 是 系统中硬件向CPU发送的一种脉冲信号。主程序在正常运行时,若是出发某个条件,就会收到IRQ,暂停主程序,执行中断请求所对应的程序。在这之后,才会返回主程序继续。

中断的触发条件有以下三类:

中断的触发的来源是多样的,都可以通过代码进行设定,来实现各种不同的功能:

外部触发:直接由某个引脚触发,适合用在按键检测、传感器触发。例如,在其他程序运行时,如果按键按下,则灯亮起。

计数器TIM触发:当计数器捕获引脚的信号达到该计数器设定的自动重装值ARR时,会清零并产生一次脉冲,该脉冲可触发中断。 例如实现:其他程序运行时,电机每转动一圈(52个脉冲)则灯亮灭翻转一次。

定时器TIM触发(特殊的计数器):将主频信号(或将主频经过分频的信号),接入计数器,当计数 器达到设定的自动重装值ARR时,会清零并产生一次脉冲,该脉冲可触发中断; 例如实现:其他程序运行时,每过500ms则灯亮灭翻转一次。

硬件触发:如UART、DMA、ADC、I2C、SPI等。