根据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位,而没有找停止位。