搜索
bottom↓
回复: 34

求助!12864液晶如何显示0--5V的电压?精确到小数点后3位

[复制链接]

出0入0汤圆

发表于 2008-8-14 17:04:47 | 显示全部楼层 |阅读模式
各位好!
我用TLC2543采集0--5V电压,要把采样结果在12864液晶上显示出来,精确到小数点后3位.例如:AD转换结果是:3000,那么实际的电压值是:(3000 / 4096) * 5 = 3.662V.

   那么,我用C语言,如何计算出"3.662V"中的个位、小数后一位、小数后两位、小数后三位?

   这个问题想得我头痛了,求助一下思路,谢谢!

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2008-8-14 17:11:41 | 显示全部楼层
将数值放大1000倍

出0入0汤圆

发表于 2008-8-14 17:12:10 | 显示全部楼层
显示的时候先把3.662放大1000倍变为整数显示,中间再加个小数点即可,内部数据处理的时候再把这1000倍去掉。

出0入0汤圆

发表于 2008-8-14 17:13:38 | 显示全部楼层
你可以把它当成3662,个位=3662/1000; 小数一位=(个位%1000)/100,小数二位==((个位%1000)%100)/10.....

出0入0汤圆

发表于 2008-8-14 18:50:43 | 显示全部楼层
上面说的是正确的

出0入0汤圆

 楼主| 发表于 2008-8-14 21:21:17 | 显示全部楼层
谢谢以上各位!
根据以上思路,我写了以下程序:

ulong tempu32 = 0;
tempu32 = (ad * 5000) / 4096;            //ad是12位AD转换结果,把这个结果放大了1000倍
ge = tempu32 / 1000;                     //个位
x1 = (tempu32 % 1000) / 100;            //小数一位
x2 = ((tempu32 % 1000) % 100) / 10;     //小数二位
x3 = ((tempu32 % 1000) % 100) % 10;     //小数三位

为什么显示总为0?

出0入0汤圆

发表于 2008-8-15 00:09:50 | 显示全部楼层
tempu32 = (ad * 5000) / 4096;

ad是什么数据内型?如果是16位的可能丢失精度。



x2 = ((tempu32 % 1000) % 100) / 10;     //小数二位
x3 = ((tempu32 % 1000) % 100) % 10;     //小数三位

有必要这样么?

出0入0汤圆

 楼主| 发表于 2008-8-15 07:48:48 | 显示全部楼层
ad是unsigned int类型.

我的思路是:假如ad的值是:3000,那么,tempu32 = (3000 * 5000) / 4096 = 3662.
个位:ge = tempu32 / 1000 = 3662 /1000 = 3  //除法得商

小数一位:x1 = (tempu32 % 1000) / 100 = (3662 % 1000) / 100 = 6  //3662 % 1000得到余数:662,662 / 100 得到商:6

小数二位:x2 = ((tempu32 % 1000) % 100) / 10 = ((3662 % 1000) % 100) / 10 = 6  //同理, 3662 % 1000得到余数:662,
                                                                              //662 % 100得到余数:62,62 / 10得到商:6
小数三位:x3 = ((tempu32 % 1000) % 100) % 10 //同理,62 % 10 得到余数:2

但在12864液晶上显示0.000V左右?液晶驱动显示程序是没有问题的

出0入0汤圆

 楼主| 发表于 2008-8-15 08:18:48 | 显示全部楼层
6楼"aviator"一语惊醒梦中人,我把uint变量ad在表达式中临时变为ulong类型,如下:

ulong tempu32 = 0;
tempu32 = ((ulong)ad * 5000) / 4096;            //ad是12位AD转换结果,把这个结果放大了1000倍
ge = tempu32 / 1000;                            //个位  
x1 = (tempu32 % 1000) / 100;                    //小数一位
x2 = ((tempu32 % 1000) % 100) / 10;             //小数二位
x3 = ((tempu32 % 1000) % 100) % 10;             //小数三位

这样就可以正常显示采集结果了.谢谢!

但好象这种方法计算出的结果有误差,例如,我测量TLC2543的5V基准,FLUKE 15B万用表显示很稳定的5.00V,但用0--5V传感器加上TLC2543测量,结果却显示:4.951V,相差大了一点了吧?

出0入0汤圆

发表于 2008-8-15 15:07:56 | 显示全部楼层
50mv的误差,可能是你电路或程序问题

出0入0汤圆

 楼主| 发表于 2008-9-9 16:04:36 | 显示全部楼层
问题已经解决。在硬件上,在TLC2543的模拟输入通道上,加了RC滤波,现在高精度的电压基准5V,用TLC2543测量的结果是:4.997V。

  结贴。

