小壁虎EFM32之ADC 采集电压

前言

最近在学习小壁虎EFM32芯片的使用,需要用ADC采集电压,学习之中,遇到一些小问题和需要注意的地方,现将其记录下来,避免以后自己再次踩坑和往后可以学而时习之;好了,进入正题。

代码

主函数:

int main (void)
{ 

    CHIP_Init();
    CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
    /* 
     *  开启LE时钟,只要使用到低频外设,都需要开启该时钟                  
     */
    CMU_ClockEnable(cmuClock_CORELE, true);    
    CMU_ClockEnable(cmuClock_GPIO, true);
    adcInit();                                                            /* ADC初始化                    */
//    EMU_EnterEM1();                                                     /* 进入EM1等待ADC转换结束       */ 

    
    while(1)
    {
       Voltage_Value = GetulVoltage_Value();                     //获取电池电压
    }
}

ADC初始化函数:

void adcInit (void)
{
    CMU_ClockEnable(cmuClock_ADC0, true);                               /* 使能ADC模块时钟              */

    ADC_Init_TypeDef tAdcInit = {
        .ovsRateSel = adcOvsRateSel2,                                   /* ADC过采样配置                */
        .lpfMode    = adcLPFilterBypass,                                /* 旁路输入滤波RC电路           */
        .warmUpMode = adcWarmupNormal,                                  /* 正常预热模式                 */
        .timebase   = ADC_TimebaseCalc(0),                              /* 基时间配置                   */
        .prescale   = ADC_PrescaleCalc(7000000, 0),                     /* ADC时钟分频配置              */
        .tailgate   = false                                            /* 不使能Tailgate               */
    };
    ADC_InitSingle_TypeDef tSingleInit = {
        .prsSel     = adcPRSSELCh0,                                     /* 选择PRS通道0                 */
        .acqTime    = adcAcqTime16,                                     /* 配置采集时间为16周期         */
        .reference  = adcRef2V5,                                        /* 使用VDD参考电压              */
        .resolution = adcRes12Bit,                                      /* 使用12位分辨率               */
        .input      = adcSingleInpCh5,                                  /* 选择ADC通道                  */
        .diff       = false,                                           /* 不采用差分采集模式           */
        .prsEnable  = false,                                           /* 禁能PRS输入                  */
        .leftAdjust = false,                                           /* 使用右对准                   */
        .rep        = false                                            /* 不使用连续转换               */
    };
    ADC_Init(ADC0, &tAdcInit);
 
    ADC_InitSingle(ADC0, &tSingleInit);                                 /* 初始化ADC单次转换            */
    /*
     *  使能单次采集完成中断
     */
    ADC_IntEnable(ADC0, ADC_IF_SINGLE);
    NVIC_EnableIRQ(ADC0_IRQn);
}

需要注意地方和修改的地方:
1、参考基准电压:
.reference = adcRef2V5, / 使用VDD参考电压 /
需要更改参考电压,如果你使用蓄电池供电,一般不采用VDD作为参考电压,因为随着电池的使用,电压会降低,导致采集到的电压数据不准确;采用内部的电压作为基准电压最为稳妥,我选用了内部电压2.5V,EFM32也提供了几种参考电压供你选择,如下:

typedef enum
{ /** Internal 1.25V reference. */
  adcRef1V25      = _ADC_SINGLECTRL_REF_1V25,
  /** Internal 2.5V reference. */
  adcRef2V5       = _ADC_SINGLECTRL_REF_2V5,
  /** Buffered VDD. */
  adcRefVDD       = _ADC_SINGLECTRL_REF_VDD,
  /** Internal differential 5V reference. */
  adcRef5VDIFF    = _ADC_SINGLECTRL_REF_5VDIFF,
  /** Single ended ext. ref. from pin 6. */
  adcRefExtSingle = _ADC_SINGLECTRL_REF_EXTSINGLE,
  /** Differential ext. ref. from pin 6 and 7. */
  adcRef2xExtDiff = _ADC_SINGLECTRL_REF_2XEXTDIFF,
  /** Unbuffered 2xVDD. */
  adcRef2xVDD     = _ADC_SINGLECTRL_REF_2XVDD
} ADC_Ref_TypeDef;

