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

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 --;
else
break;
}
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 sign
int 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';
else
GetIntToString(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.14
if((int)float_value == 0)
target[target_site++] = '0';
else
GetIntToString(target,&target_site,(int)float_value,0); // 2
if(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 --;
else
break;
}
float_value *= 10;
target[target_site++] = (int)float_value + '0';
float_value -= (int)float_value;
} // 2.14
percent_flag = num_flag = num_value = 0;
}
else
target[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 sign
int 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';
else
GetIntToString(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.14
if((int)float_value == 0)
target[target_site++] = '0';
else
GetIntToString(target,&target_site,(int)float_value,0); // 2
if(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 --;
else
break;
}
float_value *= 10;
target[target_site++] = (int)float_value + '0';
float_value -= (int)float_value;
} // 2.14
percent_flag = num_flag = num_value = 0;
}
else
target[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 --;
else
break;
}
target[site++] = getint_temp[temp_site];
}
*target_site = site;
}
uint8_t percent_flag; // mark the emergence of percentage sign
uint8_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';
else
GetIntToString(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.14
if((int)float_value == 0)
target[target_site++] = '0';
else
GetIntToString(target,&target_site,(int)float_value,0); // 2
if(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 --;
else
break;
}
float_value *= 10;
target[target_site++] = (int)float_value + '0';
float_value -= (int)float_value;
} // 2.14
percent_flag = num_flag = num_value = 0;
}
else
target[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 sign
uint8_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';
else
GetIntToString(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.14
if((int)float_value == 0)
target[target_site++] = '0';
else
GetIntToString(target,&target_site,(int)float_value,0); // 2
if(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 --;
else
break;
}
float_value *= 10;
target[target_site++] = (int)float_value + '0';
float_value -= (int)float_value;
} // 2.14
percent_flag = num_flag = num_value = 0;
}
else
target[target_site++] = string[i];
i++;
}
target[target_site] = '\0';
va_end(next_value);
if(inHandlerMode() != 0)
taskENABLE_INTERRUPTS();
}
在freertos两个任务中输出,并且在串口中断中输出浮点数成功(突然发现,task拼成了tast。。

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

最后一个%d会出现乱码。将其分成两个printf输出,可以成功输出。
==========
往期回顾:
==========
原文链接:点击阅读原文
作者:黄帅比。
平台:CSDN


