STM32利用C++语言重定向cout

STM32利用C语言重定向printft到Usart1。可利用printf函数实现打印功能,在串口调试助手上显示。

C语言代码为:

//加入以下代码,支持printf函数,不需要选择use MicroLIB(Option->Target->Use MicroLIB(勾选))
#if 1
#pragma import(__use_no_semihosting)                             
struct __FILE 
{ 
	int handle; 
}; 
FILE __stdout;        
_sys_exit(int x) 
{ 
	x = x; 
} 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

STM32利用C++语言重定向cout到Usart1。可利用cout对象实现打印功能,在串口调试助手上显示。

C++语言代码为:

#if 1
//非半主机模式 
#pragma import(__use_no_semihosting_swi)
 
namespace std{   
    struct __FILE
      {
        int handle;
      };
 
    FILE __stdout;
    FILE __stdin;
    FILE __stderr;
   
//FILE *fopen(const char * __restrict /*filename*/,
//                           const char * __restrict /*mode*/)
//    {
//        usart1<<"\n\r fopen. \n\r";
//        return NULL;
//    }
 
    int fputc(int ch, std::FILE *f)
      {
		while((USART1->SR&0X40)==0);//重定义fputc
    	USART1->DR = (u8) ch;      
		return ch;
      }

//    int fgetc(FILE *f) {
//        /* Your implementation of fgetc(). */
//        usart1<<"\n\r fgetc \n\r";
//        return 0;
//    }
   
    int ferror(FILE *stream)
      {
        /* Your implementation of ferror(). */
        return 0;
      }
 
//    long int ftell(FILE *stream){
//        /* Your implementation of ftell(). */
//        usart1<<"ftell\n\r";
//        return 0;
//    }
   
//    int fclose(FILE *f){
//        /* Your implementation of fclose(). */
//        usart1<<"\n\r fclose \n\r";
//        return 0;
//    }
   
//    int fseek(FILE *f, long nPos, int nMode){
//        /* Your implementation of fseek(). */
//        usart1<<"fseek\n\r";
//        return 0;
//    }
   
    int fflush(FILE *f)
      {
        /* Your implementation of fflush(). */
        return 0;
      }
  
	extern "C" void  _sys_exit(int) 
	  {
        /* declared in <stdlib.h> */
        abort();
        while(1);
      }
    
	extern "C" void _ttywrch(int ch) 
 	  {
		while((USART1->SR&0X40)==0);
    	USART1->DR = (u8) ch;      
        return ;
      } 
}
 
#endif

其中,注释的部分同样可以重定义。

重定向过程中,出现的部分问题:
1、加入上部分代码后,产生如下错误:

.\Objects\STM32C8T6.axf: Error: L6200E: Symbol __stderr multiply defined (by stdio_streams.o and usart.o).
.\Objects\STM32C8T6.axf: Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and usart.o).
.\Objects\STM32C8T6.axf: Error: L6200E: Symbol fflush multiply defined (by fflush.o and usart.o).
.\Objects\STM32C8T6.axf: Error: L6200E: Symbol __stdin multiply defined (by stdio_streams.o and usart.o).

解决方法:勾选Use MicroLIB选项(Option->Target->Use MicroLIB)
2、勾选Use MicroLIB选项后,出现如下错误:

.\Objects\STM32C8T6.axf: Error: L6218E: Undefined symbol __fread_bytes_avail (referred from ios.o).
.\Objects\STM32C8T6.axf: Error: L6218E: Undefined symbol mbsinit (referred from ios.o).
.\Objects\STM32C8T6.axf: Error: L6218E: Undefined symbol wmemmove (referred from ios.o).

解决方法:在文件中加入如下代码:

#ifdef __cplusplus
extern "C" {
#endif

size_t __fread_bytes_avail(void *buf, size_t nbytes, FILE *stream)
/* Read a single character into buf[] using fgetc() */
  {
  *(char *)buf = (char)fgetc(stream);
  return 1;
  }
#include "wchar.h"
int mbsinit(const mbstate_t * ps)
  {
        return -1;
  }
/// To suppress MDK-ARM Linker Error: L6218E: Undefined symbol mbsinit (referred from ios.o).
wchar_t *wmemmove(wchar_t * __restrict s1,const wchar_t * __restrict s2, size_t n) //__attribute__((__nonnull__(1,2)))
  {
        return NULL;
  }

#ifdef __cplusplus
}
#endif

keil中可能会出现红叉,不用管它。

以下为测试代码及结果:
代码:

#include <iostream>
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"

using namespace std;

 int main(void)
   {	
	  delay_init();
      LED_Init();
	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	  uart_init(9600); 
      while(1)
	    {
           cout<<"test"<<endl;	
		   delay_ms(1000);
	    }
   }

结果在串口调试助手中显示:
STM32利用C++语言重定向cout
参考文献