找回密码
 立即注册
查看: 1496|回复: 4

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

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-02-19 12:35:18

1

主题

2

回帖

35

积分

新手上路

积分
35
发表于 2024-2-18 13:24:15 | 显示全部楼层 |阅读模式
问题现象:

利用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);         
   }
}




回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2024-2-18 13:29:20 | 显示全部楼层
0.0  你设置通道的时候 是 或运算 置位 的 通道.... 需要先清除通道 再设置通道..
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:435
  • 最近打卡:2025-04-30 08:43:23

33

主题

2351

回帖

4860

积分

论坛元老

积分
4860
发表于 2024-2-18 13:30:16 | 显示全部楼层
截图202402181330119474.jpg
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-02-19 12:35:18

1

主题

2

回帖

35

积分

新手上路

积分
35
发表于 2024-2-18 14:06:07 | 显示全部楼层
_奶*** 发表于 2024-2-18 13:29
0.0  你设置通道的时候 是 或运算 置位 的 通道.... 需要先清除通道 再设置通道.. ...

原来如此,找半天没找到原因,现在可以了,感谢感谢!

点评

看好你哟~  发表于 2024-2-18 14:10
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 15:48 , Processed in 0.111815 second(s), 68 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表