打印
[开发工具]

【华大测评】+HC32F460-EVB-ADC的转换通道是如何确定的。

[复制链接]
1539|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qjp1988113|  楼主 | 2020-5-31 18:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 qjp1988113 于 2020-5-31 18:36 编辑

需要转换的ADC通道是如何确定的,我找了半天硬是没找到。怎么回事呢?请看下面流程。
下面是主函数:
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);
    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);
    }
}
看了下唯一可能涉及到需转换ADC通道引脚配置的就是在 AdcConfig();
static void AdcConfig(void)
{
    AdcClockConfig();
    AdcInitConfig();
    AdcChannelConfig();
}
在展开AdcChannelConfig():
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);
}
这里stcChCfg.u32Channel  = ADC1_SA_CHANNEL;这句应该是配置通道的设置了:
但查看宏定义:
/* 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_SA_CHANNEL就对应了ADC1_CH0 | ADC1_CH10|ADC1_CH12 | ADC1_CH13四个通道;
但是它MAIN函数里面只输出了ADCCHANNEL10:
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);

这个是怎么确定的啊?第一遍没注意,脑袋里满是STM32的固定思维。重点查看ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);
这个函数的原函数,发现上面的注释:
/**
*******************************************************************************
** \brief ADC start sequence A, check it's EOC status and get the data.
**
** \param [in] ADCx                    Pointer to ADC instance register base.
** \arg M4_ADC1                        ADC unit 1 instance register base.
** \arg M4_ADC2                        ADC unit 2 instance register base.
**
** \param [out] pu16AdcData            The address to store ADC value.
**                                     The location of the data store depends on
**                                     the parameter u8Length.
**                                     u8Length >= ADCx_CH_COUNT(ADC1_CH_COUNT or ADC2_CH_COUNT),
**                                     all of the ADC data regs will be read:
**                                     pu16AdcData[0] = data of Channel 0,
**                                     pu16AdcData[1] = data of Channel 1,
**                                     pu16AdcData[2] = data of Channel 2,
**                                                 ...
**                                     u8Length < ADCx_CH_COUNT(ADC1_CH_COUNT or ADC2_CH_COUNT),
**                                     only the data of the enabled channles will be read:
**                                     pu16AdcData[0] = data of the 1st enabled channel,
**                                     pu16AdcData[1] = data of the 2nd enabled channel,
**                                     pu16AdcData[2] = data of the 3rd enabled channel,
**                                                 ...
**
** \param [in] u8Length                The length of the ADC data to be read.
**
** \param [in] u32Timeout              Timeout(millisecond).
**
** \retval ErrorInvalidParameter       Parameter error.
** \retval ErrorTimeout                Timeout.
** \retval OperationInProgress         ADC is converting.
** \retval Ok                          No error occurred.
**
******************************************************************************/

en_result_t ADC_PollingSa(M4_ADC_TypeDef *ADCx,
                          uint16_t *pu16AdcData,
                          uint8_t u8Length,
                          uint32_t u32Timeout);

原来转换的顺序还和函数的第三个参数u8Length有很大关系:
如果
u8Length >= ADCx_CH_COUNT(ADC1_CH_COUNT or ADC2_CH_COUNT),
所以通道的值都会被读取,且按顺序依次放到 pu16AdcData数值中;
如果

u8Length <ADCx_CH_COUNT(ADC1_CH_COUNT or ADC2_CH_COUNT)
就会按照你自己开启通道的先后顺序输出。
到这里就明白了。
因为ADC_PollingSa(M4_ADC1, m_au16Adc1Value, ADC1_CH_COUNT, TIMEOUT_MS);
里面
/* ADC1 has up to 17 channels */
#define ADC1_CH_COUNT           (17u)

