STM32笔记归纳10:ADC

ADC

目录

ADC

一、逐次逼近型ADC

1.1.ADC是什么

1.2.单片机里的ADC模块

1.3.采样深度的概念

1.4.逐次逼近型ADC简介

1.5.采样保持电路

1.6.例子

二、ADC模块的结构框图

2.1.ADC的多路复用

2.2.常规序列

2.3.注入序列

2.4.例子

三、采样时间和转换时间

3.1.ADC的时钟频率

3.2.转换时间的计算方法

3.3.采样时间和信号源内阻的关系

3.4.信号源内阻的计算方法

3.5.采样时间的计算方法

四、常规序列的单通道转换

4.1.初始化IO引脚

4.2.配置ADC时钟

4.3.ADC的编程接口

4.4.初始化ADC的基本参数

4.5.配置常规序列

4.6.闭合ADC的总开关

4.7.启动并读取转换结果

五、定时器触发

5.1.连接电路

5.2.初始化串口

5.3.配置定时器1的TRGO

5.4.注入序列的编程接口

5.5.初始化ADC(注入序列)

5.6.读取并发送测量结果

六、扫描模式

6.1.扫描模式

6.2.电路连接

6.3.初始化串口

6.4.配置定时器1

6.5.配置ADC

6.6.总代码


一、逐次逼近型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);
}
相关推荐
时代的凡人10 小时前
0208晨间笔记
笔记
今天只学一颗糖11 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
不做无法实现的梦~12 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
饭碗、碗碗香15 小时前
【Python学习笔记】:Python的hashlib算法简明指南:选型、场景与示例
笔记·python·学习
Wils0nEdwards15 小时前
初中化学1
笔记
熊猫_豆豆16 小时前
同步整流 Buck 降压变换器
单片机·嵌入式硬件·matlab
饭碗、碗碗香17 小时前
【Python学习笔记】:Python 加密算法全景指南:原理、对比与工程化选型
笔记·python·学习
对牛乱弹琴的秦始皇17 小时前
IoT MQ 连接失败的排查笔记
服务器·网络·笔记
S190118 小时前
一些资源整合笔记,后续会陆续更新
笔记
marteker18 小时前
X测试协作式人工智能驱动的社区笔记
笔记