0_说明

介绍STM32F103C8T6,引脚配置,引脚工作模式。与STM32CubeMX强相关。

参考视频

1_GPIO 引脚

引脚配置

通常,电源+称为 VCC,地称为GND。但在STM32中,电源+ 称为Vdd,地称为Vss

记忆:因为NMOS管的电流从漏极(Drain)到源极(Source)形成电势差,即我们给漏极加正电压,给源极加负电压。

  • Vdd Voltage Drain-Drain
  • Vss Voltage Source-Source

img

  • 黄(黄绿)色引脚为电源及备用电池等默认引脚
  • 灰色引脚为普通IO引脚,都是可编程的。
    • 通用引脚分为GPIOAGPIOBGPIOCGPIOD 四组
    • 简写即数目:PA0……PA15、PB0……PB15、PC13……PC15、PD0和PD1

GPIO

General Purpose Input/Output

8种工作模式

img
img
img

输出模式案例

img

输入模式

img
img
浮空的引脚就像天线,会接收空间的电磁波,因此会得到随机的1、0
上拉电阻 - 当引脚悬空时,默认提供电压。
下拉电阻 - 当引脚悬空时,默认提供电压。

通用

程序直接控制引脚的输入与输出。

复用

使用其他模块来托管其输入与输出。此时该引脚可实现其他不同类型的功能。
img

复用功能重映射

将冲突的引脚移动到备用引脚上。如两个功能使用到了相同的引脚,可以将这些相同的引脚映射到备用引脚上。使得引脚不发生冲突。

IO最大输出速度

高低电压的切换是需要时间的,而不是理想状态的“瞬时”,因此波形呈现为梯形,有上升斜坡与下降斜坡。加快切换频率,中间的电压保持时间会越来越短。再加快,会发现上升沿和下降沿完全重合,此时不能有效地输出高低电压了。
STM32有三种输出速度。过快的上升沿、下降沿会导致芯片功耗增加
img

2_串口通信

单片机想要和其他设备进行通信,就必须借助各种各样的通信接口

UART

(Universal Asynchronous Receiver/Transmitter)通用异步收发器

收发方式

由Tx、Rx组成,Tx引脚用于向外发送,Rx引脚用于接收数据。
自然地,接收信号的设备使用Rx引脚与发送端的Tx引脚链接,接收端Tx引脚与发送端Rx引脚链接

数据帧

由三部分组成:起始位(1位)+ 数据位(8位或9位)+ 停止位(0.5、1、1.5、2位,常用1位)

  • 1、数据开始传输前,串口处于空闲状态。数据线上是高电压
  • 2、发送方将数据线拉低,就发送了一个起始位
  • 3、数据位由所要传输的数据转换为八位二进制,逆向传播(如发送数据2,二进制为00000010,则发送01000000)
  • 4、数据位后是停止位,即保持一段时间的高电压。
  • 5、数据帧再次回到空闲状态。等待下一帧的发送。

数据位的最后一位可以拿来作为校验位。校验方法(Parity)为奇偶校验

  • 奇校验Odd:要求有效数据和校验位中“1”的个数为奇数
  • 偶校验Even:要求有效数据和校验位中“1”的个数为偶数
    当检查1的个数与奇偶校验位相同,则数据正确,否则为错误数据。
    img

波特率

串口传输速度,即每秒发送或接收的位数。
如9600波特率,即每秒发送或接收9600个数据位,每一位约0.1毫秒
115200波特率,即每秒发送或接收115200个数据位,每一位约8.7微秒

波特率越高,数据传输的速度越快,但要注意,收发双方都要设置相同的波特率

常用数据位为8位无校验位9位带校验位

USART

(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器(不常用)

收发方式

在异步收发模式的基础上,添加了一条CK线(时钟线),用于同步收发。

串口与电脑通信

电脑一般只有USB接口,此时需要USB转TTL的模块,它的作用是将串口转为USB接口。

串口的工作模式

  • Asynchronous(异步模式)
  • Synchronous(同步模式)
  • Single-wire(Half-duplex)(单线模式)半双工
  • Multiprocessor Communication(多处理器通信)
  • LrDA (Local Ring-Independent Data Access)
  • LIN (Local Interconnect Network)
  • SmartCard (智能卡)
  • SmartCard with Card Clock

Stm32CubeMX配置的接收引脚默认为浮空模式,但由于串口的数据接收引脚可能会意外断开,所以最好配置一个上拉电阻

UART API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 通过串口向外发送数据
// 返回值:HAL_OK:发送成功、HAL_BUSY:发送中、HAL_TIMEOUT:发送超时、HAL_ERROR:发送失败
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, //串口句柄指针(STM32CubeMX自动生成)
uint8_t *pData, // 发送的数据的指针
uint16_t Size, // 数据长度,以字节为单位
uint32_t Timeout)// 超时时间,单位ms (无限期时间 HAL_MAX_DELAY)

// 通过串口接收一定数量的数据
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, //串口句柄指针(STM32CubeMX自动生成)
uint8_t *pData, // 接收的数据的指针
uint16_t Size, // 数据长度,以字节为单位
uint32_t Timeout)// 超时时间,单位ms (无限期时间 HAL_MAX_DELAY)


3_I2C总线

单片机有三个串口,分别为USART1、USART2、USART3,且是一对一的。若要链接更多设备,需要用到I2C总线。

img
SCLSDA都用开漏输出,并需分别接一个上拉电阻,阻值一般为4.7k。

逻辑线与

与运算 &:一假为假,两真为真。
逻辑线与:SCL与SDA都为1,由于上拉电阻的存在,总线输出高电压1。若有任意引脚为0,则总线输出低电压(此时上拉电阻不起作用)。
img

数据传输

  • 起始位:在SCL高电压时,向SDA发送下降沿,表示数据传输开始。
  • 寻址:主机向从机发送地址(7位或10位),每个从机有各自的地址。
    img
  • 数据传输:I2C以字节为单位传输数据,每次可以传输多个字节。
    img
  • 停止位:在数据传输结束后,SCL时高电压时,向SDA发送上升沿,表示数据传输结束。

示例:
img

传输模式

波特率 = 每秒钟传输的位数。有多种模式
STM32F103C8T6 只支持Sm、Fm模式

名称 简写 英文 最大速度
标准模式 Sm Standard Mode 100kbps
快速模式 Fm Fast Mode 400kbps
快速增强模式 Fm+ Fast Mode Plus 1Mbps
高速模式 HSm High Speed Mode 3.4Mbps
超快模式 UFm Ultra Fast Mode 5Mbps

快速模式下可以设置时钟信号的占空比。可以设置为2:1 和16:9两种,一般设置为2:1

I2C API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 向从机写数据
unit8_t data[] = {0x00, 0x8d, 0x14, 0xaf, 0xa5};
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, //i2c句柄指针
uint16_t DevAddress, //从机地址
uint8_t *pData, //数据指针 data
uint16_t Size, //数据长度 sizeof(data)/sizeof(data[0])
uint32_t Timeout) // MAL_MAX_DELAY

// 向从机读数据
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, //i2c句柄指针
uint16_t DevAddress,
uint8_t *pData, //接收缓冲区的指针
uint16_t Size,
uint32_t Timeout)

4_时钟系统

注意总线最高速度。可根据需求设置MCU的工作频率。

单片机内部结构类比电脑

img

img
时钟树:Clock Tree

数字电路可分为两类

  • 组合逻辑电路:不含有记忆元件。它的输出之和当前输入有关。
  • 时序逻辑电路:含有记忆元件。它的输出与当前、之前的输入有关。并且有时钟信号才能工作 (CP——Clock Pulse)即时钟脉冲
    时钟的快慢决定了电路运行的快慢

时钟分类

High Speed Clock(高速时钟)、Low Speed Clock(低速时钟)、External Clock(外部时钟)、Internal Clock(内部时钟)

  • 高速内部时钟HSI
  • 高速外部时钟HSE
  • 低速内部时钟LSI
  • 低速外部时钟LSE

内部时钟:精度低,成本低,内置在MCU中
外部时钟:精度高,成本高,外接在MCU外

锁相环

锁相环(Phase Locked Loop)是时钟系统设计中常用的一种技术。锁相环是一种时钟同步技术,通过将两个时钟源同步到同一个频率,从而实现时钟同步。锁相环的优点是简单、可靠,缺点是时钟同步 accuracy(精度)和时钟同步 delay(时钟延迟)都有可能。
即:对时钟信号做乘法(“超频”)

分频器

作用就是对时钟信号频率做除法(降频)

测试时钟频率代码

8MHz = 800万次/秒

1
2
3
4
5
6
7
8
//  利用程序执行一百万次循环,约耗时1秒(一次循环约8个时钟周期)
// 次代码led将以2秒的周期进行闪烁

