// 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.