发新帖本帖赏金 10.00元(功能说明)我要提问
12下一页
返回列表
打印
[综合信息]

华大HC32F460之ADC

[复制链接]
5607|34
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
binoo7|  楼主 | 2021-2-13 10:43 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
#申请原创#@小跑堂 @小跑堂  @小跑堂
今天是大年初二,我们来讲讲华大HC32F460的ADC功能
首先,片上搭载的是12位的ADC,一共有17个通道,但是,16个外部模拟输入通道和 1个内部基准电压/8bitDAC 输出的检测通道。
MCU内部集成 ADC1和 ADC2两个 ADC 模块,挂载于AHB-APB(APB3)总线



有一点需要特别说明:ADC外设的时钟源是PCLK4,
在进行ADC转换的时候有一个 A/D转换时钟 ADCLK,这个时钟的时钟源是什么呢?看一本书真的看不懂,我找了几个地方来一一印证一下,首先是系统时钟框图

从上图可以看到ADCLK 的时钟源挺多的,再次看代码

代码里列出来的是三种时钟PCLK/MPLLQ/UPLLR
具体实现的过程是这样的
/**
*******************************************************************************
** \brief  ADC clock configuration.
**
** \note
再看用户手册中的介绍,有没有很迷茫?

好啦,在这里总结一下这个时钟源到底是怎么选的根本就没有配置相关的寄存器,而是通过配置时钟后,不同的时钟比例来对应不同的时钟源选择,迷茫不?

可能是我见识比较浅,在用户手册里,还发现了ADC看门狗这个功能,他是这么说的
ADC 模块还搭载模拟看门狗功能,对任意指定通道的转换结果进行监视,检测是否超出用户设定的阀值。

具体是什么样的,我们稍后再说。
时钟配置好以后就是配置通道了

ADC 模块有多个通道,可配置为两个序列:
序列 A,序列 B 进行转换。
序列 A 和 B配有独立的通道选择寄存器 ADC_CHSELRA,ADC_CHSELRB。
寄存器每位代表一个通道,如 bit0 位写 1 表示转换 CH0,写 0 表示不转换 CH0。

两个序列可独立选择任意1 个或多个通道进行转换。
例如:ADC_CHSELRA 设置为 0x0055,ADCHSELRB 设置为 0x0002,则序列 A 的触发条件发生时,将依次转换 CH0,CH2,CH4 和 CH6 这 4个通道。序列 B 的触发条件发生时,将转换 CH1 这一个通道。
对于内部模拟通道,有 3 个可选的模拟量:8bitDAC_1 输出、8bitDAC_2 输出、内部基准电压(约 1.1V)。在选择内部模拟通道作为 ADC 转换对象时,需要先 设 置 内 部 通 道 选 择 寄 存 器 , 再 设 置 ADC 的 通 道 选 择 寄 存 器ADC_CHSELRA/ADC_CHSELRB 选择内部通道,才可以启动 ADC 转换。

下面是触发源选择,序列 A,序列 B 独立选择触发源。
可选择的触发源包括外部端口 ADTRGx,内部事件IN_TRGx0, IN_TRGx1。
其中,端口 ADTRGx 下降沿输入有效。IN_TRGx0,IN_TRGx1由寄存器 ADC_ITRGSELR0,1 设置,可以选择芯片内部丰富的事件源。此外,写寄存器 ADC_STR 可生成软件触发信号,软件触发只能在 ADC 处于待机状态时使用,并且只适用于序列 A。


下面就是通道的扫描模式,分成三种 单次扫描 多次扫描和双通道扫描
A/D 控制寄存器 ADC_CR0.MS[1:0]设为 00b 选择序列 A 单次扫描模式。
该模式下,当寄存器 ADC_TRGSR 选择的序列 A 启动条件发生,或者 ADC_STR.STRT位写 1 软件触发,ADC 启动,对序列 A 通道选择寄存器 ADC_CHSELRA 中选择的所有通道依次进行采样和转换,转换结果存入相应的数据寄存器 ADC_DR 中。ADC 转换过程中 ADC_STR.STRT 保持为 1,当所有通道转换结束后自动清 0,ADC 进入转换待机状态,等待下次触发条件的发生。
当所有通道转换结束时,序列 A 转换结束标志位 ADC_ISR.EOCAF 置 1,并产生序列A 转换结束事件 ADC_EOCA,可以用此事件启动 DMA。若 ADC_ICR.EOCAIEN 为1,中断许可的状态下,同时还产生序列 A 转换结束中断请求。


序列 A 单次扫描模式的软件流程:
1. 确认 ADC_STR.STRT 为 0,ADC 处于转换待机状态。
2. A/D 控制寄存器 ADC_CR0.MS[1:0]设为 00b 选择序列 A 单次扫描模式。
3. 设置序列 A 通道选择寄存器 ADC_CHSELRA。
4. 设置采样时间寄存器 ADC_SSTR。

5. ADC_STR.STRT 写 1 软件触发序列 A,或者设置寄存器 ADC_TRGSR 选择序列 A触发条件。
6. 查询序列 A 转换结束标志位 EOCAF。
7. 读取各通道数据寄存器 ADC_DR。
8. 写 0 清除 EOCAF 标志位,为下次转换准备。
上面的步骤 6~8 的 CPU 查询方式也可以替换成中断方式,利用 ADC_EOCA 中断来处理转换数据。或者利用 ADC_EOCA 事件启动 DMA 读取数据。

A/D 控制寄存器 ADCR0.MS[1:0]设为 01b 选择序列 A 连续扫描模式。
序列 A 连续扫描模式与序列 A 单次扫描模式动作类似,不同点在于,连续模式在所用通道转换结束后不是进入转换待机状态,而是重新开始转换序列 A。STRT 位也不会自动清 0。
当需要停止连续扫描时,对 STRT 位写 0,并读 STRT 确认为 0 以判断 ADC 进入转换待机状态。

序列 A 连续扫描模式的软件流程:
1. 确认 ADC_STR.STRT 为 0,ADC 处于转换待机状态。
2. A/D 控制寄存器 ADC_CR0.MS[1:0]设为 01b 选择序列 A 连续扫描模式。
3. 设置序列 A 通道选择寄存器 ADC_CHSELRA。
4. 设置采样时间寄存器 ADC_SSTR。
5. ADC_STR.STRT 写 1 软件触发序列 A,或者设置寄存器 ADC_TRGSR 选择序列 A触发条件。

6. 查询序列 A 转换结束标志位 EOCAF。
7. 读取各通道数据寄存器 ADC_DR。
8. 写 0 清楚 EOCAF 标志位,为下次转换准备。
9. 不需要继续转换时,对 STRT 位写 0,并读 STRT 确认为 0 以判断 ADC 进入转换待机状态。
上面的步骤 6~8 的查询方式也可以替换成中断方式,利用 ADC_EOCA 中断来处理转换数据。或者利用 ADC_EOCA 事件启动 DMA 读取数据。
注意:
– 由于是连续转换,每次扫描的间隔比较短,特别是只选择 1 个通道转换时。推荐使用 ADC_EOCA 事件启动 DMA 读取数据,避免查询方式下处理不及时导致数据丢失。

A/D 控制寄存器 ADC_CR0.MS[1:0]设为 10b 或 11b 选择双序列扫描模式,即序列 A 与序列 B 都可由各自选择的触发条件来启动扫描。
当 MS[1:0]=10b 时,序列 A 和 B 等效于两个独立的单次扫描序列。MS[1:0]=11b 序列A 为连续扫描模式,B 为单次扫描模式。
序列 A 由 ADC_TRGSR.TRGSELA[2:0]选择触发源,由 ADC_CHSELRA 选择转换的通道。序列 B 由 ADC_TRGSR.TRGSELB[2:0]选择触发源,由 ADC_CHSELRB 选择转换的通道。
当序列 A 全部通道转换结束时,序列 A 转换结束标志位 ADC_ISR.EOCAF 置 1,并产生序列 A 转换结束事件 ADC_EOCA,若 ADC_ISCR.EOCAIEN 为 1,中断许可的状态下,同时产生序列 A 转换结束中断请求。
当序列 B 全部通道转换结束时,序列 B 转换结束标志位 ADC_ISR.EOCBF 置 1,并产生序列 B 转换结束事件 ADC_EOCB,若ADC_ISCR.EOCBIEN 为 1,中断许可的状态下,同时产生序列 B 转换结束中断请求。
双序列扫描模式下,当序列 A 与序列 B 发生竞争时,序列 B 将会被优先处理,即序列B 优先级高于序列 A。




还有很多功能这里就不做一一讲解了,下面看一下官方给的代码我们来分析一下流程
/*******************************************************************************
* Copyright (C) 2016, Huada Semiconductor Co., Ltd. All rights reserved.
*
* This software is owned and published by:
* Huada Semiconductor Co., Ltd. ("HDSC").
*
* BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
* BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
*
* This software contains source code for use with HDSC
* components. This software is licensed by HDSC to be adapted only
* for use in systems utilizing HDSC components. HDSC shall not be
* responsible for misuse or illegal use of this software for devices not
* supported herein. HDSC is providing this software "AS IS" and will
* not be responsible for issues arising from incorrect user implementation
* of the software.
*
* Disclaimer:
* HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
* REGARDING THE SOFTWARE (INCLUDING ANY ACCOMPANYING WRITTEN MATERIALS),
* ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
* WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
* WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
* WARRANTY OF NONINFRINGEMENT.
* HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
* NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
* LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
* LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
* INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
* SAVINGS OR PROFITS,
* EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
* INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
* FROM, THE SOFTWARE.
*
* This software may be replicated in part or whole for the licensed use,
* with the restriction that this Disclaimer and Copyright notice must be
* included with each copy of this software, whether used in part or whole,
* at all times.
*/
/******************************************************************************/
/** \file main.c
**
** \brief ADC sample
**
**   - 2018-11-30  1.0  Wuze First version for Device Driver Library of
**     ADC
**
******************************************************************************/

