【华大测评】+HC32F460-EVB-ADC的转换通道是如何确定的。
本帖最后由 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);
printf("\nADC12_IN10 voltage is %.4fV.",
((float)m_au16Adc1Value * 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_SAMPLE_TIME;
uint8_t au8Adc2SaSampTime = 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);
printf("\nADC12_IN10 voltage is %.4fV.",
((float)m_au16Adc1Value * 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 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 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 = data of Channel 0,
** pu16AdcData = data of Channel 1,
** pu16AdcData = 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 = data of the 1st enabled channel,
** pu16AdcData = data of the 2nd enabled channel,
** pu16AdcData = data of the 3rd enabled channel,
** ...
**
** \param u8Length The length of the ADC data to be read.
**
** \param 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代表就代表通道10的输出值了。
了解是了解了,但是对这样的写法如此繁琐还是感觉不爽,而且按这样的做法,其余我们开通的几个通道,是否ADC也转换了,但是就仅仅没有读出数据呢?
这样是不是有点资源上的浪费。
本人菜鸟,希望那个大神出来解答下。
没用过这个库,如果是裸写寄存器的话,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
martinhu 发表于 2020-6-1 15:24
没用过这个库,如果是裸写寄存器的话,M4_ADC1->CR0_f.MS = 2; //0:序列A单次扫描, 1:序列A连续 ...
嗯,谢谢。看了你寄存器的写法,还真是一目了然啊。看来我得考虑考虑寄存器的写法了。 qjp1988113 发表于 2020-6-1 16:15
嗯,谢谢。看了你寄存器的写法,还真是一目了然啊。看来我得考虑考虑寄存器的写法了。 ...
有些简单的IP,其实用寄存器写也容易,
至于那些复杂的IP,像系统时钟,就用库函数比较好。
页:
[1]