This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430G2553: 在CCS上重定义printf函数,串口端显示有误

Part Number: MSP430G2553
Other Parts Discussed in Thread: MSP-EXP430G2ET

各位好,

我首先在包含了stdio.h和string.h头文件的main函数中对fputc和fputs进行重定义,代码如下:

int fputc(int ch,FILE *f)
{
    while(UCA0STAT & UCBUSY);
//    UCA0TXBUF = ch;
    UCA0TXBUF = ch&0xff;
    while(!(IFG2 & UCA0TXIFG));//等待发送完成
     return ch;
}

int fputs(const char *_ptr, register FILE *_fp)
{
  unsigned int i, len;

  len = strlen(_ptr);

  for(i=0 ; i<len ; i++){
      while(UCA0STAT & UCBUSY);
//      UCA0TXBUF = _ptr[i];
      UCA0TXBUF = _ptr[i]&0xff;
    while(!(IFG2 & UCA0TXIFG));//等待发送完成

  }
  return len;
}

printf能够输出hello world这样的字符串,但是用到如"%d"等格式符号时就出现了问题。

具体代码如下:

int main(void)
{
    int i=0;
    uint8_t buff1[4] = {0x00,0x01,0x02,0x03};
    uint32_t buff2;
    float buff3;

    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    InitSystemClock();
    InitUART();

    buff2 = (((uint32_t)buff1[0])<<24)|
               (((uint32_t)buff1[1])<<16)|
               (((uint32_t)buff1[2])<<8)|
               buff1[3]; //将4个8位数据组合成一个uint32_t的数据,符合原始数据长度
    buff3 = (float)buff2;
//    UARTSendString(buff1,4);
//    for(i=0;i<4;i++)
//    {
//        UARTSendString(buff1[i],)
//    }

//    printf("hello world!!");
    for(i=0;i<4;i++)
    {
        printf("buff1[%d] = %x\n",i,buff1[i]);
    }
    printf("buff2[1] = %u\n",buff2);
    printf("buff3[1] = %f\n",buff3);
//    printf("i = %d \n",i);
	return 0;
}

一开始我对现project的properties中的“level of printf support required”中的设置为'minimal',这个时候通过串口只能够打印出int格式的数,也只会打印一次;

当我把设置改为'full'来满足我需要打印16进制数的要求时,串口不仅一直在打印%前的语句,而且需要打印的16进制数也打印不出来;对于在‘minimal’时能够按要求打印的int格式的数也是一直打印,串口助手打印出来的是这样的:

它好像一直卡在buff1[1]的printf中没有跳到下一步。但如果设置是‘minimal’的时候,串口助手显示的是:

请帮我看看应该怎么修改我的代码或者配置,谢谢各位!

  • 你好,我查看下代码,稍后回复您。

  • 可以分别单独打印buff1,buff2,buff3看看吗?

  • 你好,代码和串口助手输出结果如下:

    int main(void)
    {
        int i=0;
        uint8_t buff1[4] = {0x00,0x01,0x02,0x03};
        uint32_t buff2;
        float buff3;
    
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
        InitSystemClock();
        InitUART();
    
        buff2 = (((uint32_t)buff1[0])<<24)|
                   (((uint32_t)buff1[1])<<16)|
                   (((uint32_t)buff1[2])<<8)|
                   buff1[3]; //将4个8位数据组合成一个uint32_t的数据,符合原始数据长度
        UARTSend4B(buff2);
        buff3 = (float)buff2;
    
        for(i=0;i<4;i++)
        {
            printf("buff1[%d] = %x\n",i,buff1[i]);
        }
    
        printf("buff2 = %u\n",buff2);
    
        printf("buff3 = %f\n",buff3);
    
    	return 0;
    }

    在properties里面设置printf是'minimal',因为设置成full的时候会一直不断输出‘buff[1]=0‘。’

  • 我首先在包含了stdio.h和string.h头文件的main函数中对fputc和fputs进行重定义,

    这个跟你的代码有什么关系?

    对于在‘minimal’时能够按要求打印的int格式的数也是一直打印,串口助手打印出来的是这样的:

    这也太奇怪了。不用for循环可以正常打印吗?

  • 1.我看网上别的帖子说需要在include了<stdio.h>和<string.h>头文件的函数中对fpuc和fputs进行重定义才能在串口使用printf函数;

    2.设置是'full'的情况下,我刚刚试了不用for循环,只打印buff1[1],也是一直打印。

  • #include <msp430.h> 
    #include "stdint.h"
    #include <stdio.h>
    #include <string.h>
    
    #define BufferSize 3
    uint8_t tx_buffer[BufferSize] = {0,1,2};
    
    /*
     * @fn:		void InitSystemClock(void)
     * @brief:	初始化系统时钟
     * @para:	none
     * @return:	none
     * @comment:初始化系统时钟
     */
    void InitSystemClock(void)
    {
    	/*配置DCO为1MHz*/
        DCOCTL = CALDCO_1MHZ;
        BCSCTL1 = CALBC1_1MHZ;
        /*配置SMCLK的时钟源为DCO*/
        BCSCTL2 &= ~SELS;
        /*SMCLK的分频系数置为1*/
        BCSCTL2 &= ~(DIVS0 | DIVS1);
    }
    /*
     * @fn:		void InitUART(void)
     * @brief:	初始化串口,包括设置波特率,数据位,校验位等
     * @para:	none
     * @return:	none
     * @comment:初始化串口
     */
    void InitUART(void)
    {
        /*复位USCI_Ax*/
        UCA0CTL1 |= UCSWRST;
    
        /*选择USCI_Ax为UART模式*/
        UCA0CTL0 &= ~UCSYNC;
    
        /*配置UART时钟源为SMCLK*/
        UCA0CTL1 |= UCSSEL1;
    
        /*配置波特率为9600@1MHz*/
        UCA0BR0 = 0x68;
        UCA0BR1 = 0x00;
        UCA0MCTL = 1 << 1;
        /*使能端口复用*/
        P1SEL |= BIT1 + BIT2;
        P1SEL2 |= BIT1 + BIT2;
        /*清除复位位,使能UART*/
        UCA0CTL1 &= ~UCSWRST;
    }
    /*
     * @fn:		void UARTSendString(uint8_t *pbuff,uint8_t num)
     * @brief:	通过串口发送字符串
     * @para:	pbuff:指向要发送字符串的指针
     * 			num:要发送的字符个数
     * @return:	none
     * @comment:通过串口发送字符串
     */
    void UARTSendString(uint8_t *pbuff,uint8_t num)
    {
    	uint8_t cnt = 0;
    	for(cnt = 0;cnt < num;cnt ++)
    	{
    		while(UCA0STAT & UCBUSY);//只要UCBUSY位(UCA0STAT的最低位)是1,就无法跳出这个while循环,不会执行到下一句
    		//__delay_cycles(5000);
    		UCA0TXBUF = *(pbuff + cnt);
    	}
    }
    /*
     * @fn:		void PrintNumber(uint16_t num)
     * @brief:	通过串口发送数字
     * @para:	num:变量
     * @return:	none
     * @comment:通过串口发送数字
     */
    void PrintNumber(uint16_t num)
    {
    	uint8_t buff[6] = {0,0,0,0,0,'\n'};
    	uint8_t cnt = 0;
    	for(cnt = 0;cnt < 5;cnt ++)
    	{
    		buff[4 - cnt] = (uint8_t)(num % 10 + '0');
    		num /= 10;
    	}
    	UARTSendString(buff,6);
    }
    /*
     * @fn:     void UARTSendByte(uint8_t buff)
     * @brief:  通过串口发送一个字节
     * @para:   pbuff:指向要发送字节的指针
     * @return: none
     * @comment:通过串口发送字符串
     */
    void UARTSendByte(uint8_t buff)
    {
        while(UCA0STAT & UCBUSY);
        UCA0TXBUF = buff;
    }
    
    /*
     * @fn:     void UARTSend4B(uint32_t buff)
     * @brief:  通过串口发送四个字节
     * @para:   buff:要发送的字节
     * @return: none
     * @comment:拆成4个字节,一个一个分别发送
     */
    void UARTSend4B(uint32_t buff)
    {
        uint8_t SendBuffer[4];
        int i;
    
        SendBuffer[0] = (buff>>24)&0xff;
        SendBuffer[1] = (buff>>16)&0xff;
        SendBuffer[2] = (buff>> 8)&0xff;
        SendBuffer[3] = (buff    )&0xff;
    
        /*将32位数据拆成4个8位数据,一个一个向串口发送*/
        for(i=0;i<4;i++)
        {
            UARTSendByte(SendBuffer[i]);
        }
    }
    
    int fputc(int ch,FILE *f)
    {
        while(UCA0STAT & UCBUSY);
    //    UCA0TXBUF = ch;
        UCA0TXBUF = ch&0xff;
        while(!(IFG2 & UCA0TXIFG));//等待发送完成
         return ch;
    }
    
    int fputs(const char *_ptr, register FILE *_fp)
    {
      unsigned int i, len;
    
      len = strlen(_ptr);
    
      for(i=0 ; i<len ; i++){
          while(UCA0STAT & UCBUSY);
    //      UCA0TXBUF = _ptr[i];
          UCA0TXBUF = _ptr[i]&0xff;
        while(!(IFG2 & UCA0TXIFG));//等待发送完成
    
      }
      return len;
    }
    
    //int putchar(int c)
    //{
    //   if(c == '\n')
    //   {
    //       while(UCA0STAT & UCBUSY);
    //       UCA0TXBUF = '\r';
    //   }
    //    while(UCA0STAT & UCBUSY);
    //    UCA0TXBUF = c;
    //return c;
    //}
    
    //int fputc(int c,FILE *f)
    //{
    //
    //    UCA0TXBUF = c;
    //    while(UCA0STAT & UCBUSY);
    //    return c;
    //}
    
    /*
     * main.c
     */
    int main(void)
    {
        int i=0;
        uint8_t buff1[4] = {0x00,0x01,0x02,0x03};
        uint32_t buff2;
        float buff3;
    
        WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
        InitSystemClock();
        InitUART();
    
        buff2 = (((uint32_t)buff1[0])<<24)|
                   (((uint32_t)buff1[1])<<16)|
                   (((uint32_t)buff1[2])<<8)|
                   buff1[3]; //将4个8位数据组合成一个uint32_t的数据,符合原始数据长度
        UARTSend4B(buff2);
        buff3 = (float)buff2;
    
        printf("buff1[1] = %x\n",buff1[1]);
    
    //    for(i=0;i<4;i++)
    //    {
    //        printf("buff1[%d] = %x\n",i,buff1[i]);
    //    }
    
    //    printf("buff2 = %u\n",buff2);
    //
    //    printf("buff3 = %f\n",buff3);
    
    //    UARTSendString(buff1,4);
    //    for(i=0;i<4;i++)
    //    {
    //        UARTSendString(buff1[i],)
    //    }
    
    //    printf("hello world!!");
    
    //    printf("buff2[1] = %u\n",buff2);
    //    printf("buff3[1] = %f\n",buff3);
    //    printf("i = %d \n",i);
    	return 0;
    }
    

    这是我整个工程的代码,我用的开发板是msp-exp430g2et。

    您给的第一个链接参考的是一个百度文档,它针对的是液晶屏的printf和scanf的使用;

    第二个链接参考的github网站代码我好像也参考过,但是编译无法通过;另一个html显示好像不太全,没有看到贴上来的代码。

  • 好的,我在我的板子上跑下看看。

  • 你好,在下面这个函数中:

    void UARTSend4B(uint32_t buff)
    {
        uint8_t SendBuffer[4];
        int i;
    
        SendBuffer[0] = (buff>>24)&0xff;
        SendBuffer[1] = (buff>>16)&0xff;
        SendBuffer[2] = (buff>> 8)&0xff;
        SendBuffer[3] = (buff    )&0xff;
    
        /*将32位数据拆成4个8位数据,一个一个向串口发送*/
        for(i=0;i<4;i++)
        {
            UARTSendByte(SendBuffer[i]);
        }
    }

    buff 的类型还是32位并没有改变,而SendBuffer是8位。这是一个问题。

    将buff2的这段代码中buff1[3]也加上强制转换:

    buff2 = (((uint32_t)buff1[0])<<24)|
    (((uint32_t)buff1[1])<<16)|
    (((uint32_t)buff1[2])<<8)|
    ((uint32_t)buff1[3]);

    以及buff1是8位,所以应该用%o.

      printf("buff1[1] = %o\n", buff1[1]);

  • 您好,非常谢谢您的答复!

    1. UARTSend4B这个函数不经过更改是可以正常直接向pc端发送32位数据的,将串口助手的接收设置改成“HEX”即可;

    2. 您提到buff1是8位数据,但是“%o”这个输出格式指的是八进制,虽然对于buff1中的0,1,2,3输出没有影响,但是八进制输出并不是我想要的输出格式;

    3. 在buff2这段代码加上了您的提议后,在“%x”的输出格式下仍是buff2=203,而理论上应该是buff2=10203。

  • 在buff2这段代码加上了您的提议后,在“%x”的输出格式下仍是buff2=203,而理论上应该是buff2=10203

    这是由于%x对于数据位数有限制,从结果来看,其最高位数应该是16位,但buff2有32位。所以应该用%lx。