/*******************************************************************************
* Include files
******************************************************************************/
#include "hc32_ddl.h"

/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/

/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/*
* If you remap the mapping between the channel and the pin with the function
* ADC_ChannleRemap, define ADC_CH_REMAP as non-zero, otherwise define as 0.
*/
#define ADC_CH_REMAP                (0u)

/* ADC clock selection definition. */
#define ADC_CLK_PCLK                (1u)
#define ADC_CLK_MPLLQ               (2u)
#define ADC_CLK_UPLLR               (3u)

/* Select PCLK as ADC clock. */
#define ADC_CLK                     (ADC_CLK_UPLLR)

/* ADC1 channel definition for this example. */
#define ADC1_SA_NORMAL_CHANNEL      (ADC1_CH0 | ADC1_CH10)
#define ADC1_SA_AVG_CHANNEL         (ADC1_CH12 | ADC1_CH13)
#define ADC1_SA_CHANNEL             (ADC1_SA_NORMAL_CHANNEL | ADC1_SA_AVG_CHANNEL)
#define ADC1_SA_CHANNEL_COUNT       (4u)

#define ADC1_AVG_CHANNEL            (ADC1_SA_AVG_CHANNEL)
#define ADC1_CHANNEL                (ADC1_SA_CHANNEL)

/* ADC1 channel sampling time.     ADC1_CH0  ADC1_CH10  ADC1_CH12   ADC1_CH13 */
#define ADC1_SA_CHANNEL_SAMPLE_TIME { 0x30,     0x80,      0x50,      0x60 }

