51单片机-PASCAL语言实例9:串口编程之多字节收发

// Test9.pas 
Program NewProgram;
// 本程序使用 Trubo51( https://turbo51.com/ ) 单片机 PASCAL 编译器
// 
// 
// 实例 9 演示了单片机串口 按自定协议收发串口数据
// 假设有PC可以发送如下多种命令给单片机        
//     .打开或关闭指定的LED灯 
//     .打开或关闭蜂鸣器
//     .查询LED灯的状态或蜂鸣器状态
//  为此,设计PC发送的命令帧为 4 个字节:
//     起始|命令|设备号|检验
//     起始:固定为 $01
//     命令
//          $4F(字符O) : 开启
//          $43(字符C) : 关闭
//          $51(字符Q ): 查询 
//        检验为前面三个字符值按位与之值
//    设备号:$31(字符 0)--$38(字符 7) LED1 -- LED8 
//              $39 (字符 9)  蜂鸣器
              
              
//      单片机发回PC的应答帧为 4 个字节:起始|设备号|状态|检验 
//      起始:固定为 $01
//        设备:
//      命令
//          $4F(O ): 已开
//          $43(C ): 已关
//   
//        检验为前面三个字符值按位与之值  
    
//  CPU 电路图请看 实例 1 
//  
//  
uses
    Delay,MyDefine;
 
Type
    
    TCmdFrame=Array[1..4] of Byte ;
var
    RxFrame,TxFrame:TCmdFrame;
    RxCnt,TxCnt:byte;
    
const
    // 命令
    CMD_BEGIN=$01  ;
    CMD_OPEN= $4F  ;        // 开启
    CMD_CLOSE=$43  ;        // 关闭
    CMD_QUERY=$51  ;        // 查询
    
    // 设备状态
    DEV_ON=CMD_OPEN ;
    DEV_OFF=CMD_CLOSE;
    
    //设备编号
    DEV_LED1=$30 ; // LED1 
    DEV_LED2=$31 ;
    DEV_LED3=$32 ; 
    DEV_LED4=$33 ;
    DEV_LED5=$34 ;
    DEV_LED6=$35 ;
    DEV_LED7=$36 ;
    DEV_LED8=$37 ;   
    DEV_FM=$39 ;       // 蜂鸣器
    
    // 接收帧各字节位置表意
    RX_FB_BEG=1;
    RX_FB_CMD=2;
    RX_FB_DEV=3;
    RX_FB_CHK=4;
    
    // 发送帧各字节位置表意
    TX_FB_BEG=RX_FB_BEG;
    TX_FB_DEV=2;
    TX_FB_STA=3;
    TX_FB_CHK=4;
    
    
    
    
function GetCheck(AFrame:TCmdFrame):byte;
begin
    // result:=AFrame[1] OR  AFrame[2]    XOR  AFrame[3]   ;
     result:=AFrame[1] +  AFrame[2] + AFrame[3] 
end;


function CheckFrame(AFrame:TCmdFrame):Boolean;
begin
    result:= (AFrame[1]=CMD_BEGIN ) 
             And ( AFrame[RX_FB_CHK] =GetCheck(AFrame)  );
end;    

procedure SendData;
begin
    
   repeat 
         if TI=FALSE then begin
            inc(Txcnt);
            SBUF:=TxFrame[TxCnt];
            While TI=FALSE do begin end;
            TI:=FALSE; 
            
         end;
    until   TxCnt=4;
       
end;


procedure ReciveData;
begin
    if RI=true then begin
         if RXCNT=4 then RXCNT:=0
         else Inc(RXCNT);
         
         RxFrame[RXCNT]:=SBUF;
        
         RI:=FALSE;
    end;
    
    
    
end;

procedure DoCommand;    
var
    ShlNum:byte;

