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

📄 wr_com.pas

📁 汇编操作串口
💻 PAS
字号:
unit wr_com;

interface
const
   //return value indicate
   RC_FAILURE = $00;
   RC_SUCCESS = $01;
   RC_RX_DATE_ERROR = $02;       //状态寄存器指示收数据错;--物理层错
   RC_NO_RX_DATE = $03;         //超时仍未从串口接收数据寄存器收到数据;
   RC_RX_CHECK_ERROR = $04;     //收到返回帧校验错 --用户层错
   RC_TX_SEND_OVERTIME = $11;  //发送超时

const

   {//8250共有10个寄存器
   COM1_STATUS_REG =  $2fd;           //线状态寄存器    LSR
   COM1_CONTROL_REG = $2fb;           //线控制寄存器    LCR
   COM1_RX_DATA_REG = $2f8;           //接收数据寄存器
   COM1_TX_DATA_REG = $2f8;           //发送保持寄存器
   COM1_MODEM_STATUS_REG = $2fe;      //modem状态寄存器
   COM1_MODEM_CONTROL_REG = $2fc;     //modem 控制寄存器
   COM1_DIVIDEFREQ_LOW_REG = $2f8;    //分频寄存器(L)
   COM1_DIVIDEFREQ_HIGH_REG = $2f9;   //分频寄存器(H)
   COM1_INTERUPPT_PERMIT_REG = $2f9;  //中断允许寄存器
   COM1_INTERUPPT_STATUS_REG = $2fa;  //中断标识寄存器   }

   COM1_STATUS_REG =  $3fd;           //线状态寄存器  LSR
   COM1_CONTROL_REG = $3fb;           //线控制寄存器  LCR
   COM1_RX_DATA_REG = $3f8;           //接收数据寄存器
   COM1_TX_DATA_REG = $3f8;           //发送保持寄存器
   COM1_MODEM_STATUS_REG = $3fe;      //modem状态寄存器
   COM1_MODEM_CONTROL_REG = $3fc;     //modem 控制寄存器
   COM1_DIVIDEFREQ_LOW_REG = $3f8;    //分频寄存器(L)
   COM1_DIVIDEFREQ_HIGH_REG = $3f9;   //分频寄存器(H)
   COM1_INTERUPPT_PERMIT_REG = $3f9;  //中断允许寄存器
   COM1_INTERUPPT_STATUS_REG = $3fa;  //中断标识寄存器

type
  TComNum = (stCOM1, stCOM2, stCOM3, stCOM4);

  TUartServo = class          //(TSerialPortUart)
  private
    FBuadRate: integer;       //波特率
    FOddEvenCheck: Integer;   //=0,无校验位;=1,形成奇校验; =3, 形成偶校验位;
    FDataBitNum: integer;            //数据位数;=3,8位;
    FComNum: TComNum;         //哪一个串口:com1,com2,com3,com4
  protected
    Function GetComStatus(): byte;         // override;   //读线状态寄存器的状态值
    Function GetReadyComValue(): byte;   //override;   //串口接收数据已准备好,可以读取一个字节
    Procedure PutReadyComValue(value: byte); //override;   //发送保持寄存器空,可以发送一个字节
    function  GetByte(var  InputValue: byte): integer; // override;//先查询线状态寄存器的状态值,若接收准备好,从串口读单个字节
    function  SendByte(output: byte): integer;  //override;            //先查询线状态寄存器的状态值,若发送准备好,向串口写单个字节
     //发一次下传帧, 下传帧五个字节
    function SendFrame(Command: byte; Data: word): integer;
    //读一次返回帧, 返回帧五个字节
    function  ReceiveFrame(var Command,Status: byte; var Data: word): integer;
  public
    //Constructor Create(WhichCom: TComNum, BuadRate,OddEvenCheck,DataBitNum:integer); //override;
    //Destructor  Destroy;// override;
    //发一个5byte下传帧,取回一个5byte返回帧的状态数据和命令号对应数据
    function TxRxUartCycle(SendCommand: byte; SendData: word; var RecieveStatus: byte;
      var RecieveData: word): integer;
    procedure InitCom();
end;
//var
   //Procedure PushStack();
   //Procedure PopStack();
implementation

//其他pas文件不能调用
Procedure PushStack();
Begin
  asm
    push dx
    push ax
  end;
End;


Procedure PopStack();
Begin
  asm
    pop ax
    pop dx
  end;
End;
//取补码; 如果正数 和零不变; 负数 减1 d0-d6取反;
function ChangeCode(RecieveData: word): Smallint;
var
  temp:word;
begin
  if  (RecieveData = $80) or  (RecieveData = $00)  then
  begin
    Result := 0;
  end
  else
    if ( (RecieveData and $80) = 0) then Result := RecieveData
    else
    begin
      temp := not ( (RecieveData and $7f)-1 );
      Result := -temp;
    end;
end;

// 初始化串口:波特率,起始和停止位,有无奇偶校验
//baudrate  4800  0018; 9600 000c; 19200 0006;  38400 0003;

procedure TUartServo.InitCom();
begin
  asm
    mov dx,COM1_CONTROL_REG //2fbh
    mov al,80h //线路控制寄存器LCR口地址2FBH,80h允许访问除数寄存器低字节DLL
    out dx,al
    mov dx,COM1_DIVIDEFREQ_LOW_REG //2f8h
    mov al,06H  //置除数寄存器低字节DLL口地址2F8H,置波特率(DLL),0cH=9600bits/sec
    out dx,al
    mov dx,COM1_DIVIDEFREQ_HIGH_REG //2f9h
    mov al, 00h //00h 置除数寄存器高字节DLH口地址2F9H,置波特率(DLH)=4
    out dx,al
    mov dx,COM1_CONTROL_REG //2fbh
    mov al,03h  //1bh   $置通信数据格式:起始位(1位),数据8位,无奇偶校验,停止位1位
    out dx,al
    mov dx,COM1_INTERUPPT_PERMIT_REG
    mov al,0    //设中断允许寄存器为0,屏蔽四种中断
    out dx, al

    {mov dx,COM1_MODEM_CONTROL_REG;
    mov al ,13h  //Modem控制寄存器:发DTR和RTS信号,内部输出输入反接,中断方式被禁止
    out dx, al  }
  end;
end;

{ function TxRxUartCycle(SendCommand: byte; SendData: word; var RecieveStatus: byte;
   var ReceiveData: word): integer;
  功能:发一个5byte下传帧,取回一个5byte返回帧的状态数据和命令号对应数据
  输入参数: SendCommand, 单字节,发送的下传帧的命令号值;
           SendData, 双字节,发送的下传帧的数据值;
  输出参数: RecieveStatus,双字节,接收的返回帧的状态值;
           ReceiveData, 双字节,接收的返回帧的数据值;
  返回值:  RC_FAILURE   在规定时间和重发次数内,上位机仍收不到合法的返回帧;
           RC_SUCCESS   在规定时间和重发次数内, 上位机成功接收到合法的返回帧;
           RC_TX_SEND_OVERTIME   超时数据仍不能发送
           RC_RX_DATE_ERROR  状态寄存器指示收数据错;
           RC_NO_RX_DATE    超时仍未从串口接收数据寄存器收到数据;
           RC_RX_CHECK_ERROR 收到返回帧校验错
}

function TUartServo.TxRxUartCycle(SendCommand: byte; SendData: word; var RecieveStatus: byte; var RecieveData: word): integer;
var
  PollResult: integer;
  SendStatus: integer;
  PollCount: integer;
begin
  PollResult := RC_FAILURE;
  PollCount := 0;

  //PushStack();  //DX ,al值保留
  //如果发送下传帧过1ms后未取到返回帧,且轮询次数少于10次,开始下一轮发和收.下传帧后收到返回帧的时间间隔定为10*100us,待测试;

  While ( (PollResult <> RC_SUCCESS) and (PollCount <= 3) ) do
  begin
    PollCount := PollCount + 1;
    SendStatus := SendFrame(SendCommand, SendData);
    if (SendStatus = RC_TX_SEND_OVERTIME) then continue;
    PollResult := ReceiveFrame(SendCommand, RecieveStatus, RecieveData);
  end;
  //PopStack();
  if (SendStatus = RC_TX_SEND_OVERTIME) then
    result:= SendStatus
  else
    result := PollResult // 轮询成功;
end;


{ function SendFrame(Command: byte; Data: word): integer;
 功能:  向下位机发4个字节的下传帧
 输入参数:  Command: byte, 下传帧的命令字节;
            Data: word, 下传帧的数据字;
 输出参数:
 返回值:  RC_SEND_OVERTIME: 上位机产生的下传帧发不下去;
          RC_SUCCESS: 上位机成功发送了下传帧
}
function TUartServo.SendFrame(Command: byte; Data: word): integer;
var
   arrOutput: Array[0..4] of byte;
begin
  //发送命令字节;
  arrOutput[0] := Command;
  if (SendByte(arrOutput[0]) = RC_TX_SEND_OVERTIME) then
  begin
    Result := RC_TX_SEND_OVERTIME;
    exit;
  end;
  //发送命令非字节;
  arrOutput[1] := (not command);
  //if (SendByte(command ->大错特错,不是arrOutput[1]) = RC_TX_SEND_OVERTIME) then
  if (SendByte(arrOutput[1]) = RC_TX_SEND_OVERTIME) then
  begin
    Result := RC_TX_SEND_OVERTIME;
    exit;
  end;
  //发送数据高字节
  arrOutput[2] := (data and $ff00) shr 8;
  if (SendByte(arrOutput[2]) = RC_TX_SEND_OVERTIME) then
  begin
    Result := RC_TX_SEND_OVERTIME;
    exit;
  end;
  //发送数据低字节;
  arrOutput[3] := data and $00ff;
  if (SendByte(arrOutput[3]) = RC_TX_SEND_OVERTIME) then
  begin
    Result := RC_TX_SEND_OVERTIME;
    exit;
  end;
  //发送校验字节,校验字节取校验字节之前的3字节无符号数求和后的和的低字节;
  arrOutput[4] := (arrOutput[0] + arrOutput[1] + arrOutput[2] +  arrOutput[3]) and $00ff ;
  if (SendByte(arrOutput[4]) = RC_TX_SEND_OVERTIME) then
  begin
    Result := RC_TX_SEND_OVERTIME;
    exit;
  end;
  Result := RC_SUCCESS;
end;


//读一次返回帧, 返回帧五个字节
{function  ReceiveFrame(var Command,Status: byte; var Data: word): integer;
 功能:
 输入参数:    Command: byte,命令号,一轮收发内返回帧和下传帧的命令值相同
 输出参数:    Status:word,读取的返回帧的状态值;
              Data:word,读取的返回帧的数据值;
 返回值:     RC_FAILURE  等待超时或校验错,收不到合法的返回帧.
             RC_RX_CHECK_ERROR 收到返回帧校验错 
             RC_RX_DATE_ERROR  状态寄存器指示收数据错;
             RC_NO_RX_DATE 等待超时,仍未从串口接收数据寄存器读到数据;
             RC_SUCCESS  规定时间内收到了合法的返回帧;
}
function TUartServo.ReceiveFrame(var Command,Status: byte; var Data: word): integer;
var
  arrInput: Array[0..4] of byte;
  i: integer;
  GetResult:integer;
begin
  //连续从com1取五个字节
  for i := 0 to 4 do
  begin
    GetResult := GetByte(arrInput[i]) ;
    //如果接收格式错,或接收数据被冲掉;马上重发应答帧
    if (GetResult = RC_RX_DATE_ERROR) then
    begin
      Result := RC_RX_DATE_ERROR;
      exit;
    end;
    if (GetResult = RC_NO_RX_DATE) then
    begin
      Result := RC_NO_RX_DATE;
      exit;
    end;
      
    {GetCount := 1;
    //如果长时间没收到数且查询次数少于2轮,开始下一轮查询
    while ( (GetResult = RC_NO_RX_DATE) and (GetCount <= 2) )  do
    begin
      GetCount := GetCount+1;
      GetResult := GetByte(arrInput[i]);
      if (GetResult = RC_RX_DATE_ERROR) then return RC_FAILURE;
    end;
    if (GetResult = RC_NO_RX_DATE) then return RC_FAILURE;  }
  end;
  //前4字节无符号数求和后的和的低字节与最后一个字节不等,则校验出错,返回失败值
  if ( ( (arrInput[0]+ arrInput[1]+arrInput[2]+ arrInput[3]) and $00ff) <> arrInput[4] ) then
  begin
    Result := RC_RX_CHECK_ERROR;
    exit;
  end;
  //接收命令字节;
  Command := arrInput[0];
  //接收状态字节
  Status := arrInput[1];
  //接收数据字
  Data := (arrInput[2] shl 8)+arrInput[3];
  result := RC_SUCCESS;
end;


{
  function  TUartServo.SendByte(output:byte ):integer;
  功能: 等待发送保持寄存器空, 以发送单个字节;
  输入参数:   output: byte,准备向发送保持寄存器发送的单字节
  输出参数:   无
  返回值:     RC_SEND_OVERTIME 发送保持寄存器保持非空, 超时仍旧发不出去;
             RC_SUCCESS 成功发送单个字节
}

function TUartServo.SendByte(output:byte): integer;
var
  GetCount: integer;
begin
  // 读8250芯片状态寄存器,若D5=1,发送保持寄存器空,可以发送数据;否则等待.
  GetCount := 0;
  while  ( (GetComStatus() and $20) = 0) and (GetCount<=100000)  do
  begin
    GetCount := GetCount+1;
  end;
  If ( GetCount>100000) then
  begin
    Result := RC_TX_SEND_OVERTIME;//RC_FAILURE;
    exit;
  end;
  PutReadyComValue(output);
  Result := RC_SUCCESS;
end;

{function GetByte(var InputValue: byte): integer;
 功能: 等待数据到达串口, 若到达检查收字节是否正确,正确则从串口取单个字节;
 输入参数:
 输出参数: InputValue:byte,从串口接收数据寄存器读取到的字节;
 返回值: RC_RX_DATE_ERROR  状态寄存器指示收数据错;
         RC_NO_RX_DATE 等待超时,仍未从串口接收数据寄存器读到数据;
         RC_SUCCESS   成功从串口接收数据寄存器读取一字节
}
function TUartServo.GetByte(var InputValue: byte) :integer;
var
  ComStatus: byte;
  GetCount: integer;
  i:integer;
Begin
   ComStatus :=GetComStatus();
   //测是否d4=1接收格式错;d2=1数接收据丢失,重叠错.无错,读数;否则放弃接收
   If ( (ComStatus and $0a) <> 0) then
   begin
     result := RC_RX_DATE_ERROR;
     exit;
   end;
   GetCount := 0;
   //d0=1, 接收准备好;d0=0, 未准备好
   While ( ((ComStatus and $01)= 0) and (GetCount<= 100000) ) do
   Begin
     ComStatus :=GeTComStatus();
     If ( (ComStatus and $0a) <> 0 ) then
     begin
       Result := RC_RX_DATE_ERROR;
       exit;
     end;
     GetCount:=GetCount + 1;
   end;
   If ( GetCount > 100000) then
   begin
     Result := RC_NO_RX_DATE;
     exit;
   end;
   InputValue := GetReadyComValue();
   Result := RC_SUCCESS;
end;

{function  GetComStatus():byte;
 功能: 读取线状态寄存器的值, 此值指示当前串口收发的状态信息
 输入参数:
 输出参数:
 返回值: integer; 读取的线状态寄存器的值,指示收发的状态信息。
}
Function TUartServo.GetComStatus():byte;
Var
   Value:byte;
Begin
  Asm
    mov dx, COM1_STATUS_REG //2fdh;
    in  al, dx
    mov Value,al
  end;
  Result := Value;
End;

//从接收数据寄存器读取一个字节
Function  TUartServo.GetReadyComValue(): byte;
var  
  value: byte;
Begin
  Asm
    mov dx,COM1_RX_DATA_REG //2f8h
    in al,dx
    mov Value,al
  end;
  Result := Value;
End;

//向发送保持寄存器发送单字节
Procedure TUartServo.PutReadyComValue(value: byte);
Begin
  asm
    mov dx,COM1_TX_DATA_REG //2f8h   {2F8H口地址}
    mov al,value  {数据发送}
    out dx,al
  end;
End;

end.
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -