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

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

[复制链接]
  • TA的每日心情
    擦汗
    2024-2-19 12:35
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    1

    主题

    2

    回帖

    33

    积分

    新手上路

    积分
    33
    发表于 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);         
       }
    }




    回复 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    1 小时前
  • 签到天数: 144 天

    [LV.7]常住居民III

    20

    主题

    1096

    回帖

    2613

    积分

    金牌会员

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

    使用道具 举报

  • TA的每日心情
    慵懒
    1 小时前
  • 签到天数: 144 天

    [LV.7]常住居民III

    20

    主题

    1096

    回帖

    2613

    积分

    金牌会员

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

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-2-19 12:35
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    1

    主题

    2

    回帖

    33

    积分

    新手上路

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

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

    点评

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

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-5-20 09:59 , Processed in 0.068322 second(s), 48 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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