uint32_t i;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
for(i=0; i<1000000; i++);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
for(i=0; i<1000000; i++);

在STM32CubeMX中配置RCC

选择启用HSE、LSE:

  • BYPASS Clock Source 旁路时钟源 。直接使用生成好的时钟信号提供给MCU
  • Crystal/Ceramic Resonator 晶体/陶瓷振荡器。通过外接电路产生时钟信号

5_SPI总线

Serial Peripheral Interface(串行外设接口)。适用于高速、双向数据传输场景。(摄像头、Flash、SD卡等)
SPI总线由四条线组成:

  • MOSI:(Master Out Slave Input) 主机输出从机输入。
    主机发送数据给从机
    主机的MOSI连接所有从机的MOSI
  • MISO:(Master In Slave Out) 主机输入从机输出。
    从机发送数据给主机
    主机的MISO连接所有从机的MISO
  • SCK:(Serial Clock),串行时钟线。
    时钟线是SPI总线中唯一必须的线,用于控制数据传输的时序。
    主机的SCK连接所有从机的SCK
  • NSS:(Negative Slave Select),负极性从机选择。
    用于控制从机是否接收数据。即从机选择(低电压有效)。主机向对应的NSS发送低电压可以选中从机
    主机的每个NSS引脚分别连接从机的NSS引脚

五个参数

波特率

SPI总线没有规定波特率的范围,一般取几兆到几十兆bps
SPI波特率选取的原则

  • 选择允许的最大值
  • 考虑设备所能承受的极限
  • 考虑电路板所能承受的极限(面包板、杜邦线组成的电路板,最高选择10Mbps的波特率,再高会产生较严重的干扰)

比特位的传输顺序(MSB First/LSB First)

无符号8位整数,从bit0至bit7的权重分别为2^0至2^7。其中bit0为LSB,bit7为MSB。

  • LSB:(Least Significant Bit) 最低有效位。
  • MSB:(Most Significant Bit) 最高有效位。
    所以有了两种传输方式:MSB First(先传最高有效位)和LSB First(先传最低有效位)

数据位长度(8位 / 16位)

  • 8位一组,每组一个字节
  • 16位一组,每组1个16位整数

时钟的极性

  • 低级性:空闲状态为低电平,数据传输时为高电平。此时把所有的上升沿称为第一边沿,所有的下降沿称为第二边沿。
  • 高级性:空闲状态为高电平,数据传输时为低电平。此时把所有的下降沿称为第一边沿,所有的上升沿称为第二边沿。

时钟的相位

  • 第一边沿采集:(1st edge capture)在第一个边沿时,数据被采集。
  • 第二边沿采集:(2nd edge capture)在第二个边沿时,数据被采集。

四种时钟模式

极性\相位 第一边沿采集0 第二边沿采集1
低级性0 00(模式0) 01(模式1)
高级性1 10(模式2) 11(模式3)

模式0:低级性,第一边沿采集
模式1:低级性,第二边沿采集
模式2:高级性,第一边沿采集
模式3:高级性,第二边沿采集

按键控制LED亮灭代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 按下并松开按键,控制LED的量、灭
uint8_t pre = 0; //保存上一次按钮的值
uint8_t cur = 0; //保存当前按钮的值
while(1){
pre = cur;

if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){
cur = 1;
}else{
cur = 0;
}
if(pre != cur){ //捕捉到了变化
HAL_Delay(10); //----------------->> 延时10ms,防按键抖动用
if (cur == 0){ //按钮按下瞬间
}else{ //按钮松开瞬间

}
}
}

STM32CubeMX中配置SPI

1、Connectivity -> 选择SPI1(2)
2、Model -> 选择Full Duplex Master(全双工主模式)。从机模式一般不用,也复杂
3、Hardware NSS Signal -> Disable(禁用)。硬件NSS一般用于多主机通信,一般用不到。
4、需选择一个GPIO引脚作为NSS引脚,并设置为推挽模式。在后续输出高低电压。最大输出速度为高速模式。默认为高电压。

SPI API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 发送数据
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, //SPI句柄
uint8_t *pData, //发送的数据指针
uint16_t Size, //数据量
uint32_t Timeout);//超时时间

// 接收数据
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, //SPI句柄
uint8_t *pData, //接收的数据指针
uint16_t Size, //数据量
uint32_t Timeout);

