使用MAXQ610微控制器上的串行端口

描述

MAXQ610微控制器提供两个标准的USART串行端口。异步模式1是MAXQ610串行端口支持的模式之一,可用于与PC COM端口和许多其他类型的传统设备通信。本应用笔记解释了MAXQ610为串行端口发送和接收操作提供的中断处理支持如何允许应用在接收到新字符或字符完成传输时快速响应串行端口。

概述

MAXQ610微控制器包括外设,允许与外部设备或系统通信。这些外设包括一个主/从串行外设接口(SPI™);用于红外(IR)通信的载波生成/调制系统;和两个独立的通用同步/异步接收器/发射器 (USART),通常称为串行端口。

本应用笔记演示了在610位异步模式下使用MAXQ10上的串行端口。此模式通常用于与 PC 上的标准 COM 端口通信和/或将调试输出发送到 PC。此模式允许两个设备或系统通过简单地商定通用位格式和波特率进行通信,而不管通信通道两端的实际工作频率如何。

本应用笔记的演示代码为MAXQ610和MAXQ610评估(评估)板编写,采用基于汇编的MAX-IDE环境。本应用笔记中介绍的演示应用的代码和项目文件可供下载。

运行演示代码需要以下硬件和软件。

MAXQ610评估板

MAXQJTAG板(串口到JTAG接口)

JTAG编程电缆(2 x 5母头对母头0.100“接头,10连接器带状电缆)

DB9 直通公对母串行电缆

5VDC 稳压中心柱正电源

具有可用 COM(串行)端口或 USB 转串行适配器的电脑

最大集成环境

终端仿真器(例如在哑终端模式下运行的 MTK、超级终端或 TeraTerm)

MAX-IDE环境的最新安装包和文档可免费下载。

最大集成开发台安装

MAXQ磁芯组装指南

开发工具指南

要运行 C 版本的演示代码,必须安装 IAR 嵌入式工作台®。该软件的评估副本在MAXQ610评估板的光盘上提供。

设置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。

将 5VDC 电源连接到串行转 JTAG 板上的 J2 插头。

将 DB9 电缆从 PC 上的 COM1 端口连接到串行到 JTAG 板上的 J1 连接器。

将JTAG编程电缆从串行转JTAG板上的P2连接到MAXQ5评估板上的P610。JTAG电缆上的红线应通向两个连接器上的引脚1(TCK)。

打开 5VDC 电源的电源。

串口模式和初始化

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 寄存器编程)

1 个数据位,1 个起始位,<> 个停止位

无奇偶校验

模式1中串行端口使用的波特率(每秒发送/接收的位数)由以下两个公式确定(如

MAXQ系列用户指南所述):

 

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

 

公式1描述了波特时钟发生器的输出。生成的输出频率由16位PR(相位)寄存器的内容控制。将较高的值加载到 PR 寄存器中会导致更高频率的波特时钟。

公式2考虑SMD或串行端口模式寄存器中控制位(SMOD)的影响。将此位设置为 1 会将最终波特率提高 4 倍。这意味着公式2也可以用以下任一方式编写,具体取决于SMOD的值:

 

当 SMOD=0 时,波特率 = 波特/64 (公式3)
当 SMOD=1 时,波特率 = 波特/16 (公式4)

 

对于大多数晶体速度和波特率组合,可以使用SMOD的任一设置。请注意,SMOD 的设置会影响要加载到 PR 寄存器中的值。对于我们的应用程序,我们将选择 SMOD=1,这意味着波特率方程简化为以下内容:

 

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

 

艺术

 

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

 

求解 PR 值为我们提供了我们最感兴趣的方程式。通常,波特率和系统时钟频率是固定的,我们只想知道产生预期波特率所需的PR寄存器设置。因此:

 

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

 

例如,使用MAXQ12评估板上的标准610MHz晶体,选择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

发送和接收字符

正确配置串行端口后,即可发送和接收字符。在模式 1 中,字符由 1 个起始位、8 个数据位和 1 个停止位组成。开始位和停止位用于同步目的,由 USART 硬件处理。其余8位携带实际数据,这意味着串行端口可以一次发送或接收单个8位字节。

通过串行端口传输字符涉及以下三个步骤。

将要传输到 SBUF 寄存器的字节值写入。

等待SCON寄存器中的TI(发送中断)位变为高电平(设置为1)。这表示硬件已完成通过串行端口传输字符。

将 TI 位清除为 0。

在开始新的传输之前,始终需要等待每次传输完成。与指令执行周期时间相比,串行端口传输所需的时间很长。因此,可以在等待串行端口传输完成的同时执行步骤 2 中的其他操作。例如,当使用115200MHz晶体以12波特率传输时,传输所需的总时间约为10×(1/115200)或87μs。在同一时间范围内,MAXQ610可以执行多达1041条指令(87μs/(1/12MHz))。

通过串行端口接收字符以类似的方式完成。

等待 RI(接收中断)位变为高电平,表示串行端口已接收到新字符。

从 SBUF 寄存器读取以获取数据字节。

将 RI 位清除为 0。