/* ADC2 channel definition for this example. */
#define ADC2_SA_NORMAL_CHANNEL      (ADC2_CH0 | ADC2_CH2)
#define ADC2_SA_AVG_CHANNEL         (ADC2_CH5)
#define ADC2_SA_CHANNEL             (ADC2_SA_NORMAL_CHANNEL | ADC2_SA_AVG_CHANNEL)
#define ADC2_SA_CHANNEL_COUNT       (3u)

#define ADC2_AVG_CHANNEL            (ADC2_SA_AVG_CHANNEL)
#define ADC2_CHANNEL                (ADC2_SA_CHANNEL)

/* ADC2 channel sampling time.      ADC2_CH0  ADC2_CH2  ADC2_CH5  */
#define ADC2_SA_CHANNEL_SAMPLE_TIME { 0x60,     0x50,     0x40 }

/* ADC resolution definitions. */
#define ADC_RESOLUTION_8BIT         (8u)
#define ADC_RESOLUTION_10BIT        (10u)
#define ADC_RESOLUTION_12BIT        (12u)

#define ADC1_RESOLUTION             (ADC_RESOLUTION_12BIT)
#define ADC2_RESOLUTION             (ADC_RESOLUTION_10BIT)

/* Scan mode definitions. */
#define ADC1_SCAN_MODE              (AdcMode_SAOnce)
#define ADC2_SCAN_MODE              (AdcMode_SAContinuous)

