/* *********************************************************************** ** 系统程序:多路信号实时采集和处理,并将处理后的数据以不同的 ** 方式显示.同时可根据按键输入实现任务调度. ** 时 间:2005/08/05. *************************************************************************** */ #include "pic18f458.h" //PIC18F458单片机头文件. #include "math.h" //C语言头文件. #include "stdlib.h" //C语言头文件. #define PI 6.283 //"HELP界面" const char HELP[3][64]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x83,0x7D,0x5D,0x9B,0xFF,0x81,0x7F,0x7F,0x81,0xFF,0x7D,0x01, 0x7D,0xFF,0x7D,0x01,0x7D,0x7D,0x83,0xFF,0x01,0x6D,0x6D,0x6D,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x83,0x7D,0x7D,0x83,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7B,0x01,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3B,0x5D,0x6D,0x73,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0x6D,0x6D,0x93,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xE7,0xC3,0x81,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0x81,0xC3,0xE7,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x81,0xBD,0xBD,0x81,0xFF,0x81,0xEF,0xD7,0xBB,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0x81,0xEF,0xEF,0x81,0xFF,0x81,0xBF,0xBF,0xBF,0xFF,0xFF,0xFF,}; // "A相 B相 C相 三相 HELP" const char ABC[20][8]={0x00,0x3E,0x41,0x41,0x22,0x00,0x7F,0x08,0x08,0x7F,0x00,0x7F,0x41,0x41,0x7F,0x00, 0x7F,0x41,0x41,0x7F,0x00,0x26,0x49,0x49,0x32,0x00,0x7F,0x49,0x49,0x49,0x00,0x00, 0x00,0x40,0x7C,0x13,0x13,0x7C,0x40,0x14,0x0C,0x7F,0x14,0x04,0x7F,0x55,0x55,0x7F, 0x00,0x41,0x7F,0x49,0x49,0x36,0x00,0x14,0x0C,0x7F,0x14,0x04,0x7F,0x55,0x55,0x7F, 0x00,0x3E,0x41,0x41,0x41,0x22,0x00,0x14,0x0C,0x7F,0x14,0x04,0x7F,0x55,0x55,0x7F, 0x00,0x20,0x2A,0x2A,0x2A,0x2A,0x20,0x14,0x0C,0x7F,0x14,0x04,0x7F,0x55,0x55,0x7F, 0x26,0x49,0x49,0x32,0x00,0x7F,0x49,0x49,0x49,0x00,0x01,0x01,0x7F,0x01,0x01,0x00, 0x00,0x7F,0x08,0x08,0x7F,0x00,0x7F,0x49,0x49,0x49,0x00,0x41,0x7F,0x41,0x00,0x00, 0x00,0x01,0x47,0x48,0x28,0x1F,0x00,0x7F,0x49,0x49,0x49,0x00,0x26,0x49,0x49,0x32, 0x7F,0x08,0x08,0x7F,0x00,0x7F,0x49,0x49,0x00,0x7F,0x40,0x40,0x41,0x7F,0x51,0X0E,}; //"U1 U2 U3" const char UB[3][8]={0x3F,0x40,0x40,0x3F,0x00,0x42,0x7F,0x40,0x3F,0x40,0x40,0x3F,0x62,0x51,0x49,0x46, 0x3F,0x40,0x40,0x3F,0x22,0x49,0x49,0x36,}; //"I1 I2 I3" const char IB[3][8]={0x41,0x7F,0x41,0x00,0x42,0x7F,0x40,0x00,0x41,0x7F,0x41,0x62,0x51,0x49,0x46,0x00, 0x41,0x7F,0x41,0x22,0x49,0x49,0x36,0x00,}; //"P1 P2 P3" const char PB[3][8]={0x41,0x7F,0x49,0x06,0x00,0x42,0x7F,0x40,0x41,0x7F,0x49,0x06,0x62,0x51,0x49,0x46, 0x41,0x7F,0x49,0x06,0x22,0x49,0x49,0x36,}; //"Q1 Q2 Q3" const char QB[3][8]={0x3E,0x51,0x61,0x3E,0x00,0x42,0x7F,0x40,0x3E,0x51,0x61,0x3E,0x62,0x51,0x49,0x46, 0x3E,0x51,0x61,0x3E,0x22,0x49,0x49,0x36,}; //"S1 S2 S3" const char SB[3][8]={0x26,0x49,0x49,0x32,0x00,0x42,0x7F,0x40,0x26,0x49,0x49,0x32,0x62,0x51,0x49,0x46, 0x26,0x49,0x49,0x32,0x22,0x49,0x49,0x36,}; // "φ1 φ2 φ3" const char LB[3][8]={0x3E,0x49,0x49,0x3E,0x00,0x42,0x7F,0x40,0x3E,0x49,0x49,0x3E,0x62,0x51,0x49,0x46, 0x3E,0x49,0x49,0x3E,0x22,0x49,0x49,0x36,}; // "φ1 φ2 φ3" const char FB[3][8]={0x7F,0x09,0x09,0x00,0x42,0x7F,0x40,0x00,0x7F,0x09,0x09,0x62,0x51,0x49,0x46,0x00, 0x7F,0x09,0x09,0x22,0x49,0x49,0x36,0x00,}; //"+ - % " const char JS[8]={0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,}; const char JC[8]={0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00,}; const char JJ[8]={0x00,0x00,0x00,0x44,0x44,0x5F,0x44,0x44,}; const char BH[8]={0x00,0x40,0x26,0x16,0x68,0x64,0x02,0x00,}; //"0 1 2 3 4 5 6 7 8 9 0. 1. 2. 3. 4. 5. 6. 7. 8. 9." const char NUM[20][8]={0x00,0x00,0x00,0x3E,0x41,0x41,0x3E,0x00,0x00,0x00,0x00,0x00,0x42,0x7F,0x40,0x00, 0x00,0x00,0x00,0x62,0x51,0x49,0x46,0x00,0x00,0x00,0x00,0x22,0x49,0x49,0x36,0x00, 0x00,0x00,0x18,0x14,0x13,0x7F,0x10,0x00,0x00,0x00,0x00,0x37,0x45,0x45,0x39,0x00, 0x00,0x00,0x00,0x3E,0x49,0x49,0x32,0x00,0x00,0x00,0x00,0x01,0x79,0x05,0x03,0x00, 0x00,0x00,0x00,0x36,0x49,0x49,0x36,0x00,0x00,0x00,0x00,0x26,0x49,0x49,0x3E,0x00, 0x00,0x00,0x3E,0x41,0x41,0x3E,0x00,0x40,0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x40, 0x00,0x00,0x62,0x51,0x49,0x46,0x00,0x40,0x00,0x00,0x22,0x49,0x49,0x36,0x00,0x40, 0x00,0x00,0x18,0x14,0x13,0x7F,0x10,0x40,0x00,0x00,0x37,0x45,0x45,0x39,0x00,0x40, 0x00,0x00,0x3E,0x49,0x49,0x32,0x00,0x40,0x00,0x00,0x01,0x79,0x05,0x03,0x00,0x40, 0x00,0x00,0x36,0x49,0x49,0x36,0x00,0x40,0x00,0x00,0x26,0x49,0x49,0x3E,0x00,0x40,}; signed int DATA[6][64]; //AD采样数据存储区. int FT[20]; //频率采样数据存储区. //U I P Q S F计算数据存储区. long UI[2][6],UP[2][6],P[3],Q[3],S[3],L[3],F; //MAX197基控制字,采样模式标志,频率采样计数,采样频率调整参数. int ADCAN=0X48,ADMO=1,CCP=0,AD=50,CHX=1; //MAX197控制字,PORTA状态暂存字,PORTB状态暂存字,AD采样计数,按键状态暂存字,AD采样通道标志位. int ADWORDS,ATRL,BTRL,ADD,KEY,CHAN; //按键功能标志位. int MAXD,MAXA,BACK,NEXT,SURE,GUID; /* ************************************************************************ ** 函 数 名:void INITIAL() ** 功能描述:系统初始子程序. *************************************************************************** */ void INITIAL() { INTCON=0X00; //<0000,0000>关总中断. ADCON1=0X07; //<0111,0000>设置数字量输入/输出口. PIE1=0X00; //<0000,0000>关外围中断1. PIE2=0X00; //<0000,0000>关外围中断2. PIE3=0X00; //<0000,0000>关外围中断3. CMCON=0X07; //<0000,0111>关比较器. TRISA=TRISA&0XF0; //设置PORTA<3:0>为输出. TRISB=TRISB&0X0F; //<0000,uuuu>设置PORTB<7:4>为输出. } /* ************************************************************************* ** 函 数 名:void DEALY(long TIME) ** 功能描述:根据TIME给定延时. **************************************************************************** */ void DELAY(long TIME) { long T; //计数参数. for(T=0;T设定TMR3工作于8位定时器方式,使用内部时钟. TMR3IE=1; //TMR3中断允许. TMR3IF=0; //清除TMR3中断标志位. TMR3IP=0; //置TMR3为断为低优先级. IPEN=1; //使能中断优先级. TMR3L=0X9A; //<1111,0101>Focs/4=1us,Focs/4*定时10u } /* ************************************************************************ ** 函 数 名:void CCPINIT() ** 功能描述:对CCP1初始化,以捕捉方式工作. *************************************************************************** */ void CCPINIT() { TRISC2=1; //RC2为输入. T1CON=0XA1; //TMR1作为了16位定时器. PEIE=1; //打开外围中断. CCP1IE=1; //CCP1中使能. CCP1CON=0X05; //CCP1工作在捕捉方式. } /* ************************************************************************ ** 函 数 名:int KEYIN() ** 功能描述:按键扫描子程序,并返回键值. *************************************************************************** */ int KEYIN() { int WORDS; //定义数据入口变量. TRISD=0XFF; //<1111,1111>设置PORTD为输入. PORTA=(PORTA|0X0D)&0XFD; //译码后实现地址选择. WORDS=PORTD; //读取PORTD端口的数据. WORDS=PORTD|WORDS; //按键抖动处理. PORTA=PORTA&0XF0; //屏蔽所有地址. return WORDS; //将读取的数据作为返回值. } /* ************************************************************************ ** 函 数 名:int GATEAIN() ** 功能描述:读取A组开关量,并返回其值. *************************************************************************** */ int GATEAIN() { int WORDS; //定义数据入口变量. TRISD=0XFF; //<1111,1111>设置PORTD为输入. PORTA=(PORTA|0X0B)&0XFB; //译码后实现地址选择. WORDS=PORTD; //读取PORTD端口的数据. PORTA=PORTA&0XF0; //屏蔽所有地址. return WORDS; //将读取的数据作为返回值. } /* ************************************************************************ ** 函 数 名:int GATEBIN() ** 功能描述:读取B组开关量,并返回其值. *************************************************************************** */ int GATEBIN() { int WORDS; //定义数据入口变量. TRISD=0XFF; //<1111,1111>设置PORTD为输入. PORTA=(PORTA|0X0C)&0XFC; //译码后实现地址选择. WORDS=PORTD; //读取PORTD端口的数据. PORTA=PORTA&0XF0; //屏蔽所有地址. return WORDS; //将读取的数据作为返回值. } /* ************************************************************************ ** 函 数 名:void LEDOUT(int WOEDS) ** 功能描述:将数据WORDS输出,并由8个LED显示. *************************************************************************** */ void LEDOUT(int WORDS) { TRISD=0X00; //<0000,0000>设置PORTD为输出. PORTA=(PORTA|0X08)&0XF8; //译码后实现地址选择. PORTD=WORDS; //将数据赋给PORTD端口. PORTA=PORTA&0XF0; //屏蔽所有地址. } /* ************************************************************************ ** 函 数 名:void LCDSTA(int E) ** 功能描述:查询LCD显示器第E片的状态. *************************************************************************** */ void LCDSTA(int E) { int STA; //定义数据入口参数. TRISD=0XFF; //<1111,1111>设置PORTD为输入. while(1) //循环,查询. { if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTB=(PORTB|0X60)&0XEF; //控制信号:可读-读-命令. STA=PORTD&0X80; //读取LCD的状态字Bt7=0/1. PORTB=PORTB&0X8F; //控制信号:锁存数据. if(STA==0X0000) //判断LCD状态是不为空闲. break; //是,跳出查询. } } /* ************************************************************************ ** 函 数 名:void LCDTRA(int TRANS,int E) ** 功能描述:向第E片LCD输入显示地址(TRANS)或命令(TRANS). *************************************************************************** */ void LCDTRA(int TRANS,int E) { TRISD=0X00; //<0000,0000>设置PORTD为输出. if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTD=TRANS; //将数据赋给PORTD端口. PORTB=(PORTB|0X40)&0XCF; //控制信号:可读-写-命令. PORTB=PORTB&0X8F; //控制信号:锁存数据. } /* ************************************************************************ ** 函 数 名:void LCDOUT(char WORDS,int CLMD,int PAGE,int E) ** 功能描述:数据WORDS由PORTD输出,并在第E片LCD的第CLMD列,第PAGE页显示. *************************************************************************** */ void LCDOUT(int WORDS,int CLMD,int PAGE,int E) { LCDTRA(CLMD,E); //设置列地址. LCDTRA(PAGE,E); //设置页地址. TRISD=0X00; //<0000,0000>设置PORTD为输出. if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTD=WORDS; //将数据赋给PORTD端口. DELAY(0); PORTB=(PORTB|0X50)&0XDF; //控制信号:可读-写-命令. PORTB=PORTB&0X8F; //控制信号:锁存数据. } /* ************************************************************************ ** 函 数 名:int LCDIN(int CLMD,int PAGE,int E) ** 功能描述:读取第E片LCD的第CLMD列,第PAGE页的数据. *************************************************************************** */ int LCDIN(int CLMD,int PAGE,int E) { int WORDS; //定义数据入口参数. LCDTRA(CLMD,E); //设置列地址. LCDTRA(PAGE,E); //设置页地址. TRISD=0XFF; //<1111,1111>设置PORTD为输入. if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTB=PORTB|0X70; //控制信号:可读-读-数据. WORDS=PORTD; //空读操作. WORDS=PORTD; //读取PORTD端口数据. PORTB=PORTB&0X8F; //控制信号:锁存数据. return WORDS; //将读取的数据作为返回值. } /* ************************************************************************ ** 函 数 名:void LCDON(int E) ** 功能描述:打开显示,并检查液晶显示器是否被打开. *************************************************************************** */ void LCDON(int E) { int STA; //定义数据入口参数. TRISD=0XFF; //<1111,1111>设置PORTD为输入. while(1) //循环,查询. { LCDTRA(0X3F,E); //打开LCD显示器. LCDSTA(E); //查询LCD的状态. if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTB=(PORTB|0X60)&0XEF; //控制信号:可读-读-命令. STA=PORTD&0X20; //将数据赋给PORTD端口. PORTB=PORTB&0X8F; //控制信号:锁存数据. if(STA==0X00) //LCD显示器是否被打开. break; //打开,跳出循环. } } /* ************************************************************************ ** 函 数 名: void LCDOFF(int E) ** 功能描述:关闭显示,并检查液晶显示器是否被关闭. *************************************************************************** */ void LCDOFF(int E) { int STA; //定义数据入口参数. TRISD=0XFF; //<1111,1111>设置PORTD为输入. while(1) //循环,查询. { LCDTRA(0X3E,E); //关闭LCD显示器. LCDSTA(E); //查询LCD的状态. if(E==1) //选择第E片LCD. PORTA=(PORTA|0X09)&0XF9; //译码后选择第1片LCD. else PORTA=(PORTA|0X0A)&0XFA; //译码后选择第2片LCD. PORTB=(PORTB|0X60)&0XEF; //控制信号:可读-读-命令. STA=PORTD&0X20; //将数据赋给PORTD端口. PORTB=PORTB&0XBF; //控制信号:锁存数据. if(STA==0X20) //LCD显示器是否被关闭. break; //关闭,跳出循环. } } /* ************************************************************************ ** 函 数 名:void LCDCLEAR(int E) ** 功能描述:将液晶显示器清屏. *************************************************************************** */ void LCDCLEAR(int E) { int PAGE,NUM,CLMD; //页地址-增量-列地址. for(NUM=0X08,PAGE=0XB8;NUM>0;NUM--,PAGE++) //页基地址0X80循环累加1. { for(CLMD=0X40;CLMD<=0X7F;CLMD++) //列基地址0X40循环累加1. { LCDOUT(0X00,CLMD,PAGE,E); //向当前地址输入0X00,清屏. } } } /* ************************************************************************ ** 函 数 名:void LCDCLEARA(int CLMD,int PAGE,int CLMDN,int PAGEN,int E) ** 功能描述:选择性清屏,起始列(CLMD)起始页(PAGE)几列(CLMDN)几页(PAGEN). *************************************************************************** */ LCDCLEAN(int CLMD,int PAGE,int CLMDN,int PAGEN) { int C,P,CADD; //计算实际的初始页地址. for(P=PAGE+0XB8;PAGEN>0;PAGEN--,P++) //页基地址0X80循环累加1. { CADD=CLMDN; //计算实际的初始列地址. for(C=CLMD+0x40 ;CADD>0;CADD--,C++) //列基地址0X40循环累加1. { if(C>0X7F) //列地址判断. LCDOUT(0X00,C-64,P,2); //向当前地址输入0X00,清屏. else LCDOUT(0X00,C,P,1); //向当前地址输入0X00,清屏. } } } /* ************************************************************************ ** 函 数 名:LCDINITI(int E) ** 功能描述:LCD初始化程序 *************************************************************************** */ void LCDINITI(int E) { LCDOFF(E); //关闭LCD. LCDCLEAR(E); //清屏. LCDON(E); //打开LCD. } /* ************************************************************************ ** 函 数 名:void LCDCH(char *WORDS,int CLMD,int PAGE) ** 功能描述:向LCD输入汉字点阵(*WORDS)16*16,并以CLMD为初始列,PAGE为初始页. *************************************************************************** */ void LCDCH(const char *WORDS,int CLMD,int PAGE) { const char *ARW; //定义汉字点阵入口数组. int P,C,NUM; //页址-列址-计数脚标. ARW=WORDS; //数组首地址的传递. P=PAGE+0XB8; //计算初始页地址. C=CLMD+0X40; //计算初始列地址. for(NUM=0;NUM<16;NUM++,C++) //列地址累加1,并记录累加次数. { if(C>0X7F) //根据C的值判断在哪片LCD显示. { LCDOUT(ARW[NUM],C-64,P,2); //向第1页当前列输入数据. LCDOUT(ARW[NUM+16],C-64,P+1,2); //向第2页当前列输入数据. } else { LCDOUT(ARW[NUM],C,P,1); //向第1页当前列输入数据. LCDOUT(ARW[NUM+16],C,P+1,1); //向第2页当前列输入数据. } } } /* ************************************************************************ ** 函 数 名:void LCDNUM(char *WORDS,int CLMD,int PAGE) ** 功能描述:向LCD输入字符数字点阵(*WORDS)8*8,并以CLMD为初始列,PAGE为页地址. *************************************************************************** */ void LCDNUM(const char *WORDS,int CLMD,int PAGE) { const char *ARW; //定义数字字符点阵入口数组. int P,C,NUM; //页址-列址-计数脚标. ARW=WORDS; //数组首地址的传递. P=PAGE+0XB8; //计算初始页地址. C=CLMD+0X40; //计算初始列地址. for(NUM=0;NUM<8;NUM++,C++) //列地址累加1,并记录累加次数. { if(C>0X7F) //根据C的值判断在哪片LCD显示 LCDOUT(ARW[NUM],C-64,P,2); //向当前列输入数据. else LCDOUT(ARW[NUM],C,P,1); //向当前列输入数据. } } /* ************************************************************************ ** 函 数 名:void OUTNUM(long N,int D,int CLMD,int PAGE) ** 功能描述:根据参数输出任意数字. *************************************************************************** */ void OUTNUM(long N,int D,int CLMD,int PAGE) { int i; for(i=0;N>0||i<=D;i++) //循环判断. { if(i==D) //个位? LCDNUM(NUM[N%10+10],CLMD,PAGE); //输出带点数. else LCDNUM(NUM[N%10],CLMD,PAGE); //输出无点数. CLMD=CLMD-6; //数字的位置. N=N/10; //取数据某位的数字. } } /* ************************************************************************ ** 函 数 名:void LCDPIEX(int X,int Y) ** 功能描述:根抿坐标(X,Y)在LCD上画点. *************************************************************************** */ void LCDPIEX(int X,int Y) { int i; //定义循环计数的变量. int CLMD,PAGE,ROW,E,DATA; //列-页-行-片-要写的数据-读出的数据. PAGE=0XB8; //第0页的地址. DATA=0X01; //参考数据上. ROW=Y; //取得行. for(i=0;i<8;i++) //循环,多次判断,取得PAGE和数据. { if(ROW<8) //行值小于8,执行if内语句. { PAGE=0XB8+i; //取得页值. DATA=DATA<63) //当列值大于63时. { E=2; //选择第2片LCD. CLMD=(X-64)+64; //取得列值. } else //否则. { E=1; //选择第2片LCD. CLMD=X+64; //取得列值. } DATA=DATA|LCDIN(CLMD,PAGE,E); //求或. LCDOUT(DATA,CLMD,PAGE,E); //向当前地址输入数据. } /* ************************************************************************ ** 函 数 名:void LCDXB(int XBCS,int WORDS) ** 功能描述:根据谐波次数(XBCS),幅度(WORDS)在LCD上自动选择位置显示频谱图. *************************************************************************** */ void LCDXB(int XBCS,int WORDS) { int CLMD,PAGE,i; //列-页-计数参数. CLMD=0X40+XBCS*6; //根据谐波次数计算列值. PAGE=0XB8; //页的初地址. for(WORDS>7;WORDS>7;PAGE++) //页地址累加1,至幅值小于8. { WORDS-8; //幅值减8. for(i=0;i<3;i++) //在相邻3列输出. LCDOUT(0XFF,CLMD+i,PAGE,1); //输出数据. } for(i=0;i<3;i++) //在相邻3列输出. LCDOUT(WORDS,CLMD+i,PAGE,1); //输出最后数据. } /* ************************************************************************ ** 函 数 名:void OUTADC(int WOEDS) ** 功能描述:向MAX197输入控制字. *************************************************************************** */ void OUTADC(int WORDS) { TRISD=0X00; //<0000,0000>设置PORTD为输出. PORTA=(PORTA|0X0E)&0XFE; //译码后实现地址选择. PORTB=(PORTB|0X10)&0XDF; //控制信号:写. PORTD=WORDS; //将数据赋给PORTD端口. PORTB=PORTB|0X30; PORTA=PORTA&0XF0; //屏蔽所有地址. } /* ************************************************************************ ** 函 数 名:int INADC() ** 功能描述:读取MAX197高低12位的AD转换数据. *************************************************************************** */ signed int INADC() { signed int WORDS; //定义数据入口参数. TRISD=0XFF; //<1111,1111>设置PORTD为输入. PORTA=(PORTA|0X0E)&0XFE; //译码后实现地址选择. PORTB=(PORTB|0X60)&0XEF; //控制信号:读高4位数据. WORDS=PORTD&0X0F; //读取PORTD端口数据. PORTB=(PORTB|0X20)&0XAF; //控制信号:读低8位数据. WORDS=PORTD+(WORDS<<8); //读取PORTD端口数据,并与低8位求和. PORTB=PORTB|0X30; //屏蔽所有地址. PORTA=PORTA&0XF0; //将读取的数据作为返回值. if(CHX==1) //双极性? { WORDS=WORDS<<4; //数据左对齐. WORDS=WORDS/16; //得到最终数据. } return WORDS; //返回数据. } /* ************************************************************************ ** 函 数 名:void ADCHX() ** 功能描述:根据参数进行双通道AD采样. *************************************************************************** */ void ADCHX() { for(ADD=0;ADD<64;ADD++) //采样64点. { OUTADC(ADWORDS); //送第一路AD控制字. DELAY(0); //延时. DATA[CHAN*2][ADD]=INADC(); //读取第一路AD转换数据. OUTADC(ADWORDS+1); //送第二路AD控制字. DELAY(0); //延时. DATA[1+CHAN*2][ADD]=INADC(); //读取第二路AD转换数据. DELAY(AD); //延时控制采样频率. } } /* ************************************************************************ ** 函 数 名:void ADSHOW() ** 功能描述:数据处理后显示两路信号波形. *************************************************************************** */ void ADSHOW() { int CH1,CH2; signed int data; //取数据,显示位置. if(CHX==0) //单极性采样. { CH1=40; //波形位置. CH2=60; //波形位置. } else { CH1=20; //波形位置. CH2=40; //波形位置. } LCDCLEAR(2); //清屏. for(ADD=0;ADD<64;ADD++) //64点. { data=(signed int)(40.0*DATA[CHAN*2][ADD]/4096.0); //数据处理. LCDPIEX(ADD+64,CH1-data); //输出显示. data=(signed int)(40.0*DATA[1+CHAN*2][ADD]/4096.0); //数据处理. LCDPIEX(ADD+64,CH2-data); //输出显示. } } /* ************************************************************************ ** 函 数 名:void ADCHD() ** 功能描述:单通道高频采样,数据处理,显示. *************************************************************************** */ void ADCHD() { long D,SHU; //数据. int n_x,k_x,i; //循环参数. float Ur,Ui,Urn,Uin; //数据处理中间变量. ADWORDS=ADCAN+7; //确定MAX197控制字. for(ADD=0;ADD<64;ADD++) //采样. { OUTADC(ADWORDS); //送控制字. DELAY(0); //延时. DATA[0][ADD]=INADC(); //读取数据. } for(ADD=0;ADD<64;ADD++) //显示波形. { D=(int)(40.0*DATA[0][ADD]/4096.0); //取数据. LCDPIEX(ADD+64,40-D); //显示. } for(n_x=0;n_x<5;n_x++) //计算. { Urn=0.0; //实部. Uin=0.0; //虚部. for(k_x=0;k_x<32;k_x++) //n_x次谐波. { D=DATA[0][k_x]; //取数据计算. Urn=Urn+D/409.6*cos((2*n_x+1)*(k_x+1)*0.196); Uin=Uin+D/409.6*sin((2*n_x+1)*(k_x+1)*0.196); } Ur=Urn/16.0; // Ui=Uin/16.0; // SHU=(long)(100*sqrt(Ur*Ur+Ui*Ui)); UI[0][n_x]=SHU; //第n_x次谐波幅值. UI[0][5]=SHU*SHU+UI[0][5]; // } UI[0][5]=(long)sqrt(UI[0][5]); //总幅值. for(i=0;i<5;i++) // { SHU=UI[0][i]*1000; // SHU=SHU/(UI[0][5]); // UP[0][i]=SHU; //第i次谐波占有率. } SHU=1000*(UI[0][5]-UI[0][0]); // UP[0][5]=SHU/UI[0][5]; //畸变率. LCDCLEAN(12,2,126,7); //清除数据显示区. for(i=0;i<6;i++) { OUTNUM(UI[0][i],1,28,2+i); //显示幅值. OUTNUM(UP[0][i],3,56,2+i); //显示占有率. } ADWORDS=ADCAN; //还原控制字. } /* ************************************************************************ ** 函 数 名:void XBFX() ** 功能描述:全周波傅立叶积分计算各次谐波的幅值,并返回结果. *************************************************************************** */ void XBFX() { long D,SHU; //数据. int n_x,k_x,i,n; //循环参数. float Ur,Ui,Urn,Uin,UIL[2]; //数据处理中间变量. for(n=0;n<2;n++) //两路信号. { for(n_x=0;n_x<5;n_x++) //计算. { Urn=0.0; //实部. Uin=0.0; //虚部. for(k_x=0;k_x<32;k_x++) //n_x次谐波. { D=DATA[CHAN*2+n][k_x]; //取数据计算. Urn=Urn+D/409.6*cos((2*n_x+1)*(k_x+1)*0.196); Uin=Uin+D/409.6*sin((2*n_x+1)*(k_x+1)*0.196); } Ur=Urn/16.0; // Ui=Uin/16.0; SHU=(long)(760*sqrt(Ur*Ur+Ui*Ui)); // UI[n][n_x]=SHU; // UI[n][5]=SHU*SHU+UI[n][5]; //第n_x次谐波幅值. if(n_x==0) UIL[n]=atan(Ui/Ur); //相位. } UI[n][5]=(long)sqrt(UI[n][5]); //总幅值. for(i=0;i<5;i++) // { SHU=UI[n][i]*1000; // SHU=SHU/(UI[n][5]); // UP[n][i]=SHU; //第i次谐波占有率. } SHU=1000*(UI[n][5]-UI[n][0]); // UP[n][5]=SHU/UI[n][5]; //畸变率. } L[CHAN]=abs((long)(1000*(UIL[0]-UIL[1])-40)); //功率因数角. S[CHAN]=(long)(UI[0][5]*UI[1][5]); //S. P[CHAN]=(long)(S[CHAN]*cos(L[CHAN]/1000.0)); //P. Q[CHAN]=(long)(S[CHAN]*sin(L[CHAN]/1000.0)); //Q. } /* *********************************************************************** ** 函 数 名:void ABCSH() ** 功能描述:显示双通道数据处理结果. ************************************************************************** */ void ABCSH() { LCDCLEAN(12,1,50,7); //清除数据显示区. OUTNUM(UI[0][5],1,54,1); //显示U*值. OUTNUM(UI[1][5],1,54,2); //显示I*值. OUTNUM(P[CHAN],2,54,3); //显示P*值. OUTNUM(Q[CHAN],2,54,4); //显示Q*值. OUTNUM(S[CHAN],2,54,5); //显示S*值. OUTNUM(L[CHAN],3,54,6); //显示L*值. OUTNUM(F,2,54,7); //显示F*值. } /* *********************************************************************** ** 函 数 名:void XBSH() ** 功能描述:谐波分析结果显示. ************************************************************************** */ void XBSH() { int n,i; //参数. LCDCLEAN(12,2,126,7); //清除数据显示区. for(n=0;n<2;n++) // { for(i=0;i<6;i++) // { OUTNUM(UI[n][i],1,28+n*64,2+i); //显示第i次谐波. OUTNUM(UP[n][i],3,56+n*64,2+i); //显示第i次谐波占有率. } } } /* *********************************************************************** ** 函 数 名:void ADALLSH() ** 功能描述:多通道数据处结果显示. ************************************************************************** */ void ADALLSH() { OUTNUM(UI[0][5],1,40,(2+CHAN)); //显示U*值. OUTNUM(UI[1][5],1,40,(5+CHAN)); //显示I*值. OUTNUM(P[CHAN],2,114,(2+CHAN)); //显示P*值. OUTNUM(Q[CHAN],2,114,(5+CHAN)); //显示Q*值. } /* *********************************************************************** ** 函 数 名:void ADALL() ** 功能描述:多通道采样处理显示. ************************************************************************** */ void ADALL() { LCDCLEAN(10,2,50,6); //清除数据显示区. LCDCLEAN(76,2,50,6); //清除数据显示区. for(CHAN=0;CHAN<3;CHAN++) // { ADWORDS=ADCAN+CHAN*2; //确定控制字. ADALLSH(); //显示. ADCHX(); //采样. XBFX(); //计算. } CHAN=0; //还原通道. ADWORDS=ADCAN; //还原控制字. } /* *********************************************************************** ** 函 数 名:void PLJS() ** 功能描述:计算频率. ************************************************************************** */ void PLJS() { int i,QH,FF[5]; //参数. QH=(CCP>9)?0:10; //判断取数位置. for(i=0;i<5;i++) // { FF[i]=FT[i+QH]; //取数. } F=(FF[4]>FF[3])?(FF[4]-FF[3]):(FF[4]+65536-FF[3]); F=(long)(100000000/F); //判断,并计算频率. } /* *********************************************************************** ** 函 数 名:void CYTZ() ** 功能描述:零点检测法,采样频率调整. ************************************************************************** */ void CYTZ() { int i,n,PL[2]; //参数. while(1) { ADCHX(); //AD采样. for(i=0,n=0;n<2;i++) //零点判断. { if(DATA[CHAN*2][i-1]<=DATA[CHAN*2][i]&&DATA[CHAN*2][i]>=DATA[CHAN*2][i+1]) { PL[n]=i; //第n个零点. n++; // } } if((PL[1]-PL[0])==32) //两个零点的间隔=32. { break; //退出. } if((PL[1]-PL[0])>32) //两个零点的间隔>32. AD++; //加大采样间隔. else AD--; //否则,减小采样间隔. if(BACK==1) //达不到要求. { BACK=0; //标志位清零. AD=50; //AD还原. break; //退出. } OUTNUM(AD,0,120,0); //显示调整结果. } } /* *********************************************************************** ** 函 数 名:void MUNS() ** 功能描述:按键功能设置. ************************************************************************** */ void MUNS() { KEY=KEYIN(); //读按键值. switch(KEY) // { case 0XFE: // { ADWORDS=ADCAN; //MAX197控制字. MAXD=1; //置标志位. MAXA=BACK=NEXT=SURE=GUID=0; //屏蔽其它标志位. CHAN=0; //确定通道. break; //退出. } case 0XFD: // { ADWORDS=ADCAN+2; //MAX197控制字. MAXD=1; //置标志位. MAXA=BACK=NEXT=SURE=GUID=0; //屏蔽其它标志位. CHAN=1; //确定通道. break; //退出. } case 0XFB: // { ADWORDS=ADCAN+4; //MAX197控制字. MAXD=1; //置标志位. MAXA=BACK=NEXT=SURE=GUID=0; //屏蔽其它标志位. CHAN=2; //确定通道. break; //退出. } case 0XF7: // { MAXA=1; //置标志位. MAXD=BACK=NEXT=SURE=GUID=0; //屏蔽其它标志位. break; //退出. } case 0XEF: // { BACK=1; //置标志位. MAXD=MAXA=NEXT=SURE=GUID=0; //屏蔽其它标志位. break; //退出. } case 0XDF: // { NEXT=1; //置标志位. MAXD=MAXA=BACK=SURE=GUID=0; //屏蔽其它标志位. break; //退出. } case 0XBF: // { SURE=1; //置标志位. MAXD=MAXA=BACK=NEXT=GUID=0; //屏蔽其它标志位. break; //退出. } case 0X7F: // { GUID=1; //置标志位. MAXD=MAXA=BACK=NEXT=SURE=0; //屏蔽其它标志位. break; //退出. } } } /* ************************************************************************ ** 函 数 名:interrupt HI_ISR() ** 功能描述:高优先级中断服务程序. *************************************************************************** */ void interrupt HI_ISR() { if(CCP1IF==1) // { CCP1IF=0; //清中断标志. FT[CCP]=CCPR1L+(CCPR1H<<8); //读计数器当前值. CCP++; //增量加1. if(CCP==20) //超出. CCP=0; //归零. } } /* *********************************************************************** ** 函 数 名:void interrupt low_priority LOW_ISR() ** 功能描述:按键功能设置. ************************************************************************** */ void interrupt low_priority LOW_ISR() { if(TMR3IF==1) { ATRL=PORTA&0X0F; //保存PORTA当前状态. BTRL=PORTB&0XF0; //保存PORTB当前状态. PORTA=PORTA&0XF0; //屏蔽所有地址. PORTB=PORTB&0X8F; //屏蔽所有控制信号. TMR3IF=0; //清中断标志. TMR3L=0X9A; //计数初值. MUNS(); //读按键,置标志位. PORTA=(ATRL|0XF0)&PORTA; //还原PORTA状态 PORTB=(BTRL|0X0F)&PORTB; //还原PORTB状态 } } /* *********************************************************************** ** 函 数 名:void GUIDE() ** 功能描述:绘制系统操作指导界面. ************************************************************************** */ void GUIDE() { int x,y; LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. for(y=0;y<3;y++) //界面占LCD屏6页. { for(x=0;x<32;x++) //102列,前51列在第一片LCD上显示. { LCDOUT(HELP[y][31-x],0X7F-x,y+0XBA,1); //输出数据. } for(x=0;x<32;x++) //102列,后51列在第一片LCD上显示. { LCDOUT(HELP[y][x+32],x+0x40,y+0XBA,2); } //输出数据. } } /* *********************************************************************** ** 函 数 名:void MUNM() ** 功能描述:按键功能设置. ************************************************************************** */ void MUNM() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(ABC[0],48,1); //标题. LCDNUM(ABC[1],56,1); //标题. LCDNUM(ABC[2],64,1); //标题. LCDNUM(ABC[3],72,1); //标题. LCDNUM(NUM[10],28,3); //0. LCDNUM(ABC[4],36,3); //A相. LCDNUM(ABC[5],44,3); // LCDNUM(NUM[11],28,4); //1. LCDNUM(ABC[6],36,4); //B相. LCDNUM(ABC[7],44,4); // LCDNUM(NUM[12],28,5); //2. LCDNUM(ABC[8],36,5); //C相. LCDNUM(ABC[9],44,5); // LCDNUM(NUM[13],28,6); //3. LCDNUM(ABC[10],36,6); //三相. LCDNUM(ABC[11],44,6); // LCDNUM(NUM[14],74,3); //4. LCDNUM(ABC[12],82,3); //SET. LCDNUM(ABC[13],90,3); // LCDNUM(NUM[15],74,4); //5. LCDNUM(ABC[14],82,4); //HEI. LCDNUM(ABC[15],90,4); // LCDNUM(NUM[16],74,5); //6. LCDNUM(ABC[16],82,5); //YES. LCDNUM(ABC[17],90,5); // LCDNUM(NUM[17],74,6); //7. LCDNUM(ABC[18],82,6); //HELP. LCDNUM(ABC[19],90,6); // LCDNUM(NUM[ADMO],110,7); //显示当前采样模式. } /* *********************************************************************** ** 函 数 名:void MUNMAX() ** 功能描述:采样模式界面. ************************************************************************** */ void MUNMAX() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(ABC[12],56,1); //标题. LCDNUM(ABC[13],64,1); //标题. LCDNUM(NUM[10],30,3); //0. LCDNUM(NUM[0],48,3); //0 LCDNUM(JS,80,3); //+ LCDNUM(NUM[5],88,3); //5 LCDNUM(NUM[11],30,4); //1. LCDNUM(JC,40,4); //- LCDNUM(NUM[5],48,4); //5 LCDNUM(JS,80,4); //+ LCDNUM(NUM[5],88,4); //5 LCDNUM(NUM[12],30,5); //2. LCDNUM(NUM[0],48,5); //0 LCDNUM(JS,72,5); //+ LCDNUM(NUM[1],80,5); //1 LCDNUM(NUM[0],88,5); //0 LCDNUM(NUM[13],30,6); //3. LCDNUM(JC,40,6); //- LCDNUM(NUM[1],48,6); //1 LCDNUM(NUM[0],56,6); //0 LCDNUM(JS,72,6); //+ LCDNUM(NUM[1],80,6); //1 LCDNUM(NUM[0],88,6); //0 } /* *********************************************************************** ** 函 数 名:void MUNABC() ** 功能描述:双通道显示界面. ************************************************************************** */ void MUNABC() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(ABC[4+CHAN*2],24,0); //标题. LCDNUM(ABC[5+CHAN*2],32,0); //标题. LCDNUM(UB[CHAN],0,1); //U*. LCDNUM(IB[CHAN],0,2); //I*. LCDNUM(PB[CHAN],0,3); //P*. LCDNUM(QB[CHAN],0,4); //Q*. LCDNUM(SB[CHAN],0,5); //S*. LCDNUM(LB[CHAN],0,6); //L*. LCDNUM(FB[CHAN],0,7); //F*. } /* *********************************************************************** ** 函 数 名:void MUNXB() ** 功能描述:谐波显示界面. ************************************************************************** */ void MUNXB() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(ABC[4+CHAN*2],24,0); //标题. LCDNUM(ABC[5+CHAN*2],32,0); //标题. LCDNUM(UB[CHAN],20,1); //U*. LCDNUM(IB[CHAN],80,1); //I*. LCDNUM(BH,40,1); //符号. LCDNUM(BH,100,1); //符号. LCDNUM(NUM[11],0,2); //1. LCDNUM(NUM[13],0,3); //3. LCDNUM(NUM[15],0,4); //5. LCDNUM(NUM[17],0,5); //7. LCDNUM(NUM[19],0,6); //9. } /* *********************************************************************** ** 函 数 名:void MUNALL() ** 功能描述:多通道界面. ************************************************************************** */ void MUNALL() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(ABC[10],24,0); //标题. LCDNUM(ABC[11],32,0); //标题. LCDNUM(UB[0],0,2); //U1. LCDNUM(IB[0],0,5); //I1. LCDNUM(UB[1],0,3); //U2 LCDNUM(IB[1],0,6); //I2. LCDNUM(UB[2],0,4); //U3. LCDNUM(IB[2],0,7); //I3. LCDNUM(PB[0],64,2); //P1. LCDNUM(QB[0],64,5); //Q1. LCDNUM(PB[1],64,3); //P2. LCDNUM(QB[1],64,6); //Q2. LCDNUM(PB[2],64,4); //P3. LCDNUM(QB[2],64,7); //Q3. } /* *********************************************************************** ** 函 数 名:void MUND() ** 功能描述:单通道界面. ************************************************************************** */ void MUND() { LCDCLEAR(1); //清屏. LCDCLEAR(2); //清屏. LCDNUM(NUM[10],0,0); //标题. LCDNUM(JJ,24,0); //符号. LCDNUM(BH,40,0); //符号. LCDNUM(NUM[11],0,2); //1. LCDNUM(NUM[13],0,3); //3. LCDNUM(NUM[15],0,4); //5. LCDNUM(NUM[17],0,5); //7. LCDNUM(NUM[19],0,6); //9. } /* ************************************************************************ ** 函 数 名: void main() ** 功能描述:主函数,实现各子程序调用和流程安排. *************************************************************************** */ void main() { INITIAL(); //系统初始化. T3INIT(); //TMR3时钟初始化. LCDINITI(1); //初始化第一片LCD. LCDINITI(2); //初始化第二片LCD. IPEN=1; //使能中断高低优先级. INTCON=INTCON|0xC0; //开总中断. TMR3ON=1; //开定时器. MUNM(); //显示主菜单. while(1) //一级while(1) { if(MAXD==1) //进入双通道数据处量. { MAXD=0; //标志位清零. MUNABC(); //显示界面. CCPINIT(); //启动获取频率数据. while(1) //二级while(1) { ABCSH(); //数据显示. ADSHOW(); //波形显示. ADCHX(); //AD采样. XBFX(); //谐波分析. PLJS(); //频率计算. if(MAXD==1) //切换采样通道. { MAXD=0; //标志位清零. MUNABC(); //重新显示界面. } if(SURE==1) // { SURE=0; //标志位清零. CYTZ(); //调整采样频率. } if(NEXT==1) //进入显示谐波数据显示界面. { NEXT=0; //标志位清零. MUNXB(); //显示界面. while(1) //三级while(1) { ADCHX(); //AD采样. XBFX(); //谐波分析. XBSH(); //数据显示. if(NEXT==1) // { NEXT=0; //标志位清零. CYTZ(); //调整采样频率. } if(MAXD==1) //切换采样通道. { MAXD=0; //标志位清零. MUNXB(); //重新显示界面. } if(BACK==1) // { BACK=0; //标志位清零. MUNABC(); //显示上级界面. break; //退出本级. } if(GUID==1) //显示HELP. { break; //退出本级. } } } if(MAXA==1) //进入多通道数据处理. { break; //退出本级. } if(BACK==1) // { BACK=0; //标志位清零. MUNM(); //显示上级界面. break; //退出本级. } if(GUID==1) //显示HELP. { break; //退出本级. } } CCP1IE=0; //关闭频率采样中断. TMR1ON=0; //关闭频率采样时钟 } if(MAXA==1) //进入多通道数据处理. { MAXA=0; //标志位清零. MUNALL(); //显示界面. while(1) //二级while(1) { ADALL(); //多通道数据采样显示. if(MAXD==1) //切换到双通道采样. { break; //退出本级. } if(BACK==1) // { BACK=0; //标志位清零. MUNM(); //显示上级界面. break; //标志位清零. } if(GUID==1) //显示HELP. { break; //退出本级. } } } if(BACK==1) //选择采样模式. { BACK=0; //标志位清零. MUNMAX(); //显示界面. while(1) // { if(MAXD==1&&CHAN==0) //模式0. { MAXD=0; //标志位清零. ADMO=0; //模式0. CHX=0; //单极性. LCDNUM(NUM[0],112,7); //显示当前采样模式. ADCAN=0X40; //基控制字. } if(MAXD==1&&CHAN==1) //模式1. { MAXD=0; //标志位清零. ADMO=1; //模式1. CHX=1; //双极性. LCDNUM(NUM[1],112,7); //显示当前采样模式. ADCAN=0X48; //基控制字. } if(MAXD==1&&CHAN==2) //模式2. { MAXD=0; //标志位清零. ADMO=2; //模式2. CHX=0; //单极性. LCDNUM(NUM[2],112,7); //显示当前采样模式. ADCAN=0X50; //基控制字. } if(MAXA==1) //模式3. { MAXA=0; //标志位清零. ADMO=3; //模式3. CHX=1; //双极性. LCDNUM(NUM[3],112,7); //显示当前采样模式. ADCAN=0X58; //基控制字. } if(SURE==1) // { SURE=0; //标志位清零. CHAN=0; //标志位清零. MUNM(); //显示上级界面. break; //退出本级. } } } if(NEXT==1) //进入单通道高速采样. { NEXT=0; //标志位清零. MUND(); //显示界面. while(1) //二级while(1). { ADCHD(); //数据采样处量显示. if(BACK==1) // { BACK=0; //标志位清零. MUNM(); //显示上级界面. break; //退出本级. } } } if(SURE==1) // { SURE=0; //标志位清零. MUNM(); //显示主界面. } if(GUID==1) // { GUID=0; //标志位清零. GUIDE(); //显示HELP. } } }