IFELSE 发表于 2024-2-18 13:24:15

STC8H单片机利用内部基准测量其它ADC通道的电压疑问| 已解决

问题现象:

利用15通道测得的基准电压去反推ADC_Vref+管脚的输入电压时是正常的,但是反推其它ADC通道时就不正常了:只要一开ADC15通道转换,其它通道的ADC值都跟ADC15通道一样,不对ADC15通道进行转换时,其它通道是正常的。这是什么原因呢?

硬件连接情况:STC8H1K单片机,ADC_Ref+和VCC接在一起(5V),ADC0用来测量电池电压(3.7V的锂电池电压分压后给到ADC0)。

利用ADC15通道反推ADC_Vref+端口的电压:经计算后为5.056V 【 测得ADC15通道的ADC值为241,读取电压值为1192,从而计算出ADC_Vref+的电压为 5056mV 】

利用ADC15通道测量值,反推ADC0通道电压:测得ADC15通道的ADC值为241,读取电压值为1192,ADC0通道的ADC值在还未运行ADC15转换程序时,是正常的193,一旦经过ADC15转换 ,ADC0就不再正常,变得跟ADC15一样为241。

有一个问题,如果使用ADC15测得的内部基准来反推ADC0通道的输入电压,即便上述测得的ADC0是正常的,那ADC_Vref+管脚的电压有什么作用呢?是不是用不到了?

【在下面代码main程序中可以看到, 第一次正常的ADC0的值为193,而ADC0通道的外部电压Vadc0用万用表实测为952mV,ADC_Vref+的电压是5056mV,Vadc0 =5056*193/1024 = 943mV,这与952mV接近。】==> 这说明第一次ADC0的值是将ADC_Ref+管脚的5.056V电压作为参考得到的。

代码如下:
//========================================================================
// 函数: 串口1初始化
//========================================================================
void Uart1_Init()
{
    P_SW1 = 0x40;                               // 将串口1配置为P3.6/P3.7端口输出(RXD_2/P3.6, TXD_2/P3.7)
    SCON = 0x50;                                 // 将串口1的模式配置为模式1(8位可变波特率),启动串口1接收
    TMOD = 0x00;                              // 配置T1的启动不受外部中断影响、16位自动重装载、作为定时器而非计数器。
    TL1 = UART1_BRT;
    TH1 = UART1_BRT >> 8;
    AUXR = 0x40;                              // 选择T1作为UART1的波特率发生器(S1ST2置0),给T1的时钟频率选择不分频(即1T模式,设置T1x12为1).      
    REN   =0;                                    // 关闭串口接收(这里只需要发给PC显示即可,无需接收),这一步也可以在SCON寄存器内设置好。
    TR1 = 1;                                       // 启动T1定时器                                                                                                                                                                                                
}

//========================================================================
// 函数: 串口1发送函数
//========================================================================
void Uart1_Send(uchar dat)
{
      SBUF = dat;
      while(!TI);
      TI = 0;
}
//========================================================================
// 函数: GPIO初始化
//========================================================================
void GPIO_INIT()
{      
      P3M1= 0x00;                           
      P3M0= 0x00;                           

      /*将ADC的IO口配置为高阻模式*/      
      P1M1|= 0x03;                                    // 将P1.0/P1.1配置为高阻输入模式,P1.0为ADC0,测量电池电压
      P1M0&= 0xFC;                                 // 将P1.0/P1.1配置为高阻输入模式,P1.1为ADC1,测量麦克风的输出信号      
}

//========================================================================
// 函数: ADC初始化函数
//========================================================================
void ADCInit()
{
    P_SW2 |= 0x80;                               // 使能访问XFR,以便设定相关寄存器
    ADCTIM = 0x3F;                               // 通道选择时间1个时钟,通道保持时间4个时钟,采样时间32个时钟,总共37个时钟
    ADCCFG = 0x2F;                               // 设置ADC转换结果为右对齐,工作频率为:FOSC/2/16,相当于32分频
         
    ADC_RES=0;ADC_RESL=0;                // 清除ADC结果寄存器
    ADC_CONTR |= ADC_POWER;         // 开启ADC电源
    delay_ms(20);                                  // 增加延时让ADC稳定.
}

