MSP430FG439上实现IO模拟UART以及移植要点解析

最近要做MSP430上的开发,一上手就要做IO模拟UART这种难度的玩意,幸好网上已经有很多现成的MSP430的软串口实现例子,本文代码大部分参考的《MSP430的Timer_A实现模拟串口功能例程》,并且成功移植到MSP430FG439之上,不过移植的过程有点匪夷所思。。。。由于才学430没几天,所以花了一周才调试出IO模拟UART。。。。 

接下来就贴上100%能在MSP430FG439上使用的代码(即使是同一Family的不同型号,也会有区别):

//利用定时器A 作串行口波特率发生器用,利用捕捉比较功能实现异步串行通信。

//芯片型号:MSP430FG439           P1.0---TXD   P1.1---RXD

//Timer_A TACLK=ACLK

//波特率为 2400BIT/S TBIT1=14 TBIT0_5=6

//帧格式:(0)XXXXXXXX(1),0为起始位,1为结束位,XXXXXXXXX为8位数据

#include  <msp430xG43x.h>

#define TBIT1 14;                      //TBIT1 为1 位时间

#define TBIT0_5 6;                    //TBIT0_5 为半位时间

#define TXD BIT0                      //使用P1.0作为发送,特殊功能脚,用CCI0A做比较输出

#define RXD BIT1                      //使用P1.1作为接收,特殊功能脚,用CCI0B做捕获输入

unsigned int TR_COUNT;                 //发收计数器

unsigned int T_DATA=0x00;              //发送缓冲器

unsigned int R_DATA=0x00;             //接收缓冲器

void init(void);                      //初始化

void txd (unsigned char byte);        //发送一字节数据

void rxd(void);                       //接收准备子程序

// ******************************************************

// 主函数

// *****************************************************

main()

{

     init();

     txd(0XFF);//由于发的第一帧会有错,所以先发送无用帧

     for(int i=0;i<255;i++)//发送0~255的数据

           txd(i);

     while(1)

     {

            rxd();                                 //准备接收

            LPM3;                               //进入休眠状态,收到数据后在唤醒

            txd(R_DATA);                 //把收到的数据重发

     }

}

// ******************************************************

// 初始化函数

// *****************************************************

void init(void)                        

{

    WDTCTL=WDTPW+WDTHOLD;                  //停止WDT

    P1DIR |= TXD;                                                 //TXD管脚为输出

    P1SEL |= (RXD+TXD);                                    //RXD和TXD都为特殊功能脚

    CCTL0|=OUT;                                                  //CCR0    OUT 设1

    TACTL|=TASSEL_1+MC_2;                          //设定时器A 时钟源ACLK,设定时器为连续模式

    _EINT();                                                            //开中断允许

}

//******************************************************

//发送一字节数据子程序

//输入参量:unsigned char 类型字节

// *****************************************************

void txd(unsigned char byte)

{  

    T_DATA=255-byte;           //关键点之一:这里与其它MSP430的软串口例程不同

    CCR0=TAR;                        //将TAR 时间存入CCR0,确定第一位 长度。

    CCR0=CCR0+TBIT1;         //将每1 位时间周期加入CCR0。

    //uart帧格式:(0)xxxxxxxx(1)

    T_DATA=T_DATA<<1;         //左移一位

    T_DATA|=BIT0;                      //最后一位为1

    TR_COUNT=10;                     //发送计数器。

    CCTL0=OUTMOD0+CCIE+OUTMOD2;              //重新设置CCTL0(CCIS1-0=00)

                                                                                     //捕获/比较模块输出模式1,充许模块中断。

    while(CCIE&CCTL0);               //等待CCIE 是否为0?为0 则表示发送完数据。

}

// *****************************************************

//接收准备子程序

//依赖TA0 中断来接收一字节数据。

// *****************************************************

void rxd(void)

{

    TR_COUNT=8;                             //接收数据位 位数

    //关键点之一:其它MSP430的软串口都是用下降沿(CM1),实践中我发现接收的问题就出在这里,所以我用CM0上升沿

    CCTL0 = SCS + CCIS0 + OUTMOD0 + CM0 + CAP + CCIE; 

    // 比较捕获为输出模式+比较捕获模块为中断允许+"上升沿捕获"+设置为捕获模式

    //+选择CCI0B 为捕获源+同步捕获

}

//*******************************************************************************

#pragma vector=TIMERA0_VECTOR       //TIMER_A 中断函数

__interrupt void cc10int(void)

{

    CCR0=CCR0+TBIT1;                   //重装下一位时间(当前时间+1 位时间)

    //---------------------------接收处理程序段

    if(CCTL0 & CCIS0)                    //是处于接收中还是发送中?

    {

        if(CCTL0&CAP)                   //是捕获模式还是比较模式?

        {        

            CCTL0&=~CAP;                //是-开始捕获,将捕获功能改为比较功能

            CCR0=CCR0+TBIT0_5;           //开始捕获位再加半位时间

        }

        else

        {

            R_DATA=R_DATA>>1;            //处于比较功能,将前面 那位向低位移.

            if(CCTL0&SCCI)                       //这句等效于(P1IN&RXD)==1,如果RXD管脚是高电平

            {

               R_DATA|=BIT7;                   //则R_DATA的最高位置1

            }

            TR_COUNT--;                 //计数器减1

            if(TR_COUNT==0)              //是否接收完8 位?

            {

                R_DATA=255-R_DATA;      //关键点之一,这里也要用255减一次

                //*****************************

                CCTL0&=~CCIE;           //是接收完,捕获/ 比较块停止中断充许

                LPM3_EXIT;             //退出低功率模式(一般,在进入LPM3 时才使用)

            }

        }

    }                              //接收结束

    //----------------------------------------------------------------

    else                                //开始发送程序段

    {

        if(TR_COUNT==0)

        CCTL0&=~CCIE;                //关捕获/比较块中断,发送结束.

        else

        {

            if(T_DATA&0x0001)           //状态寄存器C 位是1,还是0?

                CCTL0&=~OUTMOD2;         //状态寄存器C 位为0,发送0.

            else

                CCTL0|=OUTMOD2;           //状态寄存器C 位为1,发送1.

            T_DATA=T_DATA>>1;             //将字节数据向右移一位

            --TR_COUNT;                 //位计数器减1.

        }

    }

}

永不止步步 发表于03-09 09:46 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:307967个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号