/* ADC reference voltage. The voltage of pin VREFH. */
#define ADC_VREF                    (3.288f)

/* ADC accuracy. */
#define ADC1_ACCURACY               (1ul << ADC1_RESOLUTION)

/* ADC2 continuous conversion times. */
#define ADC2_CONTINUOUS_TIMES       (3u)

/* Timeout value definitions. */
#define TIMEOUT_MS                  (10u)

/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/

/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
static void SystemClockConfig(void);

static void AdcConfig(void);
static void AdcClockConfig(void);
static void AdcInitConfig(void);
static void AdcChannelConfig(void);

static void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,
                                 uint32_t u32Channel,
                                 en_pin_mode_t enMode);
static void AdcSetPinMode(uint8_t u8AdcPin, en_pin_mode_t enMode);

/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
static uint16_t m_au16Adc1Value[ADC1_CH_COUNT];
static uint16_t m_au16Adc2Value[ADC2_CH_COUNT];

static stc_clk_sysclk_cfg_t m_stcSysclkCfg =
{
    /* Default system clock division. */
    .enHclkDiv  = ClkSysclkDiv1,  // 168MHz
    .enExclkDiv = ClkSysclkDiv2,  // 84MHz
    .enPclk0Div = ClkSysclkDiv1,  // 168MHz
    .enPclk1Div = ClkSysclkDiv2,  // 84MHz
    .enPclk2Div = ClkSysclkDiv4,  // 42MHz
    .enPclk3Div = ClkSysclkDiv4,  // 42MHz
    .enPclk4Div = ClkSysclkDiv2,  // 84MHz
};

/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
*******************************************************************************
** \brief  Main function.
**
** \param  None.
**
** \retval int32_t return value, if needed.
**
******************************************************************************/
int32_t main(void)
{
    uint8_t u8Count;

    /* Configuring a new system clock if you need. */
    SystemClockConfig();

    /* Config ADC. */
    AdcConfig();

    /* Config UART for printing. Baud rate 115200. */
    Ddl_UartInit();

    /***************** Configuration end, application start **************/

    /* ADC1 sequence A single scan. */
    /* Start ADC1, wait ADC1 scan converting done, read ADC1 data. */
    ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);

    /* ADC2 sequence A continuous scan. */
    u8Count = 0u;
    ADC_StartConvert(M4_ADC2);
    while (u8Count < ADC2_CONTINUOUS_TIMES)
    {
        if (Set == ADC_GetEocFlag(M4_ADC2, ADC_SEQ_A))
        {
            ADC_GetChData(M4_ADC2, ADC2_SA_CHANNEL, m_au16Adc2Value, ADC2_SA_CHANNEL_COUNT);
            ADC_ClrEocFlag(M4_ADC2, ADC_SEQ_A);
            u8Count++;
            // TODO: USE THE m_au16Adc2Value.
        }
    }

    /*
     *  DO NOT forget to stop ADC when your mode is
     *  AdcMode_SAContinuous or AdcMode_SAContinuousSBOnce
     *  unless you need.
     */
    ADC_StopConvert(M4_ADC2);

    while (1u)
    {
        ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);
        /* ADC1 channel 10 maps pin ADC12_IN10 by default. */
        printf("\nADC12_IN10 value %d.", m_au16Adc1Value[10u]);
        printf("\nADC12_IN10 voltage is %.4fV.",
            ((float)m_au16Adc1Value[10u] * ADC_VREF) / (float)ADC1_ACCURACY);

        /* Main loop cycle is 500ms. */
        Ddl_Delay1ms(500u);
    }
}

