xsf66 发表于 2013-9-24 20:32:13

TimerA模拟Uart,接收不正确

芯片型号是Msp430F4250
参考一些样例程序做了个模拟Uart,现在调试时发现接收不正确(发送还未调试),具体来说:用串口调试软件发送几字节数据,然后用仿真器设置断点,查看接收数据是否正确。波特率定为9600。每次接收的数据只有第一个字节正确,后面全错;发送字节数超过三个时,接收字节数也不正确,比如发送8个字节,程序中显示收到6个字节。主要程序如下:

程序的大体思路:用TimerA 的 CCR0收发数据 用CCR1作接收超时判断(长时间没有收到数据时,认为数据接收完毕,开始处理数据)
                        单字节接收缓存到变量intData,每接收完一字节,存放到uchRcvBuf[]数组中,变量uchMsgLen指示已经接收的字节数

今天弄了一天也没有进展,缺失方向。恳请大家帮忙!

#define Bitime_5                0x30            //半位时长
#define Bitime                  0x6C            //一位时长

//------------------------------------------------------------------------------
// Timer_A CCR0中断服务函数
// 用于UART功能
//
#pragma vector=TIMERA0_VECTOR
__interrupt void TimerA_CCR0_ISR(void)
{
CCR0 += Bitime;
//CCTL0&=~CCIFG;
if(CCTL0 & CCIS0)   //-----逐位接收-----------------------------------------
{
    if(CCTL0 & CAP )                  // Capture mode = start bit edge
    {
      CCTL0 &= ~ CAP;                   // Capture to compare mode
      CCR0 += Bitime_5;
      CCTL1=0x0;                        // 停止接收超时检查
    }
    else
    {
      intData=intData>>1;
      if(CCTL0 & SCCI) intData|=0x80;       // Get bit waiting in receive latch
      uchBitCnt--;                            // All bits RXed?
      if(uchBitCnt==0)
      {
      uchRcvBuf=(unsigned char)intData;    //保存数据
      uchMsgLen=(uchMsgLen+1)%cst_MaxMsgLen;          //
      uchBitCnt=8;                  //准备接收下一字节
      //CCTL0|=CAP;                     //恢复为捕获模式
      CCTL0 = SCS + CCIS0 + OUTMOD0 + CM1 + CAP + CCIE;// Sync, Neg Edge, Capture
      TACCR1=TAR+Bitime*50;         //设置CCR1,定时4个字节的传输时间
      CCTL1=CCIE;                     //启用CCR1中断
      }
    }
}
else                  //-----逐位发送-----------------------------------------
{
    if(uchBitCnt==0)
      CCTL0&=~CCIE;                     
    else
    {
      if (intData & 0x01)
      CCTL0 &= ~ OUTMOD2;                     //输出1
      else
      CCTL0|=OUTMOD2;                         //输出0
      intData=intData>>1;
      uchBitCnt--;
    }
}
}

//******************************************************************************
// Timer_A CCR1\CCR2\TA中断服务
// 睡眠唤醒
//
#pragma vector=TIMERA1_VECTOR
__interrupt void TimerA_CCR1_ISR(void)
{
switch(__even_in_range(TAIV,4))
{
case 2:      //CCR1中断---------------------------------------------串口等待
    CCTL0=0;                                    //
    CCTL1=0;                                    //
    UART_ISR(uchRcvBuf,uchMsgLen);            //处理串口消息------在此处设置断点,查看接收到的数据
    uchMsgLen=0;
    uchBitCnt=8;                              //恢复TimerA CCR0设置(接收功能)
    CCTL0=SCS+CCIS0+OUTMOD0+CM1+CAP+CCIE;       // Sync, Neg Edge, Capture
    break;
   
case 10:       //TA中断-----------------------------------------------睡眠唤醒
    TACTL=0x0;
    __low_power_mode_off_on_exit();
}
}

笑笑我笑了 发表于 2013-9-24 20:36:22

我以前写的/*
* 看了很久才发现这个是软件
* 模拟UART.所以用不到UART
* 控制器.基本思想是定时器根据
* 波特率来产生中断,每次中断的
* 时候I/O根据发送内容来翻转.
*/

#include<msp430.h>

#define RED_LED BIT0
#define GRN_LED BIT6

#define BUTTON BIT3

#define TXD BIT1
#define RXD BIT2

/*
* 2400 bps -> 52
*/

#define TPB 52

int TXWord;
unsigned char bitcnt = 0;

void inituart(void);
void sendbyte(unsigned char b);
void sendstring( const char *str);

