8H8K64U-TSSOP20, ADC15通道内部固定接1.19V信号源,反推VCC电池电压
大家好8h8k64u sop20第15通道测量电池电压用例程得不到正确结果.
但是8h8k64tl可以使用例程。vref和 vdd直接连接。
请大佬们看下应该调整哪些代码。感谢
针对您描述的8H8K64U SOP20型号ADC测量异常问题,结合同类芯片开发经验,建议从以下五个技术层面进行排查:
一、硬件层验证
1. 引脚功能映射确认
需重点核对8H8K64U数据手册中SOP20封装的ADC通道物理映射。某些型号的ADC通道与GPIO编号存在非线性对应关系,例如:
通道15可能实际映射到P3.2引脚(需查阅最新版数据手册)
验证PCB布局是否将电池电压接入正确的物理引脚
2. 参考电压电路优化
虽然VREF与VDD直连,但建议:
增加10μF+100nF电容并联进行电源去耦
测量实际VDD电压波动范围(建议用示波器捕获ADC采样时刻的纹波)
二、ADC模块配置差异
1. 基准源选择寄存器
检查ADCON寄存器的VREFSEL字段配置:
```c
// 正确设置内部参考源模式
ADCON |= (0x01
[本文内容由国芯人工智能辅助生成,仅供参考] 15通道测量的是内部BGV DebugLab 发表于 2025-5-9 23:24
15通道测量的是内部BGV
#include "reg51.h"
#include "intrins.h"
#define FOSC 11059200UL
#define BRT (65536 - FOSC / 115200 / 4)
sfr AUXR = 0x8e;
sfr ADC_CONTR = 0xbc;
sfr ADC_RES = 0xbd;
sfr ADC_RESL = 0xbe;
sfr ADCCFG = 0xde;
sfr P_SW2 = 0xba;
#define ADCTIM(*(unsigned char volatile xdata *)0xfea8)
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
int *BGV; //内部1.19V参考信号源值存放在idata中
//idata的EFH地址存放高字节
//idata的F0H地址存放低字节
//电压单位为毫伏(mV)
bit busy;
void UartIsr() interrupt 4
{
if (TI)
{
TI = 0;
busy = 0;
}
if (RI)
{
RI = 0;
}
}
void UartInit()
{
SCON = 0x50;
TMOD = 0x00;
TL1 = BRT;
TH1 = BRT >> 8;
TR1 = 1;
AUXR = 0x40;
busy = 0;
}
void UartSend(char dat)
{
while (busy);
busy = 1;
SBUF = dat;
}
void ADCInit()
{
P_SW2 |= 0x80;
ADCTIM = 0x3f; //设置ADC内部时序
P_SW2 &= 0x7f;
ADCCFG = 0x2f; //设置ADC时钟为系统时钟/2/16
ADC_CONTR = 0x8f; //使能ADC模块,并选择第15通道
}
int ADCRead()
{
int res;
ADC_CONTR |= 0x40; //启动AD转换
_nop_();
_nop_();
while (!(ADC_CONTR & 0x20)); //查询ADC完成标志
ADC_CONTR &= ~0x20; //清完成标志
res = (ADC_RES << 8) | ADC_RESL; //读取ADC结果
return res;
}
void main()
{
int res;
int vcc;
int i;
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
BGV = (int idata *)0xef;
ADCInit(); //ADC初始化
UartInit(); //串口初始化
ES = 1;
EA = 1;
//ADCRead();
//ADCRead(); //前两个数据建议丢弃
res = 0;
for (i=0; i<8; i++)
{
res += ADCRead(); //读取8次数据
}
res >>= 3; //取平均值
vcc = (int)(1024L * *BGV / res); //(10位ADC算法)计算VREF管脚电压,即电池电压
//vcc = (int)(4096L * *BGV / res); //(12位ADC算法)计算VREF管脚电压,即电池电压
//注意,此电压的单位为毫伏(mV)
UartSend(vcc >> 8); //输出电压值到串口
UartSend(vcc);
while (1);
}
8h8k64u利用这个示例代码应该能反推 电池电压。但是得到00
4k64tl 能到37 左右可以用
是否是某个地址需要改动,看不太懂手册。 加的是10u0.1u 用户请先别修改程序, 直接下载"ADC.hex"测试,下载时选择主频11.0592MHZ. 测试时, 电脑的串口助手设置115200,8,n,1。
本程序演示查询方式读取15通道ADC并计算AVREF的电压值,通过串口1(P3.1)发送给上位机,波特率115200,8,n,1.
如果将AVREF与VCC连接,则计算出的电压也是单片机工作电压。
提供两个例程:
1、01A-读取15通道10位ADC计算AVREF电压-串口1(P3.1)返回结果, 适用于所有STC8系列带10位ADC的MCU。
2、01B-读取15通道12位ADC计算AVREF电压-串口1(P3.1)返回结果,适用于所有STC8H系列带12位ADC的MCU。
10位ADC测试结果截图:
12位ADC测试结果截图:
梁工 发表于 2025-5-10 11:12
用户请先别修改程序, 直接下载"ADC.hex"测试,下载时选择主频11.0592MHZ. 测试时, 电脑的串口助手设置11520 ...
直接用hex测试。
接收←ADC15=1483,AVREF=0.822V
接收←ADC15=1480,AVREF=0.823V
接收←ADC15=1472,AVREF=0.828V
接收←ADC15=1469,AVREF=0.830V
接收←ADC15=1468,AVREF=0.830V
接收←ADC15=1468,AVREF=0.830V
接收←ADC15=1468,AVREF=0.830V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1468,AVREF=0.830V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1469,AVREF=0.830V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1467,AVREF=0.831V
接收←ADC15=1468,AVREF=0.830V
接收←ADC15=1468,AVREF=0.830V
万用表测量vdd及笔记本供电3.28 应该能排除硬件吧
麻烦再看下
topofhill 发表于 2025-5-11 12:43
直接用hex测试。
接收←ADC15=1483,AVREF=0.822V
我的程序:
while (1)
{
delay_ms(500);
adc = ADC_convert(15); //Bandgap
v = (4096 * 1.19f) / adc; //计算对应的VCC电压, 12位ADC
printf("ADC15=%u,AVREF=%.3fV\n", adc, v);
}
同时打印adc值和计算的VCC电压值,你的测试返回:
接收←ADC15=1483,AVREF=0.822V
根据adc值计算AVREF = 4096*1.19/1483=3.287V,而你的返回0.822V,这个我实在想不通,计算是普通的计算,你的测试居然也出问题,没法理解。除非拿到你的样板测试,否则我没法想象原因。 12位的结果用了10位的推算公式?差了四倍
0.822×4=3.288 大明狐 发表于 2025-5-11 14:33
12位的结果用了10位的推算公式?差了四倍
0.822×4=3.288
ADC结果是12位的,并且ADC结果也是对的,就是电压不对,很奇怪的。
页:
[1]
2