CH32内部参考电压的自学笔记
2024-12-16 来源:elecfans
CH32V/F单片机能够在一定的电压范围内进行工作,以CH32V203C8T6 芯片为例,在不使用 USB 外设时,最低工作电压能够达到 2.4V。较为宽泛的工作电压,允许单片机直接使用电池供电,但由于 CH32V203C8T6 芯片没有独立的 Vref 引脚,使用 ADC 的过程中无法换算出真实的电压。为解决无法获得真实电压的问题,可以使用内置参考电压换算当前供电电压(即 ADC参考电压)。对于项目要求精确测量时,也可尝试使用该方法对 ADC 进行校准。
电源电压的换算
CH32V203C8T6 芯片内部参考电压是典型值为 1.2V,正负偏差为 0.04V 的电压范围,在 ADC 转换精度要求不高的应用场景下,可以直接使用 1.2V 换算芯片供电电压。

如果需要更加精确的转换结果,就应在稳定的供电条件下,先对内部参考电压进行测量并将结果保存在 Flash 中,实际的使用过程中,再根据已知的内部参考电压进行换算。

实现上述操作,可参考以下代码:
u16 ADC_val = 0;s32 val_mv = 0;u16 Vref = 0; // Flash中存储的内部参考电压实测值s32 Vref_To_VDD = 0; // 由Vref的实测值换算出的电源电压值
if ( *(u32*)(FAST_FLASH_PROGRAM_START_ADDR) == 0xe339e339 ) { // 判断Flash中是否有内部参考电压的实测值 printf('Address:0x%08x -> %08xrn', FAST_FLASH_PROGRAM_START_ADDR, *(u32*)(FAST_FLASH_PROGRAM_START_ADDR)); // 获取内部参考电压实测值,此时务必保证电源电压或参考电压(如果有)的准确 ADC_val = Get_ADC_Average(ADC_Channel_Vrefint, 255); // 255次取平均 ADC_val = Get_ConversionVal(ADC_val); val_mv = (ADC_val * 3300 / 4096); printf('Vref_mv -> %drn', val_mv); // 将测得的结果存储在Flash中 buf[0] = val_mv; FLASH_Unlock_Fast(); FLASH_ProgramPage_Fast(FAST_FLASH_PROGRAM_START_ADDR, buf); FLASH_Lock_Fast(); printf('Address:0x%08x -> %08xrn', FAST_FLASH_PROGRAM_START_ADDR, *(u32*)(FAST_FLASH_PROGRAM_START_ADDR));} else { printf('Address:0x%08x -> %08xrn', FAST_FLASH_PROGRAM_START_ADDR, *(u32*)(FAST_FLASH_PROGRAM_START_ADDR)); Vref = *(u32*)(FAST_FLASH_PROGRAM_START_ADDR); ADC_val = Get_ADC_Average(ADC_Channel_Vrefint, 255); // 255次取平均 ADC_val = Get_ConversionVal(ADC_val); Vref_To_VDD = (4096 * Vref / ADC_val); printf('Vref_To_VDD_mV -> %drn', Vref_To_VDD); }
ADC 初始化过程中的校准
ADC 初始化函数中完成了一次校准过程,经过校准环节可大幅减小因内部电容器组的变化而造成的精准度误差。校准过程中 ADC 仅获取了 Vcc 的采样值,与实际电压大小无关,因此,在浮动电压供电的场景中,不会引入额外的误差。获取校准值函数,通过写 ADC_CTLR2 寄存器的 RSTCAL 位置 1 初始化校准寄存器,等待 RSTCAL 硬件清 0完成初始化。置位 CAL 位,启动校准功能,校准结束后,硬件自动清除 CAL 位,将校准码存储到 ADC_RDATAR 中。使用多次校准结果,计算 ADC 补偿。
int16_t Get_CalibrationValue(ADC_TypeDef *ADCx){ __IO uint8_t i, j; uint16_t buf[10]; __IO uint16_t t;#if defined (CH32V20x_D6) __IO uint16_t p;#endif
for(i = 0; i < 10; i++){ ADC_ResetCalibration(ADCx); while(ADC_GetResetCalibrationStatus(ADCx)); ADC_StartCalibration(ADCx); while(ADC_GetCalibrationStatus(ADCx)); buf[i] = ADCx->RDATAR;// printf('CalibrationValue[%d]->%drn', i, buf[i]); }
for(i = 0; i < 10; i++){ for(j = 0; j < 9; j++){ if(buf[j] > buf[j + 1]) { t = buf[j]; buf[j] = buf[j + 1]; buf[j + 1] = t; } } }
#if defined (CH32V20x_D8) || defined (CH32V20x_D8W) t = 0; for( i = 0; i < 6; i++ ) { t += buf[i + 2]; }
t = ( t / 6 ) + ( ( t % 6 ) / 3 );
return ( int16_t )( 2048 - ( int16_t )t );#else t = 0; p = 0; /* 1024 */ for(i = 0; i < 6; i++ ){ if(buf[i+2] > 1536) break; t += buf[i+2]; }
if(i > 0){ t = ( t / i ) + ( (( t % i )*2) / i ); } else t = 1024;
/* 2048 */ j = 6-i; if(j > 0){ for(; i < 6; i++ ){ p += buf[i+2]; }
p = ( p / j ) + ( (( p % j )*2) / j ); } else p = 2048;
return ( int16_t )(((( int16_t )( 1024 - ( int16_t )t ) + ( int16_t )( 2048 - ( int16_t )p ))/2) + ((( int16_t )( 1024 - ( int16_t )t ) + ( int16_t )( 2048 - ( int16_t )p ))%2));
#endif}
可以在校准值转换的 for 循环中添加打印,观察每次校准值结果是否随芯片供电电压(即 ADC 参考电压)的改变而改变。

- STM32 ADC学习笔记:多重转换、内部参考电压、过采样、逐次逼近原理与采样时间详解
- 【GD32F303红枫派开发板使用手册】第十三讲 ADC-内部温度传感器和参考电压采样实验
- 如何通过GD32 MCU内部ADC参考电压通道提高采样精度?
- STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压
- STM32芯片ADC内部的CH17参考电压的用途
- STM8L151C8单片机学习例程(8)——内部参考电压ADC_Vrefint采集电源电压
- STM8L用内部参考电压做AD转换基准电压
- 利用ST MCU内部基准参考电压监测电源电压及其它
- STM8L通过内部参考电压计算电池电压
- 意法半导体发布Stellar P3E 汽车MCU内置AI加速
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 蓝牙信道探测技术原理与开发套件实践
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策




