Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 3892|回复: 6

[Lazarus实战宝典] Turbo51学习笔记(8) 51单片机端的串行通信代码

[复制链接]

该用户从未签到

发表于 2015-1-16 23:49:53 | 显示全部楼层 |阅读模式
本帖最后由 逍遥派掌门人 于 2015-1-16 23:58 编辑

    在不同设备上进行数据交换,最价廉物美的莫过于串行通信(RS232)了,有关串行通信的点滴可自行去百度搜索。

    在以下的篇幅里,展示51单片机如何与计算机进行通信,本节解析51单片机的Turbo51代码,下一节解析计算机端的Lazarus代码。

    先上51单片机的硬件电路图,

            

    图里有1个绿色的LED和1个蓝色的LED,计算机通过RS232控制这两个LED的亮灭。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册(注册审核可向QQ群索取)

x
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:05:01 | 显示全部楼层
    在通信之前,必须约定一个握手的协议,以保证通信的正确无误。此工作非常重要。
    通信协议可采用各种流行的协议,也可以自行约定。为了简化代码,自设定如下的通信协议:

    1、  上位机 ==> 单片机  
      格式:  起始字  + 单片机地址  +  命令  +  校验
              1byte       1byte        1byte    1byte     =  4 byte
         
      其中:
           起始字,固定为:     $7E
           单片机地址,固定为: $01
           命令,控制单片机的动作:
                   = $00     同时灭两个LED
                   = $01     亮绿色LED,灭蓝色LED
                   = $02     灭绿色LED,亮蓝色LED
                   = $03     同时亮两个LED
           校验,为前面3个字节的累加和

    2、  单片机 ==> 上位机   
      格式:  起始字  + 单片机地址  +  命令  +  参数  +  校验
              1byte       1byte        1byte    1byte    1byte    =  5 byte
              
      其中:
           起始字,固定为:     $7E
           单片机地址,固定为: $01
           命令,来自计算机端:
                   = $00     同时灭两个LED
                   = $01     亮绿色LED,灭蓝色LED
                   = $02     灭绿色LED,亮蓝色LED
                   = $03     同时亮两个LED
           参数,将当前单片机的控制状态反馈给计算机
                   = $00     两个LED都灭
                   = $01     绿色LED亮,蓝色LED灭
                   = $02     绿色LED灭,蓝色LED亮
                   = $03     两个LED都亮
           校验, 为前面4个字节的累加和
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:21:46 | 显示全部楼层
//定义用到的常量
  1. Const
  2.       BaudRate            = 9600;           {通信用的波特率}
  3.       Header                = $7E;             {起始字}
  4.       Address               = $01;             {单片机地址}
  5.       TX_Length          = 5 ;                 {按照协议,发送的字节数}
  6.       RX_Length          = 4 ;                {按照协议,接收的字节数}         
  7.       Port_Mask           = $03;              {这里与LED有关}
复制代码
//定义用到的变量
  1. var
  2.       Port_Get : byte absolute P1;         
  3.       LED_green: Boolean absolute P1.0;
  4.       LED_blue : Boolean absolute P1.1;
  5.       
  6.       RX_Buffer: Array [1..RX_Length] of Byte;    {接收缓冲区}
  7.       RX_Count : Byte;                           
  8.       TX_Buffer: Array [1..TX_Length] of Byte;    {发送缓冲区}
  9.       TX_Count : Byte;
  10.       RX_right : Boolean;
  11.       TX_right : Boolean;
  12.       TX_Need  : Boolean;
