This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

用MSP430G2553的定时器timer_A3实现uart的功能

Other Parts Discussed in Thread: MSP430G2553

    大家好!最近在开发TI推出的launchpad开发板,很实用很方便,最近一直在做一些相关的项目。

    开发过程中用到了串口,而且需要两个串口,然而G2553硬件外设只有一个串口,因此要想获得另外一个串口,可以通过软件模拟方法实现,TI的官方例程提供了使用timer0_A3的捕获和比较功能实现uart的例子。管脚使用的是P1.1(TX)、P1.2(RX),经过验证,确实好用。但是由于项目需求,我需要使用G2553内部的另一个timerA实现,即timer1_A3。代码按照官方例程,改进如下: 管脚采用的是P2.0(TX)、P2.1(RX)


//******************************************************************************
//  MSP430G2xx3 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo
//
//  Description: Use Timer_A CCR0 hardware output modes and SCCI data latch
//  to implement UART function @ 9600 baud. Software does not directly read and
//  write to RX and TX pins, instead proper use of output modes and SCCI data
//  latch are demonstrated. Use of these hardware features eliminates ISR
//  latency effects as hardware insures that output and input bit latching and
//  timing are perfectly synchronised with Timer_A regardless of other
//  software activity. In the Mainloop the UART function readies the UART to
//  receive one character and waits in LPM3 with all activity interrupt driven.
//  After a character has been received, the UART receive function forces exit
//  from LPM3 in the Mainloop which configures the port pins (P1 & P2) based
//  on the value of the received byte (i.e., if BIT0 is set, turn on P1.0).
//   MCLK = SMCLK = default DCO
//  //* An external watch crystal is required on XIN XOUT for ACLK *//
//
//               MSP430G2xx3
//            -----------------
//        /|\|              XIN|-
//         | |                 |
//         --|RST          XOUT|-
//           |                 |
//           |   CCI0B/TXD/P1.1|-------->
//           |                 | 9600 8N1
//           |   CCI0A/RXD/P1.2|<--------
// Built with  IAR Embedded Workbench Version: 5.40

//串口调试助手,下载地址:www.sudt.com/.../AccessPort137.zip
//******************************************************************************

#include "msp430g2553.h"

//------------------------------------------------------------------------------
// Hardware-related definitions
//------------------------------------------------------------------------------
#define UART_TXD  0x01// 0x02                     // TXD on P1.1 (Timer0_A.OUT0)
#define UART_RXD  0x02// 0x04                     // RXD on P1.2 (Timer0_A.CCI1A)

//------------------------------------------------------------------------------
// Conditions for 9600 Baud SW UART, SMCLK = 1MHz,设置波特率,仅仅修改下面一下数据即可,如9600,2400
//9600,2400工作稳定。波特率不宜太高。
//------------------------------------------------------------------------------
#define UART_TBIT_DIV_2     (1000000 / (9600 * 2))
#define UART_TBIT           (1000000 / 9600)

//------------------------------------------------------------------------------
// Global variables used for full-duplex UART communication
//------------------------------------------------------------------------------
unsigned int txData;                        // UART internal variable for TX
unsigned char rxBuffer;                     // Received UART character

//------------------------------------------------------------------------------
// Function prototypes
//------------------------------------------------------------------------------
void TimerA_UART_init(void);
void TimerA_UART_tx(unsigned char byte);
void TimerA_UART_print(char *string);

//------------------------------------------------------------------------------
// main()
//------------------------------------------------------------------------------
void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer

    DCOCTL = 0x00;                          // Set DCOCLK to 1MHz
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;

    P2OUT &= ~(UART_TXD + UART_RXD);
    P2SEL |= UART_TXD + UART_RXD; // Timer function for TXD/RXD pins
    P2DIR |= UART_TXD; // Set all pins but RXD to output
    P2DIR &= ~UART_RXD;
    __enable_interrupt();
  
    TimerA_UART_init();                     // Start Timer_A UART
    TimerA_UART_print("G2553 TimerA UART\r\n");
    TimerA_UART_print("READY.Echo Input,and Monitor.\r\n");
  
    for (;;)
    {
        // Wait for incoming character
        __bis_SR_register(LPM0_bits);
      
        // Echo received character,回传发送的数据
        TimerA_UART_tx(rxBuffer);  //
    }
}
//------------------------------------------------------------------------------
// Function configures Timer_A for full-duplex UART operation
//------------------------------------------------------------------------------
void TimerA_UART_init(void)
{
  TA1CCTL0 = OUT; // Set TXD Idle as Mark = '1'
    TA1CCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int
    TA1CTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode
}
//------------------------------------------------------------------------------
// Outputs one byte using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_tx(unsigned char byte)
{
    while (TA1CCTL0 & CCIE); // Ensure last char got TX'd
    TA1CCR0 = TAR; // Current state of TA counter
    TA1CCR0 += UART_TBIT; // One bit time till first bit
    TA1CCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int
    txData = byte; // Load global variable
    txData |= 0x100; // Add mark stop bit to TXData
    txData <<= 1; // Add space start bit
}

//------------------------------------------------------------------------------
// Prints a string over using the Timer_A UART
//------------------------------------------------------------------------------
void TimerA_UART_print(char *string)
{
    while (*string)
    {
        TimerA_UART_tx(*string++);
    }
}
//------------------------------------------------------------------------------
// Timer_A UART - Transmit Interrupt Handler
//------------------------------------------------------------------------------

#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0_ISR(void)
{
    static unsigned char txBitCnt = 10;

    TA1CCR0 += UART_TBIT; // Add Offset to CCRx
    if (txBitCnt == 0) // All bits TXed?
    {
        TA1CCTL0 &= ~CCIE; // All bits TXed, disable interrupt
        txBitCnt = 10; // Re-load bit counter
    }
    else
    {
        if (txData & 0x01)
        {
          TA1CCTL0 &= ~OUTMOD2; // TX Mark '1'
        }
        else
        {
          TA1CCTL0 |= OUTMOD2; // TX Space '0'
        }
        txData >>= 1;
        txBitCnt--;
    }
}
#pragma vector = TIMER1_A1_VECTOR
__interrupt void Timer1_A1_ISR(void)
{
    static unsigned char rxBitCnt = 8;
    static unsigned char rxData = 0;

    switch (TA1IV)
    {
        case TA1IV_TACCR1: // TACCR1 CCIFG - UART RX
            TA1CCR1 += UART_TBIT; // Add Offset to CCRx
            if (TA1CCTL1 & CAP) // Capture mode = start bit edge
            {
                TA1CCTL1 &= ~CAP; // Switch capture to compare mode
                TA1CCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
            }
            else
            {
                rxData >>= 1;
                if (TA1CCTL1 & SCCI) // Get bit waiting in receive latch
                {
                    rxData |= 0x80;
                }
                rxBitCnt--;
                if (rxBitCnt == 0) // All bits RXed?
                {
                    rxBuffer = rxData;           // Store in global variable
                    rxBitCnt = 8;                // Re-load bit counter
                    TA1CCTL1 |= CAP; // Switch compare to capture mode
                    __bic_SR_register_on_exit(LPM0_bits);  // Clear LPM0 bits from 0(SR)
                }
            }
            break;
        }
}

程序也是可以工作的,接收发送都可以实现,但是发送时有点问题,和timer0_A3有点区别。就是使用timer1_A3时每次发送完一个字节数据时TA1CCTL2的CCIFG的中断标志位置位,这点很是不理解,但是使用timer0_A3就没有问题

上图是使用timer1_A3时发完第一个byte时寄存器的状态

上图是使用timer1_A3发送完第二个字节时寄存器的状态,可以看到TA1CCTL2的CCIFG位置位了。TA1CTL的TAIFG也置位了,这点很奇怪。

然而用到timer0_A3时就没有问题:

上图是使用timer0_A3时发送完第一个字节后寄存器的状态

上图是使用timer0_A3时发送完第二个寄存器的状态

分别使用两种timer时的差别就是发送时timer1会比timer0慢,因为使用timer1时产生了溢出中断,timer0没有。

手册上并没有说明两种定时器的差别,我现在的代码一样(只是寄存器名和引脚改了),为什么会有如此问题!

请高手解答,说明不清楚的地方请说明,我会继续阐述。谢谢!