一.ADC简介
1.ADC~模拟数字转换器
2.ADC将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
3.输入电压范围:0~3.3V ; 转换结果范围:0-4096
4.18个输入通道,可测量16个外部和两个内部信号源。
5.规则组个注入组两个单元。
6.模拟看门狗自动检测输入电压范围。
STM32F103C8T6 ADC资源:ADC1,ADC2,10个外部输入通道
二.ADC基本结构
1.结构图
规则组和注入组
规则组:规则组最多有16个通道,但是规则组输入通道只有一个寄存器,当16个通道都有数据时,只能接收最后一数据,之前的被覆盖,需要配合DMA使用;
注入组:主入组最多有4个通道,并且有4个输入寄存器;
2.ADC预分频器:
ADC的预分频器最大为14Mhz,对于主频72Mhz单片机来说,只能选择6分频或8分频;
2.以STM32F103C8T6为例,10个外部输入通道
PA0-PA7,PB0-PB1
3.四种模式
a.单次转换,非扫描模式
b.连续转换,非扫描模式
c.单次转换,扫描模式
d.连续转换,扫描模式
4.数据对齐
一般使用右对齐
5.转换时间
ADC转换的步骤:采样,保持,量化,编码
STM32 ADC的总转换时间为:
Tconv = 采样时间 + 12.5个ADC周期
例如:当ADCCLK = 14MHz,采样时间为15个ADC周期
Tconv = 1.5 + 12.5 = 14个ADC周期 = 1us
ADCCLK最大是14MHz,最快的时间就是1us
6.校准
建议每次上点后执行一次校准
启动校准前,ADC必须处于关电状态超两个ADC的时钟周期
三,代码部分(电位器0-3.3V)
1,标准库(AD单通道)
ADC_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC1的时钟;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启RCC APB2外设时钟控制函数GPIO时钟;
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ; //选择工作模式:模拟输入模式; 使用GPIO口外部ADC模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7 ; //选择引脚:GPIO_Pin_0初始化
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //选择速度50MHZ;
GPIO_Init(GPIOA,&GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADCCLK预分频器函数;选择6分频:72MHZ/6 = 12MHZ;
//选择规则组的输入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
//结构体初始化ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; //连续转换还是单次转换模式:本项目用单次转换
ADC_InitStruct.ADC_DataAlign =ADC_DataAlign_Right ; //指定ADC数据是左对齐还是右对齐:
ADC_InitStruct.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None ; //外部触发转换类型:软件触发
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:单ADC模式通道
ADC_InitStruct.ADC_NbrOfChannel = 1; //通道数目,扫描模式下,用几个通道;非扫描模式下,此处就为1;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //扫描模式还是非扫描模式:本项目用非扫描模式
ADC_Init(ADC1,&ADC_InitStruct);
//开启ADC电源
ADC_Cmd(ADC1,ENABLE);
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
float Voltage;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"ADValue:");
OLED_ShowString(2,1,"Voltage:0.00V");
while(1)
{
ADValue = AD_GetValue(); //返回值存放在ADValue
Voltage = (float)ADValue / 4095 * 3.3; //AD值转换成电压值;
OLED_ShowNum(1,9,ADValue,4);
OLED_ShowNum(2,9,Voltage,1); //显示小数点整数部分;
OLED_ShowNum(2,11,((uint16_t)(Voltage * 100)) % 100,2); //显示小数点后两位(浮点强转为整数),先乘100,再取余数,
}
}
2.标准库(AD多通道)
ADC_Init();
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC1的时钟;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启RCC APB2外设时钟控制函数GPIO时钟;
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ; //选择工作模式:模拟输入模式; 使用GPIO口外部ADC模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_3 ; //选择引脚:GPIO_Pin_0初始化
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //选择速度50MHZ;
GPIO_Init(GPIOA,&GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADCCLK预分频器函数;选择6分频:72MHZ/6 = 12MHZ;
//结构体初始化ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; //连续转换还是单次转换模式:本项目用单次转换
ADC_InitStruct.ADC_DataAlign =ADC_DataAlign_Right ; //指定ADC数据是左对齐还是右对齐:
ADC_InitStruct.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None ; //外部触发转换类型:软件触发
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:单ADC模式通道
ADC_InitStruct.ADC_NbrOfChannel = 1; //通道数目,扫描模式下,用几个通道;非扫描模式下,此处就为1;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //扫描模式还是非扫描模式:本项目用非扫描模式
ADC_Init(ADC1,&ADC_InitStruct);
//开启ADC电源
ADC_Cmd(ADC1,ENABLE);
//对ADC进行校准
ADC_ResetCalibration(ADC1); //复位校准函数;
while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成函数;:或者这个标志位是否为SET,如果标志位完成被硬件清零,则跳出循环;
ADC_StartCalibration(ADC1); //开始校准函数;
while (ADC_GetCalibrationStatus(ADC1) == SET); //等待校准完成函数;或者这个标志位是否为SET,如果标志位完成被硬件清零,则跳出循环;
}
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
//选择规则组的输入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE); //软件触发转换函数;等待
while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//获取标志位状态函数;标志位=RESET时,转换未完成,=SET时,转换完成,跳出循环;
return ADC_GetConversionValue(ADC1); //ADC获取转换值;
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t AD0,AD1,AD2,AD3;
int main()
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"AD0:");
OLED_ShowString(2,1,"AD1:");
OLED_ShowString(3,1,"AD2:");
OLED_ShowString(4,1,"AD3:");
//OLED_ShowString(1,9,"AD7:");
while(1)
{
AD0 = AD_GetValue(ADC_Channel_0);
AD1 = AD_GetValue(ADC_Channel_1);
AD2 = AD_GetValue(ADC_Channel_2);
AD3 = AD_GetValue(ADC_Channel_3);
OLED_ShowNum(1,5,AD0,4);
OLED_ShowNum(2,5,AD1,4);
OLED_ShowNum(3,5,AD2,4);
OLED_ShowNum(4,5,AD3,4);
//OLED_ShowHexNum(1,12,AD7,4);
Delay_ms(10);
}
}
3.标准库ADC+DMA
ADC。_Init();
#include "stm32f10x.h" // Device header
//此使用工程为:ADC连续扫描,DMA循环运转的方式
uint16_t Value[4] ;
void AD_Init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //开启ADC1的时钟;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE) ;//DMA是AHB 的外设总线上的;开启RCC DM1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启RCC APB2外设时钟控制函数GPIO时钟;
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); //通道0 序列1
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); //通道1 序列2
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); //通道2 序列3
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5); //通道3 序列4
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ; //选择工作模式:模拟输入模式; 使用GPIO口外部ADC模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 |GPIO_Pin_2 | GPIO_Pin_3 ; //选择引脚:GPIO_Pin_0初始化
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //选择速度50MHZ;
GPIO_Init(GPIOA,&GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADCCLK预分频器函数;选择6分频:72MHZ/6 = 12MHZ;
//结构体初始化ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换还是单次转换模式:本项目用连续转换
ADC_InitStruct.ADC_DataAlign =ADC_DataAlign_Right ; //指定ADC数据是左对齐还是右对齐:
ADC_InitStruct.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None ; //外部触发转换类型:软件触发
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:单ADC模式通道
ADC_InitStruct.ADC_NbrOfChannel = 4; //通道数目,扫描模式下,用几个通道;连续扫描模式下,通道为4个:此处为4;
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //扫描模式还是非扫描模式:本项目用连续扫描模式
ADC_Init(ADC1,&ADC_InitStruct);
DMA_InitTypeDef DMA_InitStruct; //定义DMA结构体
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //外设站点的起始地址;外设地址对应手册
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设站点的数据宽度:本项目数组使用uint8-t,长度为字节传输
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设站点是否自增:次工程不需要自增
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Value; //存储器站点的起始地址;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;; //存储器站点的数据宽度
DMA_InitStruct.DMA_MemoryInc =DMA_MemoryInc_Enable; //存储器站点是否自增;存储器的地址是需要自增的;
DMA_InitStruct.DMA_DIR =DMA_DIR_PeripheralSRC ; //存储方向:外设站点作为源端,还是目的地;(本项目外设站作为数据源)
DMA_InitStruct.DMA_BufferSize = 4; //指定指定通道的缓冲区大小,传输计数器 (传输次数) 几个数据就传输几次
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //传输模式:是否使用自动重装 此工程使用自动重装 循环模式
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //硬件触发还是软件触发 次数使用硬件触发
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //优先级 中等优先级
DMA_Init(DMA1_Channel1,&DMA_InitStruct); //初始化DMA函数:选择DMA1的第1个通道:根据手册ADC只能配置通道1
DMA_Cmd(DMA1_Channel1,ENABLE) ;//DMA1 通道1;初始化转运
//开启ADC电源
ADC_Cmd(ADC1,ENABLE);
//开启DMA硬件触发信号函数
ADC_DMACmd(ADC1,ENABLE); //使用通道的那个触发源,就开启相对的;
//对ADC进行校准
ADC_ResetCalibration(ADC1); //复位校准函数;
while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成函数;:或者这个标志位是否为SET,如果标志位完成被硬件清零,则跳出循环;
ADC_StartCalibration(ADC1); //开始校准函数;
while (ADC_GetCalibrationStatus(ADC1) == SET); //等待校准完成函数;或者这个标志位是否为SET,如果标志位完成被硬件清零,则跳出循环;
ADC_SoftwareStartConvCmd(ADC1,ENABLE); //ADC硬件触发 ADC连续转换,DMA循环运转
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
int main()
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"AD0:");
OLED_ShowString(2,1,"AD1:");
OLED_ShowString(3,1,"AD2:");
OLED_ShowString(4,1,"AD3:");
while(1)
{
//AD_GetValue();
OLED_ShowNum(1,5,Value[0],4);
OLED_ShowNum(2,5,Value[1],4);
OLED_ShowNum(3,5,Value[2],4);
OLED_ShowNum(4,5,Value[3],4);
//OLED_ShowHexNum(1,12,AD7,4);
Delay_ms(10);
}
}
4.HAL库+CubeMX生成代码 (ADC+DMA)
1.配置外部RCC外部时钟
2.设置Debug
3.配置ADC通道
此处需要使用几个通道就勾选几个通道
ADCs_Common_Settings:
Mode:
Independent mod 独立 ADC 模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选,具体配置 ADC_CR1:DUALMOD 位。
ADC_Settings:
Data Alignment:
Right alignment 转换结果数据右对齐,一般我们选择右对齐模式。
Scan Conversion Mode:
Disabled 禁止扫描模式。如果是单通道 AD 转换使用 DISABLE。
Enabled 开启扫描模式。如果是多通道 AD 转换使用 ENABLE。
Continuous Conversion Mode:
Disabled 单次转换。转换一次后停止需要手动控制才重新启动转换。
Enabled 自动连续转换。
DiscontinuousConvMode:
Disabled 禁止间断模式。这个在需要考虑功耗问题的产品中很有必要,也就是在某个事件触发下,开启转换。
Enabled 开启间断模式。
ADC_Regular_ConversionMode:
Enable Regular Conversions 是否使能规则转换。
Number Of Conversion ADC转换通道数目,有几个写几个就行。
External Trigger Conversion Source 外部触发选择。这个有多个选择,一般采用软件触发方式。
Rank:
Channel ADC转换通道
Sampling Time 采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。
ADC_Injected_ConversionMode:
Enable Injected Conversions 是否使能注入转换。注入通道只有在规则通道存在时才会出现。
WatchDog:
Enable Analog WatchDog Mode 是否使能模拟看门狗中断。当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。
4.配置ADC_DMA
DMA模式配置为:循环模式
方向:外设到寄存器
5.配置串口,将模拟电压值发送到PC段
串口使用USART1,参数使用默认参数
代码部分
USART.C
在USART.C中定义一个数组
uint8_t u_buf[256];
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file adc.c
* @brief This file provides code for the configuration
* of the ADC instances.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "adc.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; //使能扫描模式
hadc1.Init.ContinuousConvMode = ENABLE; //开启自动连续转换模式
hadc1.Init.DiscontinuousConvMode = DISABLE; //失能不自动连续转换模式
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; //触发方式:软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2; //通道个数:2个
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA1 ------> ADC1_IN1
PA2 ------> ADC1_IN2
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2; //配置GPIO引脚
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1; //DMA通道1
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; //方向:外设到寄存器
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; //外设地址不自增
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; //寄存器地址自增
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据大小:半字
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //寄存器数据大小:半字
hdma_adc1.Init.Mode = DMA_CIRCULAR; //DMA循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW; //优先级:
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspDeInit 0 */
/* USER CODE END ADC1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PA1 ------> ADC1_IN1
PA2 ------> ADC1_IN2
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
/* USER CODE BEGIN ADC1_MspDeInit 1 */
/* USER CODE END ADC1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
USART.h
在USART.h中,定义Printf函数;
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.h
* @brief This file contains all the function prototypes for
* the usart.c file
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN Private defines */
extern uint8_t u_buf[256];//printf?????
extern UART_HandleTypeDef huart1;
#define printf(...) HAL_UART_Transmit(&huart1, (uint8_t *)u_buf, sprintf((char*)u_buf, __VA_ARGS__), 0xffff)
/* USER CODE END Private defines */
void MX_USART1_UART_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __USART_H__ */
main.c
main. c中定义一个数组,数组内存放AD电压值
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint16_t AD_Buf[2];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校准
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&AD_Buf,2); //
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
printf("AD1= V:%1.2f Value:%d\n\r",AD_Buf[0]*3.3/4096.0,AD_Buf[0]);
printf("\r\n");
HAL_Delay(100);
printf("AD2= V:%1.2f Value:%d\n\r",AD_Buf[1]*3.3/4096.0,AD_Buf[1]);
printf("\r\n");
HAL_Delay(100);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
试验效果