ADC
目录
一、逐次逼近型ADC
1.1.ADC是什么
**ADC(Analog Digital Converter):**模拟信号 数字信号 转换器
**模拟信号:**存在于自然界当中,时间连续、幅度也连续

时间连续:在任意的时间点都有值
幅度连续:某个时间点的数值精度无限
**数字信号:**存在于计算机当中,时间离散、幅度也离散

时间离散:在某些时间点上有值
幅度离散:某个时间点的数值精度有限
**狭义ADC:**将电量转换为数字量
1.2.单片机里的ADC模块

1.3.采样深度的概念
**采样深度:**用多少位二进制数表示转换结果
、
衡量ADC性能的重要指标之一
4位ADC:
0000(0V)~ 1111(3.3V)
(3.3V - 0V)/ 15 = 0.22V
2V ≈ 1001B * 0.22V = 1.98V
2V - 1.98V = 0.02V(量化误差)

12位ADC:
000000000000(0V) ~ 111111111111(3.3V)
(3.3V - 0V)/ 4095 = 0.000806V
2V ≈ 100110110001B * 0.000806V = 1.9997V
2V - 1.9997V = 0.0003V(量化误差)

1.4.逐次逼近型ADC简介

工作原理:
类似于天平称重

69g ≈ 50 + 12.5 + 6.25 = 68.75g
模拟信号: 类似于天平要称的重物
采样保持电路: 类似于放重物的托盘
**比较器:**对两个输入电压进行比较
一个为正输入、一个为负输入
- 如果正输入电压大于负输入电压,就输出1
- 如果正输入电压小于负输入电压,就输出0
类似于天平的底座 和横杆
**结果寄存器:**用来存储ADC转换后的结果
由四位二进制数组成(说明采样深度为4)
b3 代表着最大的砝码 、b0 代表着最小的砝码
写1放砝码、写0取砝码
**电压发生器:**根据结果寄存器的值产生对应大小的电压
类似于放砝码的托盘

1.5.采样保持电路

**采样:**对某一时刻的模拟信号进行采集
开关闭合、电容充电:

**保持:**维持比较器正输入电压不变
开关断开、电容无法向外发电、两端电压不变:

1.6.例子
假设当前模拟信号对应的电量是2.21V
(3.3V - 0V)/ 15 = 0.22V
b3: 2^3 1.76V **b2:**2^2 0.88V
b1: 2^1 0.44V**b0:**2^0 0.22V

二、ADC模块的结构框图
2.1.ADC的多路复用
只使用一个ADC同时转换多路的模拟信号




2.2.常规序列

**外部触发信号:**常规序列的启动信号,每产生一个上升沿,常规序列执行一遍
**常规序列:**ADC模块中的一份计划
**DR寄存器:**保存常规序列转换结构


采样时间:
开关闭合时间
工作流程:
通道开关闭合一段时间后断开,12位逐次逼近型ADC进行转换,将转换结果存储到DR寄存器中
工作示例:
将计划填入常规序列中

复用器选择TIM3_TRGO



2.3.注入序列

通道更少,只有4个
每个通道有单独的结果寄存器
优先级更高
2.4.例子
注入序列的优先级比常规序列高




三、采样时间和转换时间
3.1.ADC的时钟频率
标准库初始化后,时钟树各个节点频率都为最大频率
参考手册11 ADC

PCLK2的时钟频率为72MHz,如果不进行分频,直接输入ADC
则会远大于14MHz,所以要将分频器的分频系数设置为6,此时为12MHz

3.2.转换时间的计算方法

**转换时间:**对采样点进行转换所消耗的时间
12个bit位相当于天平的12个砝码
每种砝码尝试一次、一共要12次
假定每一次放一个砝码需要消耗一个周期
1周期 = 1 cycle = 1/12MHz = 0.083us
转换时间 = 12 cycle + 0.5 cycle(额外时间)= 12.5 cycle ≈ 1.04us | 12MHz
3.3.采样时间和信号源内阻的关系
**采样时间:**采样开关闭合的时间长度
采样时间于信号源的内阻有关


