0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

解决printf无法打印输出的问题

撞上电子 2024-01-04 08:00 次阅读

FreeRTOS中直接使用newlib库是有问题的,相信使用过freertos进行printf都能发现这个问题,这个问题网上有两种方法:1、使用printf.stdarg.c,问题在于,这个库没有包含float型的输出!你没办法printf出浮点数。2、使用优化过的printf,这个能输出float型,但是在中断中如果使用float输出,就会莫名其妙的整个程序卡住,我找不出bug。

static int inHandlerMode (void) //若在中断中__get_IPSR()返回1,否则返回0{ return __get_IPSR();} void print_usart2(char *format, ...){ char buf[64]; if(inHandlerMode() != 0) { taskDISABLE_INTERRUPTS(); } else { while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX)//若串口忙则挂起此任务 taskYIELD(); } va_list ap; va_start(ap, format); vsprintf(buf, format, ap); HAL_UART_Transmit(&huart2, (uint8_t *)buf, strlen(buf), 100); va_end(ap); if(inHandlerMode() != 0) taskENABLE_INTERRUPTS();}

这破问题一直找不到bug在哪里,烦死了,我忍不了了!敲了个伪printf,思路很简单,遍历一遍要输出的字符串,这过程中遇到%就标记,再遇到'.'这个字符就记录一下'.'后面的数字,然后从va_list中根据%x 判断一下属于哪个类型,用va_arg读取到值,再将该值的每个十进制位读取成字符后放进输出字符串里面,就完成了!代码如下:

