MSP430FG439上实现IO模拟UART以及移植要点解析
2010-01-08 13:58
211 查看
本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!
最近要做MSP430上的开发,一上手就要做IO模拟UART这种难度的玩意,幸好网上已经有很多现成的MSP430的软串口实现例子,本文代码大部分参考
>http://www.microcontrol.cn/430base.htm上的《MSP430的Timer_A实现模拟串口功能例程》,并且成功移植到MSP430FG439之上,不过移植的过程有点匪夷所思。。。。由于才学430没几天,所以花了一周才调试出IO模拟UART。。。。
接下来就贴上100%能在MSP430FG439上使用的代码(即使是同一Family的不同型号,也会有区别):
由于网上的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;)才能还原源数据。
最近要做MSP430上的开发,一上手就要做IO模拟UART这种难度的玩意,幸好网上已经有很多现成的MSP430的软串口实现例子,本文代码大部分参考
>http://www.microcontrol.cn/430base.htm上的《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. } } }
由于网上的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;)才能还原源数据。
相关文章推荐
- MSP430FG439上实现IO模拟UART以及移植要点解析
- MSNP8协议解析以及对客户端的模拟实现
- 普通IO口模拟实现SPI通信及应用解析
- 普通IO口模拟实现I2C通信及应用解析
- java枚举解析以及单例的实现
- C++中String类模拟实现以及深拷贝浅拷贝
- Android实现模拟登陆教务系统并解析网页数据
- java_security之base64原理解析以及三种代码的实现方式
- tomcat理解、模拟实现以及tomcat的配置
- 使用ListView和AsyncTask、fastjson解析Json以及适配器BaseAdapter来实现下载网络的图片以及文字并显示出来
- Android 对Layout_weight属性完全解析以及使用ListView来实现表格
- Spring定时任务的实现方式--ScheduledExecutorService and ScheduledExecutorFactoryBean的简单源码解析以及使用
- ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁
- Java多线程的两种实现方式的区别以及同步问题中的锁对象深刻解析
- 【layout_weight权重】Android 对Layout_weight属性完全解析以及使用ListView来实现表格
- 关于uIP移植以及部分特性解析和勘误
- 模拟实现string类,以及增删查改各种功能
- 使用bind实现DNS主服务器的配置以及正向解析、反向解析、主从复制
- js模拟实现重载以及默认参数
- 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)