3304|5

2776

帖子

413

TA的资源

五彩晶圆(中级)

楼主
 

MSP430G2553硬件平台之标准输出函数Printf的实现 [复制链接]

串口调试为我们调试单片机程序的时候提供了很大的方便,我们通过他可以时刻监控程序的运行情况。在学C语言的时候有一个这样的典型程序:

#include

int main(void)

{

    int year=2012;

    char * str="Hello world !";

    printf("year=%d str=%s",year,str);

    return 0;

}

其运行结果如下图1 VC环境运行窗口:




图1  VC环境运行窗口


看看上面这个printf函数,你会不会想,能否在MSP430G2553这个硬件平台上实现类似的函数功能啊?答案是肯定的。今天笔者就借助这个2553的硬件平台来实现这个标准化输出函数printf。



    首先让笔者来介绍一下可变参数表的C语言知识。说到可变参数不得不提头文件,该头文件中提供了遍历未知数目和类型的函数参数表功能,假定函数printf带有可变数目的实际参数,lastarg是他最后一个有名称的形式参数。那么在printf内声明一个类型为va_list的变量ap,那么ap将依次指向每个实际的参数。
va_list ap;
在访问任何未命名的参数之前,必须用va_start宏初始化ap一次:
Va_start(va_list ap,lastarg);
    此后每次执行完宏va_arg(va_list ap,类型);都将产生一个与下一个未命名的参数具有相同类型和数值的值,同时ap将自动指向下一个实际的参数。在执行完上述过程之后要使用宏va_end(ap);来释放指针ap。
    上面的这些C语言知识在网上遍地都是,我在这里知识简短的介绍一下,若有不明白的地方请自己查阅。
接下来让笔者将printf在msp430g2553硬件平台上实现的代码给出一遍大家参考移植。
/ ********************************************************************
* File name      :   uart.c
* Creating time  :   2012-7-13
* Author         :  李帅
* pen-name       :  亦然
* Organization   :  济南大学(2013年本科毕业)
* Function       :   该文件可用作模块儿化编程作为MSP430G2553的调试文件,该文
*                    件实现
*                    了在串口终端实现标准化输出函数Printf函数。
* Declareing     :  如有错误的地方请各位指出,交流。交流使我们共同进步!
* E-mail         :   ls_core@sina.cn
* Contact way    :   QQ:1021480125
* 博客           :   http://blog.sina.com.cn/lscore
* ********************************************************************/
#include
#include
#include
#include "uart.h"
/ ********************************************************************
*静态函数声明
* ********************************************************************/
static void Vs_Printf(char *s,char *format,va_list arg);
static void IntToString(int temp,char *pchar);
/ ********************************************************************
* 函数名   :   UartInit
* 函数功能  :  初始化msp430g2553的USCI寄存器,使其工作在UART模式
* 形参     :  无
* 返回值   :  无
* ********************************************************************/
void UartInit()
{
    / ****************************************************************************
     * P1.1设为输入作为uart的数据输入口
     * P1.2设为输出作为UART的数据输出口
     ****************************************************************************/
    P1DIR &=~BIT1;
    P1DIR |=(BIT2 );
    / ****************************************************************************
     * 将P1.1和P1.2口配置为第三功能口,UART功能
     ****************************************************************************/
    P1SEL |=  BIT1 + BIT2 ;
    P1SEL2 |= BIT1 + BIT2;
    / ****************************************************************************
     * 配置U0CTL1寄存器,在UCSWRST置位的情况下(即保持USCI软件复位的情况下配置各
     * 个寄存器的各标志位)置位UCSSEL_2配置时钟源为SMCLK。其他位为0
     ****************************************************************************/
    U0CTL1 |= UCSWRST;                      // Set SW Reset
    U0CTL1 = UCSSEL_2+ UCSWRST;               // Use SMCLK, keep SW reset
    / ****************************************************************************
     * 配置波特率大小,公式:(U0BR1<<8+U0BR0)=(int)(source_clk/baud rate)
     * U0MCTL为(source_clk/baud rate)的余数乘以8之后的值对应表中的值,实现控
     * 制调制系数
     * 大小如表所示:
     * _______________________________________________________________
     * |余数*8  |1     |2     |3     |4     |5     |6     |7     |
     * |U0MCTL |0x08  |0x88  |0x2A  |0x55  |0x6B  |0xdd  |0xef |   
     ****************************************************************************/
    U0BR0 = 0x04;                           
    U0BR1 = 0x01;
    U0MCTL = 0x2A;
    / ****************************************************************
    * 解除软件复位,使USCI开始工作
    ****************************************************************/
    U0CTL1 &= ~UCSWRST;
    / ****************************************************************
     * 允许接收中断
     ****************************************************************/
    UC0IE |= UCA0RXIE;                              // Enable RX int
}
/ ********************************************************************
* 函数名   :   UartPutchar
* 函数功能  :  向串口终端发送一个字符
* 形参     :  Txdata为待发送的字符
* 返回值   :  无
*******************************************************************/
void UartPutchar(char Txdata)
{
    if(Txdata==''){
       while(UCA0STAT & UCBUSY);
       UCA0TXBUF='';
    }
    while(UCA0STAT & UCBUSY);
    UCA0TXBUF=Txdata;
}
/ ********************************************************************
* 函数名   :   UartSendString
* 函数功能  :  向串口终端发送一个字符串
* 形参     :  pt为字符串指针。
* 返回值   :  无
*******************************************************************/
void UartSendString(char *pt)
{
    while(*pt)
        UartPutchar(*pt++);
}
/ *******************************************************************
* 函数名    :   IntToString
* 函数功能  :  将一个整形的书转化成为一个表现形式一样的字符串
* 说明      :  举例说明功能,若有一个整数为65535,该函数作用就是将
*              “65535”其转化为字符串
* 形参      :  temp为待装换的整数,pchar为转化成的字符串所存储的地址
* 返回值    :  无
********************************************************************/
void IntToString(int temp,char *pchar)
{
    char ch,*p=pchar;
    while(temp!=0){
       *pchar++=(char)(temp+0x30);
       temp/=10;
    }
    *pchar--='';
    while(pchar>p){
       ch=*p;
       *p++=*pchar;
       *pchar--=ch;
    }
}
/ ********************************************************************
* 函数名   :   Vs_Printf
* 函数功能  :  将参数指针arg所指的不定参数按照格式字符串format中的一一对应的格
*            式转化后生成一个新的字符串存于地址s中。
* 形参     :  s为最终形成的字符串存储地址,format为格式字符串,arg为不定参数指
*            针。
* 返回值   :  无
********************************************************************/
void Vs_Printf(char *s,char *format,va_list arg)
{
    char *pchar;
    char *temp;
    for(pchar=format;*pchar;pchar++){
       if(*pchar !='%'){
           *s++=*pchar;
           continue;
       }
       switch(*++pchar){
           case 'd'   :{
              IntToString(va_arg(arg,int),s);
              while(*s++);
              *--s='0';
              break;
           }
           case 's'   :{
              temp=va_arg(arg,char *);
              while(*s++=*temp++);
              *--s='0';
              break;
           }
           case 'c'   :{
              *s++=va_arg(arg,char);
              break;
           }
           default       :break;
       }
    }
    *s='';
}
/ ********************************************************************
* 函数名   :   Printf
* 函数功能  :  格式化输出
* 形参     :  fmt为格式字符串,…为不定(类型不定、个数不定)形参
* 返回值   :  无
*******************************************************************/
void Printf(char *fmt,...)
{
    / ********************************************************
     * va_list类型声明一个参数指针ap,该变量将依次引用各个参数
     * ******************************************************/
    va_list ap;
    char string[256];
    / ********************************************************
     * va_start(ap,fmt),该函数将ap指针指向参数列表中的最后一个
     * 有名参数fmt
     * ******************************************************/
    va_start(ap,fmt);
   / ********************************************************
     * Vs_Printf,该函数将ap指向的无名参数按照fmt固定的格式转化
     * 成为字符串存于string中
     * ******************************************************/
    Vs_Printf(string,fmt,ap);
    UartSendString(string);
    / ********************************************************
     * 最后调用va_end(ap)释放指针
     * ******************************************************/
    va_end(ap);
}
/ ************************ end of file ******************************/
将文件uart.c添加到工程中去,并建立主函数进行验证。笔者的写的测试主函数如下所示:
#include
#include "clock.h"
#include "uart.h"
void main()
{  
    int year=2012;
    WDTCTL = WDTPW + WDTHOLD;
    Init_Clk();
    UartInit();
    char *str="Hello World!";
    Printf("year=%d str=%s",year,str);
}
在MSP430G2553上运行该程序,会得到与图1 VC环境运行窗口相同的功能效果,如下图2串口调试窗口