/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
/**
*******************************************************************************
** \brief  Configuring a new system clock.
**         System clock frequency: 168MHz.
**         System clock source:    MPLL.
**         MPLL clock source:      XTAL(8MHz).
**
******************************************************************************/
static void SystemClockConfig(void)
{
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_mpll_cfg_t stcMpllCfg;
    stc_sram_config_t  stcSramConfig;

    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);

    /* Set bus clock division first. */
    CLK_SysClkConfig(&m_stcSysclkCfg);

    /* Switch system clock source to MPLL. */
    /* Use XTAL as MPLL source. */
    stcXtalCfg.enFastStartup = Enable;
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv  = ClkXtalLowDrv;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* Set MPLL out 168MHz. */
    stcMpllCfg.pllmDiv = 1u;
    /* sysclk = 8M / pllmDiv * plln / PllpDiv */
    stcMpllCfg.plln    = 42u;
    stcMpllCfg.PllpDiv = 2u;
    stcMpllCfg.PllqDiv = 16u;
    stcMpllCfg.PllrDiv = 16u;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* Flash read wait cycle setting. */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_4);
    EFM_Lock();

    /* If the system clock frequency is higher than 100MHz and SRAM1, SRAM2, SRAM3 or Ret_SRAM is used,
       the wait cycle must be set. */
    stcSramConfig.u8SramIdx     = Sram12Idx | Sram3Idx | SramRetIdx;
    stcSramConfig.enSramRC      = SramCycle2;
    stcSramConfig.enSramWC      = SramCycle2;
    stcSramConfig.enSramEccMode = EccMode0;
    stcSramConfig.enSramEccOp   = SramNmi;
    stcSramConfig.enSramPyOp    = SramNmi;
    SRAM_Init(&stcSramConfig);

    CLK_MpllCmd(Enable);

    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }

    /* Set system clock source. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}

/**
*******************************************************************************
** \brief  ADC configuration, including clock configuration, initial configuration
**         and channel configuration.
**
** \param  None.
**
** \retval None.
**
******************************************************************************/
static void AdcConfig(void)
{
    AdcClockConfig();
    AdcInitConfig();
    AdcChannelConfig();
}

/**
*******************************************************************************
** \brief  ADC clock configuration.
**
** \note   1) ADCLK max frequency is 60MHz.
**         2) If PCLK2 and PCLK4 are selected as the ADC clock,
**            the following conditions must be met:
**            a. ADCLK(PCLK2) max 60MHz;
**            b. PCLK4 : ADCLK = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4
**
******************************************************************************/
static void AdcClockConfig(void)
{
#if (ADC_CLK == ADC_CLK_PCLK)
    /* Set bus clock division, depends on the system clock frequency. */
    m_stcSysclkCfg.enPclk2Div = ClkSysclkDiv64;
    m_stcSysclkCfg.enPclk4Div = ClkSysclkDiv16;

    CLK_SysClkConfig(&m_stcSysclkCfg);
    CLK_SetPeriClkSource(ClkPeriSrcPclk);

#elif (ADC_CLK == ADC_CLK_MPLLQ)
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_mpll_cfg_t stcMpllCfg;

    if (CLKSysSrcMPLL == CLK_GetSysClkSource())
    {
        /*
         * Configure MPLLQ(same as MPLLP and MPLLR) when you
         * configure MPLL as the system clock.
         */
    }
    else
    {
        /* Use XTAL as MPLL source. */
        stcXtalCfg.enFastStartup = Enable;
        stcXtalCfg.enMode = ClkXtalModeOsc;
        stcXtalCfg.enDrv  = ClkXtalLowDrv;
        CLK_XtalConfig(&stcXtalCfg);
        CLK_XtalCmd(Enable);

        /* Set MPLL out 240MHz. */
        stcMpllCfg.pllmDiv = 1u;
        /* mpll = 8M / pllmDiv * plln */
        stcMpllCfg.plln    = 30u;
        stcMpllCfg.PllpDiv = 16u;
        stcMpllCfg.PllqDiv = 16u;
        stcMpllCfg.PllrDiv = 16u;
        CLK_SetPllSource(ClkPllSrcXTAL);
        CLK_MpllConfig(&stcMpllCfg);
        CLK_MpllCmd(Enable);
    }
    CLK_SetPeriClkSource(ClkPeriSrcMpllp);

#elif (ADC_CLK == ADC_CLK_UPLLR)
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_upll_cfg_t stcUpllCfg;

    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcUpllCfg);

    /* Use XTAL as UPLL source. */
    stcXtalCfg.enFastStartup = Enable;
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* Set UPLL out 240MHz. */
    stcUpllCfg.pllmDiv = 2u;
    /* upll = 8M(XTAL) / pllmDiv * plln */
    stcUpllCfg.plln    = 60u;
    stcUpllCfg.PllpDiv = 16u;
    stcUpllCfg.PllqDiv = 16u;
    stcUpllCfg.PllrDiv = 16u;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_UpllConfig(&stcUpllCfg);
    CLK_UpllCmd(Enable);
    CLK_SetPeriClkSource(ClkPeriSrcUpllr);
