************************************************************************************** 
工程名称:双机通信 
说明:此程序可以实现两个 单片机 之间的相互通信;串口采用方式1  
      工作,10位异步接受和发送,波特率可变,由定时器1控制;且含有校验 
程序说明:SCON:串口通信控制寄存器 
SBUF:串行口的收发缓冲寄存器 
 PCON:电源管理寄存器。当SMOD=1时串行口的波特率加倍。 
IE:中断允许寄存器。ES=1表示允许串行口中断 
TI:发送中断标志位,TI由硬件置位,置位表示一帧信息发送结束,TI在发送数据前必须由软件清0 
RI:接收中断标志位,RI由硬件置位,置位表示一帧信息接收结束,RI在接收数据前必须由软件清0 
完成日期:2009年8月18日 
修改日期:2009年8月23日 
*******************************************************************************************/ 
#include<reg51.h> //将51中定义常用特殊功能寄存器的变量定义文件包含进来 
#include "LCD12864.h" 
unsigned long vo_num1=0;//接收到的频率值 
unsigned long vo_num3=0;// 接收到的失真度 
unsigned int vo_num4=0;//缓存校验值 
unsigned char vo_num2[8];//缓存我们串口接收到的数据 
unsigned char m=0; 
unsigned int buf; 
unsigned int pf=0;//校验和 
#define seg_c P2 //将数码管的段显示定义到P2口 
#define bit_c P0   //将数码管的位选择定义到P0口 
#define fosc  22118400  //定义晶体振荡频率 
#define  bps  9600 //定义我们要通讯的波特率 
#define th1   256-(fosc/12/16/bps)   //利用宏计算出我们要给定时器中赋什么样的值才能满足我们需要的波特率 
//将0-F 查表 成我们键盘对应的字符  
unsigned char  code  seg[11]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0xff};//定义从0-9 所对应的段码 
unsigned char  num[8]={9,8,7,6,5,4,3,2}; //声明8个显示缓存 对应我们数码管的8个位        
/********************************************************************************** 
函数名称:串口初始化函数 
**********************************************************************************/                
void serial_init (void)  //在使用串口模式1 前要初始 化串口寄存器等... 
{            
  SCON=0x50;   //串口工作于方式1,10位异步接收/发送,波特率可变 
  TMOD=0X20; //因为模式1用到了定时器1的自动重装模式,所以要这样设置定时器 
  PCON=0X00; //为了让通讯速率更快,设置SMOD=1 那么它所在的寄存器PC0N=0X80 ,串行口的波特率加倍。 
  TH1=th1; //将宏计算的定时器初值放到TH1中 
  TL1=th1;      
  TR1=1;//启动定时器来产生串口工作所需要的波特率 
  ES =1;//允许出串口中断 
  EA=1; //打开总中断允许位 
} 
/********************************************************************************** 
函数名称:串口发送数据函数 
**********************************************************************************/  
void putbyte(unsigned char byte)// 利用硬件串口方式1 发送一个字节数据 
{ 
   SBUF=byte;//将要发送的数据送到发送缓冲区域,系统自动发送 
   while(!TI);//查询是否发送结束  当TI=1  代表发送结束 
   TI=0;//清发送结束位方便下一次发送 
} 
/********************************************************************************** 
函数名称:串口接收数据函数 
说明:采用中断方式接收数据,串口中断的服务号是4 
**********************************************************************************/  
//串口中断服务函数  无论接收中断或者发送中断都能进来 
serial () interrupt 4   
{     
  if(RI)   //RI=1,表示一桢数据接收完 
  {                          
   vo_num2[m]=SBUF; 
   m++; 
 //  if(m>8) 
//   m=0;    
   } 
    RI=0;  //RI清0之后才能接收到下一帧数据。 
 }             
