找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2912|回复: 7
收起左侧

51单片机1602电压电流表程序中的几个问题不懂,求解释

[复制链接]
ID:18488 发表于 2019-8-6 10:12 | 显示全部楼层 |阅读模式
//stc12c5a60                        
#include<STC12C5A60S2.h>
#include<stdio.h>
#include<intrins.h>//头文件

#define uchar unsigned char//宏定义
#define uint unsigned int//宏定义
#define ulint unsigned long int//宏定义
#define N 21//ADC中值滤波次数,必须为基数
#define ISP_TRIG() ISP_TRIG=0x5A,ISP_TRIG=0xA5//ISP触发命令

sbit rs=P3^5;//液晶RS
sbit rw=P3^6;//液晶RW
sbit e=P3^4;//液晶E

void AD_init(void);//ADC初始化
void delay(uint z);//延时函数
uint AD_get(uchar haha );//读ADC的数值
void LCD_data(uchar shuju);//写数据
void zhiling(uchar zhilin);//写指令
void LCD_init(void);//初始化LCD
void tablex(uint tab);//数据分解
uint filter(uchar dat);//中值滤波
void timer_init(void);//定时器初始化

uchar h1,h2,h3,h4;//LCD显示变量
ulint mas,maz;//容量计算

uchar table[]="0123456789";//显示数组
uchar table1[]=".VAWa";

void main()
{
        ulint tempv,tempa;//存放电压电流值
        AD_init();//ADC初始化
        timer_init();//定时器初始化
        LCD_init();//LCD初始化
        while(1)
        {
                tempv=filter(0x88);//设置ADC通道0、开始转换
                tablex(tempv*3);//分解数据
                zhiling(0x80);//LCD地址
                LCD_data(table[h1]);//
                LCD_data(table[h2]);//
                LCD_data(table1[0]);//
                LCD_data(table[h3]);//
                LCD_data(table[h4]);//
                LCD_data(table1[1]);//显示

                tempa=filter(0x8f);//设置ADC通道7、开始转换
                if(tempa<=10)//防止数据成负数
                        tempa=10;
                mas=tempa*3-30;//计算容量取样赋值
                tablex(tempa*3-30);//减去LM358失调的数值
                zhiling(0x88);//LCD地址
                LCD_data(table[h1]);
                LCD_data(table1[0]);
                LCD_data(table[h2]);
                LCD_data(table[h3]);
                LCD_data(table[h4]);
                LCD_data(table1[2]);

                tablex((tempv*3/10)*((tempa*3-30)/10)/10);//计算功率
                zhiling(0x80+0x40);
                LCD_data(table[h1]);
                LCD_data(table[h2]);
                LCD_data(table1[0]);
                LCD_data(table[h3]);
                LCD_data(table[h4]);
                LCD_data(table1[3]);

                tablex(maz/1000);//显示MAH
                zhiling(0x88+0x40);
                LCD_data(table[h1]);
                LCD_data(table1[0]);
                LCD_data(table[h2]);
                LCD_data(table[h3]);
                LCD_data(table[h4]);
                LCD_data(table1[4]);

        }
}
//-------------------------------------------------------------
void delay(uint z)///////////////延时程序
{
   uint x,y;
   for(x=z;x>0;x--)
   for(y=19;y>0;y--);
}
void AD_init(void)/////////////////////初始化ADC
{
P1ASF=0xff;//P1口全部作为模拟功能AD使用
ADC_RES=0;//清零转换结果寄存器高8位
ADC_RESL=0;//清零转换结果寄存器低2位
ADC_CONTR=0x80;//开启AD电源
delay(5);//等待1ms,让AD电源稳定
}