void main(void)
{
    /*关闭看门狗*/
        WDTCTL = WDTPW + WDTHOLD;
   
        /*LED设置为输出模式*/
        P1DIR |= RED_LED + GRN_LED;
        P1OUT &= ~(RED_LED + GRN_LED);
   
        /*初始化UART*/
        inituart();
   
        /*
       * 初始化按键
       * 输入模式
       */
        P1DIR &= ~BUTTON;
        /*中断标志清零*/
        P1IFG &= ~BUTTON;
        /*中断标志使能*/
        P1IE |= BUTTON;
   
        for(;;)
        {
                /*全局中断开,进入低功耗模式LPM3*/
                _BIS_SR(LPM3_bits + GIE);
                /*发送字符串*/
                sendstring("XIAO JB\r\n");
        }
}

void inituart(void)
{
    /*I/O初始化*/
        P1OUT |= TXD;
        P1DIR |= TXD;
   
        /*时钟初始化*/
        BCSCTL1 = CALBC1_1MHZ;
        DCOCTL = CALDCO_1MHZ;
        /*SMCLK4分频,SMCLK=1000KHz/4=500KHz*/
        BCSCTL2 &= ~(DIVS_3);

    /*定时器初始化,SMCLK,向上计数,500KHz/8=62.5KHz,计数器清零*/
        TACTL = TASSEL_2 + MC_1 + ID_3 + TACLR;
        TACCR0 = TPB;
}

void sendbyte(unsignedchar b)
{
        TXWord = b;
        TXWord |= 0x100;
        TXWord <<= 1;

        bitcnt = 10;
   
    /*清零计数器*/
        TACTL |= TACLR;
        /*清零中断标志位*/
        TACCTL0 &= ~CCIFG;
        /*中断使能*/
        TACCTL0 |= CCIE;

    /*等待中断发生*/
        while(TACCTL0 & CCIE)
        {
                _BIS_SR(LPM0_bits + GIE);
        }
}

/*发送一个字符串*/
void sendstring(const char *str)
{
        char *c = str;
        for(; *c; c++)
        {
                sendbyte(*c);
        }
}

/*定时器中断函数声明*/
void TimerA0(void) __attribute__((interrupt(TIMER0_A0_VECTOR)));
void TimerA0(void)
{
    /*中断标志位清零*/
        TACCTL0 &= ~CCIFG;
   
        /*如果位计数器为零,发送完毕,返回*/
        if(!bitcnt)
        {
                TACCTL0 &= ~CCIE;
                __bic_SR_register_on_exit(LPM0_bits);
                return;
        }
        else
        {   
          /*判断要发送的字节的第一位*/
                if(TXWord & 0x01)
                {
                        P1OUT |= TXD;
                        P1OUT |= RED_LED;
                        P1OUT &= ~GRN_LED;
                }
                else
                {
                        P1OUT &= ~TXD;
                        P1OUT |= GRN_LED;
                        P1OUT &= ~RED_LED;
                }
               
                /*左移,继续发送,直至bitcnt==0*/
                TXWord >>= 1;
                bitcnt --;
        }
}

/*按键中断函数声明*/
void Port_1(void) __attribute__((interrupt(PORT1_VECTOR)));
void Port_1(void)
{   
    /*清零中断标志位*/
        P1IFG &= ~BUTTON;
        /*退出低功耗模式LPM3*/
        __bic_SR_register_on_exit(LPM3_bits);
}

xsf66 发表于 2013-9-24 21:09:39

笑笑我笑了 发表于 2013-9-24 20:36 static/image/common/back.gif
我以前写的

这是模拟发送,有接收部分吗?

activeleo 发表于 2013-9-24 22:09:30

接收结束的时候判断1.5个停止位就可以了!你上BAIDU文库搜搜把!

xsf66 发表于 2013-9-25 11:15:29

activeleo 发表于 2013-9-24 22:09 static/image/common/back.gif
接收结束的时候判断1.5个停止位就可以了!你上BAIDU文库搜搜把!

百度文库没有找到有用的信息,也偿试了接收停止位(在收到第8位数据后,又执行了一个1.5位的等待--通过定时器的比较模式实现),情况与之前一模一样。

xsf66 发表于 2013-9-25 18:21:27

接收已经正常了,呵呵,心情不错。原因是主系统时钟频率比较低,中断处理程序的运行时间稍长,再次打开捕获时,错过了正确的起始位。

xsf66 发表于 2013-9-25 18:23:16

波特率降到2400,或者仍然使用9600,但是发送采用两个停止位,这两种方式都正确接收数据。

liao-ljj 发表于 2013-9-25 20:53:29

//******************************************************************************
//MSP430F20xx Demo - Timer_A, Ultra-Low Pwr UART 2400 Echo, 32kHz ACLK
//
//Description: Use Timer_A CCR0 hardware output modes and SCCI data latch
//to implement UART function @ 2400 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 echo's back the received character.
//ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO
////* An external watch crystal is required on XIN XOUT for ACLK *//       
//
//               MSP430F20xx
//            -----------------
//      /|\|            XIN|-
//         | |               | 32kHz
//         --|RST          XOUT|-
//         |               |
//         |   CCI0B/TXD/P1.5|-------->
//         |               | 2400 8N1
//         |   CCI0A/RXD/P1.1|<--------
//
#define RXD       0x02                      // RXD on P1.1
#define TXD       0x20                      // TXD on P1.5

