xtqbp
2020-10-14 16:18 阅读 150

STM32L431 供电电压Vbat计算不准,误差过大,已解决 配置原因!?

这个问题困扰我很久了,网上关于stm32l4的资料也不多,本来打算用 cubeMX配置一下ADC再测一把的,但cubeMX上的ADC1 没有IN0,也就没法计算Vref。
如果哪位大神调测过这部分代码,帮忙看看,或者直接贴已调过的代码也行,多谢!!!!

**根据手册给出的计算公式,求芯片的供电电压Vbat的电压需要先计算Vdda的电压,再计算vbat的电压,如下图所示:
**

图片说明

其中的相关参数见下图:

图片说明

问题是:用这个计算方法,算出来的电压值误差0.15V左右:
图片说明

调试的数据如下:

图片说明

代码中使用的计算公式为:
power.vbatVal = 9 * VREFINT_CAL * vbatData / vrefData / 4095;

其中:
#define VREFINT_CAL (*(u16 *)0x1FFF75AA) // 如图,值为1652
vbatData为Vbat/3 的采样值,所以公式中是*9(3*3)
vbatData 和 vrefData 均为10次采样数据的平均值

如果以上的计算公式没有问题,那就要看配置了,上代码了啊:

// 内部供电电压         ADC1_IN0
// PA0 ADC1_IN5 配置为模拟输入
// 内部温度传感器 ADC1_IN17
void freqAdcInit(void)
{
    // DMA 设置
    __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_RCC_ADC_CLK_ENABLE();
    RCC->APB2RSTR|=1<<8; //ADCs 复位
    RCC->APB2RSTR&=~(1<<8); //复位结束

    // ADC设置
    MODIFY_REG(ADC1->CR, ADC_CR_DEEPPWD_Msk, (0UL << ADC_CR_DEEPPWD_Pos));  // DEEPPWD: Deep-power-down enable
    MODIFY_REG(ADC1->CR, ADC_CR_DEEPPWD_Msk, (0UL << ADC_CR_DEEPPWD_Pos));  // DEEPPWD: Deep-power-down enable
    MODIFY_REG(ADC1->CR, ADC_CR_ADVREGEN_Msk, (1UL << ADC_CR_ADVREGEN_Pos));  // ADVREGEN: ADC voltage regulator enable

    MODIFY_REG(ADC1->CFGR, ADC_CFGR_DISCEN_Msk, (0UL << ADC_CFGR_DISCEN_Pos));      // 失能不连续模式
    MODIFY_REG(ADC1->CFGR, ADC_CFGR_CONT_Msk, (1UL << ADC_CFGR_CONT_Pos));      // 使能连续模式
    MODIFY_REG(ADC1->CFGR, ADC_CFGR_OVRMOD_Msk, (1UL << ADC_CFGR_OVRMOD_Pos));      // 过采样
    CLEAR_BIT(ADC1->CFGR, ADC_CFGR_ALIGN);      // 0 为右对齐
    MODIFY_REG(ADC1->CFGR, ADC_CFGR_RES, ADC_RESOLUTION_12B);  // 12位
    SET_BIT(ADC1->CFGR, ADC_CFGR_DMACFG);      // DMA循环内存访问
    SET_BIT(ADC1->CFGR, ADC_CFGR_DMAEN);      // 使能DMA

    MODIFY_REG(ADC1->SMPR1, ADC_SMPR1_SMP0, (0x7UL << ADC_SMPR1_SMP0_Pos));  // 采样时间47.5T
    MODIFY_REG(ADC1->SMPR1, ADC_SMPR1_SMP5, (0x7UL << ADC_SMPR1_SMP5_Pos));  // 采样时间47.5T
    MODIFY_REG(ADC1->SMPR2, ADC_SMPR2_SMP17, (0x7UL << ADC_SMPR2_SMP17_Pos));  // 采样时间47.5T

    MODIFY_REG(ADC1->CFGR, ADC_CFGR_DISCNUM, (0x0UL << ADC_CFGR_DISCNUM_Pos));  //
    MODIFY_REG(ADC1->SQR1, ADC_SQR1_L, ((ADC_CHANNELS - 1) << ADC_SQR1_L_Pos));  // 规则采样个数3 要-1
//    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ1, (0x0UL << ADC_SQR1_SQ1_Pos));  // 规则采样 1 ---- IN0
    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ1, (0x5UL << ADC_SQR1_SQ1_Pos));  // 规则采样 2 ---- IN5
//    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ3, (0x11UL << ADC_SQR1_SQ3_Pos));  // 规则采样 3 ---- IN17 温度

    //MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_PRESC_Msk, (0x7UL << ADC_CCR_PRESC_Pos));  // 16分频
    MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_CKMODE_Msk, (0x1UL << ADC_CCR_CKMODE_Pos));  // HCLK/1 时钟

}