// 发送数据的同时接收数据
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, //SPI句柄
uint8_t *pTxData, //发送的数据指针
uint8_t *pRxData, //接收的数据指针
uint16_t Size, //发送数据的数量=接收数据的数量,字节为单位
uint32_t Timeout);

Flash模块

Flash是常见的数据持久化模块,类似于硬盘。
以W25Q64为例,容量为64MBit,即8MByte。
其容量分为若干个(Block),每块64k。
每个块分为若干个扇区(Sector),每扇区4k。扇区是擦除的最小单元。
每个扇区被分为若干(Page),每页256字节。页是数据写入的最小单元。

写入过程

写使能(解锁)-> 扇区擦除 -> 延迟100ms -> 写使能(解锁)-> 页编程 -> 延迟10ms

写使能、扇区擦除、页编程都需要发送响应的指令码(在发送的数据数组中的第一个元素)。具体需查看手册。

1
2
3
4
5
// 读取例子
uint8_t response = 0xff; //接收读出的数据
uint8_t readDataCmd[] = {0x03 , 0x00 , 0x00 , 0x00} ; //{指令码 , 24位(3x8)地址}
HAL_SPI_Transmit(&hspi, readDataCmd, 4, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi, &response, 1, HAL_MAX_DELAY);

6_中断

常规程序被突发事件中断源中断,然后去执行突发事件处理代码中断响应函数,最后回到常规程序。
即“放下手头的工作处理突发事件,处理完成后继续做手头工作”。
又:单片机是“单线程”的。

中断优先级

以stm32f103为例,有bit3 – bit0共4位表示中断优先级,即0000 – 1111,换算为十进制,为0 – 15,共16个优先级。
数字越小表示优先级越高
bit3、bit2为pre-emption priority,抢占优先级,与中断嵌套中断排队有关
bit1、bit0为sub priority,子优先级,与中断排队有关

  • img
  • img
  • 中断嵌套的发生条件:新中断的抢占优先级更高。若优先级不高,则不发生嵌套,而发生排队。

NVIC配置

NVIC:(Nested Vectored Interrupt Controller)嵌套向量中断控制器,负责管理单片机内部的中断。
img
图片解释:每个模块都可以产生多个中断(模块箭头),每个中断都有独立的开关(箭头开关)负责中断的使能和禁止(中断发生了也不去响应),每个中断都可以设置优先级(四个格子),仲裁电路管理排队、嵌套。经过仲裁后的中断调用其相应函数(通过Flash中断向量表找到函数)

中断 API

1
2
3
4
5
6
7
8
// 串口使用中断方式接受一定数量的数据
// IT 表示 Interrupt 中断
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size);

// 中断响应函数(需重写这个函数)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

7_定时器

TIM:(Timer)
时钟树提供时钟信号(晶振等),定时器执行和时间相关的操作。
一个定时器有四个通道(Channel),每个通道可以独立设置。
img

时基单元

img

  • PSC: Prescaler,预分频,即时钟频率除以该值,得到定时器时钟频率。
  • CNT: Counter,计数器,计数到该值时,产生中断。
  • ARR: Auto Reload Register,自动重载寄存器
  • RCR: Repetition Counter Register,重复计数器

时钟来源

  • 来自RCC(时钟树)
  • 来自从模式控制器的触发信号TRIG
  • 来自外部参考信号ETRF

降频

时钟树的时钟频率通常过高,所以需要降频

img
时钟树中的APB分频器连接到TIM时,中间有个倍频器。倍频器在分频器等于1时为1,在分频器大于1时为2。这使得倍频器降频。这就是PSC的作用。
降频的倍数 = PSC + 1
PSC ∈ [0,65535]
eg: PSC = 3,则时钟频率为时钟树频率/4

ARR、CNT、RCR

CNT对PSC输入的脉冲进行计数。可以递增,也可以递减。CNT ∈ [0,65535]
ARR自动重装寄存器设定定时的周期。ARR ∈ [0,65535]
RCR重复计数器设定定时的周期。RCR ∈ [0,65535],次数为RCR+1。即CNT计数溢出的次数。达到后触发update事件。高级定时器才有。
CNT的计数方式:

  • 上计数 counting up:从零开始计数,达到ARR值后溢出归零。定时周期为ARR+1。
  • 下计数 counting down:从ARR开始计数,到零后溢出回归ARR。定时周期为ARR+1。
  • 中心对齐 center align:先上溢出,再下溢出。

eg:img

