目录
- 前言
- 一、时钟与中断
- 二、GPIO
- 三、ADC
- 四、定时器
-
- [4.1 基本定时器](#4.1 基本定时器)
- [4.2 通用定时器](#4.2 通用定时器)
-
- [4.2.1 输入捕获](#4.2.1 输入捕获)
- [4.2.2 输出比较](#4.2.2 输出比较)
- 五、UART
-
- [5.1 通讯的基本概念](#5.1 通讯的基本概念)
-
- [5.1.1 串行通讯与并行通讯](#5.1.1 串行通讯与并行通讯)
- [5.1.2 全双工、半双工及单工通讯](#5.1.2 全双工、半双工及单工通讯)
- [5.1.3 同步通讯与异步通讯](#5.1.3 同步通讯与异步通讯)
- [5.1.4 通信速率](#5.1.4 通信速率)
- [5.2 异步串口UART](#5.2 异步串口UART)
-
- [5.2.1 物理层](#5.2.1 物理层)
- [5.2.2 协议层](#5.2.2 协议层)
- [5.3 串口配置](#5.3 串口配置)
- 六、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的周期 - 按需求使能输出比较中断
五、UART
介绍串口UART之前先介绍一下通训的基本概念
5.1 通讯的基本概念
5.1.1 串行通讯与并行通讯
按数据通信方式分类,可分为串行通信和并行通信两种。串行和并行的对比如下图所示:
串行通信的基本特征是数据逐位顺序依次传输,优点是传输线少、布线成本低、灵活度高等优点,一般用于近距离人机交互,特殊处理后也可以用于远距离,缺点就是传输速率低。
而并行通信是数据各位可以通过多条线同时传输,优点是传输速率高,缺点就是布线成本高,抗干扰能力差,适用于短距离、高速率的通信。
5.1.2 全双工、半双工及单工通讯
根据数据传输方向,通信又可分为全双工、半双工和单工通信。全双工、半双工和单工通信的比较如下图所示:
5.1.3 同步通讯与异步通讯
根据数据同步方式,通信又可分为同步通信和异步通信。同步通信和异步通信比较如下图所示:
同步通信要求通信双方共用同一时钟信号,在总线上保持统一的时序和周期完成信息传输。优点 :可以实现高速率、大容量的数据传输,以及点对多点传输。缺点 :要求发送时钟和接收时钟保持严格同步,收发双方时钟允许的误差较小,同时硬件复杂。
异步通信不需要时钟信号,而是在数据信号中加入开始位和停止位等一些同步信号,以便使接收端能够正确地将每一个字符接收下来,某些通信中还需要双方约定传输速率。优点 :没有时钟信号硬件简单,双方时钟可允许一定误差。缺点:通信速率较低,只适用点对点传输。
5.1.4 通信速率
在数字通信系统中,通信速率(传输速率)指数据在信道中传输的速度,它分为两种:传信率和传码率。
- 传信率:每秒钟传输的信息量,即每秒钟传输的二进制位数,单位为 bit/s(即比特每秒),因而又称为比特率。
- 传码率:每秒钟传输的码元个数,单位为 Baud(即波特每秒),因而又称为波特率。
比特率和波特率的关系可以用以下式子表示:比特率 = 波特率 * log2M
其中 M 表示码元承载的信息量。我们也可以理解 M 为码元的进制数。
5.2 异步串口UART
有些MCU是USART意为同步异步串口,而UART是异步全双工串口。串口通讯 (Serial Communication) 是一种设备间非常常用的串行通讯方式,串口按位(bit)发送和接收字节。串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,双方需要约定一致的数据包格式才能正常收发数据的有关规范。在串口通信中,常用的协议包括RS-232、RS-422 和 RS-485 等。
5.2.1 物理层
根据通讯使用的电平标准不同,串口通讯可分为 TTL 标准及 RS-232 标准。通常情况下,MCU引脚发出的UART信号为TTL信号,使用 RS-232 标准的串口设备间常见的通讯结构:
在上面的通讯方式中,两个通讯设备的"DB9 接口"之间通过串口信号线建立起连接,串口信号线中使用"RS-232 标准"传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识别,所以这些信号会经过一个"电平转换芯片"转换成控制器能识别的"TTL 校准"的电平信号,才能实现通讯。
两者电平信号区别如下图:
RS-232 与 TTL 电平标准下表示同一个信号
5.2.2 协议层
STM32中的串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据:
异步通信时接收端一般会用采样定理判断信号逻辑
5.3 串口配置
为了结构简单,这边选取了一个RISC的UART框图:
UART通常会用到4根线
- VCC:电压源,一般用来给模块供电,模块自己有电可以省略
- GND:地线,必要的信号,用来同步电平
- RX:串行数据输入。
- TX:串行数据输出。当发送器使能,但不发送数据时,TX 引脚处于高电平。当发送器使能,且发送数据时,TX 引脚在起始位期间处于低电平,在停止位期间处于高电平。
UART的配置步骤如下:
- 引脚配置:主要是将RX、TX配置成对应串口的输入输出引脚,并开启对应的复用或者映射
- 使能相应的UART串口时钟
- 配置波特率
我们知道异步串口是没有同步信号CLK的,那接收端只能靠波特率来同步信号。波特率,即每秒钟传输的码元个数,在二进制系统中(串口的数据帧就是二进制的形式),波特率与波特率的数值相等,所以我们今后在把串口波特率理解为每秒钟传输的二进制位数。
波特率的配置一般有两种方式根据不同的MCU。一种是配置寄存器,根据MCU波特率计算公式,对UART时钟进行分频得到对应波特率。还有一种是类似STM32直接调用库函数,通过输入波特率,然后库函数自己计算对应的波特率配置寄存器值 - 设置通信数据长度,常规的为8位
- 设置奇偶校验位,常规为无奇偶校验
- 设置停止位长度,一般为1位
- 使能发送和接受功能
- 根据需求使能中断,如果不使能中断,系统就会轮询串口接收缓冲区