#endif
}

/**
*******************************************************************************
** \brief  ADC initial configuration.
**
******************************************************************************/
static void AdcInitConfig(void)
{
    stc_adc_init_t stcAdcInit;

    MEM_ZERO_STRUCT(stcAdcInit);

#if (ADC1_RESOLUTION == ADC_RESOLUTION_8BIT)
    stcAdcInit.enResolution = AdcResolution_8Bit;
#elif (ADC1_RESOLUTION == ADC_RESOLUTION_10BIT)
    stcAdcInit.enResolution = AdcResolution_10Bit;
#else
    stcAdcInit.enResolution = AdcResolution_12Bit;
#endif
    stcAdcInit.enDataAlign  = AdcDataAlign_Right;
    stcAdcInit.enAutoClear  = AdcClren_Disable;
    stcAdcInit.enScanMode   = ADC1_SCAN_MODE;
    /* 1. Enable ADC1. */
    PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
    /* 2. Initialize ADC1. */
    ADC_Init(M4_ADC1, &stcAdcInit);

#if (ADC2_RESOLUTION == ADC_RESOLUTION_8BIT)
    stcAdcInit.enResolution = AdcResolution_8Bit;
#elif (ADC2_RESOLUTION == ADC_RESOLUTION_10BIT)
    stcAdcInit.enResolution = AdcResolution_10Bit;
#else
    stcAdcInit.enResolution = AdcResolution_12Bit;
#endif
    stcAdcInit.enScanMode   = ADC2_SCAN_MODE;
    /* 1. Enable ADC2. */
    PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC2, Enable);
    /* 2. Initialize ADC2. */
    ADC_Init(M4_ADC2, &stcAdcInit);
}

/**
*******************************************************************************
** \brief  ADC channel configuration.
**
******************************************************************************/
static void AdcChannelConfig(void)
{
    stc_adc_ch_cfg_t stcChCfg;
    uint8_t au8Adc1SaSampTime[ADC1_SA_CHANNEL_COUNT] = ADC1_SA_CHANNEL_SAMPLE_TIME;
    uint8_t au8Adc2SaSampTime[ADC2_SA_CHANNEL_COUNT] = ADC2_SA_CHANNEL_SAMPLE_TIME;

    MEM_ZERO_STRUCT(stcChCfg);

    stcChCfg.u32Channel  = ADC1_SA_CHANNEL;
    stcChCfg.u8Sequence  = ADC_SEQ_A;
    stcChCfg.pu8SampTime = au8Adc1SaSampTime;
    /* 1. Set the ADC pin to analog mode. */
    AdcSetChannelPinMode(M4_ADC1, ADC1_CHANNEL, Pin_Mode_Ana);
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);

    /* 3. Configure the average channel if you need. */
    ADC_ConfigAvg(M4_ADC1, AdcAvcnt_32);
    /* 4. Add average channel if you need. */
    ADC_AddAvgChannel(M4_ADC1, ADC1_AVG_CHANNEL);

    stcChCfg.u32Channel  = ADC2_SA_CHANNEL;
    stcChCfg.pu8SampTime = au8Adc2SaSampTime;
    /* 1. Set the ADC pin to analog mode. */
    AdcSetChannelPinMode(M4_ADC2, ADC2_CHANNEL, Pin_Mode_Ana);
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC2, &stcChCfg);

    /* 3. Configure the average channel if you need. */
    ADC_ConfigAvg(M4_ADC2, AdcAvcnt_64);
    /* 4. Add average channel if you need. */
    ADC_AddAvgChannel(M4_ADC2, ADC2_AVG_CHANNEL);
}

