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

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

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


  1. //利用定时器A 作串行口波特率发生器用,利用捕捉比较功能实现异步串行通信。
  2. //芯片型号:MSP430FG439           P1.0---TXD   P1.1---RXD
  3. //Timer_A TACLK=ACLK
  4. //波特率为 2400BIT/S TBIT1=14 TBIT0_5=6
  5. //帧格式:(0)XXXXXXXX(1),0为起始位,1为结束位,XXXXXXXXX为8位数据
  6. #include  
  7. #define TBIT1 14;                      //TBIT1 为1 位时间
  8. #define TBIT0_5 6;                    //TBIT0_5 为半位时间
  9. #define TXD BIT0                      //使用P1.0作为发送,特殊功能脚,用CCI0A做比较输出
  10. #define RXD BIT1                      //使用P1.1作为接收,特殊功能脚,用CCI0B做捕获输入
  11. unsigned int TR_COUNT;                 //发收计数器
  12. unsigned int T_DATA=0x00;              //发送缓冲器
  13. unsigned int R_DATA=0x00;             //接收缓冲器
  14. void init(void);                      //初始化
  15. void txd (unsigned char byte);        //发送一字节数据
  16. void rxd(void);                       //接收准备子程序
  17. // ******************************************************
  18. // 主函数
  19. // *****************************************************
  20. main()
  21. {
  22. init();
  23. txd(0XFF);//由于发的第一帧会有错,所以先发送无用帧
  24. for(int i=0;i<255;i++)//发送0~255的数据
  25.     txd(i);
  26. while(1)
  27. {
  28.      rxd();                                 //准备接收
  29.      LPM3;                               //进入休眠状态,收到数据后在唤醒
  30.      txd(R_DATA);                 //把收到的数据重发
  31. }
  32. }
  33. // ******************************************************
  34. // 初始化函数
  35. // *****************************************************
  36. void init(void)                        
  37. {
  38.     WDTCTL=WDTPW+WDTHOLD;                  //停止WDT
  39.     P1DIR |= TXD;                                                 //TXD管脚为输出
  40.     P1SEL |= (RXD+TXD);                                    //RXD和TXD都为特殊功能脚
  41.     CCTL0|=OUT;                                                  //CCR0    OUT 设1
  42.     TACTL|=TASSEL_1+MC_2;                          //设定时器A 时钟源ACLK,设定时器为连续模式
  43.     _EINT();                                                            //开中断允许
  44. }
  45. //******************************************************
  46. //发送一字节数据子程序
  47. //输入参量:unsigned char 类型字节
  48. // *****************************************************
  49. void txd(unsigned char byte)
  50. {   
  51.     T_DATA=255-byte;           //关键点之一:这里与其它MSP430的软串口例程不同
  52.     CCR0=TAR;                        //将TAR 时间存入CCR0,确定第一位 长度。
  53.     CCR0=CCR0+TBIT1;         //将每1 位时间周期加入CCR0。
  54.     //uart帧格式:(0)xxxxxxxx(1)
  55.     T_DATA=T_DATA<<1;         //左移一位
  56.     T_DATA|=BIT0;                      //最后一位为1
  57.     TR_COUNT=10;                     //发送计数器。
  58.     CCTL0=OUTMOD0+CCIE+OUTMOD2;              //重新设置CCTL0(CCIS1-0=00)
  59.                                                                                      //捕获/比较模块输出模式1,充许模块中断。
  60.     while(CCIE&CCTL0);               //等待CCIE 是否为0?为0 则表示发送完数据。
  61. }
  62. // *****************************************************
  63. //接收准备子程序
  64. //依赖TA0 中断来接收一字节数据。
  65. // *****************************************************
  66. void rxd(void)
  67. {
  68.     TR_COUNT=8;                             //接收数据位 位数
  69.     //关键点之一:其它MSP430的软串口都是用下降沿(CM1),实践中我发现接收的问题就出在这里,所以我用CM0上升沿
  70.     CCTL0 = SCS + CCIS0 + OUTMOD0 + CM0 + CAP + CCIE;  
  71.     // 比较捕获为输出模式+比较捕获模块为中断允许+"上升沿捕获"+设置为捕获模式
  72.     //+选择CCI0B 为捕获源+同步捕获
  73. }
  74. //*******************************************************************************
  75. #pragma vector=TIMERA0_VECTOR       //TIMER_A 中断函数
  76. __interrupt void cc10int(void)
  77. {
  78.     CCR0=CCR0+TBIT1;                   //重装下一位时间(当前时间+1 位时间)
  79.     //---------------------------接收处理程序段
  80.     if(CCTL0 & CCIS0)                    //是处于接收中还是发送中?
  81.     {
  82.         if(CCTL0&CAP)                   //是捕获模式还是比较模式?
  83.         {         
  84.             CCTL0&=~CAP;                //是-开始捕获,将捕获功能改为比较功能
  85.             CCR0=CCR0+TBIT0_5;           //开始捕获位再加半位时间
  86.         }
  87.         else
  88.         {
  89.             R_DATA=R_DATA>>1;            //处于比较功能,将前面 那位向低位移.
  90.             if(CCTL0&SCCI)                       //这句等效于(P1IN&RXD)==1,如果RXD管脚是高电平
  91.             {
  92.                R_DATA|=BIT7;                   //则R_DATA的最高位置1
  93.             }
  94.             TR_COUNT--;                 //计数器减1
  95.             if(TR_COUNT==0)              //是否接收完8 位?
  96.             {
  97.                 R_DATA=255-R_DATA;      //关键点之一,这里也要用255减一次
  98.                 //*****************************
  99.                 CCTL0&=~CCIE;           //是接收完,捕获/ 比较块停止中断充许
  100.                 LPM3_EXIT;             //退出低功率模式(一般,在进入LPM3 时才使用)
  101.             }
  102.         }
  103.     }                              //接收结束
  104.     //----------------------------------------------------------------
  105.     else                                //开始发送程序段
  106.     {
  107.         if(TR_COUNT==0)
  108.         CCTL0&=~CCIE;                //关捕获/比较块中断,发送结束.
  109.         else
  110.         {
  111.             if(T_DATA&0x0001)           //状态寄存器C 位是1,还是0?
  112.                 CCTL0&=~OUTMOD2;         //状态寄存器C 位为0,发送0.
  113.             else
  114.                 CCTL0|=OUTMOD2;           //状态寄存器C 位为1,发送1.
  115.             T_DATA=T_DATA>>1;             //将字节数据向右移一位
  116.             --TR_COUNT;                 //位计数器减1.
  117.         }
  118.     }
  119. }



