PIC16系列单片机与PC机串行通信的软硬件实现

老夫子   2009-12-9 14:01 楼主
摘 要: 介绍一种运用 PIC16F84单片机实现与PC机串行通信的方法,并给出其硬件接口电路及通信源程序。

1 前言

美国 Microchip 公司的 PIC16 系列单片机是一种新型的 CMOS 工艺的 8 位单片机。其中, PIC16FXX 单片机的程序存储器为电可擦除闪速存储器( flash ),可多次修改程序,甚至可以在线编程。 PIC16F83 和 PIC16F84 片内数据存储器除 RAM 外,还有 64 字节的 EEPROM ,可以当作一般的或非易失性的数据存储器使用,简单方便。它还具有片内上电复位、延时电路、看门狗电路等。另外, PIC16 系列单片机功耗极低,因而是一种非常适合在各种便携式设备中使用的高性价比的单片机,并已经得到了越来越广泛的应用。

但是在许多需要大量计算的运用中,还必须借助微机的强大数据处理能力。这样必须通过通信电路实现 PIC 单片机与微机间的可靠数据传输。有的 PIC16 单片机内并没有提供串行口,所以串行通信必须通过自己设计的硬件电路和通信软件来实现。

下面介绍用查询法实现异步串行通讯的方法。同时给出了用 PIC16F84 单片机的两个 I/O 口模拟 2 线串行口的硬件接口电路、程序流程框图、单片机内通信程序以及微机内的通信程序等。

2 硬件实现方法与电路

PIC16F84 的程序存储器由 1K × 14 的闪速( flash )存储器构成,它只有 13 条 I/O 口, 1 个定时器,为了尽量节省单片机的软硬件资源,采用下述异步串行通信的实现方法。

如图 1 所示, PIC16F84 在 4MHz 时钟下,采用半双工方式,可实现 9600 波特率的异步串行数据通信, 1 位停止位, 8 位数据位,无校验位。接收和发送以低位在先(一般模式),采用软件延时。为节省篇幅,单片机内的通信程序中未提供任何握手协议,用户可根据自己的需要在软件中加入握手方式。

由于 PIC16F84 本身没有专门的串行口,这里用其 I/O 口来模拟串行口的功能。

PC 机的串行接口是符合 EIA RS-232C 规范的外部总线标准接口。 RS-232C 采用的是负逻辑,即逻辑“ 1 ”:- 5V 至- 15V ;逻辑“ 0 ”: +5V 至 +15V 。而 CMOS 电平为:逻辑“ 1 ”: 4.99V ,逻辑“ 0 ”: 0.01V ; TTL 电平的逻辑“ 1 ”和“ 0 ”则分别为 2.4V 和 0.4V 。因此在用 RS-232C 总线进行串行通信时需外接电路实现电平转换。在发送端用驱动器将 TTL 或 CMOS 电平转换为 RS-232C 电平,在接收端用接收器将 RS — 232C 电平再转换为 TTL 或 CMOS 电平。

这里选用了 MAXIM 公司的 MAX202E 来作电平转换。 MAX202E 属于 MAXIM 公司的通用串行接收 / 发送驱动器芯片。其外围电路简单,只需外接四个 0.1 μ F 的电容即可,如图 1 所示。

1.gif

图 1 接口原理图

2.gif

图 2 接收子程序框图 图 3 发送子程序框图

3 PIC16F84 单片机内通信程序的设计

图 2 和图 3 分别是串行发送和接收的子程序流程框图。发送时,通过使数据发送端 DX 为低电平并保持 B 秒( 9600 波特率时为 104 μ s )来发送起始位。随后每 B 秒钟通过置位或清零 DX 端把数据发送出去。这里的 B 是指一位所持续的时间( B=1/ 波特率)。接收时,数据接收端 DR 大约要每 B/2 秒( 9600 波特率时为 52 μ s )查询一次以检测起始位,如果检测到起始位,则在大约 1.5B 秒( 9600 波特率时为 156 μ s )后检测第一位数据位,随后每 B 秒钟检测一次其它的数据位。  相应的源程序如下:


  1. ;接收子程序
  2. Rcvr
  3. clrwdt                                    ;清片内看门狗
  4.                                           ;定时器
  5.          btfsc         RA , DR           ;检测起始位
  6.          goto          Rcvr               ;未检测到起始位
  7.          movlw         8                  ;检测到起始位
  8.          movwf         R_CNT              ; 8 位数据位
  9. Rnext
  10.          call          Delay              ;延时 B/2 秒
  11.          bcf           STATUS,C           ;清进位标志
  12.          rrf           RevReg             ; LSB 在先
  13.          btfsc         RA,DR              ;该位为 0
  14.                                           ;还是为 1
  15.          bsf           RcvReg , MSB      ;为 1
  16.          call          Delay              ;延时 B/2 秒
  17.          decfsz        R_CNT
  18.          goto          Rnext
  19.     retlw0                  ;返回
  20. ;发送子程序
  21. Xmtr
  22.     clrwdt                  ;清片内看门狗
  23.                             ;定时器
  24.     movlw      8            ;发送位数为 8
  25.     movwf      X_CNT
  26.     bcf        RA , DX     ;发送起始位
  27. Xnext
  28.     call       Delay        ;延时 B/2 秒
  29.     call       Delay        ;延时 B/2 秒
  30.     rrf        XmtReg       ; LSB 在先
  31.     btfsc      STATUS,C     ;检测将要发送
  32.                             ;的数据位
  33.     bsf        RA,DX        ;数据位为 1
  34.     btfss      STATUS , C
  35.     bcf        RA , DX     ;数据位为 0
  36.     decfsz     X_CNT        ;位计数为 0 则
  37.                             ;发停止位
  38.     goto       Xnext        ;位计数不为 0
  39.                             ;则发下一位数据位
  40. Xstop
  41.     call       Delay        ;延时 B/2 秒
  42.     call       Delay        ;延时 B/2 秒
  43.     Bsf        RA,DX        ;发送停止位
  44.     Retlw      0            ;返回
  45. ;延时子程序
  46. Delay
  47.     movlw  12   ; 52 μ S 延时
  48.     movwf  DCNT ;
  49. Dnext
  50.     decfsz DCNT
  51.     goto   Dnext ;
  52. retlw 0          ;

4 Win95 的串行通信机制及串口查询法的原理

常用的 DOS 系统主要是工作在响应中断方式。 PC 机串行通信程序大多利用其 BIOS 块的 INT14H 中断,以查询串口的方式完成异步串行通信。

Windows 系统函数即包含了通信支持中断功能。 Win95 系统为每个通信设备开辟了用户定义的输入输出缓冲区(即读 / 写缓冲区),数据进出通信口均由系统后台来完成。应用程序只需完成对输入输出缓冲区操作就可以了。实际过程是每接收一个字符就产生一个低级硬件中断, Win95 系统中的串行驱动程序就取得了控制权,并将接收到的字符放入输入数据缓冲区。然后将控制权返还正在运行的应用程序。如果输入缓冲区数据已满,串行驱动程序用当前定义的流控制机制通知发送方停止发送数据。队列中的数据按“先进先出”的次序处理。

(1) 按协议的设置初始化并打开串口,这样做就是通知 Windows 本应用程序需要这个串口,并封锁其他应用程序使它们不能使用此串口。
(2) 配置这个串口。
(3) 在串口上往返地传输数据,并在传输过程中进行校验。
(4) 不需要此串口时,关闭串口。即释放串口以供其它应用程序使用。
  在这四个步骤中,主要的程序代码集中在第( 3 )步。
  串口查询法是一种主要工作在查询方式下的实现方法。当通信程序工作在“查询”方式时,可以不考虑 Win95 的进程和线程的问题。仅在串口有数据时,去读串口缓冲区就可以了,如图 4 所示。这种方法下确定串口读取的时机、握手协议及软件纠错的实现是程序员应考虑的主要问题。
3.gif
图 4 读取接收缓冲区数据流程图

4.gif
图 5 串口初始化流程


由于这种方法主要工作在查询方式。程序员必须完成相当一部分通信状态的检测工作,许多细节(甚至包括通信过程中的字符属性的转换)也必须通过程序代码完成。这种查询方法对通信双方协议的依赖性尤其大。双方通信协议的约定对程序实现的难易程度影响很大。

串口查询法中,一般串口初始化的流程如图 5 。


值得注意的一点是,此方法下协议的约定必须满足以下条件:即甲方发送时,乙方必须在甲方发送动作之前进入循环接收状态,直到接收到字符后通过对串口读取函数 ReadFile 返回值的判断跳出循环状态。

同时,一般为了不使系统因循环等待接收而进入“死循环”状态,可以人为设置读取串口的循环次数,一般 1000 ~ 10000 次即可。 本程序的实现平台是 VB4 ,这是一种极为灵活的高级语言,它可以方便地引入汇编语言的思维,利用其 GoTo 转向语句方便地控制程序的流程,灵活方便。
5 PC 机内通信程序的实例
现约定甲方是 PC 机,乙方是单片机系统(如读卡器)。通信格式设置为 2400 波特率, 8 位数据位, 1 位停止位,无奇偶校验。 下面是一个约定好通讯协议的程序实例,协议流程如图 6 所示。 以下是甲方( PC 机)的几个子函数的程序实例。

5.gif

图 6 通信协议流程

[ 本帖最后由 老夫子 于 2009-12-9 14:19 编辑 ]

回复评论 (5)

  1. Private Function OpenThePort ( cPort as String , cBaud as String , cParity

  2. as String , cData as String , tStops asString ) As Boolean ' 打开串口的子过程

  3. Dim lResult as Long

  4. Dim lHandle as Long

  5. Dim DCB_COMM as DCB

  6. Dim cDCBConfig as String

  7. lHandle = CreateFile ( cPort , GENERIC_READ Or GENERIC_WRITE ,

  8. 0& , 0& , OPEN_EXISTING , 0& , 0& )

  9. If lHandle = -1 Then '打开串口失败

  10. OpenThePort = False

  11. MsgBox “串口可能正被其他应用程序占用!”

  12. lResult = CloseHandle ( lHandle ) '先关闭串口后再打开

  13. If lResult = 0 Then

  14. OpenThePort

  15. Exit Function

  16. End If

  17. End If

  18. cDCBConfig.band = 2400 '设置 DCB

  19. cDCBConfig.parity = None

  20. cDCBConfig.data = 8

  21. cDCBConfig.stop = 1

  22. lResult = BuildCommDCB ( cDCBConfig , DCB_COMM ) '按用户设定配置一个 DCB 结构

  23. If lResult = 0 Then

  24. OpenThePort = False

  25. MsgBox “无法建立 DCB 设备控制块”

  26. Exit Function

  27. End If

  28. lResult = SetCommState ( lHandle , DCB_Comm ) '实际设置一个串口的 DCB

  29. If lResult = 0 Then

  30. OpenThePort = False

  31. MsgBox “无法建立 DCB 设备控制块”

  32. Exit Function

  33. End If

  34. OpenThePort = True

  35. End Function

  36. Private Sub SendHand ( ) '发送握手信号的子过程

  37. Dim Nchars As Long

  38. Static Readbuff As String * 1

  39. Static Writebuff As String * 1

  40. Dim lpDCB As DCB

  41. Dim lRet As Long

  42. Dim lHandle As Long

  43. Dim lpOverlapped As OVERLAPPED

  44. Dim RNum As Integer

  45. MsgBox “请把读卡器插在串口 2 上!”,

  46. 48 ,“提示窗口”

  47. lHandle = OpenThePort ( COMM1,2400,None,8,1 )

  48. lRet = PurgeComm( lHandle , 1 ) '清输出缓冲区

  49. lRet = PurgeComm( lHandle , 0 ) '清输入缓冲区

  50. lRet = GetCommState ( lHandle , lpDCB ) '获得通讯口的状态

  51. Shand :

  52. Writebuff $ = Chr $ (&H8F)

  53. lRet = WriteFile (lHandle,Writebuff $ ,1,Nchars,lpOverlapped )

  54. '送握手信号入串口缓冲区

  55. If lRet <= 0 Then

  56. MsgBox “发送操作出错,卡握手信号未发送成功”, 16

  57. GoTo Shand '不成功则重发

  58. Else

  59. GoTo Qtest

  60. End If

  61. GoTo Shand

  62. Qtest :

  63. Readbuff$ = “ ” '清除缓冲区为空

  64. Do While lHandle '循环查询串口

  65. RNum = 0 '设置读串口次数的指针为 0

  66. ReadAgain :

  67. lRet = ReadFile( lHandle , Readbuff $, 1 , Nchars , lpOverlapped )

  68. If lRet < 0 Then

  69. MsgBox “读取应答信号时出错”, 16

  70. End If

  71. If lRet = 0 Then

  72. If RNum > 1000 Then '只读 1000 次串口,以免陷入死循环

  73. MsgBox

  74. " 卡没有插接好或卡没有接在串口上 !"

  75. GoTo CloseP

  76. End If

  77. RNum = RNum + 1

  78. GoTo ReadAgain

  79. End If

  80. If Hex $ (Asc(Readbuff)) <> Hex $ (&HFF) Then GoTo Shand

  81. '回送码不正确则返回继续发送握手信号

  82. Else

  83. Label1.Caption = “握手信号是:”

  84. + Hex $ (Asc(Readbuff $ ))

  85. Msgbox “握手信号正确,已正确联机”

  86. GoTo CloseP

  87. End If

  88. Loop

  89. CloseP : lRet = CloseHandle( lHandle )

  90. If lRet = 0 Then

  91. MsgBox “串行通讯口关闭成功”,

  92. 48 ,“提示窗口”

  93. End If

  94. End Sub



这里要注意的是:当 PC 机与单片机系统通信时,单片机数据存储区 ( RAM ) 内的数据是十六进制,在信号线上传输的是十六进制数的 ASCII 码的二进制形式;而 Windows 系统下使用的是 ANSI 码, ANSI 码仅在前 126 个与 ASCII 码相同。即在 Win95 下接收到的是十六进制数的 ASCII 码的字符串,可先转换为 ANSI 码后再在 Win95 下还原为十六进制数。
具体为: Code$=Hex $ (Asc ( Readbuff$ ) ) 另外,由于 32 位 API 函数参数的数据类型的变化,所有整形参数都被换为长整型( Long )以支持 32 位的处理,这一点在设置返回值时尤其如此。
6 结束语
以上的软硬件在我们的实践中达到了较为理想的效果。通过软件节省了硬件的开销,并通过在 PIC16F84 单片机系统和 PC 机双方的通信软件内增加握手信号,达到了软件数据校验的目的,获得了较高的通信可靠性。
参 考 文 献
1 MICROCHIP CO. PIC16/17 MICROCO-NTROLLER DATA BOOK. 1995/1996 2 李东星等 . PIC16CXX 系列单片机应用设计 . 高奇电子科技公司, 1996.10 3 美 Darwin Boyle 等 . Visual Basic 4 Developer ' s Guide. 北京:机械工 业出版社, 1997.
点赞  2009-12-9 14:06
串口通讯的概念及接口电路

随着计算机系统的应用和微机网络的发展,通信功能越来越显的重要。这里所说的通信是只计算机与外界的信息交换。因此,通信既包括计算机与外部设备之间,也包括计算机和计算机之间的信息交换。由于串行通信是在一根传输线上一位一位的传送信息,所用的传输线少,并且可以借助现成的电话网进行信息传送,因此,特别适合于远距离传输。对于那些与计算机相距不远的人-机交换设备和串行存储的外部设备如终端、打印机、逻辑分析仪、磁盘等,采用串行方式交换数据也很普遍。在实时控制和管理方面,采用多台微机处理机组成分级分布控制系统中,各CPU之间的通信一般都是串行方式。所以串行接口是微机应用系统常用的接口。   

许多外设和计算机按串行方式进行通信,这里所说的串行方式,是指外设与接口电路之间的信息传送方式,实际上,CPU与接口之间仍按并行方式工作。

1 串行通信的概念

   11.gif

所谓“串行通信”是指外设和计算机间使用一根数据信号线(另外需要地线,可能还需要控制线),数据在一根数据信号线上一位一位地进行传输,每一位数据都占据一个固定的时间长度。如图1-1所示。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,当然,其传输速度比并行传输慢。   

由于CPU与接口之间按并行方式传输,接口与外设之间按串行方式传输,因此,在串行接口中,必须要有“接收移位寄存器”(串→并)和“发送移位寄存器”(并→串)。典型的串行接口的结构如1-2所示。

   22.gif

在数据输入过程中,数据1位1位地从外设进入接口的“接收移位寄存器”,当“接收移位寄存器”中已接收完1个字符的各位后,数据就从“接收移位寄存器”进入“数据输入寄存器”。CPU从“数据输入寄存器”中读取接收到的字符。(并行读取,即D7~D0同时被读至累加器中)。“接收移位寄存器”的移位速度由“接收时钟”确定。   

在数据输出过程中,CPU把要输出的字符(并行地)送入“数据输出寄存器”,“数据输出寄存器”的内容传输到“发送移位寄存器”,然后由“发送移位寄存器”移位,把数据1位1位地送到外设。“发送移位寄存器”的移位速度由“发送时钟”确定。   接口中的“控制寄存器”用来容纳CPU送给此接口的各种控制信息,这些控制信息决定接口的工作方式。   

“状态寄存器”的各位称为“状态位”,每一个状态位都可以用来指示数据传输过程中的状态或某种错误。例如,用状态寄存器的D5位为“1”表示“数据输出寄存器”空,用D0位表示“数据输入寄存器满”,用D2位表示“奇偶检验错”等。   

能够完成上述“串<- ->并”转换功能的电路,通常称为“通用异步收发器”(UART:Universal Asynchronous Receiver and Transmitter),典型的芯片有:Intel 8250/8251,16550。
点赞  2009-12-9 14:08
顶一个
点赞  2011-7-13 17:07
点赞  2011-7-14 08:39

顶顶顶顶顶顶顶顶顶

顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶
点赞  2011-7-15 15:29
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复