CH32V/F單片機能夠在一定的電壓范圍內(nèi)進行工作,以CH32V203C8T6 芯片為例,在不使用 USB 外設(shè)時,最低工作電壓能夠達到 2.4V。較為寬泛的工作電壓,允許單片機直接使用電池供電,但由于 CH32V203C8T6 芯片沒有獨立的 Vref 引腳,使用 ADC 的過程中無法換算出真實的電壓。為解決無法獲得真實電壓的問題,可以使用內(nèi)置參考電壓換算當(dāng)前供電電壓(即 ADC參考電壓)。對于項目要求精確測量時,也可嘗試使用該方法對 ADC 進行校準(zhǔn)。
電源電壓的換算
CH32V203C8T6 芯片內(nèi)部參考電壓是典型值為 1.2V,正負偏差為 0.04V 的電壓范圍,在 ADC 轉(zhuǎn)換精度要求不高的應(yīng)用場景下,可以直接使用 1.2V 換算芯片供電電壓。
如果需要更加精確的轉(zhuǎn)換結(jié)果,就應(yīng)在穩(wěn)定的供電條件下,先對內(nèi)部參考電壓進行測量并將結(jié)果保存在 Flash 中,實際的使用過程中,再根據(jù)已知的內(nèi)部參考電壓進行換算。
實現(xiàn)上述操作,可參考以下代碼:
u16 ADC_val = 0;s32 val_mv = 0;u16 Vref = 0; // Flash中存儲的內(nèi)部參考電壓實測值s32 Vref_To_VDD = 0; // 由Vref的實測值換算出的電源電壓值
if ( *(u32*)(FAST_FLASH_PROGRAM_START_ADDR) == 0xe339e339 ) { // 判斷Flash中是否有內(nèi)部參考電壓的實測值 printf("Address:0x%08x -> %08x\r\n", FAST_FLASH_PROGRAM_START_ADDR, *(u32*)(FAST_FLASH_PROGRAM_START_ADDR)); // 獲取內(nèi)部參考電壓實測值,此時務(wù)必保證電源電壓或參考電壓(如果有)的準(zhǔn)確 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 -> %d\r\n", val_mv); // 將測得的結(jié)果存儲在Flash中 buf[0] = val_mv; FLASH_Unlock_Fast(); FLASH_ProgramPage_Fast(FAST_FLASH_PROGRAM_START_ADDR, buf); FLASH_Lock_Fast(); printf("Address:0x%08x -> %08x\r\n", FAST_FLASH_PROGRAM_START_ADDR, *(u32*)(FAST_FLASH_PROGRAM_START_ADDR));} else { printf("Address:0x%08x -> %08x\r\n", 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 -> %d\r\n", Vref_To_VDD); }
ADC 初始化過程中的校準(zhǔn)
ADC 初始化函數(shù)中完成了一次校準(zhǔn)過程,經(jīng)過校準(zhǔn)環(huán)節(jié)可大幅減小因內(nèi)部電容器組的變化而造成的精準(zhǔn)度誤差。校準(zhǔn)過程中 ADC 僅獲取了 Vcc 的采樣值,與實際電壓大小無關(guān),因此,在浮動電壓供電的場景中,不會引入額外的誤差。獲取校準(zhǔn)值函數(shù),通過寫 ADC_CTLR2 寄存器的 RSTCAL 位置 1 初始化校準(zhǔn)寄存器,等待 RSTCAL 硬件清 0完成初始化。置位 CAL 位,啟動校準(zhǔn)功能,校準(zhǔn)結(jié)束后,硬件自動清除 CAL 位,將校準(zhǔn)碼存儲到 ADC_RDATAR 中。使用多次校準(zhǔn)結(jié)果,計算 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]->%d\r\n", 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}
可以在校準(zhǔn)值轉(zhuǎn)換的 for 循環(huán)中添加打印,觀察每次校準(zhǔn)值結(jié)果是否隨芯片供電電壓(即 ADC 參考電壓)的改變而改變。
-
單片機
+關(guān)注
關(guān)注
6043文章
44623瀏覽量
638782 -
電壓
+關(guān)注
關(guān)注
45文章
5640瀏覽量
116296 -
ch32
+關(guān)注
關(guān)注
0文章
73瀏覽量
701
發(fā)布評論請先 登錄
相關(guān)推薦
評論