应用笔记 4465

MAXQ610微控制器的串口使用


摘要 : MAXQ610微控制器提供两路标准USART串口。异步模式1是MAXQ610串口支持的模式之一,可以用于实现与PC COM口及其它多种现有设备进行通信。本应用笔记介绍MAXQ610串口发送、接收操作的中断处理功能,当接收到一个新字符或发送完毕一个字符后,通过该功能,应用程序能够迅速响应串口。

简介

MAXQ610微控制器包括能够与外部器件或系统进行通信的外设。这些外设带有主机/从机串行外设接口(SPI™);红外(IR)通信载波发生器/调制系统;两路单独的通用同步/异步接收器/发送器(USART),即众所周知的串口。

本应用笔记演示在MAXQ610上以10位异步模式使用串口。该模式通常用于实现与PC标准COM口进行通信,发送调试输出。只需要有一致的公共位格式和波特率,不论通信通道两端的实际工作频率是多少,该模式就可以实现两个器件或者系统之间的通信。

本应用笔记使用基于汇编语言的MAX-IDE环境,为MAXQ610和MAXQ610评估套件(EV kit)编写了演示程序。可以下载本应用笔记涉及到的演示应用程序代码和工程文件。

需要下面的硬件和软件才能运行演示程序。
  • MAXQ610评估套件电路板
  • MAXQJTAG电路板(串口至JTAG接口)
  • JTAG编程电缆(2 x 5母头至母头0.100"插头,10连接器带状电缆)
  • DB9直通公头至母头串行电缆
  • 5VDC稳压电源,中心为正极
  • 支持COM (串行)端口或者USB至串口适配器的PC
  • MAX-IDE环境
  • 终端仿真器(例如,工作在Dumb Terminal模式下的MTK、HyperTerminal或TeraTerm)
可以免费下载最新的MAX-IDE环境安装包和文档。 必须安装IAR Embedded Workbench®才能运行C版本的演示程序,MAXQ610评估套件中的CD提供了该评估软件。

配置MAXQ610评估套件

本应用笔记涉及到的演示程序运行在MAXQ610评估套件上。为保证程序能够正常运行,实现正确的软件功能,必须正确配置评估套件电路板的跳线。在电路板上运行演示程序时所有的步骤(例如,装载程序、运行程序)都采用了相同的跳线配置。

配置MAXQ610评估套件上的跳线。
  • JH1:连接引脚2和引脚3。
  • JH2:连接引脚2和引脚3。
  • JH3:连接引脚2和引脚3。
  • 连接以下跳线(引脚1和引脚2):JH14、JH20、JH22、JH23、JH24、JH25和JH26。
正确配置MAXQ610评估套件电路板之后,对硬件进行设置,以便编译并装入演示程序。
  • 连接串口至JTAG电路板上的跳线JH1、JH2和JH3。
  • 将5V直流电源连接到串口至JTAG电路板上的插座J2。
  • 使用DB9电缆连接PC COM1端口和串口至JTAG电路板上的J1连接器。
  • 使用JTAG编程电缆,连接串口至JTAG电路板的P2和MAXQ610评估电路板上的P5。JTAG电缆上的红线应连接至两个连接器的引脚1 (TCK)。
  • 接通5V直流电源。

串口模式及其初始化

MAXQ610上的两个USART外设中的每一个都可以工作在同步或者异步模式下。当工作在同步模式(模式0)时,MAXQ610是所有操作的总线主机。它配置TXD线,使其成为所有发送和接收操作的移位时钟,而RXD用作双向数据线。采用这一配置时,只有在主机请求时,数据每次只能向一个方向传送(半双工)。

在异步工作模式(模式1、2和3)下,有两条单向数据线:TXD和RXD。TXD线传送MAXQ610串口至外部器件的异步数据,而RXD线传送从外部器件返回MAXQ610的异步数据。MAXQ610与外部器件必须在公共格式(数据位的数量、校验位和停止位)以及公共波特率(总线频率)上达成一致,才能实现通信。由于TXD和RXD线可以单独进行传送,不需要彼此同步,因此,这些模式支持数据以全双工方式传送。MAXQ610可以向TXD线上任一点的外部器件发送数据,不论外部器件当前是否在RXD上传输数据,反之亦然。

对于这一演示程序,我们将选择模式1,它具有以下特性。
  • 串行数据异步发送(在TXD上)和接收(在RXD上)
  • 专用波特时钟发生器提供的波特时钟(可以使用PR寄存器进行编程)
  • 8个数据位,1个起始位,1个停止位
  • 没有校验
串口在模式1下采用的波特率(每秒发送/接收的位数)由以下两个方程决定(正如MAXQ系列用户指南(English only)中所讨论的):

波特时钟频率(BAUD) = 系统时钟频率 × PR/217 (式1)

波特率 = BAUD × 2(SMOD × 2)/26 (式2)

式1确定了波特时钟发生器的输出。由16位PR (相位)寄存器中的内容控制所产生的输出频率。在PR寄存器中装入较大的数值会产生频率较高的波特时钟。

式2确定SMD或者串行端口模式寄存器中的控制位(SMOD)的作用。将该位设置为1,最终波特率提高4倍。这表明,根据SMOD值,式2也可以表达为以下形式:

当SMOD = 0时,波特率 = BAUD/64 (式3)

当SMOD = 1时,波特率 = BAUD/16 (式4)

对于大部分晶体速率和波特率组合,两种SMOD设置都可以采用。注意,SMOD设置影响装入到PR寄存器中的数值。在我们的应用中,选择SMOD = 1,意味着波特率公式简化为:

波特率 = (系统时钟频率 × PR/217)/16 (式5)

或者:

波特率 = (系统时钟频率 × PR)/221 (式6)

解出PR值得到我们最常用的公式。通常情况下,波特率和系统时钟频率是固定的,我们只需要知道能够产生目标波特率所需的PR寄存器设置。因此:

PR = 波特率 × 221/(系统时钟频率) (式7)

例如,使用MAXQ610评估板上的标准12MHz晶体,选择9600波特率。所需要的PR寄存器设置是(9600 × 221/12000000),大约为1677或者068Dh。

计算出PR和SMOD值之后,将USART设置为相应的模式,写入PR和SMOD值就很容易对串口进行初始化。由于我们使用了串口0,因此,针对该串口将代码写入到相应的一组寄存器中(SCON0、SMD0、PR0和SBUF0)。
;==============================================================================
;=
;=  InitSerial0
;=
;=  Set up serial port 0 to run in 10-bit asynchronous mode at
;=  9600 baud.
;=

InitSerial0:
   move    SCON0.6, #1       ; Set to mode 1 (10-bit asynchronous).
   move    SCON0.4, #1       ; Enable receiver. 
   move    SMD0.1,  #1       ; Baud rate = 1/16 of baud clock
   move    PR0, #0068Dh      ; P = 2^21 × 9600/12.000MHz
                             
   move    SCON0.0, #0       ; Clear received character flag.
   move    SCON0.1, #0       ; Clear transmit character flag.
   move    SMD0.2,  #1       ; Enable receive/transmit interrupt.
   ret
关于USART外设工作模式的详细信息,请参考MAXQ610用户指南(English only),以及MAXQ系列用户指南(English only)中的第10节(串行I/O模块)

发送和接收字符

正确配置好串口后,可以准备发送和接收字符。在模式1下,一个字符包括1个起始位,8个数据位和1个停止位。起始位和停止位用于同步目的,由USART硬件进行控制。其余的8位传送实际数据,意味着串口一次可以发送或者接收一个8位字节。

通过串口发送一个字符涉及到以下三个步骤。
  1. 把要发送的字节写入到SBUF寄存器中。
  2. 等待SCON寄存器中的TI (发送中断)位变为高电平(置为1),这表明硬件已经完成了通过串口进行的字符发送。
  3. 将TI位清零。
始终需要等待一次发送完成后才能开始另一次新的发送。相对于指令执行周期,串口发送所需要的时间较长。因此,在等待串口完成发送之前,可以在步骤2中执行其它操作。例如,当使用12MHz晶体以115200波特率进行发送时,发送所需要的总时间大约为10 × (1/115200),即87µs。在同一时间段内,MAXQ610可以执行多达1041条指令(87µs/(1/12MHz))。

以相似的方式通过串口接收一个字符。
  1. 等待RI (接收中断)位变为高电平,表明串口接收到了一个新字符。
  2. 读取SBUF寄存器,获得数据字节。
  3. 将RI位清零。
在任何时间,只有一个接收到的字符被存储(缓冲)在串口硬件中。这意味着硬件如果将RI位置为1 (表明已经接收到了一个字符),必须通过读取SBUF寄存器来获得该字符;串口接收下一字符前,必须清除RI位。如果串口接收到一个新字符,而RI位仍然为高电平,新字符会丢失。

处理串口中断

对于每一发送和接收操作,如果需要,串口操作的一个简单方法是轮询(不断检查) RI和TI位值。例如,当写入一个字符时,应用程序代码将数据字节写入SBUF,轮询TI位,直到硬件将其置为1。在发送完成之前,不会进行其它操作。类似的,接收一个新字节时,应用程序只需要轮询RI位,直到硬件将其置为高电平,然后,通过读取SBUF,取走接收到的字节。

轮询RI和TI位的方法虽然简单,但是等待发送或者接收字符的时间太长,因此牺牲了性能。此外,应用程序必须事先知道什么时候外部器件会发送新字符,应用程序不能同时发送和接收字符。

一种更灵活(但是稍有些复杂)的方法利用了TI和RI不仅仅是状态位而且还是同步中断源这一事实。MAXQ610不是连续轮询TI和RI位的状态来确定发送或者接收操作是否完成,而是当TI或者RI从0变为1时,使能中断。该方法使应用程序在需要时才响应串口,因此提高了时间效率。

这一过程的第一步是通过将IGE位(IC.0)置为1,使能所有中断。这样,MAXQ610可以从全局出发来处理中断。

然后,必须安装中断处理程序。MAXQ610使用多路固定中断矢量系统,每个中断源或者每组中断源分配不同的(不可编程)矢量地址。出于我们的目的,我们需要串行端口中断矢量,它被分配为字地址0040h。

下面的中断处理程序完成以下功能。
  1. 临时设置IC.0为0,防止其它中断(较高优先级)发生。
  2. 将PSF和Acc寄存器推入堆栈,保存这些寄存器的数值。由于随时都可以触发中断,因此,中断处理程序必须一直保存并恢复其它应用程序使用的任何寄存器。
  3. 由于TI (发送)或者RI (接收)标志都可以触发串行端口中断,因此,处理程序必须检查中断为什么被触发。
  4. 如果发送中断被触发,清除TI位,置位标志值(存储在A[15]中),向应用程序指示发送已经完成。出于演示目的,这非常简单,中断处理程序还可以针对这一状态,在SBUF中装入新值,发送下一字符。
  5. 如果触发了接收中断,清除RI位,读取来自SBUF的接收字符;根据所接收到的字符,采取相应的措施。
  6. 将Acc和PSF寄存器值从堆栈中弹出,恢复其数值。
  7. 将IC.0置为1,重新使能中断。
  8. 使用RETI指令,退出中断处理程序。
org 0040h

serialInt:
   move    IC.0, #0          ; Block any other interrupts from triggering.
   push    PSF
   push    Acc
   move    C, SCON0.0        ; Check for receive character interrupt.
   jump    C, serialInt_Rx

serialInt_Tx:
   move    SCON0.1, #0       ; Clear transmit complete interrupt flag.
   move    A[15], #1         ; Set flag to indicate transmit complete.
serialInt_done:
   move    IC.0, #1          ; Re-enable interrupts.
   pop     Acc
   pop     PSF
   reti

serialInt_Rx:
   move    SCON0.0, #0       ; Clear receive character interrupt flag.
   move    Acc, SBUF0        ; Get character from serial port.
   cmp     #'0'
   jump    E, serialInt_Rx0
   cmp     #'1'
   jump    E, serialInt_Rx1
   cmp     #'2'
   jump    E, serialInt_Rx2
   cmp     #'3'
   jump    E, serialInt_Rx3
   cmp     #'4'
   jump    E, serialInt_Rx4
   jump    serialInt_done

serialInt_Rx0:
   move    Acc, PO3
   or      #0Fh              ; Turn all LEDs off.
   move    PO3, Acc
   jump    serialInt_done


....


serialInt_Rx3:
   move    Acc, PO3
   xor     #04h              ; Toggle P3.2 state. 
   move    PO3, Acc
   jump    serialInt_done

serialInt_Rx4:
   move    Acc, PO3
   xor     #08h              ; Toggle P3.3 state.
   move    PO3, Acc
   jump    serialInt_done

开发演示应用程序

串行演示应用程序的整个架构如下。
  1. 初始化端口引脚和串口。
  2. 使能中断。
  3. 通过串口发送以下标志文本。
    	MAXQ610 Serial Port Demo
    	Type characters "1"-"4" to toggle LEDs or '0' to turn all LEDs off.
    
  4. 已经收到字符"1"、"2"、"3"、"4"或"0",相应改变LED状态。
如上面的中断处理程序代码所示,应用程序改变端口引脚P3.0、P3.1、P3.2和P3.3的输出状态,响应接收到的字符。在MAXQ610评估套件电路板(跳线JH22、JH23、JH24和JH25闭合)上,这些端口引脚驱动4个LED DS1、DS2、DS3和DS4。端口引脚上的低电平状态(0)导致LED接通(点亮),而端口引脚上的高电平状态使LED关断。
main:
   move    WDCN,  #0 
   move    PD3.0, #1         ; Set P3.0 to output mode.
   move    PO3.0, #1         ; Drive P3.0 high (LED off).

   move    PD3.1, #1         ; Set P3.1 to output mode.
   move    PO3.1, #0         ; Drive P3.1 low (LED on).

   move    PD3.2, #1         ; Set P3.2 to output mode.
   move    PO3.2, #1         ; Drive P3.2 high (LED off).

   move    PD3.3, #1         ; Set P3.3 to output mode.
   move    PO3.3, #0         ; Drive P3.3 low (LED on).

   move    PD0.2, #1         ; Set P0.2 (TXD) to output mode.
   move    PO0.2, #1         ; Idle high when not transmitting.

   call    InitSerial0
   move    IC.0, #1          ; Enable interrupts.

   move    LC[0], #12000     ; Give transceiver time to power on.
   djnz    LC[0], $      

   ; Print string to serial port.

   move    CP, #0800h
printLoop:
   move    Acc, @CP++
   nop
   jump    Z, printLoop_done
   move    GR, Acc
   move    Acc, GRL
   call    TxChar0
   move    Acc, GRH
   call    TxChar0
   jump    printLoop
printLoop_done:
   nop

mainLoop:
   nop
   jump    mainLoop


;==============================================================================
;=
;=  TxChar0
;=
;=  Outputs a character to serial port 0.
;=
;=  Inputs  : Acc - Character to send.
;=

TxChar0:
   push    Acc
   move    SBUF0, Acc        ; Send character.
   move    A[15], #0         ; Clear interrupt service routine flag.
TxChar0_Loop:
   nop
   nop
   nop
   move    Acc, A[15]        ; Check flag.
   jump    Z, TxChar0_Loop
   move    SCON0.1, #0       ; Clear the transmit flag.
   pop     Acc
   ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

org 800h

   db 0Dh, 0Ah, 0Dh, 0Ah
   db "MAXQ610 Serial Port Demo", 0Dh, 0Ah, 0Dh, 0Ah
   db "Type characters '1'-'4' to toggle LEDs or '0' to turn all LEDs off"
   db 0Dh, 0Ah, 0Dh, 0Ah
   dw 0000h
使用起始字地址0800h的DB声明来存储标志文本。这一常数和程序代码的其它部分一起被装入到MAXQ610的闪存中,可以使用上面所示的CP代码指针(printLoop)来进行恢复。由于使用CP从程序存储器中每次获取一个数据字,因此,每读取一个字,通过串口发送两个字符。

运行演示程序

使用MAX-IDE对演示程序进行编译,装入到MAXQ610评估套件中后,可以按以下步骤执行它。
  1. 关断电源,断开JTAG、电源和串行电缆。
  2. 使用串行电缆,连接PC上的COM1和MAXQ610评估电路板上的J1插座。
  3. MAXQ610评估电路板上的J3插座连接电源线。
  4. 打开电源。
  5. 打开PC上的终端仿真器程序。将其配置为通过COM1进行通信,9600波特率,8个数据位,1个停止位,没有校验。
  6. 按下并释放MAXQ610评估电路板上的RESET (SW1)。在您的终端仿真屏上应显示标志文本(MAXQ610 Serial Port Demo...)。如果没有显示,请检查您的连接和跳线设置。
  7. 输入以下字符,触发LED状态:输入"1",触发DS1;输入"2",触发DS2;输入"3",触发DS3;输入"4",触发DS4;或者输入"0",关断所有LED。字符不会回显。

C演示程序

下面的演示程序显示了相同的应用程序,在IAR™的嵌入式工作台IDE上通过C实现。为简单起见,去掉了中断处理程序。请注意,putchar函数用于通过串口0输出一个字符。这样,可以使用标准I/O库函数,例如puts()printf()
int putchar(int c)
{
   SBUF0 = c;
   while ((SCON0 & 0x02) == 0);
   SCON0 = (SCON0 ^ 0x02);
   return c;
}

void initUSART0(void)
{
   int i2;
   PD0_bit.bit2 = 1;   // Hold Tx0 line High.
   PO0_bit.bit2 = 1;   // Hold Tx0 line High.
   SMD0 = 2;           // Set baud rate select bit.
   SCON0 = 0x50;       // Set mode 1 and receive enable for UART 0.
   PR0 = 0x068D;       // 9600 baud: PR0 = 2^21 * 9600 / 12.000MHz
   for (i2 = 1; i2 < 10000; i2++);   // Give transceiver time to power on.
   SCON0 = 0x50;       
}

void main( void )
{
   int c;
   IC_bit.IGE = 0;
   WDCN       = 0;    
   PD3 = 0x0F;
   PO3 = 0x05;    // Default - DS2 and DS4 on, DS1 and DS3 off

   initUSART0();
   puts("MAXQ610 Serial Port Demo");
   puts("Type characters "1"-"4" to toggle LEDs or "0" to turn all LEDs off\n");

   while (1) {
      while ((SCON0 & 0x01) == 0);        // Wait for RI flag to go high.
      c = SBUF0;                          // Receive character.
      SCON0 = (SCON0 ^ 0x01);             // Clear RI flag.
            
      switch (c) {
         case '0' : PO3 = 0x0F;
                    break;
         case '1' : PO3 = (PO3 ^ 0x01);   // Toggle P3.0
                    break;
         case '2' : PO3 = (PO3 ^ 0x02);   // Toggle P3.1
                    break;
         case '3' : PO3 = (PO3 ^ 0x04);   // Toggle P3.2
                    break;
         case '4' : PO3 = (PO3 ^ 0x08);   // Toggle P3.3
                    break;
         default  : break;
      }
   }
}

结论

MAXQ610提供了两个在很多MAXQ微控制器上使用的标准USART串口。异步模式1是MAXQ610串口支持的模式之一,可以用于实现PC COM端口与其它多种类型的现有设备进行通信。MAXQ610串口发送和接收操作支持中断处理功能,当接收到一个新字符或者发送完毕一个字符后,通过该功能,应用程序能够迅速响应串口。

MAXQ610上的USART串口支持多种配置选择和通信模式,这已经超出了本应用笔记的讨论范围。如果需要了解详细信息,请参考上面提到的MAXQ610用户指南(English only)以及MAXQ系列用户指南(English only)第10节。

相关型号
MAXQ610 免费样品
下一步
EE-Mail 订阅EE-Mail,接收关于您感兴趣的新文档的自动通知。
© , Maxim Integrated Products, Inc.
The content on this webpage is protected by copyright laws of the United States and of foreign countries. For requests to copy this content, contact us.
APP 4465:
应用笔记 4465,AN4465, AN 4465, APP4465, Appnote4465, Appnote 4465