18650动力电池的内阻一般在10mΩ左右
模拟信号也具有内阻(信号源的内阻)


闭合采样开关,模拟信号输入电压通过导线,给电容充电
信号源内阻越大、电流越小、充电速度越慢、电容充满电的时间越长
3.4.信号源内阻的计算方法


根据计算,取内阻大小为10kΩ
**补充:**戴维南等效定理
一个仅含独立电源和电阻的线性二端网络 ,可以等效成一个电压源串联一个电阻的形式
等效出的电源的电压 等于二端网络的开路电压
等效出的电阻 等于二端网络的所有电源归零后的电阻
3.5.采样时间的计算方法

数据手册 P75

数据手册 P74


Ts > (1e4 + 1e3)* 8e - 12 * ln(2^(12+2))* 12e6
= 1.1e4 * 8e - 12 * 9.7 * 12e6
= 10.24Cycle = 0.84992us
四、常规序列的单通道转换




4.1.初始化IO引脚
将PA0引脚设置为输入模式中的模拟模式
cpp
#include "stm32f10x.h"
//声明ADC1初始化函数
void App_ADC1_Init(void);
int main(void)
{
while(1)
{
}
}
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
4.2.配置ADC时钟

cpp
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置ADC模块时钟
/*分频系数为6*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
}
4.3.ADC的编程接口

4.4.初始化ADC的基本参数
常规序列的转换结果会存放到DR中
注入序列的转换结果会存放到JDR中
它们的宽度都为16Bit
ADC有12位,要设置对齐方式
左对齐靠左写,右对齐靠右写

cpp
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置ADC模块时钟
/*分频系数为6*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC的基本参数
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
}
4.5.配置常规序列

cpp
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置ADC模块时钟
/*分频系数为6*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC的基本参数
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置常规序列
/*ADC1 常规通道0 写在第一行 采样时间为13.5周期*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
/*闭合外部触发开关*/
ADC_ExternalTrigConvCmd(ADC1,ENABLE);
}
4.6.闭合ADC的总开关
cpp
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置ADC模块时钟
/*分频系数为6*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC的基本参数
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置常规序列
/*ADC1 常规通道0 写在第一行 采样时间为13.5周期*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
/*闭合外部触发开关*/
ADC_ExternalTrigConvCmd(ADC1,ENABLE);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}
4.7.启动并读取转换结果

- 清零EOC标准位
- 软件启动发送脉冲,启动常规序列
- 通道0进行转换,转换结果存入DR
- 等待EOC标准位
- 从DR中读取结果

0 ~ 3.3V
0 ~ 4095
cpp
#include "stm32f10x.h"
//声明ADC1初始化函数
void App_ADC1_Init(void);
//声明板载LED初始化函数
void My_OnBoardLED_Init(void);
int main(void)
{
My_OnBoardLED_Init();
App_ADC1_Init();
while(1)
{
//#1:清除EOC标志位
ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
//#2:软件启动发送脉冲信号
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
//#3:等待EOC变为1
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
//#4:从DR寄存器读取转换结果
uint16_t dr = ADC_GetConversionValue(ADC1);
//#5:结果转换成电压
float voltage = dr * (3.3f / 4095);
if(voltage > 1.5)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}
else
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}
}
}
//创建ADC1初始化函数
void App_ADC1_Init(void)
{
//#1:初始化PAO引脚 模拟模式
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIOA结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置ADC模块时钟
/*分频系数为6*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC的基本参数
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置常规序列
/*ADC1 常规通道0 写在第一行 采样时间为13.5周期*/
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
/*闭合外部触发开关*/
ADC_ExternalTrigConvCmd(ADC1,ENABLE);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}
//创建板载LED初始化函数
void My_OnBoardLED_Init(void)
{
/*开启GPIOC的时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
/*GPIO结构前置声明*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PC13引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
/*设置通用输出开漏模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
/*最大输出速度为2MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
/*初始化PC13引脚*/
GPIO_Init(GPIOC,&GPIO_InitStruct);
}
五、定时器触发
使用定时器作为外部触发信号,启动常规序列

光敏传感器模拟输出接在PA0,PA0对应ADC通道0,将通道0写在注入序列第一行
通过定时器1的TRGO来产生脉冲信号启动注入序列,转换结果存放在JDR1寄存器

让update每1ms发送一次,TRGO会以1ms为间隔发送一次脉冲信号
将TRGO产生的信号传输到ADC外部触发,TRGO每产生一次上升沿
注入序列就会运行一次,通道0就会产生一次信号转换
5.1.连接电路

5.2.初始化串口

cpp
#include "stm32f10x.h"
#include "usart.h"
//声明串口初始化函数
void App_USART1_Init(void);
int main(void)
{
App_USART1_Init();
My_USART_SendString(USART1,"Hello world. \r\n");
while(1)
{
}
}
//创建串口初始化函数
void App_USART1_Init(void)
{
//#1:初始化IO引脚 PA9 AF_PP
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*选择PA9引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PA9引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置USART1参数
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构的前置声明*/
USART_InitTypeDef USART_InitStruct = {0};
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*无硬件流控*/
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为发送方向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
5.3.配置定时器1的TRGO

cpp
//创建TIM1初始化函数
void App_TIM1_Init(void)
{
//#1:配置时基单元
/*开启TIM1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*声明TIM结构变量*/
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStruct;
/*计数方向为上计数*/
TIM_TimBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
/*设置自动重装寄存器*/
TIM_TimBaseInitStruct.TIM_Period = 999;
/*设置预分频系数*/
TIM_TimBaseInitStruct.TIM_Prescaler = 71;
/*设置重复计数器*/
TIM_TimBaseInitStruct.TIM_RepetitionCounter = 0;
/*初始化TIM1*/
TIM_TimeBaseInit(TIM1,&TIM_TimBaseInitStruct);
//#3:TRGO设置为Update模式
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);
//#4:闭合TIM1总开关
TIM_Cmd(TIM1,ENABLE);
}
5.4.注入序列的编程接口