void freqADC_DMA_Init(void)
{
    __HAL_RCC_DMA1_CLK_ENABLE();
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_PL_Msk, (0x3UL << DMA_CCR_PL_Pos));  // Very high
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_MSIZE_Msk, (0x2UL << DMA_CCR_MSIZE_Pos));  // 00: 8-bits 01: 16-bits 10: 32-bits 11: Reserved
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_PSIZE_Msk, (0x2UL << DMA_CCR_PSIZE_Pos));  // 00: 8-bits 01: 16-bits 10: 32-bits 11: Reserved
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_MINC_Msk, (0x1UL << DMA_CCR_MINC_Pos));  // Memory increment mode
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_PINC_Msk, (0x0UL << DMA_CCR_PINC_Pos));  // Peripheral increment mode
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_CIRC_Msk, (0x1UL << DMA_CCR_CIRC_Pos));  // Circular mode
    MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_DIR_Msk, (0x0UL << DMA_CCR_DIR_Pos));  // DIR: Data transfer direction 0: Read from peripheral

    MODIFY_REG(DMA1_Channel1->CNDTR, DMA_CNDTR_NDT_Msk, ((DMA_DATALEN * ADC_CHANNELS) << DMA_CNDTR_NDT_Pos));  // the remaining bytes to be transmitted
    DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);      // 外设地址
    DMA1_Channel1->CMAR = (uint32_t)(fftData.adcDMAData);      // 内存地址

}
/* 检查电池余量 */
void batteryCheckTask(void)
{
    float vrefData, vbatData, persent;

    // 非电池供电不检查
    if (power.powerFlag != Power_Barttery) {
        return;
    }

// step1 采集 vref
    ADC_DMA_Stop();
    MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_VREFEN_Msk, ADC_CCR_VREFEN);  // 使能参考电压
    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ1, (0UL << ADC_SQR1_SQ1_Pos));  // 规则采样 1 ---- IN0
    MODIFY_REG(DMA1_Channel1->CNDTR, DMA_CNDTR_NDT_Msk, ((POWER_DMA_DATA_LEN) << DMA_CNDTR_NDT_Pos));  // the remaining bytes to be transmitted
    DMA1_Channel1->CMAR = (uint32_t)(power.vrefData);      // 内存地址
    ADC_DMA_Start();
    delay_ms(4);


// step2 采集 vbat
    ADC_DMA_Stop();
    MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_VBATEN_Msk, ADC_CCR_VBATEN);  // 使能BAT电压
    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ1, (18UL << ADC_SQR1_SQ1_Pos));  // 规则采样 1 ---- IN18
    MODIFY_REG(DMA1_Channel1->CNDTR, DMA_CNDTR_NDT_Msk, ((POWER_DMA_DATA_LEN) << DMA_CNDTR_NDT_Pos));  // the remaining bytes to be transmitted
    DMA1_Channel1->CMAR = (uint32_t)(power.vbatData);      // 内存地址
    ADC_DMA_Start();
    delay_ms(4);

// step3 复位adc dma
    ADC_DMA_Stop();
    MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_VBATEN_Msk, 0);  // 失能BAT电压
    MODIFY_REG(ADC1_COMMON->CCR, ADC_CCR_VREFEN_Msk, 0);  // 失能参考电压
    MODIFY_REG(ADC1->SQR1, ADC_SQR1_SQ1, (5UL << ADC_SQR1_SQ1_Pos));  // 规则采样 1 ---- IN5
    MODIFY_REG(DMA1_Channel1->CNDTR, DMA_CNDTR_NDT_Msk, ((DMA_DATALEN * ADC_CHANNELS) << DMA_CNDTR_NDT_Pos));  // the remaining bytes to be transmitted
    DMA1_Channel1->CMAR = (uint32_t)(fftData.adcDMAData);      // 内存地址
    ADC_DMA_Start();

// step4 计算Vbat电压
    vrefData = arrayAve(power.vrefData, POWER_DMA_DATA_LEN);
    vbatData = arrayAve(power.vbatData, POWER_DMA_DATA_LEN);
    power.vbatVal = 9 * VREFINT_CAL * vbatData / vrefData / 4095;
    persent = 100.0f * (power.vbatVal - VBAT_VALTEAGE_MIN) / (VBAT_VALTEAGE_MAX - VBAT_VALTEAGE_MIN);
    persent = persent > 100 ? 100 : persent;
    persent = persent < 0 ? 0 : persent;
    if (persent != power.batteryRemainPersent) {
        power.batteryRemainPersent = persent;
        power.powerFlag_old = Power_NULL;
    }

}


  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享