专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

基於DRAM的单片机通信软件程序

作者:佚名   来源:本站原创   点击数:  更新时间:2010年05月30日   【字体:
基於雙口RAM的單片機通信,軟件程序:
#define _DPRAMCOMM_H
#include < reg52.h>        // 引用标准库的头文件
#include < absacc.h>
#define uchar unsigned char 
#define LP_STT_SEM XBYTE[0x0000]    // 左端状态旗语
#define LP_PRO_SEM XBYTE[0x0001]    // 左端配置旗语
#define RP_STT_SEM XBYTE[0x0002]    // 右端状态旗语
#define RP_PRO_SEM XBYTE[0x0003]    // 右端配置旗语
#define INTL_SEM XBYTE[0x0004]   // 左中断旗语
#define INTR_SEM XBYTE[0x0005]   // 右中断旗语
#define DPRAM_INTL XBYTE[0x2FFF]   // 右端口中断
#define DPRAM_INTR XBYTE[0x2FFE]   // 左端口中断
#define READY 11     // 0x11表示准备就绪
bit get_sem(uchar *sem_type);
void InitProvRP(void);
void Prov(void);
void FillState(void);
void GetState(void);
uchar int0flag;      // 外部中断0标志
uchar rdyflag;      // 另一端准备好标志
uchar ProvTimes;     // 表示配置次数
uchar xdata *LpStateRamAddr; // 双口RAM左端状态空间起始地址
uchar xdata *LpProvRamAddr;     // 双口RAM左端配置空间起始地址
uchar xdata *RpStateRamAddr; // 双口RAM右端状态空间起始地址  
uchar xdata *RpProvRamAddr;  // 双口RAM右端配置空间起始地址
uchar xdata ArrayState[254]; // 存放状态信息的数组
/* 40ms定时中断服务子程序:
   定期更新左端单片机的状态信息,查询右端单片机的状态信息*/
void timer0_int() interrupt 1 using 1
{
 TR0 = 0;      // 关闭T0
   TH0 = 0x70;     // 重置40ms定时器的计数初值
   TL0 = 0x00; 
   FillState(); // 定期更新左端单片机状态让右端单片机可查询
   GetState();     // 定期查询右端单片机的状态信息   
}    
/* 外部中断0服务子程序:设置中断标志位int0flag,读清中断*/
void out_int0() interrupt 0 using 1
{
   uchar ch;
   int0flag = 1;  // 表示外部中断0,实际是双口RAM产生的中断
  
   get_sem(&INTL_SEM);                   // 申请并获得左中断旗语
   ch = DPRAM_INTR;       // 读清中断
   INTL_SEM = 0x01;    // 释放左中断旗语
} 


/* 主程序 */
void main()
{ 
 int0flag = 0;
 rdyflag = 0;
 ProvTimes = 0;
 LpStateRamAddr = 0x2000;
 LpProvRamAddr = 0x2400;
 RpStateRamAddr = 0x3000;
 RpProvRamAddr = 0x3400;
 /* 等待右端单片机准备就绪 */
 while(rdyflag!=1)
 {
  get_sem(&RP_STT_SEM);  // 申请并获得右端状态旗语
  if (*RpStateRamAddr == READY) 
   rdyflag = 1;   // 右端单片机准备就绪标志置1
  RP_STT_SEM = 0x01;   // 释放右端状态旗语
 }

 /* 对右端单片机进行初始配置 */
 InitProvRP(); 
 /* 通过向左端状态空间的第一地址单元写READY向右端表示左端准备就绪 */
 get_sem(&LP_STT_SEM);   // 申请并获得左端状态旗语
 *LpStateRamAddr = READY;  // 左端单片机准备就绪
 LP_STT_SEM = 0x01;    // 释放左端状态旗语

 ProvTimes++;     // 对右端口的配置次数加1  

 EA = 1;       // 开CPU中断
   EX0 = 1;      // 开外部中断0 
 ET0 =1;       // 开T/C0中断
   PX0 = 0;      // 外部中断低优先级
   PT0 = 1;      // 计数器高优先级
   TMOD = 0x01;     // T/C0工作在方式1
   TH0 = 0x70;      // 预置40ms定时器的计数初值
   TL0 = 0x00;
   TR0 = 0;      // 不启动T0

/* 右端单片机接收左端对其的初始化配置,运行正常后触发双口RAM的
左端中断,左端单片机受中断触发后对右端单片机作第二次配置,并启
动40ms定时器,开始定期更新本机的状态信息并监测右端单片机的状态 */
    while(int0flag==1)
 {
  if (ProvTimes==1)
  {
   ProvTimes++;   // 对右端口的配置次数加1
   Prov();     // 对右端口单片机二次配置
   
   /* 通过出发右端中断,通知右端单片机接受二次配置*/
   get_sem(&INTR_SEM);  // 申请并获得右中断旗语
     DPRAM_INTL = 0xFF;     // ITNR脚为低,出发右端单片机中断
     INTR_SEM = 0x01;  // 释放右中断旗语
  }

  TR0 = 1;     // 启动40ms定时器T0  
 }   
}

/* 申请并获得旗语函数 */
bit get_sem(uchar *sem_type)          
{
   *sem_type = 0x00;    // 申请旗语
   while((*sem_type!=0x00));  // 无限循环直至获得旗语    
   return(1);
}


/* 对右端单片机的初始化配置函数:为简化起见,通过向左端的配置
   空间2500H~25FFH全写0x22,表示对右端单片机的初始配置命令  */
void InitProvRP(void)
{
 uchar i;
 get_sem(&LP_PRO_SEM);   // 申请左端配置旗语 
 for (i=0;i++;i<=255)
  *(LpProvRamAddr+i) = 0x22; 
 LP_PRO_SEM = 0x01;    // 释放左端配置旗语  
}
/* 对右端单片机的二次配置函数:为简化起见,通过向左端的配置
   空间2500H~25FFH全写0x33,表示对右端单片机的初始配置命令  */
void Prov(void)
{
 uchar i;
 get_sem(&LP_PRO_SEM);   // 申请左端配置旗语 
 for (i=0;i++;i<=255)
  *(LpProvRamAddr+i) = 0x33; 
 LP_PRO_SEM = 0x01;    // 释放左端配置旗语
}
/* 更新本机状态函数:为了简化起见,此函数表示为向左端状态空
   间第一地址单元(存放设备就绪信息)以后的254字节全写0x44  */
void FillState(void)
{
 uchar i;
 get_sem(&LP_STT_SEM);   // 申请并获得左端状态旗语
 for (i=0;i++;i<=254)
  *(LpStateRamAddr+i+1) = 0x44;
 LP_STT_SEM = 0x01;    // 释放左端状态旗语
}

/* 查询另一端单片机状态函数:为简化起见,此函数表示为用数组
   ArrayState存取右端状态空间第一地址单元(存放设备就绪信息)
   以后的254字节(3001H~30FFH)包含的状态信息  */ 
void GetState(void)
{
 uchar i;
 get_sem(&RP_STT_SEM);   // 申请并获得右端状态旗语
 for (i=0;i++;i<=254)
  ArrayState[i] = *(RpStateRamAddr+i+1);
 RP_STT_SEM = 0x01;    // 释放右端状态旗语
}


关闭窗口

相关文章