|

楼主 |
发表于 2011-8-11 21:30:36
|
显示全部楼层
天风雪雨老师调试,发现图画错了。
故重新发一个。
程序也做了改动,原来的程序有点问题,EEPROM读取有时不正常。
- /*************************************
- 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);
- }
- }
- //============================串口偏程=========================
- #define reN 8
- xdata uchar reB[reN+1]={0}, reC=0; //串口接收缓冲区,reC串接收完成标识。
- sfr BRT = 0x9c; //独立波特率发生器重装寄存器
- sfr AUXR = 0x8e; //BRT控制寄存器
- void initial(void){
- SCON=0x50; //串口工作方式1(8bit),允许接收
- PCON=0x80; //波特率翻倍
- AUXR=0x15; //BRT以1T运行,选择BRT,启动BRT
- BRT = 0xef; //115200
- EA=1; //开总中断
- ES=1; //开串口中断
- REN=1; //允许接收
- }
- void sendB(char c){ //发送字节
- REN=0; //发送过程中禁止接收数据
- ES=0, TI=0; //关串口中断,中断标识置0
- SBUF = c;
- while( !TI );
- TI=0, ES=1; //关串口中断,中断标识置0
- REN=1; //允许接收
- }
- void sendS(char *B, char n){ //发送数组
- char i;
- for(i=0; i<n && B[i]; i++) sendB(B[i]);
- }
- void sendI(long a){ //发送整数
- xdata char i, B[10];
- if(a<0) sendB('-'), a = -a;
- else sendB('+');
- for(i=0;i<10;i++) B[9-i] = a%10+48, a /= 10;
- sendS(B,10);
- sendB('\r');
- sendB('\n');
- }
- void serial(void) interrupt 4 { //串口中断处理
- static char n=0;
- if(TI){ TI=0; return; } //处理发送中断
- RI=0; //清接收中断标志
- if(SBUF=='e') reC=1, reB[n++] = 0, n=0; //行结束标识
- else reC=0, reB[n++] = SBUF; //读入数据
- if(n>=reN) n=0;
- }
- //============================主程序=========================
- /**********
- 字形编码图
- 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; //片选
- xdata long pv1=0,pv2=0,pvm=0; //滤波的积分器(算法一)
- xdata float av1=0,av2=0; char avn=0; //滤波的积分器(算法二)
- xdata long Ux=0; //滤波输出
- char ms=1; //数据处理模式
- char upv=0;
- void get_adc(){
- //注意:长整形不可直接与float相加,否则损精度,必要时采用强制转换防止损度损失
- char i,en1,en2;
- long v=0; //AD转换结果
- float n; //插值因子
- long f = cs.FC0+cs.FC1*10000L; //满量程定标值
- if(P_SDO) return; //检测转换状态
- 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;
- en1 = cs.en%100; //一阶滤波步长
- en2 = cs.en/100; //二阶滤波步长
- if(!en1) en1 = 1;
- if(en2){ //滞后滤波法
- long vm = v/10000, vc = v%10000;
- if(labs(Ux-v)<1000 ){ //限幅二阶滤波
- vc += (vm-pvm)*10000L;
- pv1 += vc - pv1/en1;
- pv2 += pv1 - pv2/en2;
- }else pvm=vm, pv1=vc*en1, pv2 = pv1*en2;
- Ux = pvm*10000L + pv2/en2/en1;
- }else{ //加权平均值法
- av2 += v, avn++;
- if(avn>=en1) avn=0, av1=av2, av2=0;
- Ux = ( av1-av1*avn/en1 + av2 ) / en1;
- }
- 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(upv) sendI(v); //上载数据
- 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置为推勉输出口
- delay2(40);
- P_CS=1; delay(1);
- P_SCK=0;delay(1);
- P_CS=0;
- cs_RW(0); //读EEPROW须在上电之后200ms
- if(cs.en<0){ cs.xz0=0, cs.xz1=0, cs.FC0=0, cs.FC1=500, cs.en=406; cs_RW(1); }
- initial();//串口初始化
- while(1){
- if(reC){
- if(reB[0]=='a' && reB[1]=='0') upv=1; //发送电压指令
- if(reB[0]=='a' && reB[1]=='1') upv=0; //停止电压指令
- reC=0;
- }
- //显示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
- }
复制代码
菜单更改如下:
9、菜单使用方法:
1)K1键,切换换菜单,每按一次,会在菜单0、1、2、3、4、5之间切换。
2)菜单0是默认菜单,显示已进行非线性矫正的AD转换结果。在菜单0下,按下K2键,可以分别显示三种结果:未矫正值(无小数点)、已桥正值(末位出现小数点)、已矫正且显示到第7位(倒数第二位出现小数点)
3)菜单1设置零点偏移字数;菜单2设置中点非线性误差;
4)菜单3设置满量程字数的低4位;菜单4设置满量程字数的高3位
5)菜单5,设置滤波器步长。个位和十位设置第一阶滤波器长度,百位和千位设置第二阶滤波器长度。第二阶设置为1,相当于一个一阶滤波器,第二阶设置为0,程序转为多点平均法滤波,平均个数由个位和百位设置。
如,置为310,二阶为3,一阶为10。置为10,是10点平均滑动滤波。置为11,是一阶滤波。
6)在菜单1至5中,K2是光标移动键,K3是保存键,K4是更改键。光标移动到第6位,更改正负号。第7位显示菜单号。 |
|