STM32的ADC精度是12位,它有18个通道,可以测量16路外部和2个内部信号源,各通道的A/D转换可以单次、连续、扫描或间断模式执行,ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
主要特征:
, 12-位分辨率
转换结束,注入转换结束和发生模拟看门狗事件时产生中断
单次和连续转换模式
从通道0到通道n的自动扫描模式
自校准
带内嵌数据一致的数据对齐
通道之间采样间隔可编程
规则转换和注入转换均有外部触发选项
间断模式
双重模式(带2个ADC的器件)
ADC转换速率1MHz
ADC供电要求:2.4V到3.6V
ADC输入范围:VREF- ≤ VIN ≤ VREF+
规则通道转换期间有DMA请求产生。
关键点:12位分辨率,转换结束,注入转换结束和发生模拟看门狗事件时产生中断,供电要求2.4V到3.6V
ADC电压输入范围:ADC的电压输入范围是Vref-<= Vin<=Vref+;由VREF+,VREF-,VDDA,VSSA四个引脚决定
ADC时钟:
ADC时钟通过PCK2分频得到,最大是14MHZ,超过14MHZ读取ADC数值不准,可以是2/4/6/8分频
采样时间:采样周期最小是1.5个,此时采样最快。
ADC 的转换时间跟ADC 的输入时钟和采样时间有关,公式为:Tconv = 采样时间 +12.5 个周期。当ADCLK = 14MHZ (最高),采样时间设置为1.5 周期(最快),那么总的转换时间(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。
中断读取ADC值:
ADC转换结束后可以产生中断,ADC的中断有三种:规则通道转换结束中断,注入转换通道
转换结束中断,模拟看门狗中断
转换结束中断:ADC中断和平常用的中断一样,要配置中断服务函数,有响应的中断标志位和中断使能位
模拟看门狗中断:当ADC数值高于或者低于某个阈值时产生中断,其中低阈值和高阈值由ADC_LTR 和ADC_HTR 设置
程序如下:
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
// ´ò¿ªADCʱÖÓ
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// ADC ģʽÅäÖÃ
// ֻʹÓÃÒ»¸öADC£¬ÊôÓÚ¶ÀÁ¢Ä£Ê½
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// ½ûֹɨÃèģʽ£¬¶àͨµÀ²ÅÒª£¬µ¥Í¨µÀ²»ÐèÒª
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
// Á¬Ðø×ª»»Ä£Ê½
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ²»ÓÃÍⲿ´¥·¢×ª»»£¬Èí¼þ¿ªÆô¼´¿É
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// ת»»½á¹ûÓÒ¶ÔÆë
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ת»»Í¨µÀ1¸ö
ADC_InitStructure.ADC_NbrOfChannel = 1;
// ³õʼ»¯ADC
ADC_Init(ADCx, &ADC_InitStructure);
// ÅäÖÃADCʱÖÓΪPCLK2µÄ8·ÖƵ£¬¼´9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// ÅäÖà ADC ͨµÀת»»Ë³ÐòºÍ²ÉÑùʱ¼ä
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1,
ADC_SampleTime_55Cycles5);
// ADC ת»»½áÊø²úÉúÖжϣ¬ÔÚÖжϷþÎñ³ÌÐòÖжÁȡת»»Öµ
ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
// ¿ªÆôADC £¬²¢¿ªÊ¼×ª»»
ADC_Cmd(ADCx, ENABLE);
// ³õʼ»¯ADC У׼¼Ä´æÆ÷
ADC_ResetCalibration(ADCx);
// µÈ´ýУ׼¼Ä´æÆ÷³õʼ»¯Íê³É
while(ADC_GetResetCalibrationStatus(ADCx));
// ADC¿ªÊ¼Ð£×¼
ADC_StartCalibration(ADCx);
// µÈ´ýУ׼Íê³É
while(ADC_GetCalibrationStatus(ADCx));
// ÓÉÓÚûÓвÉÓÃÍⲿ´¥·¢£¬ËùÒÔʹÓÃÈí¼þ´¥·¢ADCת»»
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// ÓÅÏȼ¶·Ö×é
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// ÅäÖÃÖжÏÓÅÏȼ¶
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
中断读取ADC
void ADC_IRQHandler(void)
{
if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET)
{
// ¶ÁÈ¡ADCµÄת»»Öµ
ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
}
ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
}
使用DMA读取ADC值:
规则和注入通道转换结束后,除了产生中断外,还可以产生DMA 请求,把转换好的数据直接存储在内存里面,只有ADC1和ADC3可以产生DMA请求
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// ´ò¿ªDMAʱÖÓ
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// ´ò¿ªADCʱÖÓ
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// ¸´Î»DMA¿ØÖÆÆ÷
DMA_DeInit(ADC_DMA_CHANNEL);
// ÅäÖà DMA ³õʼ»¯½á¹¹Ìå
// ÍâÉè»ùַΪ£ºADC Êý¾Ý¼Ä´æÆ÷µØÖ·
DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t ) ( & ( ADCx->DR ) );
// ´æ´¢Æ÷µØÖ·£¬Êµ¼ÊÉϾÍÊÇÒ»¸öÄÚ²¿SRAMµÄ±äÁ¿
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;
// Êý¾ÝÔ´À´×ÔÍâÉè
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// »º³åÇø´óСΪ1£¬»º³åÇøµÄ´óСӦ¸ÃµÈÓÚ´æ´¢Æ÷µÄ´óС
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 ´«ÊäͨµÀÓÅÏȼ¶Îª¸ß£¬µ±Ê¹ÓÃÒ»¸öDMAͨµÀʱ£¬ÓÅÏȼ¶ÉèÖò»Ó°Ïì
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// ½ûÖ¹´æ´¢Æ÷µ½´æ´¢Æ÷ģʽ£¬ÒòΪÊÇ´ÓÍâÉèµ½´æ´¢Æ÷
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// ³õʼ»¯DMA
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// ʹÄÜ DMA ͨµÀ
DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
// ADC ģʽÅäÖÃ
// ֻʹÓÃÒ»¸öADC£¬ÊôÓÚµ¥Ä£Ê½
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// ½ûֹɨÃèģʽ£¬¶àͨµÀ²ÅÒª£¬µ¥Í¨µÀ²»ÐèÒª
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;
// Á¬Ðø×ª»»Ä£Ê½
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// ²»ÓÃÍⲿ´¥·¢×ª»»£¬Èí¼þ¿ªÆô¼´¿É
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// ת»»½á¹ûÓÒ¶ÔÆë
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// ת»»Í¨µÀ1¸ö
ADC_InitStructure.ADC_NbrOfChannel = 1;
// ³õʼ»¯ADC
ADC_Init(ADCx, &ADC_InitStructure);
// ÅäÖÃADCʱÖÓΪPCLK2µÄ8·ÖƵ£¬¼´9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// ÅäÖà ADC ͨµÀת»»Ë³ÐòΪ1£¬µÚÒ»¸öת»»£¬²ÉÑùʱ¼äΪ55.5¸öʱÖÓÖÜÆÚ
ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
// ʹÄÜADC DMA ÇëÇó
ADC_DMACmd(ADCx, ENABLE);
// ¿ªÆôADC £¬²¢¿ªÊ¼×ª»»
ADC_Cmd(ADCx, ENABLE);
// ³õʼ»¯ADC У׼¼Ä´æÆ÷
ADC_ResetCalibration(ADCx);
// µÈ´ýУ׼¼Ä´æÆ÷³õʼ»¯Íê³É
while(ADC_GetResetCalibrationStatus(ADCx));
// ADC¿ªÊ¼Ð£×¼
ADC_StartCalibration(ADCx);
// µÈ´ýУ׼Íê³É
while(ADC_GetCalibrationStatus(ADCx));
// ÓÉÓÚûÓвÉÓÃÍⲿ´¥·¢£¬ËùÒÔʹÓÃÈí¼þ´¥·¢ADCת»»
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
}