📄 简易谐波分析仪.c
字号:
PORTA=(PORTA|0X09)&0XF9; //<uuuu,1001>译码后选择第1片LCD.
else
PORTA=(PORTA|0X0A)&0XFA; //<uuuu,1010>译码后选择第2片LCD.
PORTB=(PORTB|0X60)&0XEF; //<u110,uuuu>控制信号:可读-读-命令.
STA=PORTD&0X20; //将数据赋给PORTD端口.
PORTB=PORTB&0XBF; //<u000,uuuu>控制信号:锁存数据.
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<<ROW; //取得数据.
break; //跳出for循环.
}
ROW=ROW-8; //行值减8.
}
if(X>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; //<uuuu,1110>译码后实现地址选择.
PORTB=(PORTB|0X10)&0XDF; //<uu01,uuuu>控制信号:写.
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; //<uuuu,1110>译码后实现地址选择.
PORTB=(PORTB|0X60)&0XEF; //<u110,uuuu>控制信号:读高4位数据.
WORDS=PORTD&0X0F; //读取PORTD端口数据.
PORTB=(PORTB|0X20)&0XAF; //<u010,uuuu>控制信号:读低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; //还原控制字.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -