请选择 进入手机版 | 继续访问电脑版

 找回密码
 立即注册
查看: 596|回复: 1

关于STC8G测量通道X电压计算公式的求助

[复制链接]
  • TA的每日心情
    奋斗
    昨天 09:05
  • 签到天数: 86 天

    [LV.6]常住居民II

    32

    主题

    154

    回帖

    279

    积分

    中级会员

    积分
    279
    发表于 2023-2-16 14:55:49 | 显示全部楼层 |阅读模式
    各位高手:
           我这里有两个地方不明白。见图片(改版后,图片无法上传了?)。

    //16.6.4利用 ADC 第 15 通道测量外部电压或电池电压
    //STC8G 系列 ADC 的第 15 通道用于测量内部参考信号源,由于内部参考信号源很稳定,约为 1.19V,
    //且不会随芯片的工作电压的改变而变化,所以可以通过测量内部 1.19V 参考信号源,然后通过 ADC 的
    //值便可反推出外部电压或外部电池电压。
    //2023-2-15在主涵数中增加先利用通道15读取参考电压对应的数据值,再读取通道3的测量数据值,
    //最后在主涵数中算出的测量通道的电压值。此程序在STC8G1K08A上面进行试验。
    //STC8G 系列技术手册
    //官方网站: www.STCAI.com
    //技术支持: 13922829991
    //选型顾问: 13922805190
    //深圳国芯人工智能有限公司
    //国内分销商电话: 0513-5501 2928/2929/2966
    //去纯技术交流论坛:www.STCAIMCU.com - 584 -
    //C 语言代码
    //测试工作频率为 11.0592MHz

    #include "C:\Keil_v5\C51\INC\reg51.h"
    #include "C:\Keil_v5\C51\INC\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()   //ADC初始化
    {
    P_SW2 |= 0x80;
    ADCTIM = 0x3f;  //设置 ADC 内部时序
    P_SW2 &= 0x7f;

    ADCCFG = 0x2f;  //设置 ADC 时钟为系统时钟/2/16
    ADC_CONTR = 0x8f; //使能 ADC 模块,并选择第 15 通道
    }
    int ADCRead()    //ADC读取通道0的电压
    {
    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 Delay1000us()  [url=]//@11.0592MHz[/url]
    {
    unsigned char k, j;
    k = 15;
    j = 90;
    do
    {
       while (--j);
    } while (--k);
    }

    void main()
    {
    int res3;
    int resbg;
    int TD3_TV;
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x08;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

    BGV = (int idata *)0xef;

    ADCInit();   //ADC 初始化
    UartInit();   //串口初始化
    Delay1000us();   //延时1毫秒让ADC稳定
    ES = 1;
    EA = 1;

    resbg = ADCRead();      //先读出内部参考信号源的数据值
    ADC_CONTR = 0x83;    //使能 ADC 模块,并选择第 3 通道
    res3 = ADCRead();     //再读出通道3的数据值

    ADC_CONTR = 0x0f;    //关闭 ADC 模块电源,并选择第 15 通道
       
    TD3_TV = (int)( ((((*BGV * 100L) / resbg) * res3) / 100L) );
      //上面公式中,*BGV直接除resbg会出现小数,造成最终结果TD3_TV不正确。
      //*BGV先乘100,最后再除100,能够输出正确结果。
      //但是,*BGV=1188*100=118800,已经超出65535了,但最终结果是正确的,不解?     
       //   问题在这里,有没有更好的办法解决小数和输出不正确的问题?
       //1188是烧录芯片时提示信息中的参考电压值
       
      //(10 位 ADC 算法)计算测量通道电压,即由读取值换算成电压值
    // vcc = (int)(4096L * *BGV / res); //(12 位 ADC 算法)计算 VREF 管脚电压,即电池电压
           //注意,此电压的单位为毫伏(mV)
    UartSend(*BGV >> 8); //输出内部参考信号源电压值到串口
    UartSend(*BGV);
    UartSend(resbg >> 8); //输出内部参考信号源数据值到串口
    UartSend(resbg);
    UartSend(res3 >> 8); //输出通道3数据值到串口
    UartSend(res3);
    UartSend(TD3_TV >> 8); //输出通道3电压值到串口
    UartSend(TD3_TV);
    while (1);
    }
    //上面的方法是使用 ADC 的第 15 通道反推外部电池电压的。在 ADC 测量范围内,ADC 的外部测量
    //电压与 ADC 的测量值是成正比例的,所以也可以使用 ADC 的第 15 通道反推外部通道输入电压,假设
    //当前已获取了内部参考信号源电压为 BGV,内部参考信号源的 ADC 测量值为 resbg,外部通道输入电压
    //的 ADC 测量值为 resx,则外部通道输入电压 Vx=BGV / resbg * resx;

    回复 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 09:05
  • 签到天数: 86 天

    [LV.6]常住居民II

    32

    主题

    154

    回帖

    279

    积分

    中级会员

    积分
    279
     楼主| 发表于 2023-2-16 16:59:01 | 显示全部楼层
    我似乎找到了办法。

    STC8H8K64U实验箱-V9.3 里面有一个例程 《33-P1.3做ADC-使用内部基准计算外部电压》,
    里面有这么一段:
       
        ......
        u8  i;
        u16 j;

        ......
       
        for(i=0; i<8; i++)  LED8 = 0x10; //上电消隐

        while(1)
        {
            if(B_1ms)   //1ms到
            {
                B_1ms = 0;
                if(++msecond >= 300)    //300ms到
                {
                    msecond = 0;

                #if (Cal_MODE == 0)
                //=================== 只读1次ADC, 12bit ADC. 分辨率0.01V ===============================
                    Get_ADC12bitResult(15);  //先读一次并丢弃结果, 让内部的采样电容的电压等于输入值.
                    Bandgap = Get_ADC12bitResult(15);    //读内部基准ADC, 读15通道
                    Get_ADC12bitResult(3);  //先读一次并丢弃结果, 让内部的采样电容的电压等于输入值.
                    j = Get_ADC12bitResult(3);  //读外部电压ADC
                    j = (u16)((u32)j * 119 / Bandgap);  //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V

    ......

    不是要把我的程序中变量定义那部分和公式部分,由int 型换成 u16 和 u32。再先乘后除,问题就解决了。
    等待高手给个确认。
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

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

    GMT+8, 2024-3-29 02:41 , Processed in 0.053416 second(s), 32 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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