begin
    if RxCnt=4 then begin
    // 检查收到的数据是否正常
        if not CheckFrame(RxFrame)  then exit;
        
        RxCnt:=0;    // 清零,防止重复执行下面操作
        
        // 对命令字进行分析
        Case RxFrame[RX_FB_CMD] of 
            CMD_OPEN:  begin
                // 检查设备号是否蜂鸣器
                if  RxFrame[RX_FB_DEV]=DEV_FM then FM:=FM_ON;
                // 检查设备编号是否为 LED 
                if ( RxFrame[RX_FB_DEV]>=DEV_LED1) AND 
                    ( RxFrame[RX_FB_DEV]<=DEV_LED8)   then begin
                    // 开启对应的 LED
                     ShlNum:=RxFrame[RX_FB_DEV]-DEV_LED1;
                     LED:=LED AND (NOT (1 SHL ShlNum) );
                   
                     
                end;
                
                
            end;
            CMD_CLOSE: begin
                 // 检查设备号是否蜂鸣器
                if  RxFrame[RX_FB_DEV]=DEV_FM then FM:=FM_OFF;
                // 检查设备编号是否为 LED 
                if ( RxFrame[RX_FB_DEV]>=DEV_LED1) AND 
                    ( RxFrame[RX_FB_DEV]<=DEV_LED8)   then begin
                    // 关闭对应的 LED
                     ShlNum:=RxFrame[RX_FB_DEV]-DEV_LED1;
                     LED:=LED OR (1 SHL ShlNum) ;
                     
                end;
            end;
            
            
            CMD_QUERY: begin
                //查询
                TxFrame[TX_FB_BEG]:=CMD_BEGIN;
                TxFrame[TX_FB_DEV]:=RXFrame[RX_FB_DEV] ;
                
                // 检查设备号是否蜂鸣器                
                if  RxFrame[RX_FB_DEV]=DEV_FM then  begin
                    if FM=FM_ON then TxFrame[TX_FB_STA]:=DEV_ON
                    else  TxFrame[TX_FB_STA]:=DEV_OFF;
                    
                end;
                // 检查设备编号是否为 LED 
                if ( RxFrame[RX_FB_DEV]>=DEV_LED1) AND 
                    ( RxFrame[RX_FB_DEV]<=DEV_LED8)   then begin
                    // 关闭对应的 LED
                     ShlNum:=RxFrame[RX_FB_DEV]-DEV_LED1;
                     if (LED AND (1 SHL ShlNum))=$00 then TxFrame[TX_FB_STA]:=DEV_ON
                     else  TxFrame[TX_FB_STA]:=DEV_OFF ;
                     
                end;
                TxFrame[TX_FB_CHK]:=GetCheck(TxFrame) ;
                TxCnt:=0;
                SendData;
            end;
            
        end;   // end case
        
    end;    // if Rxcnt=4
end;






// 串口中断,中断号serial在 system 中定义
procedure OnSerial; interrupt Serial;
begin
   
end;

var
    CMD:Char;
    
/// 主程序开始 //
begin

    // 环境初始化
     
    LED:=$FF ; // 全不亮
    FM:=FM_OFF ; 
    RxCnt:=0;
    TxCnt:=0;
    
    
    
    // TMOD :  D7   D6  D5  D4 |  D3  D2  D1  D0
    //                T1       |        T0
    //         GATE CT  M1  M0 |  GATE CT M1 M0
    
    TMOD:=%00100000; // 设置 T1 工作方式为 2 ,自动重装的8位定时器
    
    // TCON : D7    D6   D5   D4  |    D3   D2  D1  D0
    //       TF1   TR1  TF0  TR0 |     IE1 IT1 IE0 IT0
    
    TH1:=$FD;   //  9600 @12M
    TL1:=$FD;
    
    SM0:=FALSE;      // 设置串口通讯模式为 1
    SM1:=TRUE; 
    
    REN:=True; // 允许串口接收数据
    EA:=True;  // 全局中断开
    ES:=True;  // 串口中断开
  
    TR1:= TRUE ; // 打开定时器 1
  
    
    // 循环里的命令可以中断同步进行
    while true do begin
        
        ReciveData;
        DoCommand;
       
    end;
   
end.
上一篇:基于单片机倒车三路雷达控制报警系统设计-毕设课设资料


下一篇:RX 6800M、RX 6700M和RX 6600M参数对比选哪个