STM32笔记之 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请求,在这里你不需要去深究它,下一篇会对它进行讲解
上一篇: STM32笔记之 USART(串口)
下一篇: iPad平板电脑常用且必备操作技巧整理