2、ADC通道
.input = adcSingleInpCh5, / 选择ADC通道 /
根据你所选用GPIO口,确定通道,可参考芯片规格书PIN脚部分说明。

typedef enum
{
  /* Differential mode disabled */
  adcSingleInpCh0      = _ADC_SINGLECTRL_INPUTSEL_CH0,      /**< Channel 0. */
  adcSingleInpCh1      = _ADC_SINGLECTRL_INPUTSEL_CH1,      /**< Channel 1. */
  adcSingleInpCh2      = _ADC_SINGLECTRL_INPUTSEL_CH2,      /**< Channel 2. */
  adcSingleInpCh3      = _ADC_SINGLECTRL_INPUTSEL_CH3,      /**< Channel 3. */
  adcSingleInpCh4      = _ADC_SINGLECTRL_INPUTSEL_CH4,      /**< Channel 4. */
  adcSingleInpCh5      = _ADC_SINGLECTRL_INPUTSEL_CH5,      /**< Channel 5. */
  adcSingleInpCh6      = _ADC_SINGLECTRL_INPUTSEL_CH6,      /**< Channel 6. */
  adcSingleInpCh7      = _ADC_SINGLECTRL_INPUTSEL_CH7,      /**< Channel 7. */
  adcSingleInpTemp     = _ADC_SINGLECTRL_INPUTSEL_TEMP,     /**< Temperature reference. */
  adcSingleInpVDDDiv3  = _ADC_SINGLECTRL_INPUTSEL_VDDDIV3,  /**< VDD divided by 3. */
  adcSingleInpVDD      = _ADC_SINGLECTRL_INPUTSEL_VDD,      /**< VDD. */
  adcSingleInpVSS      = _ADC_SINGLECTRL_INPUTSEL_VSS,      /**< VSS. */
  adcSingleInpVrefDiv2 = _ADC_SINGLECTRL_INPUTSEL_VREFDIV2, /**< Vref divided by 2. */
  adcSingleInpDACOut0  = _ADC_SINGLECTRL_INPUTSEL_DAC0OUT0, /**< DAC output 0. */
  adcSingleInpDACOut1  = _ADC_SINGLECTRL_INPUTSEL_DAC0OUT1, /**< DAC output 1. */
  /* TBD: Use define when available */
  adcSingleInpATEST    = 15,                                /**< ATEST. */

  /* Differential mode enabled */
  adcSingleInpCh0Ch1   = _ADC_SINGLECTRL_INPUTSEL_CH0CH1,   /**< Positive Ch0, negative Ch1. */
  adcSingleInpCh2Ch3   = _ADC_SINGLECTRL_INPUTSEL_CH2CH3,   /**< Positive Ch2, negative Ch3. */
  adcSingleInpCh4Ch5   = _ADC_SINGLECTRL_INPUTSEL_CH4CH5,   /**< Positive Ch4, negative Ch5. */
  adcSingleInpCh6Ch7   = _ADC_SINGLECTRL_INPUTSEL_CH6CH7,   /**< Positive Ch6, negative Ch7. */
  /* TBD: Use define when available */
  adcSingleInpDiff0    = 4                                  /**< Differential 0. */
} ADC_SingleInput_TypeDef;

3、ADC采集电压

uint16_t GetulVoltage_Value(void)
{
    ADC_Start(ADC0, adcStartSingle);                                       /* 启动单次转换              */
    EMU_EnterEM1();                                                        /* 进入EM1等待ADC转换结束    */ 
    ulVoltage = ADC_DataSingleGet(ADC0) * 22300 / 4095;                    /* 计算采集到的电压值        */
 
    return (ulVoltage);
}