uint AD_get(uchar haha )//ADC读数
{
        uint rew;
        ADC_CONTR=haha;//开启AD转换
        _nop_(); _nop_(); _nop_(); _nop_();//要经过4个CPU时钟的延时
        while(!(ADC_CONTR&0x10));//等待转换完成
        ADC_CONTR&=0xe7;//关闭AD转换,ADC_FLAG位由软件清0
        rew=ADC_RES*4+ADC_RESL;//组合成10位
        delay(1);//等待
        return rew;//返回ADC值
}
void zhiling(uchar zhilin)//写指令
{
        e=0;
        rs=0;
        rw=0;
        P0=zhilin;
        delay(20);
        e=1;
        delay(20);
        e=0;
}
void LCD_data(uchar shuju)//写数据
{
        e=0;
        rs=1;
        rw=0;
        P0=shuju;
        delay(20);
        e=1;
        delay(20);
        e=0;
}
void LCD_init(void)//初始化LCD
{
delay(300);
zhiling(0x38);
delay(100);
zhiling(0x38);
delay(100);
zhiling(0x38);
delay(100);
zhiling(0x38);
zhiling(0x38);
zhiling(0x08);
zhiling(0x01);
zhiling(0x06);
zhiling(0x0c);
}
void tablex(uint tab1)//数据分解
{
        h1=tab1/1000;//1023//1
        h2=tab1%1000/100;//023//0
        h3=tab1%100/10;//23//2
        h4=tab1%10;//3
}
uint filter(uchar dat)//中位值滤波
{
   uint value_buf[N];
   uint count,i,j,temp;
   for(count=0;count<N;count++)
   {
                         AD_init();//初始化ADC
      value_buf[count] = AD_get(dat);//读ADC数值
      delay(1);
   }
   for (j=0;j<N-1;j++)
   {
      for (i=0;i<N-j;i++)
      {
         if ( value_buf[ i]>value_buf[i+1] )
         {
            temp = value_buf[ i];
            value_buf[ i] = value_buf[i+1];
            value_buf[i+1] = temp;
         }
      }
   }
   return value_buf[(N-1)/2];
}
void timer_init(void)//定时器初始化
{
        TMOD=0x01;/////////设置工作方式1
        TH0=(65536-50000)/256;///////赋值
        TL0=(65536-50000)%256;
        EA=1;ET0=1;//开总中断;开定时器中断
        TR0=1;////////启动计数器
}


程序如上,原贴连接:http://www.51hei.com/bbs/dpj-131969-1.html
看了很久其中几句就是看不懂,哪位大神给讲解下呀,谢谢
问题是下面几句看不懂
tablex(tempv*3);//分解数据

if(tempa<=10)//防止数据成负数
                        tempa=10;
                mas=tempa*3-30;//计算容量取样赋值
                tablex(tempa*3-30);//减去LM358失调的数值

tablex(maz/1000);//显示MAH


回复

使用道具 举报

ID:213173 发表于 2019-8-7 09:34 | 显示全部楼层
软件都是基于硬件条件编写的,离开硬件电路图,有些代码是很难读懂的。纵观这程序,原作者的ADC电压取样电路可能是直接或通过分压电阻取样、电流取样电路可能是毫欧级取样电阻经运算放大器LM358放大取样。经软件滤波后获取10位ADC数据,这些数据并不能直接显示电压和电流,需要经过运算和补偿才能得到接近实际电压和电流的值,并将此值通过LCD1602显示出来。
回复

使用道具 举报

ID:18488 发表于 2019-8-7 13:21 | 显示全部楼层
183755uz310t1z95z3wxu8.jpg
这个是电路图能给帮忙讲讲吗谢谢
回复

使用道具 举报

ID:213173 发表于 2019-8-8 06:34 | 显示全部楼层
maomaochong 发表于 2019-8-7 13:21
这个是电路图能给帮忙讲讲吗谢谢

楼主找的这个程序只能算是习作,有很多不成熟的地方。其运算ADC结果的方法也是粗浅的,以致楼主看不明白。
十位ADC结果换算成10进制(4舍5入):毫伏=(参考电压*十位ADC结果*10000/1024+5)/10。
再将此值按前置电路的分压比放大或运放放大倍数缩小,才能得到取样点的实际值。
回复

使用道具 举报

ID:56665 发表于 2019-8-8 08:38 | 显示全部楼层
tablex(tempv*3);//分解数据, 就是10K电阻RP2调到了1.67K的位置。
回复

使用道具 举报

ID:18488 发表于 2019-8-9 10:10 | 显示全部楼层
maomaochong 发表于 2019-8-7 13:21
这个是电路图能给帮忙讲讲吗谢谢

非常感谢我研究研究
回复

使用道具 举报

ID:18488 发表于 2019-8-9 10:11 | 显示全部楼层
m182892 发表于 2019-8-8 08:38
tablex(tempv*3);//分解数据, 就是10K电阻RP2调到了1.67K的位置。

不理解
回复

使用道具 举报

ID:112138 发表于 2021-5-11 21:40 | 显示全部楼层

这个程序应该是不全的,不知道什么原因。tempv*3的意思是电压取样1/3,这是硬件决定的,所以结果要*3.
AD值读出来不是电压值,要和基准电压AD换算转成电压值再分解显示的,这个直接显示肯定是错的,这个程序是不能用的。还有MAZ是什么莫名其妙的突然就蹦出来显示。搞不懂楼主转过来看过没有
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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