#include"iostream"#include "stdarg.h"using namespace std; void GetIntToString(char *target,int* target_site,int value,int num_value){char temp[20];int temp_site = 0,site = *target_site,flag = 0,neg_flag = 0;
if(num_value != 0)flag = 1;if(value < 0){neg_flag = 1;value = -value;}
while(value){temp[temp_site++] = (value % 10) + '0';value /= 10;}if(neg_flag)target[site++] = '-';while(temp_site--){if(flag){if(num_value != 0)num_value --;elsebreak;}target[site++] = temp[temp_site];}*target_site = site;} void my_sprintf(char* target,char* string,...){va_list next_value;int percent_flag = 0; // mark the emergence of percentage signint num_value = 0,num_flag = 0; // mark the value from the back of %.int target_site = 0,i = 0,value;double float_value;char *string_value;
va_start(next_value,string);while(string[i] != '\0'){if(string[i] == '%'){percent_flag = 1;}else if(percent_flag && string[i] == '.'){num_value = string[i+1] - '0';i++;}else if(percent_flag && percent_flag && (string[i] == 'd' || string[i] == 'c')){value = va_arg(next_value,int);if(value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,value,num_value);
percent_flag = num_value = 0;}else if(percent_flag && string[i] == 's'){value = va_arg(next_value,int);string_value = (char *)value;for(int j = 0;string_value[j] != '\0';j++)target[target_site++] = string_value[j];
percent_flag = num_flag = num_value = 0;}else if(percent_flag && string[i] == 'f'){float_value = va_arg(next_value,double); // 2.14if((int)float_value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,(int)float_value,0); // 2if(float_value < 0)float_value = -float_value;float_value -= (int)float_value;target[target_site++] = '.'; // 2.
if(num_value != 0)num_flag = 1;while(!(float_value >= -0.000001 && float_value <= 0.000001)){if(num_flag){if(num_value != 0)num_value --;elsebreak;}float_value *= 10;target[target_site++] = (int)float_value + '0';float_value -= (int)float_value;} // 2.14
percent_flag = num_flag = num_value = 0;}elsetarget[target_site++] = string[i];i++;}target[target_site] = '\0';va_end(next_value);} void my_printf(char* string,...){va_list next_value;int percent_flag = 0; // mark the emergence of percentage signint num_value = 0,num_flag = 0; // mark the value from the back of %.int target_site = 0,i = 0,value;double float_value;char target[100];char *string_value;
va_start(next_value,string);while(string[i] != '\0'){if(string[i] == '%'){percent_flag = 1;}else if(percent_flag && string[i] == '.'){num_value = string[i+1] - '0';i++;}else if(percent_flag && percent_flag && (string[i] == 'd' || string[i] == 'c')){value = va_arg(next_value,int);if(value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,value,num_value);
percent_flag = num_value = 0;}else if(percent_flag && string[i] == 's'){value = va_arg(next_value,int);string_value = (char *)value;for(int j = 0;string_value[j] != '\0';j++)target[target_site++] = string_value[j];
percent_flag = num_flag = num_value = 0;}else if(percent_flag && string[i] == 'f'){float_value = va_arg(next_value,double); // 2.14if((int)float_value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,(int)float_value,0); // 2if(float_value < 0)float_value = -float_value;float_value -= (int)float_value;target[target_site++] = '.'; // 2.
if(num_value != 0)num_flag = 1;while(!(float_value >= -0.000001 && float_value <= 0.000001)){if(num_flag){if(num_value != 0)num_value --;elsebreak;}float_value *= 10;target[target_site++] = (int)float_value + '0';float_value -= (int)float_value;} // 2.14
percent_flag = num_flag = num_value = 0;}elsetarget[target_site++] = string[i];i++;}target[target_site] = '\0';va_end(next_value);
for(int i = 0;i < target_site ;i ++) // 在devc++ 调试时的输出 printf("%c",target[i]);} int main(){uint8_t k = 10;char target[100];char a = -10,b = -100;my_printf("MotorRun,%d,%d\n",a,b);printf("%c %c",55,32);//my_printf("temp value is %c and %d\n",k,k);//my_printf("you are so %s,yes \n%f","handsome",0.09);}

不过精度的问题,不知道怎么改,所以使用这个程序输出float应该限制小数点长度。代码应该不难看懂,不过这段代码还没有实现字符宽度输出,也就是没有实现%后跟着数字的输出,在用该代码也不应该在%后加数字。突然发现这个函数的target字符串 就可以作为sprintf的输出耶,把得到target字符串的那一大串代码包装一下,就是sprintf了。在单片机的代码:通过uart2输出:

static char getint_temp[20];void GetIntToString(char *target,int* target_site,int value,int num_value){int temp_site = 0,site = *target_site;uint8_t flag = 0,neg_flag = 0; if(num_value != 0)flag = 1;if(value < 0){neg_flag = 1;value = -value;}while(value){getint_temp[temp_site++] = (value % 10) + '0';value /= 10;}if(neg_flag)target[site++] = '-';while(temp_site--){if(flag){if(num_value != 0)num_value --;elsebreak;}target[site++] = getint_temp[temp_site];}*target_site = site;} uint8_t percent_flag; // mark the emergence of percentage signuint8_t num_value,num_flag; // mark the value from the back of %.int target_site;int i,value;double float_value;char* string_value;char target[100];void my_printf(char* string,...){#if USE_PRINTF if(inHandlerMode() != 0){ taskDISABLE_INTERRUPTS();} else {while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX) //若串口忙则挂起此任务taskYIELD();} va_list next_value;i = target_site = percent_flag = num_flag = num_value = 0; va_start(next_value,string);while(string[i] != '\0'){if(string[i] == '%'){percent_flag = 1;}else if(percent_flag && string[i] == '.'){num_value = string[i+1] - '0';i++;}else if(percent_flag && (string[i] == 'd' || string[i] == 'c')){value = va_arg(next_value,int);if(value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,value,num_value); percent_flag = num_value = 0;}else if(percent_flag && string[i] == 's'){value = va_arg(next_value,int);string_value = (char *)value;for(int j = 0;string_value[j] != '\0';j++)target[target_site++] = string_value[j]; percent_flag = num_flag = num_value = 0;}else if(percent_flag && string[i] == 'f'){float_value = va_arg(next_value,double); // 2.14if((int)float_value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,(int)float_value,0); // 2if(float_value < 0)float_value = -float_value;float_value -= (int)float_value;target[target_site++] = '.'; // 2. if(num_value != 0)num_flag = 1;while(!(float_value >= -0.000001 && float_value <= 0.000001)){if(num_flag){if(num_value != 0)num_value --;elsebreak;}float_value *= 10;target[target_site++] = (int)float_value + '0';float_value -= (int)float_value;} // 2.14 percent_flag = num_flag = num_value = 0;}elsetarget[target_site++] = string[i];i++;}//target[target_site++] = '\0';va_end(next_value); HAL_UART_Transmit(&PRINTF_UART, (uint8_t *)target, target_site, 100); if(inHandlerMode() != 0)taskENABLE_INTERRUPTS();#endif} void my_sprintf(char* target,char* string,...){ if(inHandlerMode() != 0){ taskDISABLE_INTERRUPTS();} else{while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX) //若串口忙则挂起此任务taskYIELD();} va_list next_value;uint8_t percent_flag = 0; // mark the emergence of percentage signuint8_t num_value = 0,num_flag = 0; // mark the value from the back of %.int target_site = 0;int i = 0,value;double float_value;char *string_value; va_start(next_value,string);while(string[i] != '\0'){if(string[i] == '%'){percent_flag = 1;}else if(percent_flag && string[i] == '.'){num_value = string[i+1] - '0';i++;}else if(percent_flag && percent_flag && (string[i] == 'd' || string[i] == 'c')){value = va_arg(next_value,int);if(value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,value,num_value); percent_flag = num_value = 0;}else if(percent_flag && string[i] == 's'){value = va_arg(next_value,int);string_value = (char *)value;for(int j = 0;string_value[j] != '\0';j++)target[target_site++] = string_value[j]; percent_flag = num_flag = num_value = 0;}else if(percent_flag && string[i] == 'f'){float_value = va_arg(next_value,double); // 2.14if((int)float_value == 0)target[target_site++] = '0';elseGetIntToString(target,&target_site,(int)float_value,0); // 2if(float_value < 0)float_value = -float_value;float_value -= (int)float_value;target[target_site++] = '.'; // 2. if(num_value != 0)num_flag = 1;while(!(float_value >= -0.000001 && float_value <= 0.000001)){if(num_flag){if(num_value != 0)num_value --;elsebreak;}float_value *= 10;target[target_site++] = (int)float_value + '0';float_value -= (int)float_value;} // 2.14 percent_flag = num_flag = num_value = 0;}elsetarget[target_site++] = string[i];i++;}target[target_site] = '\0';va_end(next_value); if(inHandlerMode() != 0)taskENABLE_INTERRUPTS();}

在freertos两个任务中输出,并且在串口中断中输出浮点数成功(突然发现,task拼成了tast。。

523ce930-aa94-11ee-8a62-92fbcf53809c.png

彻底解决!目前使用没有bug,有bug我再来改文章。存在个bug,当传入过多参数时,后面的参数会出现乱码,如下

5243b85a-aa94-11ee-8a62-92fbcf53809c.png

最后一个%d会出现乱码。将其分成两个printf输出,可以成功输出。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61348
  • Printf
    +关注

    关注

    0

    文章

    79

    浏览量

    13478
收藏 人收藏

    评论

    相关推荐

    M451在Keil中,printf函数打印输出到哪里了?

    在Keil中,printf函数,打印输出到哪里了? 我的项目中没有使用UART0,而是使用了UART3
    发表于 01-17 07:55

    STM32例程之串口打印输出(源码下载)

    STM32串口打印输出,使用USART1输出数据,用查询的方式读取从串口接收到的数据并打印输出输入的数据。主函数:/*** @brief串口打印输出* @paramNone* @ret
    发表于 01-09 15:21

    使用printf打印输出压力值为什么会导致程序无法运行

    我用STM32F107片子对压力传感器MMR901XA 进行控制采集气囊压力值,在使用中为了能使用printf打印输出压力值,于是对printf进行了重定义,因为printf()之类的
    发表于 08-05 07:53

    重定向printf到串口打印输出

    嵌入式的开发离不开 log 的打印,我们常常使用的是重定向printf到串口打印输出,但是会对系统的实时性产生一定的影响,RTT技术可以在一定程度解决这个问题。
    发表于 08-24 07:11

    如何对printf()函数所依赖的打印输出函数fputc进行重定向呢

    如何对printf()函数所依赖的打印输出函数fputc进行重定向呢?
    发表于 11-30 06:28

    如何去使用printf这个C语言常用的打印输出函数呢

    如何去实现基于C库的printf函数呢?如何去使用printf这个C语言常用的打印输出函数呢?
    发表于 11-30 06:41

    为什么用串口3 printf打印输出会调试失败呢

    为什么用串口3 printf打印输出会调试失败呢?是什么原因呢?如何去解决呢?
    发表于 11-30 07:24

    怎么去实现printf函数打印输出

    什么是串口通信?同步通信与异步通信有何区别?怎么去实现printf函数打印输出呢?
    发表于 12-01 07:12

    怎么实现printf作为串口打印输出函数?

    怎么实现printf作为串口打印输出函数?
    发表于 12-02 06:19

    如何实现STM32对printf打印输出信息的支持呢

    如何实现STM32对printf打印输出信息的支持呢?
    发表于 12-02 06:10

    使用printf进行打印输出步骤记录

    如何使用printf进行打印输出呢?有哪些关键步骤?
    发表于 12-02 06:11

    在Keil中printf函数打印输出到哪里了?

    在Keil中,printf函数,打印输出到哪里了? 我的项目中没有使用UART0,而是使用了UART3
    发表于 08-29 07:05

    什么是串口通信?基于STM32的printf打印输出

    平时我们进行c语言编程的时候会经常用到printf函数进行打印输出,来调试代码。可是这个printf函数C库已经帮我们实现好了,通常只需要直接调用即可,但是如果在一个新的开发平台,如果库没有帮我们实现好,比如STM32开发板,那
    发表于 06-22 09:08 1.3w次阅读
    什么是串口通信?基于STM32的<b class='flag-5'>printf</b><b class='flag-5'>打印输出</b>

    简述单片机常见的打印输出方式及区别

    作者 |strongerHuang 微信公众号 | 嵌入式专栏 单片机开发中,打印输出比较常见,也比较重要,今天就为大家分享一下常见的打印输出内容以及区别。 1写在前面 在MCU项目中,printf
    的头像 发表于 09-23 09:58 3017次阅读
    简述单片机常见的<b class='flag-5'>打印输出</b>方式及区别

    单片机常见的打印输出方式及区别

    单片机开发中,打印输出比较常见,也比较重要,今天就为大家分享一下常见的打印输出内容以及区别。
    发表于 02-08 15:13 0次下载
    单片机常见的<b class='flag-5'>打印输出</b>方式及区别