/**
*******************************************************************************
** \brief  Config the pin which is mapping the channel to analog or digit mode.
**
******************************************************************************/
static void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,
                                 uint32_t u32Channel,
                                 en_pin_mode_t enMode)
{
    uint8_t u8ChIndex;
#if (ADC_CH_REMAP)
    uint8_t u8AdcPin;
#else
    uint8_t u8ChOffset = 0u;
#endif

    if (M4_ADC1 == ADCx)
    {
        u32Channel &= ADC1_PIN_MASK_ALL;
    }
    else
    {
        u32Channel &= ADC2_PIN_MASK_ALL;
#if (!ADC_CH_REMAP)
        u8ChOffset = 4u;
#endif
    }

    u8ChIndex = 0u;
    while (0u != u32Channel)
    {
        if (u32Channel & 0x1ul)
        {
#if (ADC_CH_REMAP)
            u8AdcPin = ADC_GetChannelPinNum(ADCx, u8ChIndex);
            AdcSetPinMode(u8AdcPin, enMode);
#else
            AdcSetPinMode((u8ChIndex+u8ChOffset), enMode);
#endif
        }

        u32Channel >>= 1u;
        u8ChIndex++;
    }
}

/**
*******************************************************************************
** \brief  Set an ADC pin as analog input mode or digit mode.
**
******************************************************************************/
static void AdcSetPinMode(uint8_t u8AdcPin, en_pin_mode_t enMode)
{
    en_port_t enPort = PortA;
    en_pin_t enPin   = Pin00;
    bool bFlag       = true;
    stc_port_init_t stcPortInit;

    MEM_ZERO_STRUCT(stcPortInit);
    stcPortInit.enPinMode = enMode;
    stcPortInit.enPullUp  = Disable;

    switch (u8AdcPin)
    {
    case ADC1_IN0:
        enPort = PortA;
        enPin  = Pin00;
        break;

    case ADC1_IN1:
        enPort = PortA;
        enPin  = Pin01;
        break;

    case ADC1_IN2:
        enPort = PortA;
        enPin  = Pin02;
        break;

    case ADC1_IN3:
        enPort = PortA;
        enPin  = Pin03;
        break;

    case ADC12_IN4:
        enPort = PortA;
        enPin  = Pin04;
        break;

    case ADC12_IN5:
        enPort = PortA;
        enPin  = Pin05;
        break;

    case ADC12_IN6:
        enPort = PortA;
        enPin  = Pin06;
        break;

    case ADC12_IN7:
        enPort = PortA;
        enPin  = Pin07;
        break;

    case ADC12_IN8:
        enPort = PortB;
        enPin  = Pin00;
        break;

    case ADC12_IN9:
        enPort = PortB;
        enPin  = Pin01;
        break;

    case ADC12_IN10:
        enPort = PortC;
        enPin  = Pin00;
        break;

    case ADC12_IN11:
        enPort = PortC;
        enPin  = Pin01;
        break;

    case ADC1_IN12:
        enPort = PortC;
        enPin  = Pin02;
        break;

    case ADC1_IN13:
        enPort = PortC;
        enPin  = Pin03;
        break;

    case ADC1_IN14:
        enPort = PortC;
        enPin  = Pin04;
        break;

    case ADC1_IN15:
        enPort = PortC;
        enPin  = Pin05;
        break;

    default:
        bFlag = false;
        break;
    }

    if (true == bFlag)
    {
        PORT_Init(enPort, enPin, &stcPortInit);
    }
}

/*******************************************************************************
* EOF (not truncated)
******************************************************************************/