/********************************************************************************** 
函数名称:软件延时函数 
**********************************************************************************/  
void delay(unsigned char ms) //软件延迟函数 
{ 
  unsigned int a=0; 
   while(ms--) 
   { 
     for(a=0;a<10;a++); 
   } 
} 
/********************************************************************************** 
函数名称:显示函数 
说明:数码管段选是P2口,位选是P0口。 
**********************************************************************************/  
 void display(unsigned int dis) 
{  
        unsigned char loop=0; 
         num[0]=10; 
         num[1]=10; 
         num[2]=10; 
         num[3]=dis/10000;            //得到要显示数据的万位 
         num[4]=(dis%10000)/1000;     //得到要显示数据的千位 
         num[5]=(dis%1000)/100;       //得到要显示数据的百位 
         num[6]=(dis%100)/10;         //得到要显示数据的十位 
         num[7]=(dis%10);             //得到要显示数据的个位 
  for(loop=0;loop<8;loop++) 
         { 
           bit_c=~(0x01<<loop); 
           seg_c=seg[num[loop]]; 
           delay(6); 
     seg_c=0xff;       //在这里加了这句话,消除鬼影 
         }          
}  
/********************************************************************************** 
函数名称发送校验函数 
说明: 
**********************************************************************************/  
void  check_transport( unsigned int buf) 
{   
    do 
 {   pf=0x00;                        //校验和清零 
     putbyte(buf);                   //发送数据并求解校验和   
     pf=(pf+buf&0x01+buf&0x02+buf&0x04+buf&0x08+buf&0x10+buf&0x20+buf&0x40+buf&0x80); 
                                 //求解校验和 
     putbyte(pf);                   //发送校验和     
     } while(SBUF!=0);   
} 
/********************************************************************************** 
函数名称:接收校验函数 
说明: 
**********************************************************************************/  
void check_receive() 
{   
while(1) 
   {          
  pf=0x00;                         //校验和清零                
//      vo_num4=SBUF; 
//  pf=pf+(vo_num4&0x01+vo_num4&0x02+vo_num4&0x04+vo_num4&0x08+vo_num4&0x10+vo_num4&0x20+vo_num4&0x40+vo_num4&0x80);   
        vo_num2[m]=SBUF; 
  pf=pf+( vo_num2[m]&0x01+vo_num2[m]&0x02+ vo_num2[m]&0x04+ vo_num2[m]&0x08+ vo_num2[m]&0x10+ vo_num2[m]&0x20+ vo_num2[m]&0x40+vo_num2[m]&0x80); 
                                  //求解校验和 
  if((SBUF^pf)==0x00)             //判断求出的校验和与接收到的校验和是否相等 
   { 
      putbyte(0x00);   
    m++;          
   break; 
   } 
   else  
   { 
    putbyte(0xff);              //如果不相等。则发送ff   
          } 
      }//while(1) 
}     
/********************************************************************************** 
函数名称:主函数 
说明: 
**********************************************************************************/  
void disp(void) 
{ 
 lcd_init(0); 
 refrash_charactor(); 
 lcd_clear(); 
 str_1="频率:        Hz"; 
 str_2="失真度:0.      "; 
 lcd_display(1,1,str_1); 
 lcd_display(1,2,str_2); 
} 
main() 
{ 
   unsigned char temp; 
    serial_init ();  //在使用串口模式1 前要初始   
    disp();                                      
  while(1) 
  {      
//      putbyte(0xeb)  ; 
//   putbyte(0x90)  ; 
//   putbyte(0xaa)  ; 
//   m=0;               
//      check_receive();   
     if(vo_num2[0]==0xeb&&vo_num2[1]==0x90&&vo_num2[2]==0xaa)   
  { vo_num1=vo_num2[3]*256+vo_num2[4];//频率 
   vo_num3=(vo_num2[5]*256+vo_num2[6])*10; //失真度 
   refrash_charactor(vo_num1,vo_num3); 
   lcd_display(4,1,freq); 
   lcd_display(6,2,dist); 
   m=0; 
  } 
  }//while(1)  
}