模吧

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

2741查看 | 9回复

[DIY交流] 用stc12自带ad做电压表

[复制链接]
发表于 2017-1-12 13:24:10 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
如标题,手头暂时没有stc15的单片机,想来stc12有内置的ad,于是就用内置的做了一个ad转换,第一次测量一路ad,10位精度,基准用供电电压,然后数值乱跳,现在改用两路测量,8位精度,基准用看大网上说的是用431做基准,但是手头没有,本着节约(不想再买的,也就是动手d着玩)的原则,直接用1117-2.5v的稳压芯片代替,测试通过,数值没有第一次跳的厉害了,但是测量还是不准,万用表测单节干电池是1.52v  用做的测电压在1.2~1.6之间乱跳,又看了一下网上的教程,说是需要用软件滤波,然后又百度软件滤波,看的头晕了,也没看明白个什么,就此发帖想问题一下各位,有用软件滤波的没,就是那个中位值平均算法,取12个数据掐头去尾算平均,废话不说了,直接贴程序,写的比较乱。。。
下面是程序

#include<reg52.h>

#define u8 unsigned char
#define u16 unsigned int

sfr P1M1=0x91;
sfr P1ASF=0x9d;
sfr ADC_CONTR=0xbc;
sfr ADC_RES=0xbd;
sfr ADC_RESL=0Xbe;

sbit a=P0^0;
sbit b=P0^1;
sbit c=P0^2;
sbit d=P0^3;
sbit e=P0^4;
sbit f=P0^5;
sbit g=P0^6;
sbit h=P0^7;

sbit p20=P2^0;
sbit p21=P2^1;
sbit p22=P2^2;
sbit p23=P2^3;

unsigned char data1;
unsigned char data2;
unsigned char data3;
unsigned char data4;

void delay1ms()                //@12.000MHz
{
        unsigned char i, j;

        i = 12;
        j = 169;
        do
        {
                while (--j);
        } while (--i);
}

/*void delay10us()                //@12.000MHz
{
        unsigned char i;

        i = 27;
        while (--i);
}  */

void delayms(unsigned int n)                 //毫秒延时
{
        while(n--)
        {
                delay1ms();
        }               
}

void display(unsigned char n)           //数码管显示函数
{
                if(n==1)
                {a=1;b=0;c=0;d=1;e=1;f=1;g=1; //1
        }

                if(n==2){a=0;b=0;c=1;f=1;g=0;e=0;d=0; //2
                }

                if(n==3){a=0;b=0;c=0;d=0;e=1;f=1;g=0;  //3
}

                if(n==4){f=0;g=0;a=1;d=1;e=1;b=0;c=0;          //4
}
               
                if(n==5){a=0;b=1;e=1;f=0;g=0;c=0;d=0;          //5
}

                if(n==6){a=0;b=1;f=0;g=0;e=0;d=0;c=0;          //6
}

                if(n==7){a=0;b=0;c=0;d=1;e=1;f=1;g=1;          //7
}

                if(n==8){a=0;b=0;c=0;d=0;e=0;f=0;g=0;          //8
}
               
                if(n==9){a=0;b=0;c=0;d=0;e=1;f=0;g=0;          //9
}

                if(n==0){a=0;b=0;c=0;d=0;f=0;e=0;g=1;          //0
                }
}

void display_adc(unsigned int b)   //b=1234                //计算函数
{
        data1=b/1000;                // 千位         1234/1000=1
        data2=b%1000/100;  // 百位        1234%1000/100=2
        data3=b%100/10;           // 十位        1234%100/10=3
        data4=b%10;                   // 个位        1234%10=4
}
u8 adc_contr(u8 ch)           //ad转换函数+通道选择
{
                ADC_CONTR=0;   //清空adc-contr
                ADC_RES=0;
                delayms(1);                //延迟5ms
                ADC_CONTR=ch|0x88;         //10001111  打开adc转换电源,速度默认,打开adc转换,启用p17管脚ad转换
                delayms(5);        //延迟1ms保障数据可以写入
                while(!(ADC_CONTR&0x10));
                ADC_CONTR&=0x67; //关闭adc电源,关闭adc转换
                delayms(1);
                return ADC_RES;
        //        adc1=ADC_RES;//读出外部基准值
        //        ADC_RES=0;//清空adc——res的值       
}

void main()
{
        u16 adc,adc1,adc2,c,b/*,d*/;
        P1M1=0xff;          //设置io模式                p1口为高阻态
        P1ASF=0xc0;         //设置io工作模式        p17.p16为ad输入,p17为外部基准输入
        P2=0;
        P0=0xff;
        while(1)
        {
                       
                delayms(3);
                c++;
                if(c>100)        //0.5秒转换一次
                {
                c=0;
                adc1=adc_contr(7);//基准电压值
                adc2=adc_contr(6);//测量电压值

                adc=243*adc2/adc1;           //基准是243,计算被测电压
        //        adc=adc*4;
        /*        adc=adc*2;                            这些是10位精度时的程序,现在是8位精度,所以注释起来了
                adc=adc*10/51;
                adc<<=2;
                d=ADC_RESL;
                d&=0x03;
                adc|=d;          */
                display_adc(adc);         //显示被测电压
                }
                b++;
                if(b>=4)
                {
                        b=0;
                }
                if(b==0)
                {
                        P2=0xfe;
                        display(data1);
                }
                if(b==1)
                {
                        P2=0xfd;
                        display(data2);
                }
                if(b==2)
                {
                        P2=0xfb;
                        display(data3);
                }
                if(b==3)
                {
                        P2=0xf7;
                        display(data4);
                }
                               
        }               
}

 楼主| 发表于 2017-1-12 13:47:30 | 显示全部楼层
来几张爆照
用stc12自带ad做电压表 电压表 作者:w6125818 9608
用stc12自带ad做电压表 电压表 作者:w6125818 633
用stc12自带ad做电压表 电压表 作者:w6125818 9268
发表于 2017-1-12 14:11:26 | 显示全部楼层
#include<STC15.H>
#include<delay.h>
#include<STCAD.H>
#include<IO.C>
void AD_Init() //AD初始化
{
P1M1=0xF0; //设置相应的I/O口为高阻 P1.4-P1.5-P1.6-P1.7
P1M0=0x00;
ADC_RES=0; //
ADC_RESL=0; //ADC转换结果寄存器清0
P1ASF=0xF0; //设置相应的I/O口为ADC模拟通道 P1.4-P1.5-P1.6-P1.7
ADC_CONTR |= ADC_POWER; //打开AD转换电源
ADC_CONTR |= ADC_SPEEDH; //设置AD转换速度
delay(1);
}
uint ADC_result(uchar x) //AD转换结果
{
uint result;
ADC_CONTR& = 0xF8; //清通道
ADC_CONTR |= x; //切换通道,x为通道,如x=5,就是P1.5
delay_us(30); //切换通道延时
ADC_CONTR |= ADC_START; //开启AD转换
delay_us(4); //
while(!(ADC_CONTR& ADC_FLAG)); //等待AD转换结束
ADC_CONTR& = ~ADC_FLAG; //清除AD转换结束标志位
result = ADC_RES<< 2; //ADC高8位结果左移2位
result = result | ADC_RESL; //合成10位转换结果
return result; //返回转换结果
}
uint U(uchar x) //测量电压40次去除最大最小求平均
{
uint U[40],min,max,S;
uchar i;
for(i=0;i<40;i++)
{
U[i]=ADC_result(x); //获取x通道ADC结果
}
for(i=1,min=U[0];i<=39;i++)
{
if(U[i]<min) min=U[i]; //求最小值
}
for(i=1,max=U[0];i<=39;i++)
{
if(U[i]>max) max=U[i];
} //求最大值
for(i=0,S=0;i<=39;i++) S+=U[i];
S=S-min-max;
S /= 38 ; //减去最大最小求平均
return S; //返回计算结果
}
发表于 2017-1-12 14:21:18 | 显示全部楼层
上面的代码就是带ADC软件滤波的
调用u int(x);函数就可以转换了
括号里的X代表你想要转换的通道1/8
程序的大概意思和萝莉大神的
延时函数很像
意思就是uint ADC_result函数被 uint u函数调用然后转换40次掐头去尾÷平均值
你滤波想滤波多少次就该下参数就可以


 楼主| 发表于 2017-1-12 14:41:31 | 显示全部楼层
ldy7474 发表于 2017-1-12 14:21
上面的代码就是带ADC软件滤波的
调用u int(x);函数就可以转换了
括号里的X代表你想要转换的通道1/8

这个代码我也看了,他这个只是一部分,没有主函数
发表于 2017-1-12 14:46:45 | 显示全部楼层
小样学晕了吧你直接在主函数调用int u();括号里写上你要转换的通道号就可以你可以这样写ADC=u int(1);这样写你不就把1通道的值传递给ADC这个变量了吗  
发表于 2017-1-12 14:50:17 | 显示全部楼层
变量再拆成个 十 白 千 传递到dats1/4这几个变量中调用dasplay(data1);不就可以显示了呵呵
发表于 2017-1-12 16:17:34 | 显示全部楼层
这个你得上单片机网站求助。
发表于 2017-1-12 18:53:13 | 显示全部楼层
顶一个
发表于 2017-1-15 01:24:53 | 显示全部楼层
高手啊!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|关于模吧|APP下载|广告报价|小黑屋|手机版|企业会员|商城入驻|联系我们|模吧 ( 冀公网安备13080502000084号 )

© 2013-2020 Moz8.com 模吧,玩出精彩!