STM8S_库函数_USART串口重定向printf

大家好,我是单片机爱好者-MCU起航。这一节我们继续介绍如何使用库函数方式控制STM8S103F3P6片上的串口。上一节说了USART的基本用法,可以接受、发送字节,也可以发送一些字符串。但使用上不是很方便,也不够灵活。这一节我们看下它的串口如何重定向到printf上,使用printf函数来打印输出相关的数据。

printf()函数是式样化输出函数, 一般用于向准则输出设备按规定式样输出消息。

上一节,串口输出,可以是16进制数,可以是字符串。但如果是浮点型数据,那就很费劲了,需要写一堆的转换函数。

但是,这一切在printf()函数里已经给我们写好了,咱们只需要直接调用即可,但是格式一定要正确。 举例如下:

int intValue = 2;

printf(“1.正常输出整型:%i\n”,intValue);//输出2

char charValue = ‘a’;

printf(“13.字符输出:%c\n”,charValue);//输出a

float floatValue = 6.9f;

printf(“7.正常输出浮点型:%f\n”,floatValue);//输出6.900000

上面三个例子,分别对应整形、字符型和浮点型数据的输出。不同数据的输出,%后面跟着的字符不一样,大家一定要注意。

演示代码如下:

/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "uart.h"
#include <stdio.h>
const unsigned char mcu_str01[] ="hello,everyone!\r\n";
u8 send_flag = 0;
/* Private defines -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


void main(void)
{
  Uart1_Init();
  enableInterrupts();                 //使能中断
  while (1)
  {
    printf("\r\nhello,state gird!");
  }
  
}

首先,包含了这个库“stdio.h”,因为函数“printf”在这个库里,要使用的话,一定要包含。

然后是串口初始化,和上一节一样,设置波特率、有效字节、停止位等,不一样的地方在于,要对printf做重定向,代码如下:

#include "uart.h"

/* 
由于不同的编译器 putcha 和 getchar 形参和返回值略有不同。 
因此此处采用宏定义的方式区别。 

_RAISONANCE_ 和 _COSMIC_ 这2个宏是由编译器自动添加的预编译宏 
*/ 
#ifdef _RAISONANCE_ 
#define PUTCHAR_PROTOTYPE int putchar (char c) 
#define GETCHAR_PROTOTYPE int getchar (void) 
#elif defined (_COSMIC_) 
#define PUTCHAR_PROTOTYPE char putchar (char c) 
#define GETCHAR_PROTOTYPE char getchar (void) 
#else /* _IAR_ */ 
#define PUTCHAR_PROTOTYPE int putchar (int c) 
#define GETCHAR_PROTOTYPE int getchar (void) 
#endif /* _RAISONANCE_ */ 

void Delay(uint16_t nCount)
{
  /* Decrement nCount value */
  while (nCount != 0)
  {   
    nCount--;
  }
}

void Uart1_Init(void)
{
    UART1_DeInit();		/* 将寄存器的值复位 */

	/*
	 * 将UART1配置为:
	 * 波特率 = 115200
	 * 数据位 = 8
	 * 1位停止位
	 * 无校验位
	 * 使能接收和发送
	 * 使能接收中断
	 */

    UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO , UART1_SYNCMODE_CLOCK_DISABLE , UART1_MODE_TXRX_ENABLE);
    UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
    UART1_Cmd(ENABLE);
}

void UART1_SendByte(u8 data)
{
	UART1_SendData8((unsigned char)data);

	/* 等待传输结束 */
	while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
}

void UART1_Sendstr(const unsigned char *p_str)
{
//  u8 i = 0;
  while(*p_str != '\0')
  {
    UART1_SendByte(*p_str);
 //   Delay(1000);
    p_str++;
  }
}

PUTCHAR_PROTOTYPE 
{ 
  /* 发送一个字符 c 到UART1 */ 
  UART1_SendByte(c); 
  return (c); 
}

除此之外,还要对该工程包含的库做修改:

如图,之前这里选的是normal,现在改成FULL。

这里说一下使用printf函数的优缺点,优点很明显,使用灵活、方便,无论是调试,还是打印重要信息,都可以。

同时,缺点也要注意下:1、占用flash空间,因为library从normal改成了full,同时添加了一个stdio.h库,导致小容量的单片机对这种方式非常敏感,很容易出现flash不够用的情况。

2、printf操作速度会慢一些。虽然人眼感受不到,但确实慢了。因为这种方式相当于对串口的操作做了很多封装和调用,效率自然低了。

那么,除此之外,还有没有别的实现方法?

答案当然是有的。

首先,我们的目的是什么?

使用printf函数!因为要包含相关的库,所以使用的过程中要修改library,使它包含更多的内容。

在这个过程中,因为library包含了很多无用的内容,所以导致程序占用flash空间。如何解决?

我们可以手写一个需要的库,只把我们要的功能写进来,这样就避免了flash空间的浪费。如何实现,万能的网友已经帮我们写好了。代码比较大,我就不贴了。大家感兴趣的话,直接下载工程文件即可。

打完收工!

想要获取相关程序完整的工程文件,可以关注公众号:单片机爱好者,然后回复关键词:STM8S。可以获取完整的下载链接,里面包含工程文件、视频、PPT、数据手册等所有相关资料。

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据