显然我们带入的参数符合u8Length >= ADCx_CH_COUNT(ADC1_CH_COUNT or ADC2_CH_COUNT)
依次按顺序输出
又因为ADC1的顺序是:
#define ADC1_CH0                (0x1ul << 0u)       ///< Default mapping pin ADC1_IN0
#define ADC1_CH1                (0x1ul << 1u)       ///< Default mapping pin ADC1_IN1
#define ADC1_CH2                (0x1ul << 2u)       ///< Default mapping pin ADC1_IN2
#define ADC1_CH3                (0x1ul << 3u)       ///< Default mapping pin ADC1_IN3
#define ADC1_CH4                (0x1ul << 4u)       ///< Default mapping pin ADC12_IN4
#define ADC1_CH5                (0x1ul << 5u)       ///< Default mapping pin ADC12_IN5
#define ADC1_CH6                (0x1ul << 6u)       ///< Default mapping pin ADC12_IN6
#define ADC1_CH7                (0x1ul << 7u)       ///< Default mapping pin ADC12_IN7
#define ADC1_CH8                (0x1ul << 8u)       ///< Default mapping pin ADC12_IN8
#define ADC1_CH9                (0x1ul << 9u)       ///< Default mapping pin ADC12_IN9
#define ADC1_CH10               (0x1ul << 10u)      ///< Default mapping pin ADC12_IN10
#define ADC1_CH11               (0x1ul << 11u)      ///< Default mapping pin ADC12_IN11
#define ADC1_CH12               (0x1ul << 12u)      ///< Default mapping pin ADC12_IN12
#define ADC1_CH13               (0x1ul << 13u)      ///< Default mapping pin ADC12_IN13
#define ADC1_CH14               (0x1ul << 14u)      ///< Default mapping pin ADC12_IN14
#define ADC1_CH15               (0x1ul << 15u)      ///< Default mapping pin ADC12_IN15
#define ADC1_CH16               (0x1ul << 16u)
#define ADC1_CH_INTERNAL        (ADC1_CH16)         ///< 8bit DAC_1/DAC_2 or internal VERF, dependent on CMP_RVADC


所以m_au16Adc1Value[10u]代表就代表通道10的输出值了。
了解是了解了,但是对这样的写法如此繁琐还是感觉不爽,而且按这样的做法,其余我们开通的几个通道,是否ADC也转换了,但是就仅仅没有读出数据呢?
这样是不是有点资源上的浪费。
本人菜鸟,希望那个大神出来解答下。





使用特权

评论回复
沙发
martinhu| | 2020-6-1 15:24 | 只看该作者
没用过这个库,如果是裸写寄存器的话,M4_ADC1->CR0_f.MS     = 2;        //0:序列A单次扫描, 1:序列A连续扫描, 2:序列A单次扫描&序列B单次扫描, 3:序列A连续扫描&序列B单次扫描
模式如果选择单次扫描,那么启动之后,会把使能的channel都扫一遍。

其实除了配置模式以外,CHSELRA0和CHSELRB0 选择使能哪个channel,然后设置时间,然后设置channel对应的引脚就好了

    M4_ADC1->CHSELRA0 = 0x0003;        //b15~b0: 序列A通道选择,一位代表一个通道: CH0, CH1
    M4_ADC1->CHSELRB0 = 0x000C;        //b15~b0: 序列B通道选择,一位代表一个通道: CH2, CH3
   
    M4_ADC1->SSTR0 = 25;              //b7~b0: 采样周期数,5~255,
    M4_ADC1->SSTR1 = 25;              //b7~b0: 采样周期数,5~255,
    M4_ADC1->SSTR2 = 25;              //
    M4_ADC1->SSTR3 = 25;
    //SEQA:Normal ADC
    M4_ADC1->CHMUXR0_f.CH00MUX = 0x0;        //0:ADC1_IN0 PA00
    M4_ADC1->CHMUXR0_f.CH01MUX = 0x1;        //0:ADC1_IN1 PA01
    //SEQB:
    M4_ADC1->CHMUXR0_f.CH02MUX = 0x2;        //0:ADC1_IN2 PA02  
    M4_ADC1->CHMUXR0_f.CH03MUX = 0x3;        //0:ADC1_IN3 PA03

使用特权

评论回复
板凳
qjp1988113|  楼主 | 2020-6-1 16:15 | 只看该作者
martinhu 发表于 2020-6-1 15:24
没用过这个库,如果是裸写寄存器的话,M4_ADC1->CR0_f.MS     = 2;        //0:序列A单次扫描, 1:序列A连续 ...

嗯,谢谢。看了你寄存器的写法,还真是一目了然啊。看来我得考虑考虑寄存器的写法了。

使用特权

评论回复
地板
martinhu| | 2020-6-2 09:12 | 只看该作者
qjp1988113 发表于 2020-6-1 16:15
嗯,谢谢。看了你寄存器的写法,还真是一目了然啊。看来我得考虑考虑寄存器的写法了。 ...

有些简单的IP,其实用寄存器写也容易,
至于那些复杂的IP,像系统时钟,就用库函数比较好。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