<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【STM32 系列】多路USART串口Printf重定向詳解——通用

      引言

      通常情況下,標準的printf函數只能將輸出重定向到一個串口。然而,當我們需要在多個串口上進行輸出,而又不希望為每個串口單獨封裝發送函數時,就可以考慮將printf的輸出重定向到多個串口。接下來,本文將詳細介紹如何實現這一目標。

      注:

      • 本篇文章的代碼根據正點原子所提供代碼改寫。
      • 正點原子所提供代碼能在不使用半主機模式下能夠正確編譯和運行代碼,這包括聲明一些特殊的匯編指令和函數定義,以避免編譯器默認使用半主機模式(不需要勾選 “Use MicroLIB”)
      • 本篇文章代碼是基于CubeMX編寫的HAL庫,但是所涉及HAL庫的內容不多,稍微修改,即可兼容標準庫。

      單個串口的printf重定向

      單個串口的重定向,可以參考正點原子所提供代碼,直接cope進自己工程中即可。

      //usart.c
      

      /*****************************************************************************************/
      /
      加入以下代碼, 支持printf函數, 而不需要選擇use MicroLIB */

      if 1

      if (__ARMCC_VERSION >= 6010050) /* 使用AC6編譯器時 */

      __asm(".global __use_no_semihosting\n\t"); /* 聲明不使用半主機模式 /
      __asm(".global __ARM_use_no_argv \n\t"); /
      AC6下需要聲明main函數為無參數格式,否則部分例程可能出現半主機模式 */

      else

      /* 使用AC5編譯器時, 要在這里定義__FILE 和 不使用半主機模式 */

      pragma import(__use_no_semihosting)

      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. */
      };

      endif

      /* 不使用半主機模式,至少需要重定義_ttywrch_sys_exit_sys_command_string函數,以同時兼容AC6和AC5模式 */
      int _ttywrch(int ch)
      {
      ch = ch;
      return ch;
      }

      /* 定義_sys_exit()以避免使用半主機模式 */
      void _sys_exit(int x)
      {
      x = x;
      }

      char *_sys_command_string(char *cmd, int len)
      {
      return NULL;
      }

      /* FILE 在 stdio.h里面定義 */
      FILE __stdout;

      /* 重定義fputc函數, printf函數最終會通過調用fputc輸出字符串到串口 */
      int fputc(int ch, FILE f)
      {
      while ((USART_UX->ISR & 0X40) == 0); /
      等待上一個字符發送完成 */

      USART_UX-&gt;TDR = (uint8_t)ch;            /* 將要發送的字符 ch 寫入到DR寄存器 */
      return ch;
      

      }

      endif

      /******************************************************************************************/

      多串口的printf重定向

      usart.h文件

      對正點原子的源碼進行了一點小的改動,首先在usart.h文件中添加了一個枚舉類型,方便用來索引某個串口,用于printf定向:

      其次增加了一個新的串口句柄,存儲當前使用的USART句柄(標準庫注意修改此處):

      最后添加了一個當前串口的索引,用于存儲當前使用的USART索引:

      以下就是上面所說的在usart.h中所需要增加的代碼:

      //usart.h
      

      /******************** 以下是多路USART串口printf重定向 ********************/

      /* 定義USART索引枚舉 /
      typedef enum {
      USART_NONE, /
      無USART /
      USART1_IDX, /
      USART1索引 /
      USART2_IDX, /
      USART2索引 /
      USART3_IDX, /
      USART3索引 */
      }Current_USART_Indx;

      extern UART_HandleTypeDef* Current_USART_Handle; /* 當前某個USART的句柄 /
      extern Current_USART_Indx Current_USART_Printf_Indx; /
      當前某個USART的索引 */

      void Set_Current_USART(Current_USART_Indx indx); /* 函數聲明,用于設置當前使用的USART */

      usart.c文件

      Set_Current_USART函數用于設置當前使用的USART。它接受一個Current_USART_Indx類型的參數,并根據該參數更新Current_USART_Handle句柄和Current_USART_Printf_Indx索引

      /* 
       * 簡介:設置當前使用的USART
       * 參數:indx - 要設置的USART索引
       * 這個參數可以是:USARTx_IDX,其中x可以從1~3
       * 使用舉例:(必須要將其放在printf函數前面,指定其中一個串口)
       * 		Set_Current_USART(USART1_IDX);
       * 		printf("我是串口1\r\n");
       */
      void Set_Current_USART(Current_USART_Indx indx)
      {
      	switch(indx)
        {
          case USART1_IDX:
          Current_USART_Handle = &huart1;
          Current_USART_Printf_Indx = USART1_IDX;
          break;
          case USART2_IDX:
          Current_USART_Handle = &huart2;
          Current_USART_Printf_Indx = USART2_IDX;
          break;
          case USART3_IDX:
          Current_USART_Handle = &huart3;
          Current_USART_Printf_Indx = USART3_IDX;
          break;
          default:
          Current_USART_Handle = NULL;
          Current_USART_Printf_Indx = USART_NONE;
          break;
        }
      }

      fputc函數是printf函數輸出字符時調用的底層函數,進行了一些改變,使其可以隨時自定義重定向到不同串口:

      /* 
       * 簡介:重定義fputc函數,用于將字符輸出到當前設置的USART
       * 參數:
       * ch - 要發送的字符
       * f  - 文件指針(在此實現中未使用)
       * 返回值:發送的字符(或EOF如果出錯)
       */
      int fputc(int ch, FILE *f)
      {
        if(Current_USART_Handle == NULL){			/* 如果當前沒有設置USART句柄,則返回EOF表示錯誤 */
          return EOF;
        }
        /* 根據當前設置的USART句柄,選擇對應的USART外設發送字符 */
        if(Current_USART_Handle == &huart1){		
      	while ((USART1->ISR & 0X40) == 0); 		/* 等待USART1發送完成,然后發送字符 */
      	USART1->TDR = (uint8_t)ch; 				/* 將要發送的字符 ch 寫入到DR寄存器 */
        }
        else if(Current_USART_Handle == &huart2){
      	while ((USART2->ISR & 0X40) == 0); 		/* 等待USART2發送完成,然后發送字符 */
      	USART2->TDR = (uint8_t)ch; 				/* 將要發送的字符 ch 寫入到DR寄存器 */
        }
        else if(Current_USART_Handle == &huart3){
      	while ((USART3->ISR & 0X40) == 0); 		/* 等待USART3發送完成,然后發送字符 */
      	USART3->TDR = (uint8_t)ch; 				/* 將要發送的字符 ch 寫入到DR寄存器 */
        }
        return ch;								/* 返回發送的字符 */
      }

      此文件中全部的重定向代碼:

      #if 1
      #if (__ARMCC_VERSION >= 6010050)           /* 使用AC6編譯器時 */
      __asm(".global __use_no_semihosting\n\t"); /* 聲明不使用半主機模式 */
      __asm(".global __ARM_use_no_argv \n\t");   /* AC6下需要聲明main函數為無參數格式,否則部分例程可能出現半主機模式 */
      

      else

      /* 使用AC5編譯器時, 要在這里定義__FILE 和 不使用半主機模式 */

      pragma import(__use_no_semihosting)

      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. */
      };

      endif

      /* 不使用半主機模式,至少需要重定義_ttywrch_sys_exit_sys_command_string函數,以同時兼容AC6和AC5模式 */
      int _ttywrch(int ch)
      {
      ch = ch;
      return ch;
      }

      /* 定義_sys_exit()以避免使用半主機模式 */
      void _sys_exit(int x)
      {
      x = x;
      }

      char *_sys_command_string(char *cmd, int len)
      {
      return NULL;
      }

      /************************** 以下是多串口printf重定向函數 *************************/
      /
      FILE 在 stdio.h里面定義 */
      FILE __stdout;

      UART_HandleTypeDef* Current_USART_Handle = NULL;
      Current_USART_Indx Current_USART_Printf_Indx = USART_NONE;

      /*

      • 簡介:重定義fputc函數,用于將字符輸出到當前設置的USART
      • 參數:
      • ch - 要發送的字符
      • f - 文件指針(在此實現中未使用)
      • 返回值:發送的字符(或EOF如果出錯)
        */
        int fputc(int ch, FILE f)
        {
        if(Current_USART_Handle == NULL){ /
        如果當前沒有設置USART句柄,則返回EOF表示錯誤 /
        return EOF;
        }
        /
        根據當前設置的USART句柄,選擇對應的USART外設發送字符 /
        if(Current_USART_Handle == &huart1){
        while ((USART1->ISR & 0X40) == 0); /
        等待USART1發送完成,然后發送字符 /
        USART1->TDR = (uint8_t)ch; /
        將要發送的字符 ch 寫入到DR寄存器 /
        }
        else if(Current_USART_Handle == &huart2){
        while ((USART2->ISR & 0X40) == 0); /
        等待USART2發送完成,然后發送字符 /
        USART2->TDR = (uint8_t)ch; /
        將要發送的字符 ch 寫入到DR寄存器 /
        }
        else if(Current_USART_Handle == &huart3){
        while ((USART3->ISR & 0X40) == 0); /
        等待USART3發送完成,然后發送字符 /
        USART3->TDR = (uint8_t)ch; /
        將要發送的字符 ch 寫入到DR寄存器 /
        }
        return ch; /
        返回發送的字符 /
        }
        /
      • 簡介:設置當前使用的USART
      • 參數:indx - 要設置的USART索引
      • 這個參數可以是:USARTx_IDX,其中x可以從1~3
      • 使用舉例:(必須要將其放在printf函數前面,指定其中一個串口)
      •  Set_Current_USART(USART1_IDX);
        
      •  printf("我是串口1\r\n");
        

      /
      void Set_Current_USART(Current_USART_Indx indx)
      {
      switch(indx)
      {
      case USART1_IDX:
      Current_USART_Handle = &huart1;
      Current_USART_Printf_Indx = USART1_IDX;
      break;
      case USART2_IDX:
      Current_USART_Handle = &huart2;
      Current_USART_Printf_Indx = USART2_IDX;
      break;
      case USART3_IDX:
      Current_USART_Handle = &huart3;
      Current_USART_Printf_Indx = USART3_IDX;
      break;
      default:
      Current_USART_Handle = NULL;
      Current_USART_Printf_Indx = USART_NONE;
      break;
      }
      }
      /
      ************************* 以下是單串口printf重定向函數 ************************/
      /

      • 簡介:單個串口printf重定向fputc函數
      • 重定義fputc函數, printf函數最終會通過調用fputc輸出字符串到串口
      • int fputc(int ch, FILE *f)
      • {
      • while ((USART2->ISR & 0X40) == 0); 等待上一個字符發送完成
      • USART2->TDR = (uint8_t)ch; 將要發送的字符 ch 寫入到DR寄存器
      • return ch;
      • }
        */

      endif

      main.c中引用

      在使用printf函數之前,需要先調用Set_Current_USART函數設置當前使用的USART。然后,就可以像平常一樣使用printf函數了,輸出的字符串將會通過指定的USART發送到串口。

      
      Set_Current_USART(USART1_IDX); /* 想要指定不同串口必須在printf前加上此函數 */
      printf("我是串口1\r\n");
      Set_Current_USART(USART2_IDX); /* 想要指定不同串口必須在printf前加上此函數 */
      printf("我是串口2\r\n");
      Set_Current_USART(USART3_IDX); /* 想要指定不同串口必須在printf前加上此函數 */
      printf("我是串口3\r\n");

      通過這種方式,我們可以非常方便地在STM32項目中實現多路USART串口printf重定向,從而大大提高調試的效率和便利性。

      博客導航

      博客導航

      posted @ 2024-11-27 12:39  膝蓋中箭衛兵  閱讀(509)  評論(0)    收藏  舉報  來源
      ORCID iD icon https://orcid.org/0000-0001-5102-772X
      主站蜘蛛池模板: 国精偷拍一区二区三区| 疏附县| 久久亚洲精品中文字幕波多野结衣| 人妻少妇精品系列一区二区| 成人午夜视频一区二区无码 | 午夜A理论片在线播放| 激情亚洲专区一区二区三区| 日韩人妻无码精品久久| 亚洲永久精品日韩成人av| 亚洲成熟女人毛毛耸耸多| 精品国产成人网站一区在线| 宽甸| 中文字幕有码高清日韩| 亚洲 日本 欧洲 欧美 视频| 日本久久99成人网站| 国产精品午夜福利免费看| 亚洲成aⅴ人在线观看| xxxxbbbb欧美残疾人| 国产精品三级在线观看无码| 丰满高跟丝袜老熟女久久| 滨海县| 亚洲国产精品自产拍久久| 久久精品99国产国产精| 国产一区二区三区精品自拍| 南澳县| 精品人妻中文字幕在线| 狠狠躁日日躁夜夜躁欧美老妇 | 亚洲精品久久婷婷丁香51| 国产无遮挡免费视频免费| 无码人妻丰满熟妇奶水区码 | 国产成人8x视频一区二区| 午夜福利免费视频一区二区| 久久国产精品老人性| 日韩老熟女av搜索结果| 岛国最新亚洲伦理成人| 亚洲av无码精品色午夜蛋壳| 亚洲色偷偷色噜噜狠狠99| 丰满老熟妇好大bbbbb| 涩涩爱狼人亚洲一区在线| 少妇激情一区二区三区视频小说| 无码人妻一区二区三区线|