ADC转换的流程在主函数已经说的很清楚了,我把主函数摘下来大家一看就清楚了
/* Configuring a new system clock if you need. */
    SystemClockConfig();

    /* Config ADC. */
    AdcConfig();

    /* Config UART for printing. Baud rate 115200. */
    Ddl_UartInit();

    /***************** Configuration end, application start **************/

    /* ADC1 sequence A single scan. */
    /* Start ADC1, wait ADC1 scan converting done, read ADC1 data. */
    ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);

    /* ADC2 sequence A continuous scan. */
    u8Count = 0u;
    ADC_StartConvert(M4_ADC2);
    while (u8Count < ADC2_CONTINUOUS_TIMES)
    {
        if (Set == ADC_GetEocFlag(M4_ADC2, ADC_SEQ_A))
        {
            ADC_GetChData(M4_ADC2, ADC2_SA_CHANNEL, m_au16Adc2Value, ADC2_SA_CHANNEL_COUNT);
            ADC_ClrEocFlag(M4_ADC2, ADC_SEQ_A);
            u8Count++;
            // TODO: USE THE m_au16Adc2Value.
        }
    }

    /*
     *  DO NOT forget to stop ADC when your mode is
     *  AdcMode_SAContinuous or AdcMode_SAContinuousSBOnce
     *  unless you need.
     */
    ADC_StopConvert(M4_ADC2);

    while (1u)
    {
        ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);
        /* ADC1 channel 10 maps pin ADC12_IN10 by default. */
        printf("\nADC12_IN10 value %d.", m_au16Adc1Value[10u]);
        printf("\nADC12_IN10 voltage is %.4fV.",
            ((float)m_au16Adc1Value[10u] * ADC_VREF) / (float)ADC1_ACCURACY);

        /* Main loop cycle is 500ms. */
        Ddl_Delay1ms(500u);
    }

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 10.00 元 2021-02-22
理由:恭喜通过原创文章审核!请多多加油哦!

沙发
jcky001| | 2021-2-14 15:03 | 只看该作者
大年初二还在给我们科普,楼主辛苦哈

使用特权

评论回复
板凳
edyd| | 2021-2-15 20:21 | 只看该作者
大年初四来顶贴,不错不错!学习了!

使用特权

评论回复
地板
zhuotuzi| | 2021-2-22 23:35 | 只看该作者
来学习一下。

使用特权

评论回复
5
guijial511| | 2021-2-23 08:49 | 只看该作者
不错,学习了。

使用特权

评论回复
6
wanduzi| | 2021-2-23 20:06 | 只看该作者
看看是啥啊。

使用特权

评论回复
7
huangcunxiake| | 2021-2-23 22:37 | 只看该作者
看不懂。高深

使用特权

评论回复
8
pzljun| | 2021-4-7 01:06 | 只看该作者
这个坑货的模拟采集,没有设置基准源的寄存器~

使用特权

评论回复
9
caigang13| | 2021-4-7 09:45 | 只看该作者
感谢楼主的详细讲解

使用特权

评论回复
10
aspoke| | 2021-4-10 21:17 | 只看该作者
非DMA方式 多路ADC   

使用特权

评论回复
11
232321122| | 2021-4-10 21:17 | 只看该作者
         

使用特权

评论回复
12
ghuca| | 2021-4-10 21:18 | 只看该作者
如何得到最佳adc精度  

使用特权

评论回复
13
soodesyt| | 2021-4-10 21:19 | 只看该作者
总结的非常到位。   

使用特权

评论回复
14
plsbackup| | 2021-4-10 21:20 | 只看该作者
单片机的性能怎么样  

使用特权

评论回复
15
mnynt121| | 2021-4-10 21:20 | 只看该作者
期待楼主更多的分享了。  

使用特权

评论回复
16
kmzuaz| | 2021-4-10 21:21 | 只看该作者
ADC 规则通道 和 注入通道的区别

使用特权

评论回复
17
qiufengsd| | 2021-4-10 21:21 | 只看该作者
能同时接32个模拟通道吗  

使用特权

评论回复
18
sdCAD| | 2021-4-10 21:22 | 只看该作者
17个通道吗

使用特权

评论回复
19
fengm| | 2021-4-10 21:25 | 只看该作者
         

使用特权

评论回复
20
plsbackup| | 2021-4-10 21:26 | 只看该作者
转换 速度可以到多少呢  

使用特权

评论回复
发新帖 本帖赏金 10.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

456

帖子

9

粉丝