|
發布時間: 2025-12-28 16:49
正文摘要:STC15W408AS 利用bandgap計算VCC電壓。 我的VCC電壓是5V,但計算出來確實9.3V,請大家幫忙看看代碼問題。謝謝 //初始化ADC void AdInit() { P1ASF ... |
|
串口發送BGV5的值為0x04D9, 換算為電壓為1242mv,與芯片讀取的電壓一致。看起來應該沒有問題, 但芯片5V vcc供電,但實際串口發送的是4238mv, ADC采集vcc供電的電壓也是4238mv, 請再幫忙解釋一下。 uint idata BGV5 _at_ 0xef; void main() { uchar i; P1M0 = 0x00;P1M1 = 0x80; //P1.7高阻用作ADC輸入 P3M0 = 0x00;P3M1 = 0x00; P5M0 = 0x00;P5M1 = 0x00; InitUart(); //初始化串口 InitADC(); //初始化ADC //BGV5=IapReadByte(IAP_ADDRESS)<<8|IapReadByte(IAP_ADDRESS+1);//程序開始時讀取EEPROM中保存的BandGap數據 //BGV5=0x04D9; /*if(BGV5==0xffff) //如果EEPROM中沒有有效數據 { BGV5=0x0100; //內部BandGap參考電壓在標準5V VCC的ADC轉換值 IapEraseSector(IAP_ADDRESS); //擦除EEPROM IapProgramByte(IAP_ADDRESS, BGV5>>8);//寫高8位 IapProgramByte(IAP_ADDRESS+1, BGV5);//寫低8位 }*/ while (1) { P1ASF = 0x00; //不設置P1口為模擬口,開通ADC內部第9通道 Delay_ms(1); BGVx=GetADCResult(0); //讀ADC的內部第9通道 // 當前VCC_mV = 標準電壓mV * 標準電壓BandGap轉換值 / 當前電壓BandGap轉換值 VCC = 5000*(long)BGV5/BGVx; //計算當前VCC電壓 dis_buf[0]=VCC/1000%10+'0'; dis_buf[1]=VCC/100%10+'0'; dis_buf[2]=VCC/10%10+'0'; dis_buf[3]=VCC%10+'0'; dis_buf[4]=' '; P1ASF = 0x80; //設置P1.7為模擬口,開通ADC第8通道 Delay_ms(1); VINx=GetADCResult(7); //讀ADC的第8通道 VIN=VCC*(long)VINx/1023; //計算第8通道當前輸入電壓 dis_buf[5]=VIN/1000%10+'0'; dis_buf[6]=VIN/100%10+'0'; dis_buf[7]=VIN/10%10+'0'; dis_buf[8]=VIN%10+'0'; dis_buf[9]='\n'; for(i=0;i<10;i++) SendData(dis_buf[i ]); //串口發送當前VCC電壓和當前輸入電壓 // SendData((BGV5>>8)&0xff); // SendData(BGV5&0xff); Delay_ms(1000); } } |
| P1ASF = 0x00;這句有問題,需要ADC的端口要轉成模擬狀態的 |
|
問題出在:uint adc_val=(ADC_RES*256+ADC_RESL);數據溢出。 要改為:uint adc_val=((uint)ADC_RES*256+ADC_RESL); |
samxon 發表于 2026-1-6 09:13
|
samxon 發表于 2026-1-5 11:12 假設 0x04D7 (十進制:1239) 是間隙基準源的電壓值 (1239mV),則讀取這個電壓值的代碼可以改成:
“adc_val 值是 0x02” :這個數據應該是雙字節,所以這個數據是有問題的。假設完整的數據是 adc_val = 0x0102 (十進制:258),則電源電壓的值為:1.239V * 1023 / 258 = 4.9128 V 。 即 adc_val = 0x0102 是在 Vcc = 4.9128V 時,測量間隙基準源電壓所得到到 ADC 讀數。 參考 11# 的說明。 |
samxon 發表于 2025-12-29 19:24 如果read_bandgap_voltage()讀到的0x4d7是Vbg的mV數,那么這句: (long)(read_bandgap_voltage()*1024)/adc_val); 就是對的,現在的問題是adc_val應該在255左右,檢查下為什么這個值錯的離譜吧! |
samxon 發表于 2026-1-5 11:12 STC15W408AS 讀取0xef 的值為0x04D7,你憑什么說 明顯是 1239mv。你根據什么理由或資料證明地址0xef 里的數據是內部參考電壓值?STC15W用戶手冊哪里有此說明?官方示例程序也沒有類似應用。不可能憑空找一個數據就能得到正確結果。 |
WL0123 發表于 2026-1-4 16:37 STC15W408AS 讀取0xef 的值為0x04D7, 明顯是 1239mv,這個應該怎樣處理。謝謝。 #define ID_ADDR_RAM 0xef //BandGap地址 unsigned int read_bandgap_voltage(){ return (*(unsigned char idata *)ID_ADDR_RAM <<8) |*(unsigned char idata *)(ID_ADDR_RAM + 1); } |
samxon 發表于 2026-1-4 09:43 10-位 ADC 的值范圍為 0x0000 ~ 0x03FF。0x04D7 不是一個有效的 ADC 數據。 說明: ① 數據本身錯誤,或者 ② read_bandgap_voltage() 中的代碼有問題。 |
發表于 2026-1-4 12:59 STC15W408AS的EEPROM共有10個扇區,各扇區首地址分別為0x0000、0x0200、0x0400......。BGV就2個字節的數據,只要沒搞錯你愛存哪里都可以。BGV不是憑空來的,必須是此芯片在某特定電源電壓下測得的。這與STC8系列有所不同。STC8系列出廠時已將內部1.19V參考信號源電壓值保存在指定地址:BGV = (int idata *)0xef;,前者保存的是ADC轉換值,后者保存的是電壓值,易混淆。后期處理不當會出錯。 |
|
這個讀取BGV 的地址為什么不是0xef ,而是0x0000呢 我定義的地址是#define ID_ADDR_RAM 0xef //BandGap地址 #define IAP_ADDRESS 0x0000 //測試地址 |
Jack315 發表于 2026-1-3 11:04 串口打印出來, adc_val值是0x02, read_bandgap_voltage()值是0x04D7, 反正最后得到的就不是VCC的真實電壓。謝謝。 |
samxon 發表于 2026-1-2 17:37
測量ADC的第9通道推算VCC電壓計算INV.rar
(19.65 KB, 下載次數: 0)
|
|
中斷函數 adc_isr() 中: adc_val 值是多少? read_bandgap_voltage() 函數的返回值是多少? 最后得到的 vcc_voltage 是多少? 能不能上傳一個 STC15W408AS 的數據手冊,或給個鏈接。 想具體看看 BandGap 和 ADC 相關部分的硬件結構和編程信息。 |
Jack315 發表于 2026-1-2 01:14 VCC供電是5V, 以下代碼還是無法獲取到真實電壓值。請大家幫忙看看是什么問題導致的。 void AdInit() { P1ASF = 0x00; ADC_RES = 0; ADC_RESL = 0; CLK_DIV = 0x20; ADC_CONTR = 0x88; _nop_();_nop_(); ADC_CONTR |= 0x08; delay_ms(20); EADC = 1; } unsigned int read_bandgap_voltage(){ return (*(unsigned char idata *)ID_ADDR_RAM <<8) |*(unsigned char idata *)(ID_ADDR_RAM + 1); } void adc_isr() interrupt 5{ uint adc_val=(ADC_RES*256+ADC_RESL); uint vcc_voltage=5.0*((float)read_bandgap_voltage()/(float)adc_val); P1ASF=0x00; ADC_CONTR = 0x88|0x00; _nop_();_nop_();_nop_();_nop_(); //等待四個機器周期 while(!(ADC_CONTR&ADC_FLAG)); ADC_CONTR &=~ADC_FLAG; } |
|
測量 VCC 的步驟: ① 給定一個比較精確的電源電壓 VCCA ,得到 BandGap (間隙基準源)的 ADC 讀數 BGVA。據此可計算出 BandGap 的基準電壓 VBG 。 ② 當電源電壓為 VCCX 時,得到另一個 BandGap 的 ADC 讀數為 BGVX。則 VCCX = BGVX * VBG / BGVA 。 10 位 ADC 的值范圍為:0x000 ~ 0x3FF (十進制:0~1023)。 假設 VCCA = 5.00V,間隙基準源的基準電壓為 VBG = 1.25V,則 BGVA 的值為:1.25V / 5.00V * 1023 = 255.75。 四舍五入得到 256。即此時的 ADC 讀數應為 BGVA = 0x100 (十進制:256)。 假設在待測電源電壓下 BandGap 的 ADC 讀數為 BGVX = 0x266 (十進制:614), 則 VCCX = BGVX * VBG / BGVA = 614 * 1.25 / 256 = 2.998V 【說明】 ① 注意到測量 VBG 時,ADC 的量化作用導致了測量誤差:5.00V * 256 / 1023 = 1.251222V 。為提高測量精度,可用不同的 VCCA 進行測量,然后對計算出的 VBG 值求平均作為 VBG 的 “精確” 值。 ② 注意到 10位 ADC 的讀數需要三個 Nibble(半字節),比較方便的類型為雙字節的無符號整數(可以定義為 UInt16)。 以上述假設的數據為例: UInt16 BGVA = 0x0100、UInt16 BGVX = 0x0266、float VBG = 1.25; float VCCX = (float) BGVX * VBG / (float) BGVA 。 假設要用 UInt16 來表示 VCCX ,可以先將 VCCX 乘以一個適當的常數 (float) C,以保留足夠的輸出精度: UInt16 Result = (UInt16) (VCCX * C) 。 若最大 VCCA = 5.5V 時,輸出為 0xFFFF,則 C 可取為 65535 / 5.5 = 11915.4545454545 。 |
samxon 發表于 2025-12-29 19:24 // 當前VCC_mV = 標準電壓mV * 標準電壓BandGap轉換值 / 當前電壓BandGap轉換值 VCC = 5000 * (long)BGV5 / BGVx; |
shuiquan3 發表于 2025-12-29 21:55 A/D 轉換模塊的參考電壓源 STC15 系列單片機的參考電壓源是輸入工作電壓 Vcc,所以一般不用外接參考電壓源。如 7805 的輸 出電壓是 5V,但實際電壓可能是 4.88V 到 4.96V,用戶需要精度比較高的話,可在出廠時將實際測出的 工作電壓值記錄在單片機內部的 EEPROM 里面,以供計算。 如果有些用戶的 Vcc 不固定,如電池供電,電池電壓在 5.3V--4.2V 之間漂移,則 Vcc 不固定,就需 要在 8 路 A/D 轉換的一個通道外接一個穩定的參考電壓源,來計算出此時的工作電壓 Vcc,再計算出其 他幾路 A/D 轉換通道的電壓。如下圖所示,可在 ADC 轉換通道的第二通道外接一個 2.5V( 或 1V,或...) 的基準參考電壓源,由此求出此時的工作電壓 Vcc,再計算出其它幾路 A/D 轉換通道的電壓( 理論依據 是短時間之內, Vcc 不變)。
|
| 這里提出另外一個問題:計算讀取的電壓時,1024應該為1023,STC手冊中給出的是1024,也是錯誤的。請大家討論。 |
| 請教:stc15w408as如何使用外部基準電壓? |
| 請教:STC15W408AS如何使用外部基準電壓,接哪個引腳,還是P1口隨便接? |
| 保存在 RAM 的 基準點壓參考值,開機后有可能被改寫,建議從 CODE中讀取。 或者,開機后,優先讀取 RAM中的參考值,再執行其他代碼。 |
|
經過反復排查 void adc_isr() interrupt 5{ ADC_CONTR &= ~0x10; uint vcc_voltage=(float)(5.0*bandgap/adc_val); 串口打印出來 bandgap是D7, adc_val是02, vcc_voltage結果是十進制24, 為什么vcc_voltate不是十進制537呢。 |
| 添加一個基準電壓再采樣計算 |
| 添加一個基準電壓比較再采集計算 |