复制代码
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:28:21 | 显示全部楼层
本帖最后由 逍遥派掌门人 于 2015-1-17 00:38 编辑

       51单片机的接收和发送都进入同一个串行中断,而且是接收或发送一个字节就产生一个中断,故此,关键的串行中断代码如下:
  1. Procedure RS232; Interrupt Serial;
  2. begin
  3.     If (RI = True) then          {接收中断}
  4.     begin
  5.        RI := False;
  6.        if (RX_right = False) then
  7.        begin
  8.            RX_Buffer[RX_Count] := SBUF;       {接收字节}
  9.           inc(RX_Count);
  10.           if (RX_Count > RX_Length) then  RX_right := True;   {判断是否接收完毕}
  11.       end;
  12.   end;

  13.   If (TI =True) then          {发送中断}
  14.   begin
  15.      TI := False;
  16.      if  (TX_right = False) then
  17.     begin
  18.         if TX_Count < (TX_Length + 1) then    {判断是否已经发送完毕}
  19.        begin
  20.           SBUF := TX_Buffer [TX_Count];       {发送字节}
  21.           Inc (TX_Count);
  22.       end
  23.       else  TX_right := True;
  24.     end;
  25. end;

  26. end;
复制代码
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:44:30 | 显示全部楼层
本帖最后由 逍遥派掌门人 于 2015-1-17 00:46 编辑

//处理接收到的数据
  1. Procedure Do_receive;
  2. var
  3.    number   : byte;
  4.    checksum : byte;
  5. begin
  6.   if (RX_right = True) then
  7.   begin
  8.     if ((RX_Buffer[1] = Header) and (RX_Buffer[2] = Address)) then                  {判断是否合法}
  9.     begin
  10.       checksum := 0;
  11.       for number := 1 to (RX_Length-1) do checksum:= checksum + RX_buffer[number];   {计算校验和}
  12.       if (checksum = RX_buffer[RX_Length]) then                                      {校验通过}
  13.       begin
  14.         case  RX_buffer[3] of     {判断命令}
  15.           $01:                    
  16.               begin
  17.                 LED_green := False;     {亮绿色LED}
  18.                 LED_blue  := True;      {灭蓝色LED}
  19.               end;
  20.           $02:
  21.               begin
  22.                 LED_green := True;     {灭绿色LED}
  23.                 LED_blue  := False;    {亮蓝色LED}
  24.               end;  
  25.           $03:
  26.               begin
  27.                 LED_green := False;   {亮绿色LED}
  28.                 LED_blue  := False;   {亮蓝色LED}
  29.               end;  
  30.           $00:
  31.               begin
  32.                 LED_green := True;     {灭绿色LED}
  33.                 LED_blue  := True;     {灭蓝色LED}
  34.               end;        
  35.         end;
  36.         TX_Buffer[3] := RX_buffer[3];
  37.         TX_Need := True;                           {发送应答}
  38.         TX_Buffer[4] := (not Port_Get) and Port_Mask;    { 获取LED控制脚的状态}
  39.       end;           
  40.     end;

  41.     RX_Count := 1;         
  42.     RX_right := False;         
  43.   end;  
  44. end;
复制代码
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:49:42 | 显示全部楼层

//待发送数据的预处理
  1. Procedure Do_send;
  2. var
  3.    number  : byte;
  4.    checksum: byte;
  5. begin
  6.   if  (TX_Need = True) then
  7.   begin
  8.     checksum := 0;
  9.     for number := 1 to (TX_Length -1) do checksum := checksum + TX_Buffer[number];    {计算校验和}
  10.     TX_Buffer[TX_Length] := checksum;
  11.     TX_Count := 1;
  12.     TX_right := False;
  13.     TX_Need  := False ;   
  14.     TI       := True;                      {开启发送}
  15.   end;
  16. end;   
复制代码
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2015-1-17 00:52:36 | 显示全部楼层
本帖最后由 逍遥派掌门人 于 2015-1-17 00:54 编辑

//主循环
  1. begin
  2.   Init;          {初始化单片机,此处略}

  3.   Repeat
  4.     Do_receive;
  5.     Do_send;
  6.   until False;
  7. end.
复制代码
单片机部分就此完成。
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

GMT+8, 2024-9-12 04:40 , Processed in 0.027298 second(s), 9 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表