目录
- 前言
- 一、时钟与中断
- 二、GPIO
- 三、ADC
- 四、定时器
- 4.1 基本定时器
- 4.2 通用定时器
- 4.2.1 输入捕获
- 4.2.2 输出比较
- 五、UART
- 六、IIC
- 七、SPI
前言
本文主要讲单片机外设的功能,即这些外设是什么,可以用来干什么,了解了之后我们就可以通过相应的寄存器配置来驱动这些外设。本文带大家深入了解一下这些外设的工作原理,知道了功能之后,对应任意一个MCU都可以找相应功能的寄存器。因为寄存器名字可以不同,配置方式可以不同,但是功能不可能有很大的差异。这样才能在换一个平台MCU的情况下,实现快速入手
一、时钟与中断
在之前首先了解一下寄存器,与远古时代的汇编不同,现在都是C语言操作寄存器。那寄存器是什么,百度百科说的很笼统,我们可以将寄存器比做成可以被软件控制的开关,通过不同的开关组合状态,就可以形成我们想要的功能。
然后我们再了解一下时钟,学过数电的都知道,系统内部改变状态都需要一个CLK脉冲信号,这边到MCU就是一个时钟信号。以下所有外设都需要时钟的支持,当然我们可以通过寄存器和选择器来配置系统时钟,并对其作相应的分频和倍频,来得到我们需要的时钟频率。以下就是M4内核的时钟树结构:
不过时钟不需要太关心,我们只需要知道常用的主频是多少Hz就行,因为对于像STM32之类,使用库函数都被官方封装好了时钟,然后被启动文件直接上电执行。如果是RISC或者STM8内核之类,其实配置时钟就一两个寄存器,一般就是主频选择和时钟分频。其他如51内核的,一般情况下不需要配置时钟,MCU默认开启,除非需要修改时钟的情况下才需要配置。
有了上面的基础就可以开始中断部分了,首先要知道中断是什么?中断是一种发生了一个外部的事件时调用相应的处理程序的过程。这个概念可能不好理解,那我们直接需要知道就是中断可以用来干什么,怎么来触发中断的就行。正常情况下,计算机所有指令都是随着系统时钟从上到下执行,但是中断可以在系统指令执行期间优先执行。
通常情况下,中断需要一个触发源,即触发中断的信号,如外部中断、定时器、ADC等等,出发后程序运行进入中断函数,原主函数位置会保存到栈空间,等中断函数执行完成之后,再从栈空间读取继续主函数的运行。
上图就是STM32的中断控制器,其他MCU也很类似,由上大概可以知道需要配置的寄存器如下,然后再对比参考手册找相应的寄存器:
- 中断触发源:即触发中断信号的来源
- 中断优先级:部分MCU需要配置中断优先级,即高优先级的中断优先处理
- 中断触发类型:比如在上升沿触发
- 中断使能:即开启中断功能
- 中断标志位:主要是触发中断和中断完成标志位,需要软件判断和设置
二、GPIO
GPIO( general purpose intput output) 是通用输入输出端口的简称。那什么是输入输出呢?我们都知道芯片只能处理数字信号,数字信号在数据上体现为逻辑0和逻辑1,实际上代表了高电平(5V或3.3V)和低电平(0V)两种状态。那输入就是MCU通过I/O口来检测外部电平状态,而输出就是MCU向外部输出不同的电平状态。
知道I/O的功能之后,我们就可以来配置GPIO,需要配置的参数如下:
- I/O时钟
ARM系列需要单独开启IO时钟,其他如51、STM8、RISC等不需要配置,只需要初始化系统时钟即可。 - 方向控制
方向控制就是配置IO口输入输出模式,基本所有MCU都需要配置 - 输入模式配置
当IO被用于输入模式时,一般可设置为上拉、下拉或浮空模式。所谓的上拉就是接一个上拉电阻,上拉电阻连接正极,提供5V或者3.3V电压,即默认高电平。浮空模式就是没有高低电平状态,I/O口电压跟随周围电路状态 - 输出模式配置
当IO被用于输出模式时,一般可设置为推挽、开漏或准双向口。准双向口和推挽的区别是,推挽是强上下拉,可以提供更大的电流。开漏输出时会关闭内部上拉电阻,只能下拉输出,上拉输出需要外部加上拉电阻。由于开漏相当于MOS开关,所以可以用于IIC电路电平匹配 - 数据寄存器
当I/O口作为输入的时候,可以读取数据寄存器,查看I/O口高低电平状态;当I/O口作为输出时,将数据写进数据寄存器,此时对应的引脚就可以输出相应的电平状态 - I/O复用与映射
I/O复用是一个很常见的功能,就是将普通的I/O口当作其他外设使用,比如复用为ADC可以当作模拟输入,复用给定时器作为PWM输出等等;而映射就是当复用的I/O引脚不够用的时候,可以把其他外设比如ADC的某个通道,映射到特定的引脚,原来的I/O作为其他用途
三、ADC
首先要知道ADC是什么?ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模数转换器,是指将连续变化的模拟信号转换为离散的数字信号的器件。
那ADC有什么用呢?我们在电路中通常会使用一些传感器,这些传感器可以将一些模拟量转换成不同的阻值,比如温度传感器,他的阻值会随着温度的变换而变化,此时我们只要测量出阻值就可以根据线性表得出温度。而ADC最基本的作用就是测量电压,然后我们就可以根据电压值计算出阻值,从而得到最终温度。
上图就是STM32内部ADC框架,还是很复杂的,不过一些MCU的ADC没有那么多功能,我们可以去掉上图的3和7,以一个RISC的内部ADC框架来说明,如下图:
这样了解ADC就会简单点,ADC具体配置如下:
- ADC时钟配置
- 使能ADC时钟,即开启ADC
- 选择时钟源,即时钟信号的来源,比如系统时钟,内部晶振,外部晶振
- 进行时钟分频
- 采样延迟,防止采样抖动,可以选择延迟一段时间后采样
- 通道选择
- I/O配置:使用ADC采样一定是用的某个I/O口,将其设置成模拟输入模式
- 通道选择:每个ADC几个通道,分别对应不同的I/O口,也可以使用I/O映射功能
- 触发模式选择
- 触发源:一般可以定时器中断触发,ADC中断触发,或者软件触发
- 触发方式:一般有上升沿、下降沿、低电平等等之类触发
-
参考电压选择
参考电压是什么?参考电压就是ADC测量的范围,一般用Vref-和Vref+两个参考元组成,而输入电压Vin的范围就是:Vref- ≤ Vin ≤ Vref+ 。
那我们通常把参考电压的负极接地,即Vref- = 0V;然后将参考电压正极接内部或者外部的其他电源,如2V、3.3V或者5V电压 -
数据对齐与处理
在了解数据处理之前,先了解一下ADC最重要的参数,就是ADC的精度。通常MCU的ADC精度是12位的,当然有些专用ADC可能有更高的精度。那为什么要了解精度呢?我们要知道通常MCU内部数据为8位或者8的倍数位,那此时12位数据用8位明显不够,用16位又多了。此时就需要配置数据对其方式,16位左对齐那么低4位数据无效;同理右对齐那么高4位的数据无效。
我们配置好之后,直接去读取的数据只是ADC的数据,而不是实际电压值。那这电压值怎么换算呢?这里就需要综合ADC精度和参考电压了,实际电压值=采样值/(2^精度)*(Vref+ - Vref-)+ Vref-,这个公式应该不难理解,就是根据参考电压,然后按照比例得出电压值。而我们精度12位就是4096,Vref-接地为0V,所以最终电压计算如下所示:
四、定时器
定时器最基本的功能就是定时与计数了,这有什么用呢?我们都知道可以软件里写一个死循环用来延迟,但是这种延迟会占系统CPU资源,而且会被中断打断,导致延迟不准确。此时我们可以用定时器设置计数标志位,从而可以得到精准的延迟。首先我们看一下定时器分类,定时器基本有以下3种类型:
- 基本定时器:基本定时器是最简单的定时器,只有计数和定时作用,可以设置中断
- 通用定时器:在基本定时器的基础上,再加上捕获/比较功能,一般用来PWM输出
- 高级定时器:它一般有4路捕获/比较通道,此外还有编码器接口与刹车中断,一般用来电机控制
正常情况下,如ARM、STM8、RISC之类PWM是由通用定时器产生的。而8051定时器没有PWM功能,其他如STC8H用的51内核,它的PWM是额外的专用定时器。本小节就讲常规的基本定时器与通用定时器功能
4.1 基本定时器
首先看一下基本定时器框图,为了简单,这边选了一个RISC的基本定时器:
从上图很容易看出,先是时钟进来分频,然后计数器就开始进行计数,基本定时器一般只支持递增计数,当计数值CNT与影子寄存器值相等时,计数器就会清零并产生更新事件,然后自动重装寄存器ARR就把值写入影子寄存器。如果使能中断,触发更新事件就会产生中断,然后我们可以在中断里清除中断标志位。工作方式如下所示:
大致的工作原理如上,根据流程我们需要配置的参数如下:
- 时钟配置
- 选择相应的定时器,并使能定时器时钟
- 选择时钟源(有些MCU是默认的,比如STM32)
- 设置分频系数
- 计数设置
对于基本定时器只需要设置自动重载寄存器ARR的值即可。此时定时器产生更新事件的时间,即定时时间=系统时钟/分频系数/(计数值+1)。因为计数器是从0开始计数
4.2 通用定时器
这边同样用一个RISC的通用定时器举例,框图如下所示:
可以看出与基本定时器明显的区别就是多了几路捕获/比较通道。此外通用计数器的位数更高,并且有些通用定时器可以递减计数。那这边有个问题,捕获和比较分别是什么呢?下面会重点介绍输出比较,简略介绍输入捕获功能
4.2.1 输入捕获
输入捕获一般应用在两个方面,一个方面是脉冲跳变沿时间测量,另一方面是 PWM 输入测量。
- 测量脉宽或者频率
当测量频率时,可以记录两次上升沿的时间;如果是测量脉宽就记录三个值,其中v3-v1是周期,v2-v1是脉宽 - PWM 输入模式
测量脉宽和频率还有一个更简便的方法就是使用 PWM 输入模式。与上面那种只使用一个捕获寄存器测量脉宽和频率的方法相比,PWM 输入模式需要占用两个捕获寄存器。以STM32寄存器举例:
下面我们以一个更加具体的时序图来分析下 PWM 输入模式:
PWM 信号由输入通道 TI1 进入,配置 TI1FP1 为触发信号,上升沿捕获。当上升沿的时候 IC1 和IC2 同时捕获,计数器 CNT 清零,到了下降沿的时候,IC2 捕获,此时计数器 CNT 的值被锁存到捕获寄存器 CCR2 中,到了下一个上升沿的时候,IC1 捕获,计数器 CNT 的值被锁存到捕获寄存器 CCR1 中。其中 CCR2 测量的是脉宽,CCR1 测量的是周期。
4.2.2 输出比较
在STM32F4输出比较模式总共有 8 种,具体的由寄存器 CCMRx 的位 OCxM[2:0] 配置。我们这里只讲解最常用的 PWM 模式。
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。我们可以让定时器产生PWM,在计数器频率固定时,PWM 频率或者周期由自动重载寄存器(TIMx_ARR)的值决定,其占空比由捕获/比较寄存器(TIMx_CCRx)的值决定。PWM 产生原理示意图如下图所示:
PWM 模式分为两种,PWM1 和 PWM2,总得来说是差不多:
定时器产生 PWM 的方式有许多种,下面我们以边沿对齐模式(即递增计数模式/递减计数模式)为例,PWM 模式 1 或者 PWM 模式 2 产生 PWM 的示意图,如下图所示:
有了上面的基础就可以开始配置PWM了,步骤如下:
- I/O配置
由于PWM输出使用的是定时器的某个通道,这个通道对应某个I/O口,所以要先开启对应I/O的复用或者映射,并将其配置为输出模式 - 定时器配置
定时器配置可以参考4.1小节的基本定时器的配置 - 使能PWM输出比较通道,并选择PWM模式
这个PWM输出通道指的是定时器捕获/比较通道,比如上面通用定时器框图里的CH1。至于PWM模式上面有讲 - 使能比较输出并配置输出极性
这里的比较输出使能是指主通道或者互补通道的使能,输出极性就是在对应的PWM模式下,当有效时输出电平为高电平还是低电平 - 配置比较值
这里的比较值就是PWM脉宽,即上面捕获比较值寄存器CCR。通常CCR需要小于自动重载值ARR,ARR配置就相当于PWM的周期 - 按需求使能输出比较中断