stm32f1系列的四种定时器

  • TIM1 and TIM8:高级定时器,支持定时、PWM、捕获、比较等。(Advanced Timer)
  • TIM2 to TIM5:通用定时器,支持定时、PWM、捕获等。(General Timer)
  • TIM9 to TIM14:通用定时器,支持定时、PWM等。(General Timer)
  • Tim6 and TIM7:基本定时器。(Basic Timer)

寄存器预加载

PSC ARR RCR具有寄存器预加载机制。(缓冲机制)。为了安全,防止动态改变ARR时CNT“跑飞”至最大值。PSC、RCR强制开启预加载,无法关闭。ARR默认关闭,需手动开启

  • 活动寄存器(Active Register)
  • 影子寄存器(Shadow Register)
    向寄存器写值,值会先进入影子寄存器,当触发update事件后,再写入活动寄存器。

输出比较

PWM信号(Pulse Width Modulation脉冲宽度调制信号)

  • 占空比: 占空比 = 输出信号的持续时间/定时周期 * 100%
  • 周期恒定,占空比可调。用占空比调节信号的大小。

CCR:(Capture/Compare Register)捕获/比较寄存器,用于设定输出信号的持续时间。CCR ∈ [0,65535]
img

时基单元决定周期,CCR决定占空比。

CCR输出模式

img

输入捕获

定时器有四个通道,可作为输入,也可以作为输出。做输入时,把外部信号输入进来,然后使用定时器对这个信号的时间参数进行测量,这种功能就叫输入捕获
做输出时,使用定时器向外输出精确定时的方波信号,这种功能叫输出比较
输入捕获就是捕捉信号变化的时间点,并把它保存下来。利用这个就可以对输入信号的时间参数进行测量。
img

从模式控制器

img

作为从机 作为主机
(被控制) (控制别人)
Slave Mode disable 从模式禁止 Reset 复位
Encoder Mode 1 编码器模式1 Enable 使能
Encoder Mode 2 编码器模式2 Update 更新
Encoder Mode 3 编码器模式3 Compare Pulse 输出比较脉冲
Reset Mode 复位模式 Compare OC1Ref 输出比较参考信号1
Gated Mode 门模式 Compare OC2Ref 输出比较参考信号2
Trigger Mode 触发模式 Compare OC3Ref 输出比较参考信号3
External Clock Mode1 外部时钟模式1 Compare OC4Ref 输出比较参考信号4

相关中断

  • define TIM1_BRK_IRQChannel ((u8)0x18) 刹车功能
  • define TIM1_UP_IRQChannel ((u8)0x19) 定时溢出中断,时间到了就触发。
  • define TIM1_TRG_COM_IRQChannel ((u8)0x1A) 定时器触发中断
  • define TIM1_CC_IRQChannel ((u8)0x1B) 定时器捕获比较中断,设置CCR寄存器值可以触发。

相关API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 以中断方式启动时基单元
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
// 回调函数
// 每发生一次update中断,调用一次回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

// 启动PWM的正常输出
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
// 启动PWM的互补输出
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

/**************** 读写寄存器接口************** */
// 预分配器PSC
__HAL_TIM_SET_PRESCALER(__HANDLE__, __VALUE__)
__HAL_TIM_GET_PRESCALER(__HANDLE__)
// 计数器CNT
__HAL_TIM_SET_COUNTER(__HANDLE__, __VALUE__)
__HAL_TIM_GET_COUNTER(__HANDLE__)
// 自动重装寄存器ARR
__HAL_TIM_SET_AUTORELOAD(__HANDLE__, __VALUE__)
__HAL_TIM_GET_AUTORELOAD(__HANDLE__)
// 重复计数器RCR
__HAL_TIM_SET_REPETITIONCOUNTER(__HANDLE__, __VALUE__)
__HAL_TIM_GET_REPETITIONCOUNTER(__HANDLE__)
// 捕获/比较寄存器CCR
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __VALUE__)
__HAL_TIM_GET_COMPARE(__HANDLE__, __CHANNEL__)

// 查询标志位的值
__HAL_TIM_GET_FLAG(__HANDLE__ , __FLAG__) // 返回uint32_t :0、1

// 清除CC1标志位
__HAL_TIM_CLEAR_FLAG(&htim1 , TIM_FLAG_CC1)

// 启动定时器
__HAL_TIM_IC_Start(&Htim1 , TIM_CHANNEL_1)


//关闭定时器
HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim , uint32_t Channel)

8_ADC

