时钟控制器和TIM、DMA、ADC、UART控制器
一、时钟控制器
一、四种时钟源
RC振荡器: • RC振荡器的优点是成本低,启动速度要比晶振快,但是精度没有晶振/陶 瓷谐振器高。
无源晶体振荡器: 工作原理是基于压电效应和共振原理交互作用而产生的。需要借助于 时钟电路才能产生振荡信号,自身无法振荡起来。
有源晶体振荡器: 内部是一个完整的振荡电路,原理与无源晶振类似,有源晶振需要外 部电源供电才能起振。
内部时钟源:
HSI 内部高速时钟源 (内部 RC 振荡器,自带,快但不准)
LSI 内部低速时钟源(内部 RC 振荡器约32kHz,自带低速,省电但不准)
外部时钟源:
HSE 外部高速时钟源 (外接,准但启动慢)
LSE 外部低速时钟源(外部 32.768kHz 晶振或陶瓷谐振器,外接晶振,准又省电)
二、系统时钟
内部PLL基于HSI或HSE 输入的时钟频率进行倍频,从而得到系统时钟 SYSCLK。
SYSCLK即常说的系统时钟,可以通过System Clock Mux选择器来选择 输入的源时钟,有HSI、HSE、PLLCLK三种输入源。
将SYSCLK时钟经过AHB Prescaler分频器分频后就得到了HCLK时钟, HCLK时钟为AHB总线提供的时钟信号,
三、外设时钟
APB总线时钟可分为APB1和APB2时钟,APB时钟输入源 都是由HCLK时钟提供时钟输入。之后经过APB Prescaler分频后得到 APB外设时钟。
外设控制器时钟主要通过AHB总线时钟、APB1总线时钟、 APB2总线时钟来提供时钟输入。每条总线上都可以挂载多个外设控制器。
二、DMA控制器
DMA代表直接存储器访问。
DMA是一种嵌入式系统中用于高效传输数据的机制,提供在外设与存储器、存储器和存储器之间的高速数据传输, 它允许外设中的数据直接传输到系统存储器,而无需通过CPU的干预。 特别是在大量数据传输的场景下,通过减少CPU的干预,系统性能得到提升。
作用是解放CPU
1.DMA的仲裁器
DMA中的仲裁器是一个用于管理多个DMA通道之间竞争访问系统总线的组 件。
当系统中有多个外设或DMA设备需要访问系统内存时,可能会存在竞争条件。
仲裁器的任务是协调这些通道的访问。
• 软件优先级:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:
• 最高优先级(Very High)
• 高优先级(High)
• 中等优先级(Medium)
• 低优先级(Low)
• 硬件优先级:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。
DMA_SxNDTR计数器在数据存储结束后递减,该计数器中包含仍需执行的事务数。
2.DMA的传输模式
数据传输方向使用DMA_SxCR寄存器中的DIR[1:0]位进行配置,有三种可能的传 输方向:存储器到外设、外设到存储器或存储器到存储器。
2.1FIFO
启用FIFO后,每个数据流都有一个独立的4字(16字节)FIFO,源地址 中的数据不会之间由DMA搬运到目标地址中,而是先将数据存入FIFO中, 当到达设置的阈值时DMA会从FIFO中将数据取出放入存储器。
2.2DMA的指针增量
根据DMA_SxCR寄存器中PINC和MINC位的状态,外设和存储器指针在 每次传输后可以自动向后递增或保持常量。
• 当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。
• 当设置为保持常量时,每次传输的将会是同一个内存地址中存放的数据。
如果使能了递增模式,则根据在DMA_SxCR寄存器PSIZE(外设数据宽度)或MSIZE(存储器数据宽 度)位中编程的数据宽度,下一次传输的地址将是前一次传输的地址递增 1(对于字节)、 2(对 于半字)或 4(对于字)。
在直接模式下,不允许源与目标的传输数据宽度不同,二者必须相等,并由 DMA_SxCR中的PSIZE位定义,MSIZE位无效。 当使用内部FIFO时,源和目标数据的数据宽度可以通过DMA_SxCR寄存器的 PSIZE和MSIZE 位(可以是8、16或32位)编程。
当PSIZE和MSIZE不相等时: 在DMA_SxNDTR寄存器中配置的要传输的数据项数目的数据宽度等于外设总线的宽度(由PSIZE位配置)。 例如,将PSIZE[1:0]位配置为半字,则要传输的字节数等于2×NDT。
3.DMA的循环模式
循环模式可用于处理循环缓冲区和连续数据流(例如ADC扫描模式)。
可以使用DMA_SxCR寄存器中的CIRC位使能此特性。 当激活循环模式时,要传输的数据项的数目在数据流配置阶段自动用设置的初始值进行加载,并继续响应 DMA 请求。
4.DMA的双缓冲模式
通过将DMA_SxCR寄存器中的DBM位置1,即可使能双缓冲区模式,存储器到存储器模式不适用。
在此模式下,DMA_SxM0AR与DMA_SxM1AR寄存器互相协作,每次事务结束 时,DMA 控制器都从一个存储器目标交换为另一个存储器目标。 软件在处理一个存储器区域的同时,DMA传输还可以填充/使用第二个存储器区 域。
4.1DMA的流控制器
控制要传输的数据数目的实体称为流控制器。
流控制器使用DMA_SxCR寄存器中的PFCTRL位针对每个数据流独立配置。
• DMA控制器:在这种情况下,要传输的数据项的数目在使能DMA数据流之前由软件编程到 DMA_SxNDTR寄存器。
• 外设源或目标:当要传输的数据项的数目未知时属于这种情况。当所传输的是最后的数据时,外 设通过硬件向DMA控制器发出指示。仅限能够发出传输结束信号的外设支持此功能(SDIO)。
当外设流控制器用于给定数据流时,写入DMA_SxNDTR的值对DMA传输没有作用。一旦使能数据流,硬件即会将该值强制置为0xFFFF。
5.DMA的搬运模式
5.1外设到存储器模式
• 源地址:外设的数据寄存器地址 • 目标地址:存储器中的一段空间 直接模式:不使用FIFO的阈值级别控制:每完成一次从外设到存储器的数据传输后,相应的数据 立即就会移出并存储到目标中。 使能FIFO:每次产生外设请求,数据流都会启动数据源到 FIFO 的传输。达到 FIFO 的阈值级别 时, FIFO 的内容移出并存储到目标中。
5.2存储器到外设模式
• 源地址:存储器中的一段空间 • 目标地址:外设的数据寄存器地址 直接模式:不使用FIFO的阈值级别控制:每完成一次从存储器到外设的数据传输后,相应的数据 立即就会移出并存储到目标中。 使能FIFO:数据流会立即启动传输,从源目标完全填充 FIFO。每次发生外设请求, FIFO的内容 都会移出并存储到目标中。当FIFO的级别小于或等于预定义的阈值级别时,将使用存储器中的数 据完全重载FIFO。
5.3存储器到存储器模式
• 源地址:存储器中的一段空间 • 目标地址:存储器中的一段空间 使能FIFO:通过将 DMA_SxCR寄存器中的使能位 (EN) 置 1 来使能数据流时,数据流会立即开 始填充FIFO,直至达到阈值级别。达到阈值级别后, FIFO 的内容便会移出,并存储到目标中。
6.DMA的HAL库
DMA控制器初始化配置结构体
typedef struct { uint32_t Channel; /* 数据流的通道编号 */ uint32_t Direction; /* 数据传输方向 */ uint32_t PeriphInc; /* 外设地址递增模式 */ uint32_t MemInc; /* 存储器地址递增模式 */ uint32_t PeriphDataAlignment; /* 外设数据宽度 */ uint32_t MemDataAlignment; /* 存储器数据宽度 */ uint32_t Mode; /* DMA传输模式 */ uint32_t Priority; /* 数据流优先级 */ uint32_t FIFOMode; /* 直接模式/FIFO模式 */ uint32_t FIFOThreshold; /* FIFO阈值级别*/ uint32_t MemBurst; /* 存储器突发模式 */ uint32_t PeriphBurst; /* 外设突发模式 */ }DMA_InitTypeDef;三、TIM定时器
1.基本定时器
基本定时器,TIM6和TIM7的功能: 生成时基(定时) 驱动数模转换器(DAC)
图 基本定时器结构细分
1. 时钟源(内部时钟CK_INT)
基本定时器(TIM6和 TIM7)的时钟源来源于APB1总线时钟。
2. 预分频器(PSC)
负责对定时器输入时钟进行分频,它的主要作用是通过降低定时器的输入时钟频率,为定时器的计时和定时功能提供更灵活的时间控制。
TIMx_PSC寄存器是定时器的预分频器寄存器,用于设置定时器的预分频因子,分频因子决定了定时器的时钟频率。需要注意的是实际的分频值是TIMx_PSC+1,例如,当TIMx_PSC寄存器的值为0时,实际的分频因子的大小为 0 + 1 = 1。
3. 计数器
计数器通过对输入时钟(由预分频器分频后的时钟信号),记录经过的时间。
计数器的计数模式有三种,递增计数、递减计数、中央对齐计数,但是,基本定时器仅支持递增模式。
TIMx_CNT寄存器是计数寄存器,用于存储定时器的计数值。
4. 自动重装载器ARR
控制计数器的最大计数值,从而影响定时器的溢出时间和功能行为。 TIMx_ARR是自动重装载器的重装载值寄存器,当TIMx_CNT寄存器等于TIMx_ARR寄存器时,计数器上溢,TIMx_CNT寄存器的值自动重置为 0,同时产生一个UEV更新信号。
2.UEV事件
可能产生UEV事件的信号来源:
①计数器上溢(TIMx_CNT寄存器值==TIMx_ARR寄存器值)
②手动产生(将TIMx_EGR.UG位写1)
产生UEV事件的信号来源是否可以产生一个UEV的更新事件,取决于TIMx_CR1.UDIS位域。 TIMx_CR1.UDIS为0时,允许产生更新事件;TIMx_CR1.UDIS为1时,则禁止产生UEV事件。
3.更新中断和DMA请求
生成更新中断和DMA请求的两种情况(取决于TIMx_CR1.URS位域):
TIMx_CR1.URS设置为1时:只有计数器上溢(TIMx_CNT寄存器值==TIMx_ARR寄存器值),会生成更新中断和DMA请求.
TIMx_CR1.URS设置为0时: 所有以下事件都会生成更新中断或 DMA 请求。此类事件包括:
—计数器上溢 (TIMx_CNT寄存器值==TIMx_ARR寄存器值)
—将 UG 位置 1
—通过从模式控制器生成的更新事件
4.通用定时器
4.1TIM2-TIM5
彼此间完全独立,不共享任何资源。
1、时钟源 2、控制器 3、时基单元 4、输入控制 5、输入捕获/输出比较 6、输出控制
4.2 TIM2到TIM5的框图
图 通用定时器TIM3举例
对时钟源CK_INT进行预分频:通过TIMx_PSC设置预分频系数,注意:实际的预分频系数= TIMx_PSC+1.
5.PWM输出
PWM(Pulse Width Modulation)简称脉冲宽度调制,是利用微处理器的数字输出来对模拟电路进行控制的 一种非常有效的技术,广泛应用在测量、通信、工控等方面。
PWM的频率 是指在1秒钟内,信号从高电平到低电平再回到高电平的次数,也就是说一秒钟PWM有多少个周期,单位Hz。
占空比是一个脉冲周期内,高电平的时间与整个周期时间的比例,单位是% (0%-100%)
计数器模式:由CR1寄存器下的CMS和DIR共同决定。
PWM模式1
在递增计数模式下,只要TIMx_CNT<TIMx_CCR1,通道1便为无效状态(OC1REF=0),否则为有效状态 (OC1REF=1)。
在递减计数模式下,只要TIMx_CNT>TIMx_CCR1,通道1便为无效状态(OC1REF=0),否则为有效状态 (OC1REF=1)。
PWM模式2
在递增计数模式下,只要TIMx_CNT<TIMx_CCR1,通道1便为有效状态(OCxREF=1),否则为无效状态 (OCxREF=0)。
在递减计数模式下,只要TIMx_CNT>TIMx_CCR1,通道1便为有效状态(OCxREF=1),否则为无效状态 (OCxREF=0)。
当TIMx_CNT=TIMx_CCR1时,TIMx_SR寄存器“捕获/比较中断标志(CC1IF)”置1,如果CC1中断使能还会触发捕获/比较中 断。 当计数器发生溢出时,如果TIMx_CR1寄存器UDIS为0允许UEV更新,“更新中断标志(UIF)”置1,如果UIE中断使能还会触 发更新中断。
四、ADC控制器
1.ADC转换的主要流程
ADC将模拟信号转换为数字量,一般都需要经过三个步骤:采样、量化和编码。
1.1采样
首先要对模拟信号进行采样,采样的作用就是将时间上连续的模拟信号离散化。
简单来说就是以固定的时间间隔采集连续信号,这样就 可以得到一个在时间上离散的信号,而这个固定的时间间隔被称为采样周期,用T表示,那么采样频率Fs = 1 / T,单位是Hz,公式中的分母1 表示1s,那么其含义就是1s有几个时间间隔,也就等价于1s时间可以采集多少个点。
采样一定会造成连续信号的损失,采样的频率越高,信号的损失越小。
如果一个系统以超过信号最高频率 至少两倍的速率对模拟信号进行均匀采样,那么原始信号就能从采样产生的离散值中完全恢复(奈奎斯特采样定理Fs > 2fmax)。
1.2量化
量化的作用其实就是将采样出来的模拟信号值进行分级,然后每一个级别对应一个数字值。
量化的两种方式:四舍五入和只舍不入
量化方式一:只舍不入法,量化中不足量化单位部分舍弃掉。
量化方式二:四舍五入,以 量化间隔 / 2 为分界,进行取舍。
1.3编码
编码的含义就是用“1”和“0”的组合,为每个量化等级进行编号, 从而代替相应区间的电压值。
2.ADC的分辨率和参考电压
分辨率:量化间隔越小,把规定范围的电压分成的份数就越多,这就代表它的分辨率越高,分辨率也就是系统能够测量的最小电压。在上面的例子中, 我们将10V的电压分成16份,也就是2的四次方,所以它的分辨率就是4位,那如果我们将电压分成1024份,也就是2的10次方,所以它的分辨率 就是10位,量化将直接从0.625V变成了0.0098V。常见的ADC分辨率一般有8位、10位、12位等等。
参考电压:要想得到量化的间隔,就需要两个参数,一个就是分辨率,确定划分的份数,另一个就是一个基准电压,例子中的10V, 这个基准电压被称为参考电压(VREF)。STM32的ADC控制器,其参考电压一般是3.3V。
逐次逼近型ADC
是一种使用二分搜索算法实现数字信号的转换。 通过具体示例介绍这种算法:这里以为一个 分辨率为5位的ADC为例,参考电压为32mV, 那么量化间隔就是1mV。
3.ADC的输入通道与转换序列
3.1输入通道
ADC 通道指的是将模拟信号输入到ADC 控制器的单个输入路径或者是信号通道,通常,一个ADC控制器可以具有多个输入通道,每 个通道都可以连接到一个模拟信号源。
外部通道:每个ADC控制器都有16个,来自外部的GPIO端口。
内部通道:只有ADC1控制器具有,有3个内部 通道,通道16连接的是芯片内部的温度传感器; 通道17连接的是芯片内部的参考电压;通道18 连接的是电池或者是其它电源采集VBAT通道。 通过ADC通道进行输入的模拟电压的范围,VREF- ≤ VIN ≤ VREF+
3.2转换序列
当多个ADC 通道,以任意顺序进行转换时,就有了转换序列的概念。
长度:指的就是我们需要转换的通道个数;顺序:指的就是想以什么样的顺序转换需要转换的通道。
转换序列有两种:规则序列和注入序列。
3.3规则序列
最大长度为16,从规则序列1(SQ1)开始,依次进行转换,转换的个数就是我们设置的长度。
1、设置需要转换的规则序列长度(通过ADC_SQR1.L位) 当规则转换序列的长度设置为3时,规则序列的转换顺序和长度 如右侧图示:
2、为规则序列添加转换通道(通过ADC_SQRx.SQRn位)
ADC_SQRx寄存器有三个,ADC_SQR1、ADC_SQR2、ADC_SQR3,由于给规则序列添加需要转换的通道。 ADC_SQR3 寄存器用于为规则序列1(SQ1)到序列6(SQ6)设置转换通道。 ADC_SQR2 寄存器用于为规则序列7(SQ7)到序列12(SQ12)设置转换通道。 ADC_SQR1 寄存器用于为序列13(SQ13)到序列16(SQ16)设置转换通道。
3.4注入序列
注入序列的长度最大为4,从注入序列1(JSQ1),到注入序列4(JSQ4)
注入序列的转换顺序与设置的注入序列长度有关。
1、注入序列的转换长度由ADC_JSQR.JL位设置
2、为注入序列添加转换通道,由ADC_JSRQ.JSQx位设置
4.转换触发源
4.1软件触发
规则序列的软件触发:当ADC控制器被使能后,若ADC_CR2.SWSTART位被写入1时,即可触发开始对规则序列中的通道进行转换。转换一旦开始,ADC_CR2.SWSTART位将会被控制器清0。
注入序列的软件触发:当ADC控制器被使能后,若ADC_CR2.JSWSTART位被写入1时,即可触发开始对注入序列中的通道进行转换。当 转换开始时,ADC_CR2.JSWSTART位将会被控制器清0。 ADC控制器使能:简单来说就是给ADC控制器上电,通过向ADC_CR2.ADON位写1,即可上电ADC。
启动ADC 转换有两种方式,一种是软件触发,另外一种是事件触发。规则序列和注入序列有各自的ADC 启动转换 触发源。
规则序列的转换触发源通过ADC_CR2.EXTEN位进行选择;
注入序列的转换触发源通过ADC_CR2.JEXTEN位进行选择;
4.2事件触发
外部触发转换,可以通过外部事件(例如,定时器捕获、EXTI中断线)触发转换,事件源可以通过ADC_CR2.EXTSEL(规则序列外部事件源 选择)和ADC_CR2.JEXTSE(注入序列外部事件源选择)位进行选择。外部事件能够以所选的极性(上升沿、下降沿、上升和下降沿)触发转换。
5.ADC时钟
ADC外设挂载在APB2外设时钟总线上。ADC具有两个时钟,其来源都是APB2。
ADC的时钟1:用于模拟电路的时钟ADCCLK
ADC的时钟2:用于数字接口的时钟
ADC_SMPR2寄存器,用于设置通道0 到通道9 的采样周期数;ADC_SMPR1寄存器,用于设置通道10 到 通道18 的采样周期数。
一个通道的总转换完成时间和ADC设置的分辨率和设置的采样时间有关系:
12位ADC:Tconv= 通道采样周期数 + 12个ADCCLK周期
10位ADC:Tconv = 通道采样周期数 + 10个ADCCLK周期
8位ADC:Tconv= 通道采样周期数 + 8个ADCCLK周期
6位ADC:Tconv= 通道采样周期数 + 6个ADCCLK周期
6.扫描模式和转换模式
6.1 扫描模式的含义
ADC 扫描模式是一种连续对多个输入通道进行转换的模式,这种模式下,ADC 会按照预先定义的顺序对多个输入通道轮流进行转换。
6.2 什么情况下使用扫描模式 如果设置的序列长度大于1时,则为多通道转换,就需要使用扫描模式。 如果序列的长度为1时,则是单通道转换,单通道转换则不需要开启扫描模式。 注意:如果关闭了扫描模式,即使序列设置的长度大于1,ADC 仍然按照单通道进行转换。
6.3 扫描模式和非扫描模式的切换 ADC的扫描模式和非扫描模式,由ADC_CR1.SCAN位进行控制
ADC_CR1.SCAN = 0,禁止扫描模式,也就是使用非扫描模式
ADC_CR1.SCAN = 1,使能扫描模式,也就是使用扫描模式
6.4连续转换模式的含义
连续转换模式,指的是ADC 按照序列设置的长度,完成一次序列的转换后,回到序列头开始新一轮的转换。 注意:触发注入无法进行连续转换,注入序列想要连续转换的唯一例外情况是使用自动注入,将注入序列 配置为在规则序列之后,自动转换。
6.5单次转换模式的含义
ADC 的单次转换模式,是指ADC 按照序列设置的长度,完成一次序列的转换后,ADC 停止。
注意:触发注入无法进行连续转换,注入序列仅在自动注入模式下,可进行连续转换。
7.数据寄存器和数据对齐
数据寄存器有两类:一类是规则数据寄存器ADC_DR, 另一类就是注入数据寄存器ADC_JDRx(x为1到4)。
规则数据寄存器只有一个,有效长度是16bit,共用一个数据寄存器ADC_DR。
注入数据寄存器则有四个,有效长度是16bit,ADC_JDR1、 ADC_JDR2、ADC_JDR3、ADC_JDR4。
数据对齐 数据对齐,其实就是ADC 转换完成的结果,在数据寄存器中的存储方式,对齐方式有两种:左对齐和右对齐。
五、UART控制器
串口通讯
串口通讯是一种通过串行(一位接着一位地)传输数据的通信方式。
串口硬件连接非常简单,只需要Tx、Rx和GND 3条线,接线时两个设备 的Tx与Rx要交叉连接,GND直接可以直接连接。
串口的波特率表示在1秒钟内,两个串口设备之间能传输多少个码元,在 串口通信中,波特率等于比特率。
波特率的计算
一帧完整的串口数据帧由开始位、传输数据、校验位和停止位组成。
•开始位是以低电平开始,停止位总是以高电平结束。
常用的串口的校验位分为奇校验和偶校验两种:
•奇校验是保证一帧数据中高电平的个数为奇数个
• 偶校验是保证一帧数据中高电平的个数为偶数个
如果在传输中启用了校验位,那么数据位将被占用1位用作校验位。
停止位除了1位停止位,还可以配置为0.5位1.5位或2位停止位
串口收发流程
•发送流程
• 将串口数据写入内存
• 程序将内存中的数据填入串口控制器的TDR寄存器
• TDR寄存器中的数据自动传入发送移位寄存器,由移位寄存器将数据从TX引脚发生出去
•接收流程
• 当RX引脚上有数据时,会依次流入接收移位寄存器
• 接收移位寄存器接收完成后将数据写入RDR寄存器
• 程序读取RDR寄存器的数据写入内存中使用
常用的串口电平标准有TTL标准、RS232标准、RS485标准
TTL电平标准
在TTL标准规定在0~0.4V这个范围时为逻辑0,在2.4V~5V这个范围时为逻辑1
TTL电平转RS232电平
当1个大于2.4V的TTL电平经过MAX232后被转化为-3~-15V的RS232电平。 当1个小于0.8V的TTL电平经过MAX232后被转化为3V~15V的RS232电平
RS232最大的好处就是抗干扰能力有了很大的提升
TTL电平转RS485电平
在RS485中是用A线电压与B线电压的差值来确定逻辑1和逻辑0的。 • 用A线电压减去B线电压,如果在+2~+6v的范围内则都属于逻辑1 • 用A线电压减去B线电压,如果在-2~-6v的范围内则都属于逻辑0
Modbus协议
• Modbus是一种基于串行通信的通信协议
一帧modbus协议包含地址域、功能码、数据和差错校验四部
常用功能码
| 功能码(Hex) | 操作类型 | 说明 | 常用场景 |
|---|---|---|---|
| 0x01 | Read Coils | 读取线圈状态 | 读取或监控开关量输出(DO)状态 |
| 0x02 | Read Discrete Inputs | 读取离散输入状态 | 读取传感器或按钮的开关量输入(DI) |
| 0x03 | Read Holding Registers | 读取保持寄存器 | 读取设备测量值、运行状态或参数设定值 |
| 0x04 | Read Input Registers | 读取输入寄存器 | 采集只读的模拟量传感数据(如温度、压力) |
| 0x05 | Write Single Coil | 写单个线圈 | 控制单个继电器闭合/断开或设备启停 |
| 0x06 | Write Single Register | 写单个保持寄存器 | 修改或设置单个设备参数、阈值 |
| 0x0F (15) | Write Multiple Coils | 写多个线圈 | 批量控制多路数字量输出(DO) |
| 0x10 (16) | Write Multiple Registers | 写多个保持寄存器 | 批量下发配置参数或指令 |
| 0x17 (23) | Read/Write Multiple Registers | 读写多个寄存器 | 单次请求内同时完成保持寄存器的读写操作 |