由于网上的MSP430例程都几乎一致(都是出自TI的例程),并且大体思路没有错误(不同型号之间的设置会有变化),所以接下来介绍一下初学者移植时也许遇到的问题:
1.这里用了有特殊功能的IO脚,所以一定要对照芯片资料来确定自己所用的430对应功能在哪个IO上;
2.重点:要清楚串口帧的格式,这里用到的是10位:(0)XXXXXXXX(1),0开头,1结尾。
很多移植上的问题都是由此引起:
(1)由于发送时,从低位开始,即从1先开始发送,0最后发送,所以XXXXXXX要掉转一次(T_DATA=255-byte;);
(2)由于未知其他寄存器对TXD的影响,发送首帧时也许会出错,所以真正判断是否发送成功要从第二针开始(txd(0XFF););
(3)接收的时候,也容易受到帧格式的影响。。。。网上的例程都是用下降沿(CM1),但RXD脚收到帧的第一位却是1,最后一位是0(正如前面所说的低位先发),所以改为CM0上升沿就可以收到了,收到的次序是1XXXXXXX0,XXXXXXX也要掉转一次(R_DATA=255-R_DATA;)才能还原源数据。

本文来自hellogv的博客:http://blog.csdn.net/hellogv/archive/2010/01/08/5157906.aspx

回复评论 (1)

曾用AVR模拟uart,晶振7.7328,波特率老上不到57600,9600通信却是正常的。
点赞  2010-1-27 10:35
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复