在任何给定时间,串行端口硬件中仅存储(缓冲)一个接收的字符。这意味着,如果硬件将 RI 位设置为 1(表示已接收到字符),则必须通过读取 SBUF 寄存器来获取该字符;在串行端口接收下一个字符之前,必须清除 RI 位。如果串口接收到新字符,并且RI位仍然很高,则新字符将丢失。

处理串行端口中断

操作串行端口的一种简单方法是根据需要简单地轮询(重复检查)每个发送或接收操作的 RI 和 TI 位的值。例如,写入字符时,应用程序代码会将数据字节写入 SBUF,然后轮询 TI 位,直到硬件将其设置为 1。在传输完成之前,不会发生其他操作。同样,要接收新字节,应用程序只需轮询 RI 位,直到硬件将其设置为高,然后通过读取 SBUF 卸载接收的字节。

这种轮询 RI 和 TI 位的方法为了简单起见牺牲了性能,因为等待发送或接收字符需要花费大量时间。此外,应用程序必须提前知道何时需要来自外部设备的新字符,并且应用程序不能同时发送和接收字符。

一种更灵活(但稍微复杂)的方法利用了 TI 和 RI 不仅是状态位,而且还是同步中断源的事实。当TI或RI从610变为0时,MAXQ1无需连续轮询TI和RI位的状态来确定发送或接收操作何时完成。此方法允许应用程序更有效地花费时间,因为它仅在需要时响应串行端口。

此过程的第一步是通过将 IGE 位 (IC.0) 设置为 1 来启用所有中断。这样就可以对整个MAXQ610进行全局级别的中断处理。

接下来,必须安装中断处理例程。MAXQ610采用多固定中断矢量系统,为每个中断源或中断源组分配不同的(不可编程)矢量地址。出于我们的目的,我们对串行端口中断向量感兴趣,它被分配给字地址 0040h。

下面的中断处理程序例程执行以下功能。

通过临时将 IC.0 设置为 0 来防止发生其他中断(优先级较高)。

将 PSF 和 Acc 寄存器推送到堆栈以保存其值。由于可以随时触发中断,因此中断处理程序必须始终保存和还原其他应用程序代码使用的任何寄存器。

由于串行端口中断可以由 TI(传输)或 RI(接收)标志触发,因此处理程序代码必须检查触发中断的原因。

如果触发了传输中断,请清除 TI 位并设置一个标志值(存储在 A[15] 中),以向应用程序指示传输已完成。这只是为了演示目的;中断处理程序还可以通过将新值加载到 SBUF 中来传输下一个字符来对此情况做出反应。

如果触发了接收中断,请清除 RI 位;读取从 SBUF 收到的字符;并根据收到的字符采取适当的操作。

通过从堆栈中弹出 Acc 和 PSF 寄存器值来恢复它们。

通过将 IC.0 设置为 1 来重新启用中断。

使用 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

构建演示应用程序

串行演示应用程序的整体框架如下。

初始化端口引脚和串行端口。

启用中断。

通过串行端口传输以下横幅文本。

	MAXQ610 Serial Port Demo
	Type characters "1"-"4" to toggle LEDs or '0' to turn all LEDs off.

收到字符“1”、“2”、“3”、“4”或“0”时,请相应地更改 LED 状态。

如上面的中断处理程序代码所示,应用程序通过更改端口引脚 P3.0、P3.1、P3.2 和 P3.3 的输出状态来响应收到的字符。在MAXQ610评估板上(跳线JH22、JH23、JH24和JH25闭合),这些端口引脚驱动DS4、DS1、DS2和DS3个LED。端口引脚 (4) 上的低状态会导致 LED 亮起(亮起),而端口引脚上的高状态会导致 LED 熄灭。 横幅文本使用从单词地址 0h 开始的数据库语句进行存储。该常量数据与其余程序代码一起加载到MAXQ0800的闪存中,可以使用CP代码指针进行检索,如上所示(printLoop)。由于每次使用 CP 从程序存储器中获取都会检索一个字的数据,因此在读取每个字后,会通过串行端口传输两个字符。

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

 

使用MAX-IDE编译演示代码并加载到MAXQ610评估板后,可以按如下方式执行。

关闭电源并断开JTAG、电源和串行电缆。

将PC上COM1的串行电缆连接到MAXQ1评估板上的J610。

将电源线插入MAXQ3评估板上的J610。

打开电源。

在PC上打开终端仿真程序。将其配置为通过 COM1 以 9600 波特进行通信,具有 8 个数据位、1 个停止位且无奇偶校验。

按下并释放MAXQ1评估板上的复位(SW610)。横幅文本(MAXQ610串行端口演示...)应显示在终端仿真器屏幕上。如果没有,请检查您的连接和跳线设置。

键入字符以切换 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串行端口的两个实例。MAXQ610串行端口支持的模式之一,异步模式1,可用于与PC COM端口和许多其他类型的传统设备通信。MAXQ610为串行端口发送和接收操作提供中断处理支持,允许应用在接收新字符或字符完成传输时快速响应串行端口。

审核编辑:郭婷

 
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分