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。。
徹底解決!目前使用沒有bug,有bug我再來改文章。存在個bug,當傳入過多參數時,后面的參數會出現亂碼,如下
最后一個%d會出現亂碼。將其分成兩個printf輸出,可以成功輸出。
-
FreeRTOS
+關注
關注
12文章
484瀏覽量
62395 -
Printf
+關注
關注
0文章
83瀏覽量
13732
發布評論請先 登錄
相關推薦
評論