出0入0汤圆

发表于 2008-9-13 14:15:04 | 显示全部楼层
记号

出0入0汤圆

发表于 2008-9-13 14:31:40 | 显示全部楼层
呵呵,12bit的AD显示小数点后3位,最后一位只是计算的,不准确。
数学计算公式,非常容易错误,特别是整数运算,一不小心就溢出。
万用表是5V,ADC结果最大是4095,如果分母是4096,则永远不会到5V了,是4.999。
4.997就是4094了,按道理应该是4095,说明电路因为RC滤波电压有减少。

出0入0汤圆

 楼主| 发表于 2008-9-14 00:23:20 | 显示全部楼层
传感器是0 -5V,12位A/D的分辨率是:5 / 4096 = 0.001220703125V,显示到小数点后3位,应该可以吧?

出0入0汤圆

 楼主| 发表于 2008-9-14 00:29:27 | 显示全部楼层
数学计算可以比上面的简单一点:

tempu32 = ((ulong)ad * 5000) / 4096;       //显示数字放大1000倍
ge = tempu32 / 1000;                       //个位
x1 = (tempu32 / 100) % 10;                 //小数点后1位
x2 = (tempu32 / 10) % 10;                  //小数点后2位
x3 = tempu32 % 10;                                 //小数点后3位

出0入0汤圆

发表于 2010-8-18 22:15:42 | 显示全部楼层
回复【14楼】wyb4993
#include<pic.h>
#include<pic1687x.h>
#define uchar unsigned char
#define uint  unsigned int
//__CONFIG(0x3B31);
const uchar table[]={"电流:"};
const uchar table2[]={"电压:"};
uchar table1[]={"0123456789"};
void delay(uint x);
void init();
void init1();
void lcd_init();
void clear_p();
void chk_busy();
void send_i(unsigned char x);
void send_d(unsigned char x);
void qushu(int counts,const unsigned char *ps);
bit busy;      
#define  rs  RE2                    
#define  rw  RE1                  
#define  e   RE0                  
#define  psb RA2                  
#define  rst RA1  
void disp();
uint get_ad();
void main()
{
        uint temp;
        uchar a1,a2,a3,a4;
        while(1)
        {
                init();
                temp=get_ad();
                a1=temp/1000;
                a2=temp%1000/100;
                a3=temp%100/10;
                a4=temp%10;
                disp(a1,a2,a3,a4);
                delay(500);       
        }       
}
void delay(uint x)
{
        uint a,b;
        for(a=x;a>0;a--)
                for(b=110;b>0;b--);
}
void init()
{
        TRISA=0x01;
        TRISD=0;
        TRISE=0;
        PORTA=0x00;
        PORTE=0x00;
        PORTD=0X00;
        ADCON0=0x41;
        ADCON1=0x8e;
        delay(10);
}
/*
void init1()
{
  TRISA=0X00;                       
  TRISD=0X00;  
  TRISE=0X00;               
  ADCON1=0X06;                  
}
*/
uint get_ad()
{
        uint adval;
        float advalf;
        ADGO=1;
        while(ADGO);
        adval=ADRESH;//00000000 00000011
        adval=adval<<8|ADRESL;//00000011 11111111
        advalf=adval/1023.0*5.0;//==2.3843
        adval=advalf*1000;
        return (adval);       
}

void lcd_init()
{
  rst=0;                            //复位LCD
  delay(10);                        //保证复位所需要的时间
  rst=1;                            //恢复LCD正常工作
  delay(10);        
  psb=1;                            //设置LCD为8位并口通信
  send_i(0x30);                     //基本指令操作
// send_i(0x01);                     //清除显示
  send_i(0x06);                     //指定在写入或读取时,光标的移动方向
  send_i(0x0c);                     //开显示,关光标,不闪烁
}

void qushu(int counts,const unsigned char *ps)
{
  int i;                         //定义循环变量
for(i=1;i>0;i--)          //循环counts次
     {  
       send_d(*ps);             //查表取数并调用显示一个字节数据函数送显示
       delay(20);                //延长一定时间,确保能看到数据一个个的显示出来
       ps++;                    //取下一个数据
     }
}
/*void clear_p()
{
//send_i(0x01);                  //清除所有显示
  send_i(0x34);                  //扩展指令操作
  send_i(0x30);                  //基本指令操作
}*/
void send_d(unsigned char x)
{
   chk_busy();                  //检测LCD是否工作繁忙
   rs=1;                        //设置该字节数据是显示数据
   rw=0;                        //设置该次操作为写
   PORTD=x;                     //送数据口PORTD
   e=1;                         //使能
   delay(10);                       
   e=0;                         //禁止
}
void send_i(unsigned char x)
{
   chk_busy();                  //检测LCD是否工作繁忙
   rs=0;                        //设置该字节数据为控制命令
   rw=0;                        //设置此次操作为写
   PORTD=x;                     //送数据口PORTD
   e=1;                         //使能
   delay(10);
   e=0;                         //禁止
}
void chk_busy()
{  
   busy=1;                      //先置位繁忙标志位
   TRISD=0XFF;                  //更改通信为输入
   rs=0;                        //设置该字节数据为命令代码
   rw=1;                        //设置此次操作为读
   while(busy)                  
      {
                 delay(10);
         e=1;                   //使能
         delay(10);
         if(!RD7) busy=0;       //检测LCD是否工作繁忙
         delay(10);
         e=0;                   //禁止
      }
   e=0;                         //禁止
   TRISD=0X00;                  //恢复通信为输出
}
void disp(a1,a2,a3,a4)
{
                init();                    
                lcd_init();                  
        //        clear_p();
        send_i(0x80);                  
                qushu(0X05,table);
                send_i(0x30);
                send_i(0x90);

        send_i(0x90);                  
             qushu(0X05,table2);
                send_d(table1[a1]);
                delay(20);
                send_d('.');
                delay(20);
                send_d(table1[a2]);
                delay(20);
                send_d(table1[a3]);
                delay(20);
                send_d(table1[a4]);
                delay(20);
这个程序在液晶上能显示出来,但是不能测量到电压,哪位高手指点一下啊……

出0入0汤圆

发表于 2010-8-20 17:09:41 | 显示全部楼层
看看我刚刚写的:我用的12232显示的!精确到小数点后6位!
#include<reg52.h>
#include<intrins.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit adwr=P3^6;         //AD采集WR端口
sbit adrd=P3^7;         //AD采集RD端口
sbit SCLK=P0^2;         //12232液晶端口定义
sbit SID=P0^1;
sbit CS=P0^0;
uchar code disps[]={"The V is:"};
uchar code disps1[]={"江苏赛福特"};
uchar code disps2[]={"汽车安全专家!"};
uchar v[10];
uchar flag_uart,flag_time,t0_num,a,flag_on,ad_val;
float ad_vo;
void delay_1ms(uint xms)         //延时MS
{
        uint i,j;
        for(i=xms;i>0;i--)
        for(j=110;j>0;j--);
}
void send_command(uchar command_data)  //向液晶发送命令
{
        uchar i;
        uchar i_data;
        i_data=0xf8;
        CS=1;
        SCLK=0;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        i_data=command_data;
        i_data&=0xf0;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        i_data=command_data;
        i_data<<=4;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        CS=0;
        delay_1ms(10);
}
void send_data(uchar command_data)        //向液晶发送数据
{
        uchar i;
        uchar i_data;
        i_data=0xfa;
        CS=1;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        i_data=command_data;
        i_data&=0xf0;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        i_data=command_data;
        i_data<<=4;
        for(i=0;i<8;i++)
        {
                SID=(bit)(i_data&0x80);
                SCLK=0;
                SCLK=1;
                i_data=i_data<<1;
        }
        CS=0;
        delay_1ms(10);       
}
void display_s()                //液晶第一行显示
{
        uchar b;
        send_command(0x80);
        for(b=0;b<9;b++)
        {
                send_data(disps);
        }
}
uchar get_ad()                 //获取AD转换数据
{
        uchar adval;
        adwr=1;
        _nop_();
        adwr=0;
        _nop_();
        adwr=1;
        P1=0xff;
        adrd=1;
        _nop_();
        adrd=0;
        _nop_();
        adval=P1;
        adrd=1;
        return adval;
}
void lcd_init()          //液晶初始化
{
        uint b;
        delay_1ms(100);
        send_command(0x30);
        send_command(0x02);
        send_command(0x06);
        send_command(0x0c);
        send_command(0x01);
        send_command(0x80);
    for(b=0;b<10;b++)
    {
                send_data(disps1);
    }
        send_command(0x91);
    for(b=0;b<13;b++)
    {
                send_data(disps2);
    }
        delay_1ms(3000);
        send_command(0x30);
        send_command(0x02);
        send_command(0x06);
        send_command(0x0c);
        send_command(0x01);
}
void main()                  //主程序
{
        uint b;
        float a;
        long ad;
        lcd_init();
        display_s();
        while(1)
        {
                ad_val=get_ad();
/*                v[0]=ad_val/100+'0';
                v[1]=ad_val%100/10+'0';
                v[2]=ad_val%10+'0';
                v[3]='V';
                send_command(0x90);
            for(b=0;b<4;b++)
            {
                send_data(v);
             }                 */
                ad=((float)(ad_val*5/256)*1000000);
               
                v[0]=ad/1000000+'0';
                v[1]='.';
                v[2]=ad%1000000/100000+'0';
                v[3]=ad%1000000%100000/10000+'0';
                v[4]=ad%1000000%100000%10000/1000+'0';
                v[5]=ad%1000000%100000%10000%1000/100+'0';
                v[6]=ad%1000000%100000%10000%1000%100/10+'0';
                v[7]=ad%1000000%100000%10000%1000%100%10+'0';
                v[8]='V';      
                send_command(0x92);
            for(b=0;b<9;b++)
            {
                send_data(v);
             }

        }
}

出0入0汤圆

发表于 2010-8-20 17:10:46 | 显示全部楼层
我使用的ADC0804

出0入0汤圆

发表于 2010-8-20 21:13:50 | 显示全部楼层
回复【17楼】sjx_83
-----------------------------------------------------------------------

0804 是8位的... 0-255   精确多了也没用 AD精度不够

出0入0汤圆

发表于 2010-8-20 21:17:59 | 显示全部楼层
回复【6楼】aviator  
-----------------------------------------------------------------------

mark

出0入0汤圆

发表于 2010-8-29 00:11:36 | 显示全部楼层
ADC0804 采集完的数直接 / 采集精度 * 电源电压

出0入0汤圆

发表于 2010-8-29 00:21:54 | 显示全部楼层
难道这么多人就没人知道用sprintf吗?
sprintf(string,"ad_result=%0.3f",ad_result);
Disp_String(string);

出0入0汤圆

发表于 2010-8-29 00:45:31 | 显示全部楼层
回复【21楼】binghe167  星夜冰河
难道这么多人就没人知道用sprintf吗?
sprintf(string,"ad_result=%0.3f",ad_result);
disp_string(string);
-----------------------------------------------------------------------
就是因为知道才不用这个函数的!你知道这个函数编译之后占用多少代码空间,要执行多少时间吗?

出0入0汤圆

发表于 2010-8-29 01:03:12 | 显示全部楼层
tempu32 = (ad * 5000) / 4096;
或许这样算会更高效:
tempu16 = ad+(ad>>2)-(ad>>5)+(ad>>9);

出0入0汤圆

发表于 2011-1-7 17:08:50 | 显示全部楼层
正需要这方面的资料。

出0入0汤圆

发表于 2011-1-7 17:11:16 | 显示全部楼层
大家好。
我遇到个问题,我用电位器给ADC0804提供模拟量,转换数字量后由12864显示,连接好后,在显示位置只显示55,能指点一下是什么原因吗?
谢谢。

出0入0汤圆

发表于 2011-1-9 07:56:59 | 显示全部楼层
问题已解决,我的连线太乱,好像是数据口与电源连接了。我将线拆除,重新连了一遍,没经过锁存器。
现在正常了。

出0入0汤圆

发表于 2011-1-9 12:50:52 | 显示全部楼层
MARK.

出0入0汤圆

发表于 2011-1-12 09:46:54 | 显示全部楼层
MARK.

出0入0汤圆

发表于 2012-2-21 11:53:51 | 显示全部楼层
回复【楼主位】wyb4993
-----------------------------------------------------------------------
首先我要给大家纠正一个错误:以5V电压表为例
除以4096是不对的,应该是除以4095,并且也不能写成/,这是求模,实际我们的问题是0-4095显示成0-5000,AD_data*5000除以4095.
4095对应5V,AD_dat对应x,列方程把x求出来就是了.大家可以算算0x0FFF应该对应5V,如果除以4096还能显示5.000V吗?
5000是量程5000mv而不应该是基准电压的5.000V.基准电压的5.000V是计算测量分辨率的,跟我们显示的数字是两码事.

出0入0汤圆

发表于 2012-11-30 22:53:42 | 显示全部楼层
Mark! Mark!

出0入0汤圆

发表于 2012-12-13 12:41:53 | 显示全部楼层
这个可以记下了

出0入0汤圆

发表于 2013-3-25 15:14:04 | 显示全部楼层
记下了。

出0入0汤圆

发表于 2013-3-25 15:22:49 | 显示全部楼层
可以将浮点型 转换成字符串 然后以字符串的方式显示

出0入0汤圆

发表于 2013-7-9 16:45:06 | 显示全部楼层
不用不知道
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 12:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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