单片机中printf函数的重映射
单片机中printf函数的重映射
一、源自于:大侠有话说1.如果你在学习单片机之前学过C 语言,那么一定知道printf 这个函数.它最最好用的功能
除了打印你想要的字符到屏幕上外,还能把数字进行格式化.例如十进制的33, 用十进制
方式输出就是33,用十六进制的形式就输出成21,如果用字符形式输出,那就是ASCII 码
表对应的!.
2. 51 年代,一些人软件仿真的时候也很喜欢使用printf,但实际代码运行中,用的人则不多,因
为别说51 年代,就是用AVR 的,也会觉得printf 这个函数耗费的CPU 资源相当可观.所以
printf 在8 位单片机时代,熟悉的人的确不多.但到了ARM 时代,情况则大为不同.毕竟
ARM 的处理能力和51 完全不是一个级别,这使得不少人开始喜欢使用printf 在实际项目
中作为调试过程的串口输出.因为它的格式化功能实在是相当方便.
而本例程就是教会你这么使用printf.
3.程序把printf 的输出对象设定为串口1.有一个标准的函数是必须要自己定义的,那就是
fputc,把这个函数的功能写成串口输出一个字符.建议在串口的初始化模块中定义
int fputc(int ch)。
STM32 printf函数重映射
STM32 printf 函数重映射/* Private function prototypes -----------------------------------------------*/#ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker- >Libraries->Small printf set to Yes) calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endif /* __GNUC__ *//** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */PUTCHAR_PROTOTYPE{ /* Place your implementation of fputc here */ /* Loop until the end of transmission */ while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET) {} /* write a character to the USART */ USART_SendData(EVAL_COM1, (uint8_t) ch);return ch;}某人的解释:这段代码的意思是将C 语言的库函数printf 重定向,或重映射,这词有点太专业,简单的讲:就是C 语言的库中printf 函数会调用PUTCHAR_PROTOTYPE 这个硬件接口函数,向显示器上输出char 型变量,用来显示,STM32 当然是没有显示器的,所以就用UART 输出Char 型变量到PC 机,由PC 机的超级终端来显示,说白了,就是原来送到显示器上的显示数据,现在送到STM32 的串口上;如果调不过去,你要注意两点:1.你的板子上用的是不是USART1,如果是,那连到PC 的串口,就可以在超级终端上,看到打印出来的东西了,如果不是,请参考第2 点.2.先将你的板子上的USART 初始化,然后把PUTCHAR_PROTOTYPE 函数体中的USART1 换成你现在用的那个USART.于免费送一个注意点,当然以上也都免费,呵呵1.STM32 的外设输出引脚可以重映射,如USART2,要注意板子上,是按原来的引。
STM32开发printf和scanf函数的重定向——修改HAL标准库用printf函数发。。。
//这个变量是其他.c文件定义的 extern UART_HandleTypeDef huart1; uint8_t ch; uint8_t ch_r; //重写这个函数,重定向printf函数到串口,意思就是说printf直接输出到串口,其默认输出到控制台的 /*fputc*/ int fputc(int c, FILE * f) { ch=c; HAL_UART_Transmit(&huart1,&ch,1,1000);//发送串口 return c; }
您使用的浏览器不受支持建议使用新版浏览器
STM32开发 printf和 scanf函数的重定向 ——修改 HAL标准库用 printf函 数 发 。 。 。
首先在main.c文件中添加标准输入输出库
#include <stdio.h>
然后在stm32cubemFra bibliotek生成的文件中,找到usart.c文件,在后面添加如下代码
//重定向scanf函数到串口 意思就是说接受串口发过来的数据,其默认是接受控制台的数据 /*fgetc*/ int fgetc(FILE * F) { HAL_UART_Receive (&huart1,&ch_r,1,0xffff);//接收 return ch_r; }
stm32重定向printf的原理
stm32重定向printf的原理在嵌入式系统中,调试是一个非常重要的环节。
而在调试过程中,printf函数是最常用的调试手段之一。
在STM32中,printf函数默认是向串口发送数据,但是有时候我们需要将printf函数的输出重定向到其他设备或者接口上。
本文将以STM32为例,介绍如何实现printf函数的重定向。
一、printf函数的实现原理printf函数是C语言标准库中的一个输出函数,其原型为:int printf(const char *format, ...);。
printf函数的作用是将格式化的字符串输出到标准输出设备上。
在STM32中,默认情况下,printf 函数的输出设备是串口。
其实现原理如下:1.调用stm32fxxx_hal_uart.c中的HAL_UART_Transmit函数,将格式化的字符串发送到串口中。
2.在stm32fxxx_hal_uart.c中,HAL_UART_Transmit函数通过USARTx_SR寄存器判断发送是否完成,如果未完成,则等待发送完成。
3.发送完成后,HAL_UART_Transmit函数返回。
二、printf函数的重定向在某些情况下,我们需要将printf函数的输出重定向到其他设备或接口上,例如:SD卡、LCD屏幕、WiFi模块等。
这时候,我们需要自定义一个输出函数,并将其与printf函数关联起来,实现printf函数的重定向。
下面,我们将以重定向printf函数输出到LCD 屏幕为例,介绍如何实现printf函数的重定向。
1.定义一个输出函数我们先定义一个输出函数,将其命名为LCD_Printf,其实现原理如下:void LCD_Printf(char *str){/* 将格式化的字符串输出到LCD屏幕上 */}2.将LCD_Printf函数与printf函数关联在main函数中,我们需要将LCD_Printf函数与printf函数关联起来,代码如下:/* 重定向printf函数 */int fputc(int ch, FILE *f){/* 将字符转换成字符串 */char str[2] = {0};str[0] = ch;/* 调用LCD_Printf函数,将字符输出到LCD屏幕上 */LCD_Printf(str);return ch;}在上述代码中,我们定义了一个名为fputc的函数,该函数的作用是将printf函数的输出重定向到LCD屏幕上。
printf和scanf家族函数底层IO函数重定向至串口
printf和scanf家族函数底层I/O函数重定向至串口神枪摘要:C标准库的printf是输出给显示器的,而scanf则是从键盘上把数据输入到指定的变量之中。
在ARM嵌入式开发中,往往需要通过串口进行一些调试、输入以及输出等。
那么,就得对这些家族函数的底层I/O函数进行修改,这样才能真正使用标准的C库printf和scanf家族函数。
一、概述和printf和scanf相关的家族函数包括:输出: printf、puts、putc、putchar、fprintf、fwrite、fputs等。
输入: scanf、gets、getc、getchar、fscanf、fread、fgets等。
被输入输出调用的底层I/O函数,包括fputc、fgetc、ferror等。
综上所述,我们只要将fputc和fgetc重新定向至串口就可以了!二、实现方法如果使用C标准库函数,则要避免链接使用半主机模式的相关函数,Retarge.c文件中的#pragma import(__use_no_semihosting_swi) 和 _sys_exit 函数实现就是来确保不链接半主机模式函数的。
好在Keil MDK已经为我们提供了这样的接口文件Retarge.c。
文件位置:C:\Keil\ARM\Startup,(C:\Keil\为我的Keil安装根目录)文件名称:Retarget.c文件内容:因此我们的工作就是:(1) 将该Retarget.c文件加入到自己的工程中。
(2) 提供Serial.c文件(名字随意),在文件中实现sendchar和getkey函数。
(3) sendchar为串口单字符发送函数,getkey为串口单字符接收函数。
这两个函数的实现如下:(1) 以LPC1758为例(2) 以STM32F103为例至此,所有工作已完毕,可以调用printf、scanf等函数了。
单片机程序巧用printf
1、在 KEIL 下使用 printf 函数,以 STM32 为例 在 uart.c 中添加如下代码 View Code /************************************************ ******************************* 函数名:fputc 输 入: 输 出:
return (int)USART_ReceiveData(USART1); }
这样,只要在需要用 printf 的文件里#include ;就 可以了,printf 会自已的调用 fputc 函数来实现串口数 据的输出。 2、添加 Retarget.c,实现在 KEIL 下使用 printf 函数, 以 LPC2478 为例
int sendchar (int ch) { // Write character to Serial Port while (!(U0LSR & 0x20)); return (U0THR = ch); } int getkey (void) { // Read character from Serial Port while (!(U0LSR & 0x01)); return (U0RBR); } 这样,只要在需要用 printf 的文件里#include ;就 可以了,printf 会通过 Retarget 中的 fputc 函数调用 sendchar 来实现串口数据的输出。 事实上,和第一种的方式是一样的。 3、自定义 printf 函数,以 AVR 为例 前面介绍的是在 KEIL 编译器上使用 printf 函数,但 不是所有的编译器平台都能适用,因此有时候我们需要
printf在单片机c语言中作用
printf在单片机c语言中作用以printf在单片机c语言中的作用为题,需要详细介绍和解释printf函数在单片机中的作用和使用方法。
首先,我们来了解一下单片机和c语言的基本概念。
单片机是一种集成了微处理器、存储器和各种外设接口的微型计算机系统。
它通常用于控制和管理各种电子设备。
而c语言是一种通用的高级程序设计语言,广泛应用于嵌入式系统开发领域,尤其是在单片机编程中。
在单片机中,printf函数是一个非常重要的输出函数,它可以将格式化的数据打印输出到终端设备或其他输出设备上。
printf函数的语法格式如下:printf("格式控制字符串", 参数列表);其中,格式控制字符串用来定义输出的格式,它可以包含普通字符和格式转换说明符。
参数列表是一个可选项,用来指定要输出的数据。
printf函数可以输出各种类型的数据,如整数、浮点数、字符等。
下面我们通过一些具体的例子来说明printf函数的使用方法。
1. 输出整数型数据:int num = 123;printf("整数:%d\n", num);上述代码将会在终端上输出"整数:123"。
2. 输出浮点型数据:float f = 3.14;printf("浮点数:%f\n", f);上述代码将会在终端上输出"浮点数:3.140000"。
3. 输出字符型数据:char ch = 'A';printf("字符:%c\n", ch);上述代码将会在终端上输出"字符:A"。
4. 输出字符串:char str[] = "Hello World!";printf("字符串:%s\n", str);上述代码将会在终端上输出"字符串:Hello World!"。
关于printf()函数重定义
简单地说:想在mdk 中用printf,需要同时重定义fputc函数和避免使用semihosting(半主机模式),标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数。
例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下:#ifdef __GNUC__/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endif /* __GNUC__ */PUTCHAR_PROTOTYPE{/* Place your implementation of fputc here *//* e.g. write a character to the USART */USART_SendData(USART1, (uint8_t) ch);/* Loop until the end of transmission */while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);return ch;}因printf( )之类的函数,使用了半主机模式。
使用标准库会导致程序无法运行,以下是解决方法: 方法1.使用微库,因为使用微库的话,不会使用半主机模式.方法2.仍然使用标准库,在主程序添加下面代码:#pragma import(__use_no_semihosting)_sys_exit(int x){x = x;}struct __FILE{int handle;/* Whatever you require here. If the only file you are using is *//* standard output using printf() for debugging, no file handling *//* is required. */};/* FILE is typedef’ d in stdio.h. */FILE __stdout;如果使用的是MDK,请在工程属性的“Target-》Code Generation中勾选Use MicroLIB”;今天参考了一下论坛,使用微库可以很好的解决这个问题。
printf()为什么有重入和性能上的问题?
这个概念在嵌入式操作系统中比较重要,由于存在任务的调度,它实时系统,可剥夺型内核中是危险的,如同一个安静的水雷。
可能会被触发,也可能安然无恙。
由于它运行结果的不可预期性,会使系统带来隐患。
printf()经常有重入解释不可重入函数不可以在它还没有返回就再次被调用。
例如printf,malloc,free等都是不可重入函数。
因为中断可能在任何时候发生,例如在printf执行过程中,因此不能在中断处理函数里调用printf,否则printf 将会被重入。
函数不可重入大多数是因为在函数中引用了全局变量。
例如,printf会引用全局变量stdout,malloc,free 会引用全局的内存分配表。
个人理解:如果中断发生的时候,当运行到printf的时候,假设发生了中断嵌套,而此时stdout资源被占用,所以第二个中断printf等待第一个中断的stdout资源释放,第一个中断等待第二个中断返回,造成了死锁,不知这样理解对不对。
不可重入函数指的是该函数在被调用还没有结束以前,再次被调用可能会产生错误。
可重入函数不存在这样的问题。
不可重入函数在实现时候通常使用了全局的资源,在多线程的环境下,如果没有很好的处理数据保护和互斥访问,就会发生错误。
常见的不可重入函数有:printf --------引用全局变量stdoutmalloc --------全局内存分配表free --------全局内存分配表在unix里面通常都有加上_r后缀的同名可重入函数版本。
如果实在没有,不妨在可预见的发生错误的地方尝试加上保护锁同步机制等等。
下面引用一段别人的解释:这主要在多任务环境中使用,一个可重入的函数简单来说,就是:可以被中断的函数。
就是说,你可以在这个函数执行的任何时候中断他的运行,在OS的调度下去执行另外一段代码而不会出现什么错误。
而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函数是不能运行在多任务环境下的。
单片机重映射
单片机重映射随着科技的发展和应用的广泛,单片机(Microcontroller)在各个领域中得到了广泛的应用。
单片机重映射(Remapping)是指将单片机的引脚或者功能进行重新分配和配置,以满足特定应用需求的一种技术手段。
通过单片机重映射,可以使单片机具备更多的功能和扩展性,提高系统的灵活性和效率。
单片机重映射涉及到对单片机的引脚和功能进行重新配置,使其能够适应不同的应用场景。
在单片机设计中,通常会有一些功能模块或引脚需要被多个外设所共享,而这些外设可能需要在不同的时间段内使用。
为了解决这个问题,就需要对单片机进行重映射,将不同的功能或引脚分时使用,从而实现多个外设的共享。
单片机重映射的具体实现方法可以有多种,比较常见的有软件重映射和硬件重映射两种方式。
软件重映射是通过软件编程的方式实现的,通过对单片机的寄存器进行设置和配置,将某个引脚或功能从一个外设映射到另一个外设。
软件重映射的优点是灵活性高,可以根据需要随时进行配置和修改。
但是,软件重映射的缺点是需要占用额外的处理器资源和时间,并且可能会影响系统的实时性能。
硬件重映射是通过硬件电路的方式实现的,通过对单片机的引脚进行物理连接和切换,将某个引脚或功能从一个外设映射到另一个外设。
硬件重映射的优点是实时性好,不会影响系统的性能和时序要求。
但是,硬件重映射的缺点是配置和修改比较困难,需要设计和制造专门的硬件电路。
单片机重映射的应用非常广泛。
在嵌入式系统中,由于单片机的引脚和功能资源有限,需要通过重映射来实现多个外设的共享。
比如,一个单片机可能需要同时连接多个传感器、执行器和通信模块,通过重映射可以将不同的功能映射到不同的引脚上,从而实现多个外设的并行工作。
在工业控制系统中,单片机重映射也发挥着重要的作用。
工业控制系统通常需要连接大量的传感器、执行器和通信设备,通过重映射可以将不同的功能映射到不同的引脚上,从而实现系统的灵活配置和扩展。
单片机重映射还可以用于汽车电子、医疗设备、智能家居等领域。
printf在单片机中的用法
pchar++;
}
while(TI0==0){};
TI0=0;
sprintf(PrintChar,"Test complete.\n");
send_string_com(PrintChar,15);
正确的输出如下:
正确的代码如下:
pchar = XRAM_START;
TI0=1;
for (i = 0; i < RAM_SIZE; i++)
{
*pchar= 0;
ES0=0;
printf("writing 0x%04x:%u\n",(unsigned)pchar,(unsigned) *pchar);
SFRPAGE_SAVE = SFRPAGE; //c8051f120特殊功能寄存器分页
SFRPAGE = UART0_PAGE;
TI0=1;
printf ("\n\nTest complete.");
TI0=0; //可以省略
WinAVR库中的printf()是可以直接传输数据到串口上的,但之前需要初始化很多东西。下面是avr-lib中的一个例子:
#include <stdio.h> static int uart_putchar(char c, FILE *stream); static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); static int uart_putchar(char c, FILE *stream) { if (c == ''\n'') uart_putchar(''\r'', stream); loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; } int main(void) { init_uart(); stdout = &mystdout; printf("Hello, world!\n"); return 0; }
