STM32笔记之 ADC(模数转换)

写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

目录

一、模拟量和数字量

二、ADC介绍

三、功能特征

四、转换模式

五、数据对齐方式

六、数据计算

七、代码实现


一、模拟量和数字量

在开篇之前,先来了解点硬件知识

模拟(类比)信号:在时间和数值上均具有连续性,即对应于任意时间值 t均有确定的函数值 u或 i,并且 u或 i的幅值是连续取值的

数字(数位)信号:在时间和数值上均具有离散性,u或 i的变化在时间上不连续,总是发生在离散的瞬间,且它们的数值是一个最小量值得整数倍,并以此倍数作为数字信号的数值

所以,所谓的 ADC转换实际就是把模拟信号的模拟量转换成数字信号的数字量

同样的,DAC则是反过来把数字信号的数字量变成模拟信号的模拟量

二、ADC介绍

从数据手册上我们可以了解到,我们实验所用的 ADC转换,它的采样数据最多支持 12bit(即:4096个数据),有多达18个通道,可测量 16个外部和 2个内部信号源。各通道的 A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在 16位数据寄存器中。

三、功能特征

四、转换模式

1、单次转换模式

2、连续转换模式

五、数据对齐方式

1、右对齐

2、左对齐

六、数据计算

在上面我们获取到 ADC是 12位分辨率,也就是说总的有 12bit的数值,然而,我们最终需要的是电压值,所以要进行数据换算,这个可以参考以前那篇 ADC采样值转化成电压值详解

值得注意的是,数据类型一定要处理好,必要时要强制转换一下数据类型,否则会出现计算不准的情况

七、代码实现

bsp_adc.c 源文件

#include "bsp_adc.h"
#include "bsp_uart.h"


// ADC1转换的电压值通过MDA方式传到SRAM
__IO uint16_t ADC_ConvertedValue;

/************************************************
函数名称 : Get_ADCx_Result
功    能 : ADC数据获取
参    数 : Ch ---- 通道
返 回 值 : temp ---- 转换计算后的电压值(放大 1000倍)
*************************************************/
float Get_ADC_Result(void)
{
	float temp;

	temp =(float) ADC_ConvertedValue / 4096*VDD_VALUE;	// 读取转换的 AD值

#if 1
	printf(">>>>> 电压值:%d\r\n",(int)temp);
	
#endif

	return temp;                 
}

/************************************************
函数名称 : ADCx_GPIO_Config
功    能 : ADC GPIO配置
参    数 : 无
返 回 值 : 无
*************************************************/
static void ADCx_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/* Enable ADCxGPIO clock */
	ADC_GPIO_APBxClock_FUN(ADC_GPIO_CLK, ENABLE);
	
	/* Configure PB.00 (ADC Channel8) as analog input */
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
	GPIO_Init(ADC_PORT, &GPIO_InitStructure);				
}

/************************************************
函数名称 : ADCx_Mode_Config
功    能 : ADC模式配置
参    数 : 无
返 回 值 : 无
*************************************************/
static void ADCx_Mode_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	
	/* Enable DMA1 clock */
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/* Enable ADCx clock */
	ADC_APBxClock_FUN(ADC_CLK, ENABLE);
	
	/* Restoration DMA ADC Channel*/
	DMA_DeInit(ADC_DMA_CHANNEL);
	
	/* DMA init structure parameters values */
	DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t )(&(ADCx->DR));	
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	
	DMA_InitStructure.DMA_BufferSize = 1;	
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 	
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;	
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	
	DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
	
	/* Enable DMA ADC channel */
	DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
	
	/* ADC init structure parameters values */
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;      // 设置 ADC模式,因为只使用一个ADC,属于单模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE ;          // 禁止扫描模式,多通道才要,单通道不需要
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;      // 使能连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	// 转换结果右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	                // 转换通道 1个		
	ADC_Init(ADCx, &ADC_InitStructure);
	
	/* ADCCLK = PCLK2/8 */
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	
	/* ADCx regular channel configuration */
	ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
	
	/* Enable ADCx DMA */
	ADC_DMACmd(ADCx, ENABLE);
	
	/* Enable ADCx */
	ADC_Cmd(ADCx, ENABLE);
	
	/* Enable ADCx reset calibration register */  
	ADC_ResetCalibration(ADCx);
	/* Check the end of ADCx reset calibration register */
	while(ADC_GetResetCalibrationStatus(ADCx));
	
	/* Start ADCx calibration */
	ADC_StartCalibration(ADCx);
	/* Check the end of ADCx calibration */
	while(ADC_GetCalibrationStatus(ADCx));
	
	/* Start ADCx Software Conversion */
	ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}

/************************************************
函数名称 : ADCx_Init
功    能 : 各 ADC口初始化
参    数 : 无
返 回 值 : 无
*************************************************/
void ADCx_Init(void)
{
	ADCx_GPIO_Config();
	ADCx_Mode_Config();
}


/*---------------------------- END OF FILE ----------------------------*/


bsp_adc.h 头文件

#ifndef __BSP_ADC_H
#define __BSP_ADC_H


#include "stm32f10x.h"

#define VDD_VALUE	3300

// 注意:用作 ADC采集的 IO必须没有复用,否则采集电压会有影响
/******************** ADC1输入通道(引脚)配置 **************************/
#define    ADCx                          ADC1
#define    ADC_APBxClock_FUN(x, y)       RCC_APB2PeriphClockCmd(x, y)
#define    ADC_CLK                       RCC_APB2Periph_ADC1

#define    ADC_GPIO_APBxClock_FUN(x, y)  RCC_APB2PeriphClockCmd(x, y)
#define    ADC_GPIO_CLK                  RCC_APB2Periph_GPIOC

#define    ADC_PORT                      GPIOC
#define    ADC_PIN                       GPIO_Pin_1

#define    ADC_CHANNEL                   ADC_Channel_11
#define    ADC_DMA_CHANNEL               DMA1_Channel1

extern __IO uint16_t ADC_ConvertedValue;

float Get_ADC_Result(void);
void ADCx_Init(void);


#endif	/* __BSP_ADC_H */


/*---------------------------- END OF FILE ----------------------------*/

mian.c 文件

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "bsp.h"
#include "bsp_uart.h"
#include "bsp_adc.h"


const uint32_t Baudrate_1 = 115200;		// 波特率设置	支持的波特率:115200,19200,9600,38400,57600,1200,2400,4800

/************************************************
函数名称 : main
功    能 : 主函数入口
参    数 : 无
返 回 值 : 无
*************************************************/
int main(void)
{	
    /* Initial Configuration */
    SystemInit();
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    SysTick_Init();
    UART1_Comfig(Baudrate_1);
    ADCx_Init();
	
    /* -------- End -------- */

	
    /* Infinite loop */
    while (1)
    {
        Get_ADC_Result();
        Delay_us(0x3FFFF);
    }
}

在上面的例程中,使用了 DMA请求,在这里你不需要去深究它,下一篇会对它进行讲解

发布了48 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42992084/article/details/104101082