2 串口调试窗口

这样有了printf函数以后向串口打印信息就方便多了。也为调试程序铺平了道路。

    写到这里笔者有所感悟,顺便谈谈,我身边有51单片机,C8051单片机,凌阳单片机,msp430单片机,飞思卡尔单片机,还有强悍一点儿的就是三星的S3C2440。想想看,这么多单片如果不找到一个合理的、科学的学习方法,我们只能是越学越糊涂。因为我发现我身边的好多同学不管学什么单片机,当他拿到一款陌生的单片机之后,首先就去网上找现成的例程,然后下下来放在自己单片机上调,等调通了,这就算自己的程序了,然后换个内部资源继续这种方法调,不用多长时间下来,这一款单片机就算是学完了,然后再换一款单片机继续前面的做法。周而复始,等把所有的单片机学了一遍了,感觉自己什么也学过了,什么也会了。其实不然,他在这过程中根本没有将这些知识消化为自己的。在这过程中他只是充当了一个操作工的角色,根本没自己的思想与思路在内。这种做法是令人悲哀的。记住,切莫把自己培养成一个操作工。
    合理的学习方法就是要做到举一反三。举个例子来说明这个问题,懂微机原理的人明白,我们刚学C语言时写的调用的printf函数是运行在x86硬件平台上的;而今天笔者做的这个程序是运行在MSP430G2553这个平台上的;其实这个函数之前笔者已经在学S3C2440时在arm920的架构下已经实现了,今天这个程序已经算是在移植了。不同的硬件平台实现了相同的函数功能。拿着同一个功能在三种硬件平台上实现。这过程中就是在培养自己的学习思路。这点是最重要的。


分享自:http://t.cn/zW6pgjZ
                                                    

最新回复

学习  详情 回复 发表于 2014-9-2 17:58

赞赏

1

查看全部赞赏

 
点赞 关注(5)
个人签名

回复
举报

1万

帖子

28

TA的资源

裸片初长成(高级)

沙发
 
好文章,应该加精!
 
 

回复

846

帖子

0

TA的资源

纯净的硅(中级)

板凳
 
写的非常好,赞一个!!
 
 
 

回复

12

帖子

2

TA的资源

一粒金砂(初级)

4
 
赞一个。。。
 
 
 

回复

125

帖子

0

TA的资源

纯净的硅(中级)

5
 
学习一下
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

6
 
学习
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
【回帖赢京东卡】说说无线技术那些事儿
即日起—2月28日,参与回帖讨论都有机会赢取【30元京东卡】

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表