//   Conditions for 2400 Baud SW UART, ACLK = 32768

#define Bitime_50x06                      // ~ 0.5 bit length + small adjustment
#define Bitime    0x0E                      // 427us bit length ~ 2341 baud

volatile unsigned int RXTXData;
volatile unsigned char BitCnt;

void TX_Byte (void);
void RX_Ready (void);

//M. Buccini / L. Westlund
//Texas Instruments Inc.
//October 2005
//Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.40A
//******************************************************************************

#include <msp430.h>
/* main.c */
#include <stdio.h>
#include "linkedlist.h"
void print_item(link p)
{
printf("%d\n", p->item);
}

int main (void)
{
WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
CCTL0 = OUT;                              // TXD Idle as Mark
TACTL = TASSEL_1 + MC_2;                  // ACLK, continuous mode

P1SEL = TXD + RXD;                        //
P1DIR = TXD;                              //
P1DIR |= 0x01;                            // Set P1.0 to output direction
//LPM3;
// Mainloop
for (;;)
{
P1OUT ^= 0x01;                            // LED Flash
RX_Ready();                               // UART ready to RX one Byte
_BIS_SR(LPM3_bits + GIE);               // Enter LPM3 w/ interr until char RXed
TX_Byte();                              // TX Back RXed Byte Received

link p = make_node(10);
insert(p);
p = make_node(5);
insert(p);
p = make_node(90);
insert(p);
p = search(5);
delete(p);
free_node(p);
traverse(print_item);
destroy();
p = make_node(100);
push(p);
p = make_node(200);
push(p);
p = make_node(250);
push(p);
while (p = pop())
{
print_item(p);
free_node(p);
}



}
}


// Function Transmits Character from RXTXData Buffer
void TX_Byte (void)
{
unsigned char Tar = 0;                   // Warning: undefined behavior: the order of volatile accesses is undefined in this statement
unsigned char Ccr = 0;                   //

BitCnt = 0xA;                           // Load Bit counter, 8data + ST/SP
Tar = TAR;
Ccr = CCR0;
//while ( CCR0 != TAR )                     // Prevent async capture
//CCR0 = TAR;                           // Current state of TA counter
while ( Ccr != Tar )                     // Prevent async capture
    CCR0 = TAR;                           // Current state of TA counter

CCR0 += Bitime;                           // Some time till first bit
RXTXData |= 0x100;                        // Add mark stop bit to RXTXData
RXTXData = RXTXData << 1;               // Add space start bit
CCTL0 =CCIS0 + OUTMOD0 + CCIE;          // TXD = mark = idle
while ( CCTL0 & CCIE );                   // Wait for TX completion
}


// Function Readies UART to Receive Character into RXTXData Buffer
void RX_Ready (void)
{
BitCnt = 0x8;                           // Load Bit counter
CCTL0 = SCS + OUTMOD0 + CM1 + CAP + CCIE;   // Sync, Neg Edge, Cap
}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
CCR0 += Bitime;                           // Add Offset to CCR0

// TX
if (CCTL0 & CCIS0)                        // TX on CCI0B?
{
    if ( BitCnt == 0)
    CCTL0 &= ~ CCIE;                        // All bits TXed, disable interrupt
    else
    {
      CCTL0 |=OUTMOD2;                  // TX Space
      if (RXTXData & 0x01)
      CCTL0 &= ~ OUTMOD2;                   // TX Mark
      RXTXData = RXTXData >> 1;
      BitCnt --;
    }
}
// RX
else
{
    if( CCTL0 & CAP )                     // Capture mode = start bit edge
    {
    CCTL0 &= ~ CAP;                         // Switch from capture to compare mode
    CCR0 += Bitime_5;
    }
    else
    {
    RXTXData = RXTXData >> 1;
      if (CCTL0 & SCCI)                     // Get bit waiting in receive latch
      RXTXData |= 0x80;
      BitCnt --;                            // All bits RXed?
      if ( BitCnt == 0)
//>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      {
      CCTL0 &= ~ CCIE;                      // All bits RXed, disable interrupt
      _BIC_SR_IRQ(LPM3_bits);               // Clear LPM3 bits from 0(SR)
      }
//>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }
}
}

/*------------------------------------------------------------------------------
    if ((0x10 & P1IN)) P1OUT |= 0x01;       // if P1.4 set, set P1.0
    else P1OUT &= ~0x01;                  // else reset
------------------------------------------------------------------------------*/
页: [1]
查看完整版本: TimerA模拟Uart,接收不正确