Analog to Digital Converter (模拟信号到数字信号的转换)

模拟信号 数字信号
时间和幅度都连续 时间和幅度都离散
自然界的信号 计算机的信号

12位逐次逼近型ADC

SAR (Successive Approximation Register) 逐次逼近寄存器

12位

  • 12位指的是采样深度(使用多少位二进制数来表示一个采样点)
  • 如0-3.3v电压,使用4位ADC采样,即0000-1111,表示把0-3.3v电压分成$2^4-1$份,每份对应0.22v。
  • ADC的采样深度越深,转换的结果越精细。采样深度是权衡ADC性能的重要指标之一

逐次逼近型

img
其结构类似天平,每一次比较进行寄存器调整,直到采样结束。

四位逐次逼近型ADC示例

  • 输入2.21v模拟信号
  • 采样保持电路闭合–电容充电–采样保持电路断开–此后由于电容储能,保证后续输入电压不会改变。
  • 向结果寄存器最高位 $b_1$(代表1.76v)写1,
  • 此时电压发生器输出的电压就是1.76v,比2.21v小,
  • 所以继续向低一位的寄存器$b_2$(代表0.88v)写1,
  • 此时电压发生器输出的电压就是1.76 + 0.88 > 2.21 ,所以将其改为0,向低一位寄存器$b_3$(代表0.44v)写1,。
  • 以此类推,逐步逼近。直到采样结束。

ADC的基本原理

  • 对于stm32f103c8t6来说,ADC输入有12个,其中p0-p9为模拟输入引脚,还有一个内置温度计,一个参考电压。
  • 12个ADC各有一个开关,开关控制ADC的采样通道。
  • 常规序列、注入序列:对12个ADC进行顺序或注入采样。
  • img

ADC采样时间和转换时间

采样时间:放重物。转换时间:调整砝码

完成一次转换的总时间 = 采样时间 + 转换时间

采样时间、转换时间都需要表示成ADC时钟周期的倍数

$$时钟周期(Cycles) = \frac {1}{ADC时钟频率} $$

  • eg: ADC时钟频率为14MHz,则$时钟周期Cycles = \frac{1}{14}us$
  • eg:
    • $转换时间 = 0.9us = 12.5 * \frac{1}{14}us = 12.5cycle$
    • $采样时间 = 0.1us = 1.5 * \frac{1}{14}us = 1.5cycle$

转换时间

(采样深度 + 0.5 )个ADC时钟周期

采样时间

即采样开关闭合的时间,即采样电容充电的时间。

  • 事实:采样精度本身就是有限的
  • 电容充电只能随时间增加而无限接近输入的采样电压。所以出现了采样效率与采样精度的抉择。
  • 只需保证采样误差远小于ADC的最大精度即可结束采样。
  • $采样误差 < \frac 1 4 *ADC分辨率 $
    • 例:对应stm32f103c8t6,采样深度12位,则$分辨率 = \frac {(3.3-0)} {(2^{12}-1)} \approx 0.8mV $
    • 量程: 0-3.3v,分辨率:0.8mV,则$采样误差 < \frac 1 4 *0.8mV = 0.2mV $

最优采样时间:

  • 模拟输入信号的内阻与采样电容是串联关系,所以根据欧姆定律,内阻越大,充电电流越小,充电速度越小,采样时间越长。
  • 理论上,采样时间只于信号源内阻有关。
  • $$ T_{最优采样时间} = (R_{信号源内阻} + R_{采样电路的电阻}) * C_{采样电容} * ln(2^{采样深度+2})$$
  • 对于stm32f103c8t6来说,$R_{采样电路电阻} = 1kΩ,C_{采样电容} = 8pF , 采样深度 = 12 $
  • 最终带入 $$T_{最优采样时间} = (R_{信号源内阻} + 1000) * 77.6 * 10^{-12} $$

表示为周期的形式: $采样时间*采样频率 $
对于stm32f103c8t6来说,只有8个周期档位可以选择。实际开发中,选择相近的周期选择即可

API

1
2
3
4
5
6
7
8
9
// 启动常规序列
HAL_ADC_Start(ADC_HandleTypeDef *hadc);

//等待转换结束
// 以轮训(标志位)的方式等待(常规序列)转换完成
HAL_ADC_PollForConversion(ADC_HandleTypeDef *hadc, uint32_t Timeout);

// 获取转换结果
HAL_ADC_GetValue(ADC_HandleTypeDef *hadc);