5.5.初始化ADC(注入序列)
cpp
//创建ADC初始化函数
void App_ADC_Init(void)
{
//#1:初始化IO引脚
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*输入模式为模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:初始化时钟
/*设置分频器的分配系数为6分频*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置注入序列
/*设置注入序列长度为1*/
ADC_InjectedSequencerLengthConfig(ADC1,1);
/*外部触发信号为TIM1_TRGO*/
ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
/*闭合注入序列开关*/
ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
/*ADC1 注入序列通道1 写在第一行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}
5.6.读取并发送测量结果
cpp
#include "stm32f10x.h"
#include "usart.h"
//声明串口初始化函数
void App_USART1_Init(void);
//声明TIM1初始化函数
void App_TIM1_Init(void);
//声明ADC初始化函数
void App_ADC_Init(void);
int main(void)
{
App_TIM1_Init();
App_USART1_Init();
App_ADC_Init();
while(1)
{
//#1:等待注入序列转换完成
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC) == RESET);
//#2:读取转换的结果
uint16_t jdr1 = ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
//#3:清除JEOC标志位
ADC_ClearFlag(ADC1,ADC_FLAG_JEOC);
//#4:把结果转换成电压
float voltage = jdr1 * (3.3f / 4095);
//#5:串口发送结果
My_USART_Printf(USART1,"%.3f\n",voltage);
}
}
//创建串口初始化函数
void App_USART1_Init(void)
{
//#1:初始化IO引脚 PA9 AF_PP
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*选择PA9引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PA9引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置USART1参数
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构的前置声明*/
USART_InitTypeDef USART_InitStruct = {0};
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*无硬件流控*/
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为发送方向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
//创建TIM1初始化函数
void App_TIM1_Init(void)
{
//#1:配置时基单元
/*开启TIM1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*声明TIM结构变量*/
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStruct;
/*计数方向为上计数*/
TIM_TimBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
/*设置自动重装寄存器*/
TIM_TimBaseInitStruct.TIM_Period = 999;
/*设置预分频系数*/
TIM_TimBaseInitStruct.TIM_Prescaler = 71;
/*设置重复计数器*/
TIM_TimBaseInitStruct.TIM_RepetitionCounter = 0;
/*初始化TIM1*/
TIM_TimeBaseInit(TIM1,&TIM_TimBaseInitStruct);
//#3:TRGO设置为Update模式
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);
//#4:闭合TIM1总开关
TIM_Cmd(TIM1,ENABLE);
}
//创建ADC初始化函数
void App_ADC_Init(void)
{
//#1:初始化IO引脚
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
/*输入模式为模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:初始化时钟
/*设置分频器的分配系数为6分频*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*关闭扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置注入序列
/*设置注入序列长度为1*/
ADC_InjectedSequencerLengthConfig(ADC1,1);
/*外部触发信号为TIM1_TRGO*/
ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
/*闭合注入序列开关*/
ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
/*ADC1 注入序列通道1 写在第一行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}
六、扫描模式
6.1.扫描模式
使能ADC对多路信号转换的能力

电位器:



6.2.电路连接

6.3.初始化串口
cpp
#include "stm32f10x.h"
#include "usart.h"
//声明串口初始化函数
void App_USART1_Init(void);
int main(void)
{
App_USART1_Init();
My_USART_Printf(USART1,"Hello world. \r\n");
while(1)
{
}
}
//创建串口初始化函数
void App_USART1_Init(void)
{
//#1:初始化IO引脚 PA9 AF_PP
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*选择PA9引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PA9引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置USART1参数
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构的前置声明*/
USART_InitTypeDef USART_InitStruct = {0};
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*无硬件流控*/
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为发送方向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
6.4.配置定时器1

cpp
//创建TIM1初始化函数
void App_TIM1_Init(void)
{
//#1:配置时基单元
/*开启TIM1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*声明TIM结构变量*/
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStruct;
/*计数方向为上计数*/
TIM_TimBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
/*设置自动重装寄存器*/
TIM_TimBaseInitStruct.TIM_Period = 999;
/*设置预分频系数*/
TIM_TimBaseInitStruct.TIM_Prescaler = 71;
/*设置重复计数器*/
TIM_TimBaseInitStruct.TIM_RepetitionCounter = 0;
/*初始化TIM1*/
TIM_TimeBaseInit(TIM1,&TIM_TimBaseInitStruct);
//#3:TRGO设置为Update模式
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);
//#4:闭合TIM1总开关
TIM_Cmd(TIM1,ENABLE);
}
6.5.配置ADC
cpp
//创建ADC初始化函数
void App_ADC_Init(void)
{
//#1:初始化IO引脚 PA0 PA1 AIN
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0 PA1引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
/*输入模式为模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0 PA1引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:初始化时钟
/*设置分频器的分配系数为6分频*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*开启扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置注入序列
/*设置注入序列长度为2*/
ADC_InjectedSequencerLengthConfig(ADC1,2);
/*外部触发信号为TIM1_TRGO*/
ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
/*ADC1 注入序列通道0 写在第一行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
/*ADC1 注入序列通道1 写在第二行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_13Cycles5);
/*闭合注入序列开关*/
ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}
6.6.总代码
cpp
#include "stm32f10x.h"
#include "usart.h"
//声明串口初始化函数
void App_USART1_Init(void);
//声明TIM1初始化函数
void App_TIM1_Init(void);
//声明ADC初始化函数
void App_ADC_Init(void);
int main(void)
{
App_USART1_Init();
App_TIM1_Init();
App_ADC_Init();
while(1)
{
//#1:等待注入序列转换完成
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC) == RESET);
//#2:读取转换的结果
uint16_t jdr1 = ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
uint16_t jdr2 = ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2);
//#3:清除JEOC标志位
ADC_ClearFlag(ADC1,ADC_FLAG_JEOC);
//#4:把结果转换成电压
float v1 = jdr1 * (3.3f / 4095);
float v2 = jdr2 * (3.3f / 4095);
//#5:串口发送结果
My_USART_Printf(USART1,"%.3f,%.3f\n",v1,v2);
}
}
//创建串口初始化函数
void App_USART1_Init(void)
{
//#1:初始化IO引脚 PA9 AF_PP
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*选择PA9引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
/*设置复用输出推挽模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
/*最大输出速度为10MHz*/
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
/*初始化PA9引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:配置USART1参数
/*开启USART1模块时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/*USART结构的前置声明*/
USART_InitTypeDef USART_InitStruct = {0};
/*波特率为115200*/
USART_InitStruct.USART_BaudRate = 115200;
/*无硬件流控*/
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/*数据位为8位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*停止位为1位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*校验方式为无*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*收发方向为发送方向*/
USART_InitStruct.USART_Mode = USART_Mode_Tx;
/*初始化USART1*/
USART_Init(USART1,&USART_InitStruct);
/*闭合串口总开关*/
USART_Cmd(USART1,ENABLE);
}
//创建TIM1初始化函数
void App_TIM1_Init(void)
{
//#1:配置时基单元
/*开启TIM1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/*声明TIM结构变量*/
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStruct;
/*计数方向为上计数*/
TIM_TimBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
/*设置自动重装寄存器*/
TIM_TimBaseInitStruct.TIM_Period = 999;
/*设置预分频系数*/
TIM_TimBaseInitStruct.TIM_Prescaler = 71;
/*设置重复计数器*/
TIM_TimBaseInitStruct.TIM_RepetitionCounter = 0;
/*初始化TIM1*/
TIM_TimeBaseInit(TIM1,&TIM_TimBaseInitStruct);
//#3:TRGO设置为Update模式
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);
//#4:闭合TIM1总开关
TIM_Cmd(TIM1,ENABLE);
}
//创建ADC初始化函数
void App_ADC_Init(void)
{
//#1:初始化IO引脚 PA0 PA1 AIN
/*开启GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
/*声明GPIO结构变量*/
GPIO_InitTypeDef GPIO_InitStruct;
/*选择PA0 PA1引脚*/
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
/*输入模式为模拟模式*/
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
/*初始化PA0 PA1引脚*/
GPIO_Init(GPIOA,&GPIO_InitStruct);
//#2:初始化时钟
/*设置分频器的分配系数为6分频*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/*开启ADC1时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//#3:初始化ADC
/*声明ADC结构变量*/
ADC_InitTypeDef ADC_InitStruct;
/*关闭连续模式*/
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
/*对齐方式为右对齐*/
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
/*外部触发信号为软件启动*/
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/*模式为独立模式*/
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
/*常规序列的通道数为1*/
ADC_InitStruct.ADC_NbrOfChannel = 1;
/*开启扫描模式*/
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
/*初始化ADC1*/
ADC_Init(ADC1,&ADC_InitStruct);
//#4:配置注入序列
/*设置注入序列长度为2*/
ADC_InjectedSequencerLengthConfig(ADC1,2);
/*ADC1 注入序列通道0 写在第一行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
/*ADC1 注入序列通道1 写在第二行 采样时间为13.5周期*/
ADC_InjectedChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_13Cycles5);
/*外部触发信号为TIM1_TRGO*/
ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
/*闭合注入序列开关*/
ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
//#5:闭合总开关
ADC_Cmd(ADC1,ENABLE);
}