求助,交流采样的算法(不是请教,是求助)
求助,交流采样的算法(不是请教,是求助)求交流采样的算法,我搞了快半年了,还是一点眉目都没有,开始我想用准同步算法的,可发现计算量太大,想用非同步算法,可是能求出一个周期的实际采样点,却不知道,在频率变化时怎么补尝,所以求非同步算法(硬件没有做过0检测).
我以前也发过帖子,可还是没能解决 楼主什么地方用的?信号频率变化大么?要求精度多高还要补偿? 我以前写过一个简单的12点傅式采样算法程序,默认频率不变的。 一个项目全部软硬件都是新的,硬件软件都不是熟悉的,成功率会很低,建议你别用AVR32,给你的建议你要仔细看看,就目前状态你应该选用一颗比较熟悉的MCU,采样、计量用ATT7022B,用第7路去做谐波,其他所有的数据项都直接使用7022B内部计算结果。 用均方根算法,如果要计算谐波用傅立叶如果要求准确用锁相环控制采样。MCP有一片文章讲过一种方法,也是一种同步采样的方法,但是我还没看的很懂。 不用那么麻烦,根据频率设定定时去读7022B的采样寄存器就行了,外部用模拟开关选择采集那一路信号。 在电力上,信号频率是45-55HZ,关键是的要求三相的3,5,7次谐波,电压有效值,有功功率,电量,频率,所以不能用计量芯片, 晕倒,你不知道有三相多功能的计量芯片,无语。 不是,我刚才字打错了,我知道,我还用过CS5463,我是说求三相的3,5,7次谐波,还有每次谐波的电压畸变率所以不能用计量芯片 CS5463,ATT7022都可以输出采样值,根据频率选取整周期采样点去计算就行了 顶一下 请问一下tidsp,ATT7022B如何访问采样寄存器,我看资料上面没有提供三相电压、电流采样寄存器的入口地址 第7路可以访问 哦,是的,那就是说需要采用第7路AD对三相电压、电流进行分时采样咯!
不知道有没有什么后门能够提供另外六路AD的采样值寄存器的访问入口啊,呵呵
非常感谢! 只有ACTION的才知道有无后门 呵呵,那是,谢谢 那么请问,用第7路去采样(采样频率是3.2K)的话,是否是第7路能直接输出瞬时值,那么在50HZ的情况下就是一个周期采样64个点,而ATT7022B又没有缓存,那么就是说,MCU和计量新片之间要通过SPI总线要有两种速度进行通信,比如1秒钟读一次前六路的值,而读第7路则要0.0003125S(是采样频率3.2K的倒数)读一次,而且读的时间要很准,否则数据就会出错? 是要读的很准时,一定要用硬件SPI去读,最好使用有FIFO的,读回来算也是个麻烦事情,频率改变一点,只要不是50,算谐波就要用一定的算法了,直接FFT结果一塌糊涂。 关注! 跟踪中 关键是计量新片没有缓存,就算是用中断的方式,比如在要读第7路的时候,同时要读前6路的参数了,那读出的第7路的数据就可能错过一位,那你做FFT就会有问题,另你把读出的数据加窗了没? 7022没中断,只能以更高的速度去读,读回来丢弃重复的,想同时读6路不现实,丢数据或频率不是50加窗起不了多大作用,用迭代法吧。 记号! 还真没搞过三相的..... 丢数据你怎么处理?频率不是50到不难办,读6路的AD转换值,如果一秒钟出一次数据,我认为那可能还来得急,比如每一路读5个周期,那么6路在30个周期左右是能读完的.
tidsp你是哪里的?是做电力的吗?我是南京的,你呢?能留个联系方式吗?我的QQ:824879061 看看这个PIC的,MAX197采样根据频率调节采样时间(转)
/* ***********************************************************************
** 系统程序:多路信号实时采集和处理,并将处理后的数据以不同的
** 方式显示.同时可根据按键输入实现任务调度.
** 时 间:2005/08/05.
*************************************************************************** */
#include "pic18f458.h" //PIC18F458单片机头文件.
#include "math.h" //C语言头文件.
#include "stdlib.h" //C语言头文件.
#define PI 6.283
//"HELP界面"
const char HELP={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={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={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={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={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={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={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={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={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={0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,};
const char JC={0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00,};
const char JJ={0x00,0x00,0x00,0x44,0x44,0x5F,0x44,0x44,};
const char BH={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={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; //AD采样数据存储区.
int FT; //频率采样数据存储区.
//U I P Q S F计算数据存储区.
long UI,UP,P,Q,S,L,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; //<uuuu,0000>设置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<TIME;T++) //延时.
; //空语句.
}
/* ************************************************************************
** 函 数 名:void T3INIT()
** 功能描述:TMR3作为定时器,定时10us,产生系统时钟点滴.
*************************************************************************** */
void T3INIT()
{
T3CON=0X20; //<1010,0000>设定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; //<uuuu,1101>译码后实现地址选择.
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; //<uuuu,1011>译码后实现地址选择.
WORDS=PORTD; //读取PORTD端口的数据.
PORTA=PORTA&0XF0; //屏蔽所有地址.
return WORDS; //将读取的数据作为返回值.
}
/* ************************************************************************
** 函 数 名:int GATEBIN()
** 功能描述:读取B组开关量,并返回其值.
*************************************************************************** */
int GATEBIN()
{
int WORDS; //定义数据入口变量.
TRISD=0XFF; //<1111,1111>设置PORTD为输入.
PORTA=(PORTA|0X0C)&0XFC; //<uuuu,1100>译码后实现地址选择.
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; //<uuuu,1000>译码后实现地址选择.
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; //<uuuu,1001>译码后选择第1片LCD.
else
PORTA=(PORTA|0X0A)&0XFA; //<uuuu,1010>译码后选择第2片LCD.
PORTB=(PORTB|0X60)&0XEF; //<u110,uuuu>控制信号:可读-读-命令.
STA=PORTD&0X80; //读取LCD的状态字Bt7=0/1.
PORTB=PORTB&0X8F; //<u000,uuuu>控制信号:锁存数据.
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; //<uuuu,1001>译码后选择第1片LCD.
else
PORTA=(PORTA|0X0A)&0XFA; //<uuuu,1010>译码后选择第2片LCD.
PORTD=TRANS; //将数据赋给PORTD端口.
PORTB=(PORTB|0X40)&0XCF; //<u100,uuuu>控制信号:可读-写-命令.
PORTB=PORTB&0X8F; //<u000,uuuu>控制信号:锁存数据.
}
/* ************************************************************************
** 函 数 名: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; //<uuuu,1001>译码后选择第1片LCD.
else
PORTA=(PORTA|0X0A)&0XFA; //<uuuu,1010>译码后选择第2片LCD.
PORTD=WORDS; //将数据赋给PORTD端口.
DELAY(0);
PORTB=(PORTB|0X50)&0XDF; //<u101,uuuu>控制信号:可读-写-命令.
PORTB=PORTB&0X8F; //<u000,uuuu>控制信号:锁存数据.
}
/* ************************************************************************
** 函 数 名: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; //<uuuu,1001>译码后选择第1片LCD.
else
PORTA=(PORTA|0X0A)&0XFA; //<uuuu,1010>译码后选择第2片LCD.
PORTB=PORTB|0X70; //<u111,uuuu>控制信号:可读-读-数据.
WORDS=PORTD; //空读操作.
WORDS=PORTD; //读取PORTD端口数据.
PORTB=PORTB&0X8F; //<u000,uuuu>控制信号:锁存数据.
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; //<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&0X8F; //<u000,uuuu>控制信号:锁存数据.
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; //<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,C-64,P,2); //向第1页当前列输入数据.
LCDOUT(ARW,C-64,P+1,2); //向第2页当前列输入数据.
}
else
{LCDOUT(ARW,C,P,1); //向第1页当前列输入数据.
LCDOUT(ARW,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,C-64,P,2); //向当前列输入数据.
else
LCDOUT(ARW,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,CLMD,PAGE); //输出带点数.
else
LCDNUM(NUM,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=INADC(); //读取第一路AD转换数据.
OUTADC(ADWORDS+1); //送第二路AD控制字.
DELAY(0); //延时.
DATA=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/4096.0); //数据处理.
LCDPIEX(ADD+64,CH1-data); //输出显示.
data=(signed int)(40.0*DATA/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=INADC(); //读取数据.
}
for(ADD=0;ADD<64;ADD++) //显示波形.
{
D=(int)(40.0*DATA/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; //取数据计算.
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=SHU; //第n_x次谐波幅值.
UI=SHU*SHU+UI; //
}
UI=(long)sqrt(UI); //总幅值.
for(i=0;i<5;i++) //
{
SHU=UI*1000; //
SHU=SHU/(UI); //
UP=SHU; //第i次谐波占有率.
}
SHU=1000*(UI-UI); //
UP=SHU/UI; //畸变率.
LCDCLEAN(12,2,126,7); //清除数据显示区.
for(i=0;i<6;i++)
{
OUTNUM(UI,1,28,2+i); //显示幅值.
OUTNUM(UP,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; //数据处理中间变量.
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; //取数据计算.
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=SHU; //
UI=SHU*SHU+UI; //第n_x次谐波幅值.
if(n_x==0)
UIL=atan(Ui/Ur); //相位.
}
UI=(long)sqrt(UI); //总幅值.
for(i=0;i<5;i++) //
{
SHU=UI*1000; //
SHU=SHU/(UI); //
UP=SHU; //第i次谐波占有率.
}
SHU=1000*(UI-UI); //
UP=SHU/UI; //畸变率.
}
L=abs((long)(1000*(UIL-UIL)-40)); //功率因数角.
S=(long)(UI*UI); //S.
P=(long)(S*cos(L/1000.0)); //P.
Q=(long)(S*sin(L/1000.0)); //Q.
}
/* ***********************************************************************
** 函 数 名:void ABCSH()
** 功能描述:显示双通道数据处理结果.
************************************************************************** */
void ABCSH()
{
LCDCLEAN(12,1,50,7); //清除数据显示区.
OUTNUM(UI,1,54,1); //显示U*值.
OUTNUM(UI,1,54,2); //显示I*值.
OUTNUM(P,2,54,3); //显示P*值.
OUTNUM(Q,2,54,4); //显示Q*值.
OUTNUM(S,2,54,5); //显示S*值.
OUTNUM(L,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,1,28+n*64,2+i); //显示第i次谐波.
OUTNUM(UP,3,56+n*64,2+i); //显示第i次谐波占有率.
}
}
}
/* ***********************************************************************
** 函 数 名:void ADALLSH()
** 功能描述:多通道数据处结果显示.
************************************************************************** */
void ADALLSH()
{
OUTNUM(UI,1,40,(2+CHAN)); //显示U*值.
OUTNUM(UI,1,40,(5+CHAN)); //显示I*值.
OUTNUM(P,2,114,(2+CHAN)); //显示P*值.
OUTNUM(Q,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; //参数.
QH=(CCP>9)?0:10; //判断取数位置.
for(i=0;i<5;i++) //
{
FF=FT; //取数.
}
F=(FF>FF)?(FF-FF):(FF+65536-FF);
F=(long)(100000000/F); //判断,并计算频率.
}
/* ***********************************************************************
** 函 数 名:void CYTZ()
** 功能描述:零点检测法,采样频率调整.
************************************************************************** */
void CYTZ()
{
int i,n,PL; //参数.
while(1)
{
ADCHX(); //AD采样.
for(i=0,n=0;n<2;i++) //零点判断.
{
if(DATA<=DATA&&DATA>=DATA)
{
PL=i; //第n个零点.
n++; //
}
}
if((PL-PL)==32) //两个零点的间隔=32.
{
break; //退出.
}
if((PL-PL)>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=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,0X7F-x,y+0XBA,1); //输出数据.
}
for(x=0;x<32;x++) //102列,后51列在第一片LCD上显示.
{
LCDOUT(HELP,x+0x40,y+0XBA,2);
} //输出数据.
}
}
/* ***********************************************************************
** 函 数 名:void MUNM()
** 功能描述:按键功能设置.
************************************************************************** */
void MUNM()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(ABC,48,1); //标题.
LCDNUM(ABC,56,1); //标题.
LCDNUM(ABC,64,1); //标题.
LCDNUM(ABC,72,1); //标题.
LCDNUM(NUM,28,3); //0.
LCDNUM(ABC,36,3); //A相.
LCDNUM(ABC,44,3); //
LCDNUM(NUM,28,4); //1.
LCDNUM(ABC,36,4); //B相.
LCDNUM(ABC,44,4); //
LCDNUM(NUM,28,5); //2.
LCDNUM(ABC,36,5); //C相.
LCDNUM(ABC,44,5); //
LCDNUM(NUM,28,6); //3.
LCDNUM(ABC,36,6); //三相.
LCDNUM(ABC,44,6); //
LCDNUM(NUM,74,3); //4.
LCDNUM(ABC,82,3); //SET.
LCDNUM(ABC,90,3); //
LCDNUM(NUM,74,4); //5.
LCDNUM(ABC,82,4); //HEI.
LCDNUM(ABC,90,4); //
LCDNUM(NUM,74,5); //6.
LCDNUM(ABC,82,5); //YES.
LCDNUM(ABC,90,5); //
LCDNUM(NUM,74,6); //7.
LCDNUM(ABC,82,6); //HELP.
LCDNUM(ABC,90,6); //
LCDNUM(NUM,110,7); //显示当前采样模式.
}
/* ***********************************************************************
** 函 数 名:void MUNMAX()
** 功能描述:采样模式界面.
************************************************************************** */
void MUNMAX()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(ABC,56,1); //标题.
LCDNUM(ABC,64,1); //标题.
LCDNUM(NUM,30,3); //0.
LCDNUM(NUM,48,3); //0
LCDNUM(JS,80,3); //+
LCDNUM(NUM,88,3); //5
LCDNUM(NUM,30,4); //1.
LCDNUM(JC,40,4); //-
LCDNUM(NUM,48,4); //5
LCDNUM(JS,80,4); //+
LCDNUM(NUM,88,4); //5
LCDNUM(NUM,30,5); //2.
LCDNUM(NUM,48,5); //0
LCDNUM(JS,72,5); //+
LCDNUM(NUM,80,5); //1
LCDNUM(NUM,88,5); //0
LCDNUM(NUM,30,6); //3.
LCDNUM(JC,40,6); //-
LCDNUM(NUM,48,6); //1
LCDNUM(NUM,56,6); //0
LCDNUM(JS,72,6); //+
LCDNUM(NUM,80,6); //1
LCDNUM(NUM,88,6); //0
}
/* ***********************************************************************
** 函 数 名:void MUNABC()
** 功能描述:双通道显示界面.
************************************************************************** */
void MUNABC()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(ABC,24,0); //标题.
LCDNUM(ABC,32,0); //标题.
LCDNUM(UB,0,1); //U*.
LCDNUM(IB,0,2); //I*.
LCDNUM(PB,0,3); //P*.
LCDNUM(QB,0,4); //Q*.
LCDNUM(SB,0,5); //S*.
LCDNUM(LB,0,6); //L*.
LCDNUM(FB,0,7); //F*.
}
/* ***********************************************************************
** 函 数 名:void MUNXB()
** 功能描述:谐波显示界面.
************************************************************************** */
void MUNXB()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(ABC,24,0); //标题.
LCDNUM(ABC,32,0); //标题.
LCDNUM(UB,20,1); //U*.
LCDNUM(IB,80,1); //I*.
LCDNUM(BH,40,1); //符号.
LCDNUM(BH,100,1); //符号.
LCDNUM(NUM,0,2); //1.
LCDNUM(NUM,0,3); //3.
LCDNUM(NUM,0,4); //5.
LCDNUM(NUM,0,5); //7.
LCDNUM(NUM,0,6); //9.
}
/* ***********************************************************************
** 函 数 名:void MUNALL()
** 功能描述:多通道界面.
************************************************************************** */
void MUNALL()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(ABC,24,0); //标题.
LCDNUM(ABC,32,0); //标题.
LCDNUM(UB,0,2); //U1.
LCDNUM(IB,0,5); //I1.
LCDNUM(UB,0,3); //U2
LCDNUM(IB,0,6); //I2.
LCDNUM(UB,0,4); //U3.
LCDNUM(IB,0,7); //I3.
LCDNUM(PB,64,2); //P1.
LCDNUM(QB,64,5); //Q1.
LCDNUM(PB,64,3); //P2.
LCDNUM(QB,64,6); //Q2.
LCDNUM(PB,64,4); //P3.
LCDNUM(QB,64,7); //Q3.
}
/* ***********************************************************************
** 函 数 名:void MUND()
** 功能描述:单通道界面.
************************************************************************** */
void MUND()
{
LCDCLEAR(1); //清屏.
LCDCLEAR(2); //清屏.
LCDNUM(NUM,0,0); //标题.
LCDNUM(JJ,24,0); //符号.
LCDNUM(BH,40,0); //符号.
LCDNUM(NUM,0,2); //1.
LCDNUM(NUM,0,3); //3.
LCDNUM(NUM,0,4); //5.
LCDNUM(NUM,0,5); //7.
LCDNUM(NUM,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,112,7); //显示当前采样模式.
ADCAN=0X40; //基控制字.
}
if(MAXD==1&&CHAN==1) //模式1.
{
MAXD=0; //标志位清零.
ADMO=1; //模式1.
CHX=1; //双极性.
LCDNUM(NUM,112,7); //显示当前采样模式.
ADCAN=0X48; //基控制字.
}
if(MAXD==1&&CHAN==2) //模式2.
{
MAXD=0; //标志位清零.
ADMO=2; //模式2.
CHX=0; //单极性.
LCDNUM(NUM,112,7); //显示当前采样模式.
ADCAN=0X50; //基控制字.
}
if(MAXA==1) //模式3.
{
MAXA=0; //标志位清零.
ADMO=3; //模式3.
CHX=1; //双极性.
LCDNUM(NUM,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.
}
}
} 不太好看,上文件
点击此处下载 ourdev_249202.txt(文件大小:46K) (原文件名:Program.txt) 不错,几点建议
1、即使是电压电流同时采样,因前端互感器及滤波电路参数差异,还是要补偿相位差,否则会功率值引起较大的误差。
2、在有谐波时,P!=S*COS
3、没看懂怎么控制采样间隔。
4、10us定时中断对单片机来说负荷太重了吧。 丢数据你怎么处理?
丢数据的话,整个项目枪毙。 用硬件锁相环电路做N倍频处理,给CPU中断信号进行采样,可以避免输入信号频率变换带来的采样间隔误差,一般一个周波采样16点应该够用了,再做傅立叶 国标要求21次谐波 24楼很开放呀牛人,28楼正解,我们原来就是这么做的 21次谐波 最少要64个点,一般要128个点 讨论的好 做个标记 28楼的方法是通行的方法,如果你的硬件不具备频率跟踪的能力,仅靠软件(我个人的认识)是无法准确控制采样间隔的。 28楼的效果最好,跟踪频率变化的。
如果不具备硬件跟踪,那么就软件做了。
测周期,然后实时改变采样间隔。
电网频率不会变化很激烈和频繁的,还是比较稳定的 MARK mark 不错 不过我是通过AD采样做 记号! 我也在做交流采样,用的是ARM2138,现在也是想求助一个傅氏12点交流采样的算法。请问1楼的朋友如何联系?谢谢 关注中............. 记号 都是牛人啊!
学习中。。。 mark mark mark Mark 点数稍微多取一些,比如32点、64点每周期。采样率根据电网频率自动锁定(软件根据频率修改采样率)。这样即使不同步,也没有关系,只要是整数个周期,均方根值计算结果不会有大的跳动。如果用于计量的话还是需要用专用芯片有保障,如果纯粹测量显示的话单片机完全可以搞定,显示用滤波搞一下可以保证显示不乱跳。 mark 关注 mark 看了半天也不知道怎么弄 回复【25楼】xzyang
-----------------------------------------------------------------------
这个傅里叶变换算法直接就能带吗 能不能再细讲讲 楼主有具体要求么?
一直想做电力方面的东东,可是没机会。 路过 MARK一下 关注! mark 准同步采样法:ad采样数据-》fir滤波->测频率-》根据频率调整采样点(软件调整,硬件一直固定采样频率)做到跟随基频频率变化(即准同步)-》fft运算,平滑采样值,去掉量化噪声-》fft结果实部平方+虚部平方再开方
我这的做法,但细节不清楚! mark 回复【58楼】chinaye1程序猿
-----------------------------------------------------------------------
这个方法是用来测谐波的吧!? 回复【楼主位】myworkmail
-----------------------------------------------------------------------
请问楼主同步算法是用来做什么的?
测量高次谐波还是做什么用? -----------------------------------------------------------------------
电力上的交流电流信号采样的话,当电网频率不是很稳定的时候,例如出现变频器,中频炉等大型功率设备器件时,就会出现多次谐波,时候交流电流处理就要做处理了 mark,在找合适的算法 交流工频信号要求可以定时采样,对N个周期的采样绝对值求平均值即可,精度很好
页:
[1]