⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sinewaveparametersmeasuring.c

📁 我的毕业设计
💻 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 + -