根据MSP430F4270官网提供的例程:slac077h\MSP430F42x0_MSP430FG42x0_Code_Examples\C\msp430x42x0_ta_uart9600.c,修改适配I2041,单字节收发在波特率正常的时候是可以正常的。
例程中多是使用的ACLK,2400波特率;我想提一下波特率,改用SMCLK,8分频,计数得到2400/4800/9600/115200。本来也是可以正常工作的,但是不知什么原因在调试过程中突然出现波特率对不上的情况,使用示波器看到MCU发出的波形波特率有一个1.5倍的偏差,将一位/半位定时计数除以1.5后,就可正常工作。
调试过程如下:
1、在排查无果后,我怀疑是不是芯片损坏,时钟不准了,重新烧写以前用过的程序,发现一切正常,片子是好的。
2、OK,我再调试模拟串口程序,这时就发现,之前的问题好了,波特率的计算不存在那个1.5的偏差了。。。
3、对比两个程序,在初始化部分,模拟串口的代码只是少了系统主时钟的设定,加上,也没出现问题。
4、我就以为找到问题所在并解决了,开始调试多字节收发的问题,结果经过一个周末,今天上班在继续调试的时候,那个问题又出现了! -_-||
没办法了,现将代码贴出来寻求大家的帮助!先谢谢了!!
#include <msp430.h> #define RXD BIT4 // RXD on P2.4 TA1.O CCI0B #define TXD BIT0 // TXD on P2.0 TA1.O CCI0A #define TAUCRXIFG BIT0 // RXD on P2.4 #define TAUCTXIFG BIT1 // TXD on P2.0 unsigned char taUCIFG = 0; unsigned char uart_rx_len; //串口接收长度计数器 unsigned char uart_rx_buff[20]; //串口0接收缓冲 unsigned char uart_tx_buff[20]; unsigned char uart_tx_len; // Conditions for 9600 Baud SW UART, SMCLK = 16384000 unsigned int Bitime_5; // ~ 0.5 bit length + small adjustment unsigned int Bitime; // ~ 9620 baud unsigned int RXData = 0x00; unsigned int TXData = 0x00; unsigned int BitCnt; void TimeA_Uart_Init(unsigned long Baud); void TX_Byte (unsigned char byte); void RX_Ready (void); void Send_TimeA_Uart_len(unsigned char *buffer,unsigned char len); int main (void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer // FLL_CTL0 |= XCAP14PF; // Configure load caps //CLK_INIT 后加为解决波特率偏差问题,结果发现没用。。。 CSCTL0 = 0x00; // DCOBYP = 0; DCOR = 0; Internal Resistor Mode CSCTL1 |= DIVM__1 | DIVS__1; // MCLK = DCO/1, SMCLK = DCO/1 TimeA_Uart_Init(2400); __bis_SR_register(GIE); uart_rx_len = 0; unsigned char data[10] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99}; Send_TimeA_Uart_len(data,10); // Mainloop for (;;) { RX_Ready(); // UART ready to RX one Byte __bis_SR_register(CPUOFF); // Enter LPM0 Until character RXed TX_Byte(RXData); // TX Back RXed Byte Received } } void TimeA_Uart_Init(unsigned long Baud) { switch(Baud) { case 9600: TA1CCTL0 = OUT; // TXD Idle as Mark TA1CTL = TASSEL_2 | MC_2 | ID_3; // SMCLK, continuous mode P2SEL0 |= TXD | RXD; // P1.0/1 TA0 for TXD/RXD function P2SEL1 &= ~(TXD | RXD); // P1.0/1 TA0 for TXD/RXD function P2DIR = TXD; // TXD output on P1 Bitime = 213; // 16384000/8/9600 ~9615 baud Bitime_5 = 107; // Bitime/2 ~0.5 bit length + small adjustment break; case 2400: TA1CCTL0 = OUT; // TXD Idle as Mark TA1CTL = TASSEL_2 | MC_2 | ID_3; // SMCLK, continuous mode P2SEL0 = TXD + RXD; // P1.0/1 TA0 for TXD/RXD function P2DIR = TXD; // TXD output on P1 Bitime = 853; // 16384000/8/2400 ~2401 baud Bitime_5 = 427; // Bitime/2 ~0.5 bit length + small adjustment break; default: break; } } void Send_TimeA_Uart_len(unsigned char *buffer,unsigned char len) { for(unsigned char i=0;i<len;i++) //检测最终是不是到了这么多位数据 { TXData = *buffer++; TX_Byte(TXData); } } // Function Transmits Character from RXTXData Buffer void TX_Byte (unsigned char byte) { TXData = byte; BitCnt = 0xA; // Load Bit counter, 8data + ST/SP TA1CCR0 = TAR; // Current state of TA counter TA1CCR0 += Bitime; // Some time till first bit TXData |= 0x100; // Add mark stop bit to RXTXData TXData = TXData << 1; // Add space start bit TA1CCTL0 = OUTMOD0 + CCIE; // TXD = mark = idle while ( TA1CCTL0 & CCIE ); // Wait for TX completion } // Function Readies UART to Receive Character into RXTXData Buffer void RX_Ready (void) { BitCnt = 0x8; // Load Bit counter TA1CCTL0 = SCS + CCIS0 + OUTMOD0 + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture } // Timer A0 interrupt service routine #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer_A (void) { TA1CCR0 += Bitime; // Add Offset to CCR0 // RX if (TA1CCTL0 & CCIS0) // RX on CCI0B? { if( TA1CCTL0 & CAP ) // Capture mode = start bit edge { TA1CCTL0 &= ~CAP; // Capture to compare mode TA1CCR0 += Bitime_5; } else { RXData = RXData >> 1; if (TA1CCTL0 & SCCI) // Get bit waiting in receive latch RXData |= 0x80; BitCnt --; // All bits RXed? if ( BitCnt == 0) //>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< { TA1CCTL0 &= ~CCIE; // All bits RXed, disable interrupt taUCIFG |= TAUCRXIFG; uart_rx_buff[uart_rx_len++] = RXData; __bic_SR_register_on_exit(CPUOFF); // Clear LPM0 bits from 0(SR) } //>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } } // TX else { if ( BitCnt == 0) TA1CCTL0 &= ~ CCIE; // All bits TXed, disable interrupt else { TA1CCTL0 |= OUTMOD2; // TX Space if (TXData & 0x01) TA1CCTL0 &= ~ OUTMOD2; // TX Mark TXData = TXData >> 1; BitCnt --; } } }
PS : 还想请教下,模拟串口要想收发多字节能不能做,怎么做?
比如,如何将一个缓冲区的数据加起止位送中断发出?
如何判断接收停止位,例程中在接收时,只收8位,而没有找停止位。