//========================================================================
// 函数: ADC转换函数
//========================================================================
uint ADCRead(uchar ch)
{
    uint adc_dat;                                       
    ADC_RES = 0;
    ADC_RESL = 0;                                          // 将结果寄存器的数据清零   
    ADC_CONTR |= ADC_START|ch;                  // 启动ADC转换/设定ADC通道(ch为0时为ADC0--P1.0端口,ch为1时为ADC1--P1.1端口...ch为15时为ADC15,即第15通道)      
    _nop_();
    _nop_();

    while (!(ADC_CONTR & ADC_FLAG));            // 查询ADC完成标志
    ADC_CONTR &= ~ADC_FLAG;                     // 转换完成后,清完成标志

   adc_dat = (ADC_RES<<8)|ADC_RESL;         
    return adc_dat;
}

//========================================================================
// 函数: 读取8次ADC数据取平均
//========================================================================
uint AdcDat_Avg8(uchar ch)
{
    uint adc_avg8 ;
    uint i;
    ADCRead(ch);
    ADCRead(ch);                                  // 先转换两次,丢掉前两个数据
    adc_avg8 = 0;
    for (i=0; i<8; i++)
    {
      adc_avg8 += ADCRead(ch);            // 读取8次电池ADC值
    }
   adc_avg8 >>=3;                               // 取8次平均值
   return adc_avg8;
}
//========================================================================
// 函数: ADC电压读取函数
//========================================================================
uint Read_Adc_Vol()
{
         uint ADC_CH0 = 0;                                          // ADC0的ADC值
         uint ADC_CH15 = 0;                                        // ADC15的ADC值
         uint BAT_V = 0;                                              // 电池电压

         ADC_CH0 = AdcDat_Avg8(0);                        
         Uart1_Send(ADC_CH0 >>8 );                        // 读取ADC0的值,此处实测:当不转换前面的ADC15通道时,实测为00 C1 即193
         Uart1_Send(ADC_CH0);

         ADC_CH15 = AdcDat_Avg8(15);                        
         Uart1_Send(ADC_CH15 >>8 );                         // 读取内部参考源电压对应ADC值,此处实测为 00 F1 即241,经过此处之后,ADC0就不再为00 C1,而是00 F1
         Uart1_Send(ADC_CH15);

         return BAT_V;
}

//========================================================================
// main函数
//========================================================================
void main()
{               
    P_SW2 |= 0x80;                                                            
    GPIO_INIT();                              // 初始化GPIO
    Uart1_Init();                           // 串口初始化      
    ADCInit();                              // ADC初始化
    while(1)
   {      
      Read_Adc_Vol();                  // 串口打印信息:00 C1 00 F1 00 F1 00 F1 00 F1 00 F1··· ··· 循环 00 F1; ==> 即只有第一次还未转换ADC15时,打印的ADC0是正常的,一旦转换过ADC15,ADC0就不正常了,变得更ADC15一样了,这是什么原因?
      delay_ms(3000);         
   }
}




_奶咖君_ 发表于 2024-2-18 13:29:20

0.0你设置通道的时候 是 或运算 置位 的 通道.... 需要先清除通道 再设置通道..

_奶咖君_ 发表于 2024-2-18 13:30:16

IFELSE 发表于 2024-2-18 14:06:07

_奶咖君_ 发表于 2024-2-18 13:29
0.0你设置通道的时候 是 或运算 置位 的 通道.... 需要先清除通道 再设置通道.. ...

原来如此,找半天没找到原因{:sweat:},现在可以了,感谢感谢!{:handshake:}
页: [1]
查看完整版本: STC8H单片机利用内部基准测量其它ADC通道的电压疑问| 已解决