需要注意的地方:
1、ulVoltage = ADC_DataSingleGet(ADC0) * 22300 / 4095;
“22300”怎样得到的?
采集电压图
在这里插入图片描述
电路图使用了串联分压,电压计算公式:R2/(R1+R2)*参考电压
R2:3.3M
R1:390K
参考电压:2.5V
在这里插入图片描述
完成以上的操作就可以正常的读取到电池电压了。

总结

本次记录和分享到此结束,其实ADC采集电压是平时最常用的一种模拟量转换,没有难度,初学者注意细节便能熟练灵活的使用到自己代码和电路之中。

完整函数:

#include "efm32.h"	
#include "em_cmu.h"
#include "em_emu.h"
#include "em_adc.h"
#include "em_lcd.h"
#include "em_chip.h"
#include "em_gpio.h"
#include "system.h"
#include "segmentlcd.h"

extern void adcInit(void);
uint16_t  ulVoltage;
uint16_t Voltage_Value = 0;

uint16_t GetulVoltage_Value(void)
{
    ADC_Start(ADC0, adcStartSingle);                                       /* 启动单次转换              */
    EMU_EnterEM1();                                                        /* 进入EM1等待ADC转换结束    */ 
    ulVoltage = ADC_DataSingleGet(ADC0) * 22300 / 4095;                    /* 计算采集到的电压值        */
    return (ulVoltage);
}
int main (void)
{ 

    CHIP_Init();
    CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
    /* 
     *  开启LE时钟,只要使用到低频外设,都需要开启该时钟                  
     */
    CMU_ClockEnable(cmuClock_CORELE, true);    
    CMU_ClockEnable(cmuClock_GPIO, true);
    adcInit();                                                            /* ADC初始化                    */
//    EMU_EnterEM1();                                                     /* 进入EM1等待ADC转换结束       */ 
    while(1)
    {
       Voltage_Value = GetulVoltage_Value();                     //获取电池电压
    }
}
void adcInit (void)
{
    CMU_ClockEnable(cmuClock_ADC0, true);                               /* 使能ADC模块时钟              */

    ADC_Init_TypeDef tAdcInit = {
        .ovsRateSel = adcOvsRateSel2,                                   /* ADC过采样配置                */
        .lpfMode    = adcLPFilterBypass,                                /* 旁路输入滤波RC电路           */
        .warmUpMode = adcWarmupNormal,                                  /* 正常预热模式                 */
        .timebase   = ADC_TimebaseCalc(0),                              /* 基时间配置                   */
        .prescale   = ADC_PrescaleCalc(7000000, 0),                     /* ADC时钟分频配置              */
        .tailgate   = false                                            /* 不使能Tailgate               */
    };
    ADC_InitSingle_TypeDef tSingleInit = {
        .prsSel     = adcPRSSELCh0,                                     /* 选择PRS通道0                 */
        .acqTime    = adcAcqTime16,                                     /* 配置采集时间为16周期         */
        .reference  = adcRef2V5,                                        /* 使用VDD参考电压              */
        .resolution = adcRes12Bit,                                      /* 使用12位分辨率               */
        .input      = adcSingleInpCh5,                                  /* 选择ADC通道                  */
        .diff       = false,                                           /* 不采用差分采集模式           */
        .prsEnable  = false,                                           /* 禁能PRS输入                  */
        .leftAdjust = false,                                           /* 使用右对准                   */
        .rep        = false                                            /* 不使用连续转换               */
    };
    ADC_Init(ADC0, &tAdcInit);
 
    ADC_InitSingle(ADC0, &tSingleInit);                                 /* 初始化ADC单次转换            */
    /*
     *  使能单次采集完成中断
     */
    ADC_IntEnable(ADC0, ADC_IF_SINGLE);
    NVIC_EnableIRQ(ADC0_IRQn);
}
void ADC0_IRQHandler (void)
{
    ADC_IntClear(ADC0, ADC_IF_SINGLE);                                  /* 清ADC中断标志位              */
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值