大家好!最近在开发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没有。
手册上并没有说明两种定时器的差别,我现在的代码一样(只是寄存器名和引脚改了),为什么会有如此问题!
请高手解答,说明不清楚的地方请说明,我会继续阐述。谢谢!


