📄 sinewaveparametersmeasuring.c
字号:
/*********************************************************
河海大学本科毕业设计
基于单片机和CPLD的正弦波参数测量仪
整机控制模块MCS-51单片机
河海大学
计算机及信息工程学院
江苏 常州
QQ:415151404
2008年6月
*********************************************************
基于单片机和CPLD的正弦波参数测量仪
介绍了一种基于单片机和复杂可编程逻辑器件(CPLD)的正弦波参数测量仪,
测量参数包括幅值、频率和相位。
整机控制模块以MCS-51单片机为核心,
由液晶显示器和4位独立键盘组成。
用户通过4位独立键盘选择相应功能,并通过LCD1602显示。
单片机不仅要管理 4位独立键盘和LCD1602,
还要控制ADC0831采样幅值并串行读取8位数据,
并且给CPLD发送指令,接受CPLD分批发送的数据。
*********************************************************/
/*****************头文件的定义******************/
#include <reg52.h>
#include <stdio.h>
#include <string.h>
#include <intrins.h>
/*****************宏定义******************/
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define LCM_Data P1 //LCD的数据端口
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
#define CPLD_Data P0 //CPLD的数据端口
/*****************4位独立按键定义******************/
sbit KEY_OK=P2^0;
sbit KEY_CANCEL =P2^1;
sbit KEY_GO=P2^2;
sbit KEY_BACK=P2^3;
/*****************LCD的控制端口的定义******************/
sbit LCM_RS=P2^7;
sbit LCM_RW=P2^6;
sbit LCM_E =P2^5;
/*****************ADC0831的端口定义******************/
sbit T0831_CS=P3^7;//片选I/O端口
sbit T0831_SK=P3^6;//时钟I/O端口
sbit T0831_DO=P2^4;//数据I/O端口
/*****************CPLD的端口定义******************/
sbit CPLD_0=P3^2;//3位单片机指令
sbit CPLD_1=P3^3;
sbit CPLD_2=P3^4;
sbit CPLD_lock=P3^1;//CPLD锁存端
sbit fenpin_100=P3^0;//CPLD100分频使能端
sbit fenpin_10=P3^5;//CPLD10分频使能端
/*****************各屏幕固定显示内容的定义******************/
uchar code INI1[]="WELCOME"; //初始化界面
uchar code INI2[]="Sin Wave Measure";
uchar code MEASURE[]="To measure the"; //功能选择
uchar code FREQUENCY[]="frequency ?"; //测频率
uchar code AMPLITUDE[]="amplitude ?"; //测幅值
uchar code PHASIC[]="phasic ?"; //测相位
/*****************全局变量******************/
uchar pos_neg; //相位超前滞后标志位
/******************LCD函数的说明*********************/
void WriteDataLCM(uchar WDLCM);
void WriteCommandLCM(uchar WCLCM,bit uBuysC);
void ReadStatusLCM(void);
void LCMInit(void);
void DisplayOneChar(uchar X, uchar Y, uchar DData);
void displaylistchar(uchar x,uchar y, uchar code *listdata);
/******************延时函数的说明*********************/
void Delay5Ms(void);
void Delay30Ms(void); //读取CPLD数据等待延时
void Delay1s(void); //测量显示延迟
void Kbdelays(void); //键消抖的延时函数
/******************各屏幕显示函数的说明*********************/
void welcome();
void FPAselect();
void DisplayFre();
void DisplayPha();
void DisplayAmp();
/******************读CPLD数据函数的说明*********************/
uint ReadN1();
uint ReadN2();
uchar ReadAmp();
/********************矩阵键盘函数**********************/
// 键消抖的延时函数
void Kbdelays(void)
{
uchar i;
for(i=300;i>0;i--);
}
/********************LCD1602的函数**********************/
//写数据函数: E =高脉冲 RS=1 RW=0
void WriteDataLCM(uchar WDLCM)
{
ReadStatusLCM(); //检测忙
//LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
LCM_Data = WDLCM;
LCM_E = 1; //若晶振速度太高可以在这后加小的延时
_nop_();
_nop_();
_nop_();
//LCM_Data = WDLCM;
LCM_E = 0;//重设E=0
}
//写指令函数: E=高脉冲 RS=0 RW=0
void WriteCommandLCM(uchar WCLCM,bit BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
//P2=0x38;
LCM_RS = 0;
LCM_RW = 0;
LCM_Data = WCLCM;
LCM_E = 1; //若晶振速度太高可以在这后加小的延时
LCM_E = 1;
_nop_();
_nop_();
_nop_();
//LCM_Data = WCLCM;
LCM_E = 0;//重设E=0
}
//正常读写操作之前必须检测LCD控制器状态:E=1 RS=0 RW=1;DB7: 0 LCD控制器空闲,1 LCD控制器忙。
//检测忙信号,等待LCD空闲函数
void ReadStatusLCM(void)
{
LCM_Data = 0x0FF;
LCM_E = 1;
LCM_RS = 0;
LCM_RW = 1;
_nop_();
_nop_();
_nop_();
while (LCM_Data & Busy); //检测忙信号
LCM_E = 0;
}
void LCMInit(void) //LCM初始化
{
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
//Delay400Ms();
WriteCommandLCM(0x08,1); //关闭显示
//Delay400Ms();
WriteCommandLCM(0x01,1); //显示清屏
//Delay400Ms();
WriteCommandLCM(0x06,1); // 显示光标移动设置
//Delay400Ms();
WriteCommandLCM(0x0c,1); // 显示开及光标设置
//Delay400Ms();
}
//按指定位置显示一个字符
void DisplayOneChar(uchar X, uchar Y, uchar DData)
{
Y &= 0x01;
X &= 0x0F; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 1); //这里不检测忙信号,发送地址码
WriteDataLCM(DData);
}
/**************按指定位置显示一串字符******************/
void displaylistchar(uchar x,uchar y, uchar code *listdata)
{
uchar i=0;
for(i=0;i<strlen(listdata);i++ )
{
if(x<=0x0F) //x坐标应小于0x0F
{
DisplayOneChar(x, y, listdata[i]); //显示单个字符
x++;
}
else if(y==0)
{
y++;
x=x-0x0F;
DisplayOneChar(x, y, listdata[i]);
}
}
}
//5ms延时
void Delay5Ms(void)
{
uint c=5552;
while(c--);
}
//30ms延时
void Delay30Ms(void)
{
Delay5Ms();
Delay5Ms();
Delay5Ms();
Delay5Ms();
Delay5Ms();
Delay5Ms();
}
//约1s延时
void Delay1s(void)
{
uchar A = 2;
uint B;
while(A--)
{
B=7269;
while(B--);
}
}
/********************各屏幕显示子函数**********************/
/********************第一屏,开机后显示**********************/
void welcome()
{
WriteCommandLCM(0x0c,1); // 显示开及光标设置
Delay30Ms();
WriteCommandLCM(0x01,1);
displaylistchar(4,0,INI1);
displaylistchar(0,1,INI2);
while(1)
{
Kbdelays();
if(KEY_OK==0) //按OK键进入功能选择屏
{
FPAselect();
}
}
}
/********************第二屏,功能选择**********************/
void FPAselect(void)
{
uchar i=1; //i=1,2,3
Delay30Ms();
WriteCommandLCM(0x0c,1); // 显示开及光标设置
Delay30Ms();
WriteCommandLCM(0x01,1);
displaylistchar(0,0,MEASURE);
displaylistchar(0,1,FREQUENCY);
while(1)
{
Kbdelays();
if(KEY_GO==0 || KEY_BACK==0) //按GO、BACK键选择测频、测幅或测相
{
if(KEY_GO==0 ){i++;if(i>=4) i=1;}
else {i--;if(i<1) i=3;}
WriteCommandLCM(0x0c,1);
Delay30Ms();
WriteCommandLCM(0x01,1);
if(i==1)
{
displaylistchar(0,0,MEASURE);
displaylistchar(0,1,FREQUENCY);
}
else if(i==2)
{
displaylistchar(0,0,MEASURE);
displaylistchar(0,1,PHASIC);
}
else if(i==3)
{
displaylistchar(0,0,MEASURE);
displaylistchar(0,1,AMPLITUDE);
}
}
if(KEY_OK==0 )
{
if(i==1)DisplayFre();
if(i==2)DisplayPha();
if(i==3)DisplayAmp();
}
if(KEY_CANCEL==0 ) welcome(); //按CEL键回到欢迎界面
}
}
/********************第三屏,显示测量值**********************/
void DisplayFre(void) //显示频率值
{
uchar Frequency[7];
ulong N1;
while(1)
{
Delay30Ms();
CPLD_lock=0;
_nop_();
_nop_();
CPLD_lock=1; //CPLD_lock上升沿锁存CPLD所有测量值
Delay30Ms();
N1=ReadN1();
N1=6000000/N1; //读取计数值
if(N1>1000) //如果频率值大于1KHz,10分频后重新读取测量值
{
fenpin_10=0;//CPLD10分频使能
fenpin_100=1;//CPLD100分频使能关闭
Delay30Ms();
CPLD_lock=0;
_nop_();
_nop_();
CPLD_lock=1;
Delay30Ms();
N1=ReadN1();
N1=60000000/N1;
}
if(N1>10000) //如果频率值大于10kHz,100分频后重新读取测量值
{
fenpin_10=1;//CPLD10分频使能关闭
fenpin_100=0;//CPLD100分频使能
Delay30Ms();
CPLD_lock=0;
_nop_();
_nop_();
CPLD_lock=1;
Delay30Ms();
N1=ReadN1();
N1=600000000/N1;
}
if(N1>100000) //如果频率值大于100kHz,1000分频后重新读取测量值
{
fenpin_100=0;//CPLD100分频使能
fenpin_10=0;//CPLD10分频使能
Delay30Ms();
CPLD_lock=0;
_nop_();
_nop_();
CPLD_lock=1;
Delay30Ms();
N1=ReadN1();
N1=600000000/N1*10; //*10放到后面避免超出ulong范围
}
Frequency[0]=N1/1000000 +'0'; //获取7位频率显示数值
Frequency[1]=N1/100000-N1/1000000*10 +'0';
Frequency[2]=N1/10000-N1/100000*10 +'0';
Frequency[3]=N1/1000-N1/10000*10 +'0';
Frequency[4]=N1/100-N1/1000*10 +'0';
Frequency[5]=N1/10-N1/100*10 +'0';
Frequency[6]=N1-N1/10*10 +'0';
WriteCommandLCM(0x0c,1); // 显示开及光标设置
Delay30Ms();
WriteCommandLCM(0x01,1);
DisplayOneChar(0,0, 'F');
DisplayOneChar(1,0, ':');
DisplayOneChar(2,0, Frequency[0]); //依次显示7位频率数值
DisplayOneChar(3,0, Frequency[1]);
DisplayOneChar(4,0, Frequency[2]);
DisplayOneChar(5,0, Frequency[3]);
DisplayOneChar(6,0, Frequency[4]);
DisplayOneChar(7,0, Frequency[5]);
DisplayOneChar(8,0, Frequency[6]);
DisplayOneChar(9,0, 'H');
DisplayOneChar(10,0, 'z');
fenpin_100=1; //100分频使能端关闭
fenpin_10=1; //10分频使能端关闭
Delay1s();
if(KEY_CANCEL==0) welcome(); //按CEL键返回欢迎界面
}
}
void DisplayPha(void) //显示相位
{
uchar Phasic[3];
ulong N1,N2;
while(1)
{
do
{
Delay30Ms();
CPLD_lock=0;
_nop_();
_nop_();
CPLD_lock=1; //CPLD_lock上升沿锁存CPLD所有测量值
Delay30Ms();
N1=ReadN1(); //读取频率计数值
N2=ReadN2(); //读取异或后计数值
N2=180*N2/N1;//求取相位差值
}
while(N2>180); //如果得到测量值大于180度则重新测量
Phasic[0]=N2/100+'0'; //获取3位相位显示数值
Phasic[1]=N2/10-N2/100*10+'0';
Phasic[2]=N2-N2/10*10+'0';
WriteCommandLCM(0x0c,1); // 显示开及光标设置
Delay30Ms();
WriteCommandLCM(0x01,1);
DisplayOneChar(0,0, 'P');
DisplayOneChar(1,0, ':');
DisplayOneChar(2,0,pos_neg ); //显示超前滞后位
DisplayOneChar(3,0, Phasic[0]); //依次显示3位相位差数值
DisplayOneChar(4,0, Phasic[1]);
DisplayOneChar(5,0, Phasic[2]);
DisplayOneChar(6,0, 'd');
Delay1s();
if(KEY_CANCEL==0) welcome(); //按CEL键返回欢迎界面
}
}
void DisplayAmp(void) //显示幅值
{
uchar i;
uchar Ampl[4];
uint Amp;
while(1)
{
Amp=ReadAmp(); //读取8位ADC采样数据
Amp=28*Amp; //求取幅值
Ampl[0]=Amp/1000; //获得4位幅度显示数值
Ampl[1]=Amp/100-Amp/1000*10;
Ampl[2]=Amp/10-Amp/100*10;
Ampl[3]=Amp-Amp/10*10;
for(i=0;i<=3;i++) Ampl[i]+='0';
WriteCommandLCM(0x0c,1); // 显示开及光标设置
Delay30Ms();
WriteCommandLCM(0x01,1);
DisplayOneChar(0,0, 'A');
DisplayOneChar(1,0, ':');
DisplayOneChar(2,0, Ampl[0]); //依次显示3位相位差数值
DisplayOneChar(3,0, Ampl[1]);
DisplayOneChar(4,0, Ampl[2]);
DisplayOneChar(5,0, Ampl[3]);
DisplayOneChar(6,0, 'm');
DisplayOneChar(7,0, 'V');
Delay1s();
if(KEY_CANCEL==0) welcome(); //按CEL键返回欢迎界面
}
}
uint ReadN1(void) //读原信号计数值
{
uint N1,buf;
Delay30Ms();
N1=0;
CPLD_0=0;
CPLD_1=0;
CPLD_2=0;
Delay30Ms();
buf=CPLD_Data ; //读原信号计数值低8位
N1+=buf;
CPLD_0=1;
CPLD_1=0;
CPLD_2=0;
Delay30Ms();
buf=CPLD_Data ; //读原信号计数值高8位
N1+=buf*256;
return N1; //返回原信号16位计数值
}
uint ReadN2(void) //读异或后信号计数值
{
uint N2,buf;
Delay30Ms();
N2=0;
CPLD_0=0;
CPLD_1=1;
CPLD_2=0;
Delay30Ms();
buf=CPLD_Data ; //读异或后信号计数值低8位
N2+=buf;
CPLD_0=1;
CPLD_1=1;
CPLD_2=0;
Delay30Ms();
buf=CPLD_Data ; //读异或后信号计数值高8位
N2+=buf*256;
CPLD_0=0;
CPLD_1=0;
CPLD_2=1;
Delay30Ms();
pos_neg=CPLD_Data ;//读取超前滞后位
if(pos_neg==0)pos_neg='+'; //当S2超前S1时显示‘+’
else pos_neg='-';
return N2; //返回异或后信号16位计数值
}
uchar ReadAmp(void) //读取ADC8位数据
{
uchar i,DataSoute;
T0831_CS=1;
_nop_();
_nop_();
T0831_SK=1;
T0831_CS=0;
T0831_SK=0;
_nop_();
for(i=0;i<8;i++)
{
T0831_SK=1;
T0831_SK=0;
if(T0831_DO) DataSoute++;
DataSoute<<=1;
}
T0831_CS=1; T0831_SK=1;
_nop_();
_nop_();
return(DataSoute);
}
/**************************主函数定义****************************/
void main(void)
{
LCMInit(); //LCM初始化
fenpin_100=1; //100分频使能端关闭
fenpin_10=1; //10分频使能端关闭
welcome();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -