以下是7位半的程序
不过,7位半测到了100nV,我的电路噪声大,最后一字(第8位)跳得很历害。最后第二字不会跳。
菜单5由两个参数合成,二阶滤波的两个系数,一并放在菜单5,如系数1是5,系数2是6,则应在菜单5中写入605
菜单0中,按下K2,可以在“无矫正”“有矫正7字”“有矫正8字”三种状态下显示。
- /*************************************
- 6位半LTC2400驱动程序
- xjw01 于莆田 2011.7
- **************************************/
- //====================================
- #define uchar unsigned char
- #define uint unsigned int
- #define ulong unsigned long
- #include <reg52.h>
- #include <math.h>
- void delay(uint loop) { uint i; for(i=0;i<loop;i++); } //延时函数
- //void delay2(uint k){ for(;k>0;k--) delay(10000); } //长延时,k=100大约对应1秒
- //============================EEPROW偏程=========================
- sfr IAP_data = 0xC2;
- sfr IAP_addrH = 0xC3;
- sfr IAP_addrL = 0xC4;
- sfr IAP_cmd = 0xC5;
- sfr IAP_trig = 0xC6;
- sfr IAP_contr = 0xC7;
- /********************
- 写字节时,可以将原有数据中的1改为0,无法将0改为1,只能使用擦除命令将0改为1
- 应注意,擦除命令会将整个扇区擦除
- *********************/
- uchar readEEP(uint k){ //读取
- IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
- IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
- IAP_contr = 0x80; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
- IAP_cmd = 1; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
- IAP_trig = 0x5A; //先送5A
- IAP_trig = 0xA5; //先送5A再送A5立即触发
- return IAP_data;
- }
- void writeEEP(uint k, uchar da){ //写入
- IAP_data = da; //传入数据
- IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
- IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
- IAP_contr = 0x80; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
- IAP_cmd = 2; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
- IAP_trig = 0x5A; //先送5A
- IAP_trig = 0xA5; //先送5A再送A5立即触发
- }
- void eraseEEP(uint k){ //擦除
- IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
- IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
- IAP_contr = 0x80; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
- IAP_cmd = 3; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
- IAP_trig = 0x5A; //先送5A
- IAP_trig = 0xA5; //先送5A再送A5立即触发
- }
- xdata struct Ida{
- int xz0; //零点偏移
- int xz1; //中点偏移
- int FC0; //满程低4位
- int FC1; //满程高4位
- int en;
- } cs;
- void cs_RW(char rw){
- uchar i,*p = &cs;
- if(rw){
- eraseEEP(0);
- for(i=0;i<sizeof(cs);i++) writeEEP(i,p[i]);
- }else{
- for(i=0;i<sizeof(cs);i++) p[i]=readEEP(i);
- }
- }
- /**********
- 字形编码图
- 32
- -
- 64| | 128
- - 16
- 1| | 8
- _. 4
- 2
- **********/
- uchar code zk[20]={235,136,179,186,216,122,123,168,251,250}; //字库
- uchar disp[7]={235,136,179,186,216,122,123};
- sfr P1M1=0x91; //P1端口设置寄存器
- sfr P1M0=0x92; //P1端口设置寄存器
- sfr P0M1=0x93; //P0端口设置寄存器
- sfr P0M0=0x94; //P0端口设置寄存器
- sfr P2M1=0x95; //P2端口设置寄存器
- sfr P2M0=0x96; //P2端口设置寄存器
- sfr P3M1=0xB1; //P3端口设置寄存器
- sfr P3M0=0xB2; //P3端口设置寄存器
- sbit ds0=P2^1; //数码管扫描口
- sbit ds1=P2^2; //数码管扫描口
- sbit ds2=P2^3; //数码管扫描口
- sbit ds3=P2^4; //数码管扫描口
- sbit ds4=P2^5; //数码管扫描口
- sbit ds5=P2^6; //数码管扫描口
- sbit ds6=P2^7; //数码管扫描口
- sbit K0=P3^4; //键盘
- sbit K1=P3^5; //键盘
- sbit K2=P3^6; //键盘
- sbit K3=P3^7; //键盘
- //功能程序开始
- void cls(){ char i; for(i=0;i<7;i++) disp[i]=0; } //清屏
- void showDig(long f){ //显示数字
- uchar i;
- cls();
- for(i=0;i<7;i++) { disp[i]=zk[f%10], f/=10; if(!f) break; }
- }
- sbit P_SCK=P1^0; //时钟
- sbit P_SDO=P1^1; //数据
- sbit P_CS =P1^2; //片选
- long pv=0,pv2=0,Um=0; //滤波的积分器
- long Ux=0; //滤波输出
- char ms=1; //数据处理模式
- void get_adc(){
- //注意:长整形不可直接与float相加,否则损精度,必要时采用强制转换防止损度损失
- char i,en,en2;
- long v=0,vc,vm; //AD转换结果
- float n; //插值因子
- long f = cs.FC0+cs.FC1*10000L; //满量程定标值
- if(P_SDO) return; //检测转换状态
- if(ms==2) en = cs.en/100; //取模式2下的滤波参数
- for(i=0;i<32;i++){ //读取串行数据
- P_SCK = 1; delay(1);
- v <<= 1;
- if(P_SDO) v++;
- P_SCK = 0; delay(1);
- }
- v = v/16-0x02000000; //截取24bit,并处理符号位
- v*=10, vm = v/10000, vc = v%10000;
- en = cs.en%100; if(!en) en=1; //一阶滤波步长
- en2= cs.en/100; if(!en2) en2=1; //二阶滤波步长
- if(labs(Ux-v)<1000 ){ //限幅二阶滤波
- vc += (vm-Um)*10000L;
- pv += vc - pv/en;
- pv2 += pv - pv2/en2;
- }else Um=vm, pv=vc*en, pv2 = pv*en2;
- Ux = Um*10000L + pv2/en2/en;
- n = 0.1*Ux/0x01000000; if(n<0||n>1) n =0; //抛物线插值因子
- for(i=0,v=0;i<8;i++) v += Ux*(f&7), v>>=3, f>>=3; //尺长变换
- if(ms!=0) v -= (int) ( (cs.xz0 + cs.xz1*n*(1-n)*4)*10 );//非线性改正
- if(ms!=2) v /= 10; //不扩展字数
- showDig(labs(v)); //显示
- if(v<0) disp[6] += 16; //显示负号
- if(ms==1) disp[0]+=4; //标识已矫正
- if(ms==2) disp[1]+=4; //标识已矫正并扩展
- }
- int inc_cs(int a,char d){ //a的d位加1
- char i,f=1;
- int v=10;
- if(d<0) return a;
- if(d==5) return -a;
- if(a<0) a=-a,f=-1;
- for(i=0;i<d;i++) v*=10;
- if(a%v+v/10 < v) return f*(a+v/10);
- else return f*(a+v/10-v);
- }
- main(){
- uchar dispN=0; char nx=0; //显示扫描索引
- uchar menu=0,gb=-1,kn=0,K,zz=0;
- int *p;
- P2M0 = 0xFE; //P2.1234567置为推勉输出
- //P1M0 = 0x05; //P1.02置为推勉输出
- //P1M1 = 0x02; //P1.1置为高阻抗
- //P3M0 = 0x0C; //P3.23置为推勉输出口
- delay(20000);
- P_CS=1; delay(1);
- P_SCK=0;delay(1);
- P_CS=0;
-
- cs_RW(0);
- if(cs.en<0){ cs.xz0=0, cs.xz1=0, cs.FC0=0, cs.FC1=500, cs.en=406; cs_RW(1); }
- while(1){
- //显示disp
- dispN = (++dispN)%7; //扫描器移动
- nx++; if(nx>100)nx-=200;
- ds0=ds1=ds2=ds3=ds4=ds5=ds6=0;
- if(dispN==0) ds0=1;
- if(dispN==1) ds1=1;
- if(dispN==2) ds2=1;
- if(dispN==3) ds3=1;
- if(dispN==4) ds4=1;
- if(dispN==5) ds5=1;
- if(dispN==6) ds6=1;
- if(dispN==gb && nx>0) P0 = 255; //不显示
- else P0 = ~disp[dispN]; //显示
- K = ( ~(P3>>4) ) & 15;
- if(K) { if(kn<255) kn++; } else kn = 0; //判断是否有按键按下
- if(kn!=20) K=0; //按下时间不够长,键值无产
- if(K==1) { menu++; if(menu>5) menu=0,gb=-1; else gb=0; } //切换菜单
- if(menu==0) { //读取AD电压
- if(K==2) ms=(++ms)%3; //设置显示模式
- get_adc();
- }
- if(menu>=1&&menu<=5){
- if(menu==1) p = &cs.xz0;
- if(menu==2) p = &cs.xz1;
- if(menu==3) p = &cs.FC0;
- if(menu==4) p = &cs.FC1;
- if(menu==5) p = &cs.en;
- if(K==2) { gb++; if(gb>5) gb=0; } //光标键
- if(K==4) cs_RW(1); //保存
- if(K==8) *p = inc_cs(*p,gb); //改值
- showDig( abs(*p) );
- if(*p<0) disp[5]=16; //显示负号
- disp[6] = zk[menu]; //显示菜单号
- disp[gb]+=4; //用小数点表示光标
- }
- delay(4000);
- }//while end
- }
复制代码 |