一種STM32的串列埠控制檯的實現(非常實用)

一.背景

曾經玩Linux時非常喜歡這種基於出串列埠的控制檯, 通過簡單的串列埠TX和RX能實現嵌入式硬體的人機互動,非常實用,  那麼STM32能否實現通過超級終端與使用者互動的構想呢? 答案是肯定的,由於這個UART控制平臺就像應用程式套上一層可訪問的外科(Shell)故而我將這種基於UART的控制平臺簡稱Shell,構架和效果如下圖:

這張圖箭頭指向的是輸入的指令,其餘是STM32串列埠輸出的資訊,, 可以看到通過這些簡單的指令輸入我們通過Shell可以做很多事情:

1. 現場裝置發生故障,可以通過Shell可以檢視裝置的故障狀態統計資訊

2. 能實現串列埠程式升級(需要Shell+IAP驅動程式支援)

3. 能讀寫訪問引數區,實現對裝置引數的本地配置

4. 配置多功能訊號指示燈(LED燈可顯示65535種訊號,同一時刻只能顯示一個.

5. 程式開發階段基於Shell,可以極其方便的除錯編寫的驅動程式(開發極力推薦),非常好用.

二.Shell基礎篇

Shell基礎程式只有三個檔案:

console.h:用於定義STM32用於Shell的實體串列埠

shell.cshell平臺實現主體

shell.h標頭檔案,任意的驅動檔案可呼叫,就像<stdio.h>一樣

shell.c目前包含三個部件:

shell模組(必選)Shell模組初始化時已初始化好Led模組

Led模組(必選)Ledx_on(x),Ledx_off(x),Ledx_div(x),函式是對編碼訊號進行控制,而不是直接對硬體實體控制,這樣每個LED實體就像通道一樣可以選擇非常多的訊號源顯示.

精密延時模組(可選)啟動需要對其初始化,此模組可用於記錄時間點,並判斷時間是否到(再也不用Delayms()這樣的函式浪費效率實現時序了.

三. 程式檔案:

1. console.h

[cpp] view
plain
 copy

  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作組 
  4. ** 
  5. **———————————File Info———————————— 
  6. ** File Name:               shell_hal.h 
  7. ** Last modified Date:      2014/5/26 14:22:35 
  8. ** Last Version:            V1.0   
  9. ** Description:             本地Shell檔案介面 
  10. ** 
  11. **—————————————————————————— 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2014/5/26 14:22:34 
  14. ** Version:                 V2 
  15. ** Descriptions:            只適合STM32程式 
  16. **—————————————————————————— 
  17. ** Libraries:               STM32F10x_StdPeriph_Driver 
  18. ** version                  V3.5 
  19. *******************************************************************************/  
  20.   
  21. /****************************************************************************** 
  22. 更新說明: 
  23. ******************************************************************************/  
  24.   
  25. /****************************************************************************** 
  26. *********************************  應 用 資 料 ******************************** 
  27. ******************************************************************************/  
  28.   
  29. #ifndef _SHELL_HAL_  
  30. #define _SHELL_HAL_  
  31. /****************************************************************************** 
  32. ********************************* 檔案引用部分 ******************************** 
  33. ******************************************************************************/  
  34. //包含庫檔案  
  35. #include "stm32f10x.h"  
  36. #include "stm32f10x_gpio.h"  
  37. #include "stm32f10x_rcc.h"  
  38. #include "stm32f10x_tim.h"  
  39.   
  40. /****************************************************************************** 
  41. ******************************** 可 配 置 參 數 ******************************* 
  42. ******************************** MNCS_IMAGE影象板 ***************************** 
  43. ******************************************************************************/  
  44. /*———————*  
  45. *     UART埠配置 
  46. *———————-*/  
  47. //IO配置  
  48. #define CONSOLE                 USART3   
  49. #define CONSOLE_TX_PORT         GPIOB  
  50. #define CONSOLE_TX_PIN          GPIO_Pin_10  
  51. #define CONSOLE_RX_PORT         GPIOB  
  52. #define CONSOLE_RX_PIN          GPIO_Pin_11  
  53.   
  54. //時鐘配置  
  55. #define CONSOLE_GPIO_RCC_INIT() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE)  
  56. #define CONSOLE_UART_RCC_INIT() RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE)  
  57.   
  58. //中斷優先順序  
  59. #define CONSOLE_UART_PRIO       7       //建議[0..15]  
  60.   
  61. //中斷向量配置  
  62. #define CONSOLE_IRQn            USART3_IRQn;  
  63. #define CONSOLE_IRQHandler      USART3_IRQHandler  
  64.   
  65. /*———————*  
  66. *     四個LED定義 
  67. *———————-*/  
  68. #define LED0_VALID              1           //非零表示使能對應的LED,0:無效  
  69. #define LED0_PORT               GPIOB  
  70. #define LED0_PIN                GPIO_Pin_13  
  71.   
  72. #define LED1_VALID              1           //非零表示使能對應的LED,0:無效  
  73. #define LED1_PORT               GPIOB  
  74. #define LED1_PIN                GPIO_Pin_15  
  75.   
  76. #define LED2_VALID              0           //非零表示使能對應的LED,0:無效  
  77. #define LED2_PORT               GPIOA  
  78. #define LED2_PIN                GPIO_Pin_11  
  79.   
  80. #define LED3_VALID              0           //非零表示使能對應的LED,0:無效  
  81. #define LED3_PORT               GPIOA  
  82. #define LED3_PIN                GPIO_Pin_11  
  83.   
  84. #define LED4_VALID              0           //非零表示使能對應的LED,0:無效  
  85. #define LED4_PORT               GPIOA  
  86. #define LED4_PIN                GPIO_Pin_11  
  87.   
  88. #define LED5_VALID              0           //非零表示使能對應的LED,0:無效  
  89. #define LED5_PORT               GPIOA  
  90. #define LED5_PIN                GPIO_Pin_11  
  91.   
  92. /*———————*  
  93. *        時基BASE 
  94. *———————-*/  
  95. #define TIMEDly                 TIM4  
  96. #define TIMEDly_IRQn            TIM4_IRQn  
  97. #define TIMEDly_IRQHandler      TIM4_IRQHandler  
  98.   
  99. //時鐘配置              
  100. #define TIMEDly_RCC_INIT()      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  
  101.   
  102. //初始化LGPIO口  
  103. #define LEDx_GPIO_RCC_INIT()    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE)  
  104. //——————————————————————————  
  105.   
  106. /****************************************************************************** 
  107. ******************************* 以下引數無需更改 ****************************** 
  108. ******************************************************************************/  
  109. /*———————*  
  110. *  注意以下區域無需使用者更改 
  111. *———————-*/  
  112. #if LED0_VALID  
  113.   #define LED0_ON()             (LED0_PORT->BRR  = LED0_PIN)  
  114.   #define LED0_OFF()            (LED0_PORT->BSRR = LED0_PIN)  
  115.   #define LED0_DIV()            (LED0_PORT->ODR  ^= LED0_PIN)  
  116. #else  
  117.   #define LED0_ON()             __NOP()  
  118.   #define LED0_OFF()            __NOP()  
  119.   #define LED0_DIV()            __NOP()  
  120. #endif  
  121.   
  122. #if LED1_VALID  
  123.   #define LED1_ON()             (LED1_PORT->BRR  = LED1_PIN)  
  124.   #define LED1_OFF()            (LED1_PORT->BSRR = LED1_PIN)  
  125.   #define LED1_DIV()            (LED1_PORT->ODR ^= LED1_PIN)  
  126. #else  
  127.   #define LED1_ON()             __NOP()  
  128.   #define LED1_OFF()            __NOP()  
  129.   #define LED1_DIV()            __NOP()  
  130. #endif   
  131.   
  132. #if LED2_VALID  
  133.   #define LED2_ON()             (LED2_PORT->BRR  = LED2_PIN)  
  134.   #define LED2_OFF()            (LED2_PORT->BSRR = LED2_PIN)  
  135.   #define LED2_DIV()            (LED2_PORT->ODR ^= LED2_PIN)  
  136. #else  
  137.   #define LED2_ON()             __NOP()  
  138.   #define LED2_OFF()            __NOP()  
  139.   #define LED2_DIV()            __NOP()  
  140. #endif    
  141.   
  142. #if LED3_VALID  
  143.   #define LED3_ON()             (LED3_PORT->BRR  = LED3_PIN)  
  144.   #define LED3_OFF()            (LED3_PORT->BSRR = LED3_PIN)  
  145.   #define LED3_DIV()            (LED3_PORT->ODR ^= LED3_PIN)  
  146. #else  
  147.   #define LED3_ON()             __NOP()  
  148.   #define LED3_OFF()            __NOP()  
  149.   #define LED3_DIV()            __NOP()  
  150. #endif  
  151.   
  152. #if LED4_VALID  
  153.   #define LED4_ON()             (LED4_PORT->BSRR = LED4_PIN)  
  154.   #define LED4_OFF()            (LED4_PORT->BRR  = LED4_PIN)  
  155.   #define LED4_DIV()            (LED4_PORT->ODR ^= LED4_PIN)  
  156. #else  
  157.   #define LED4_ON()             __NOP()  
  158.   #define LED4_OFF()            __NOP()  
  159.   #define LED4_DIV()            __NOP()  
  160. #endif  
  161.   
  162. #if LED5_VALID  
  163.   #define LED5_ON()             (LED5_PORT->BSRR = LED5_PIN)  
  164.   #define LED5_OFF()            (LED5_PORT->BRR  = LED5_PIN)  
  165.   #define LED5_DIV()            (LED5_PORT->ODR ^= LED5_PIN)  
  166. #else  
  167.   #define LED5_ON()             __NOP()  
  168.   #define LED5_OFF()            __NOP()  
  169.   #define LED5_DIV()            __NOP()  
  170. #endif  
  171. /****************************************************************************** 
  172. ******************************* printf支援檔案 ******************************** 
  173. ******************************************************************************/  
  174. /* Private function prototypes ———————————————–*/  
  175. #ifdef __GNUC__  
  176. /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf 
  177.    set to ‘Yes’) calls __io_putchar() */  
  178. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)  
  179. #else  
  180. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)  
  181. #endif /* __GNUC__ */  
  182.   
  183. /****************************************************************************** 
  184. ***********************************   END  ************************************ 
  185. ******************************************************************************/  
  186. #endif  

2. shell.h

[cpp] view
plain
 copy

  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作組 
  4. ** 
  5. **———————————File Info———————————— 
  6. ** File Name:               shell.h 
  7. ** Last modified Date:      2014/3/5 15:42:05 
  8. ** Last Version:            V2    
  9. ** Description:             none 
  10. ** 
  11. **—————————————————————————— 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2014/3/5 15:42:11 
  14. ** Version:                 V2 
  15. ** Descriptions:            none 
  16. **—————————————————————————— 
  17. ** Libraries:               無關 
  18. ** version                  無關 
  19. *******************************************************************************/  
  20.   
  21. /****************************************************************************** 
  22. 更新說明: 
  23. ******************************************************************************/  
  24.   
  25. /****************************************************************************** 
  26. *********************************  應 用 資 料 ******************************** 
  27. ******************************************************************************/  
  28.   
  29. #ifndef _SHELL_H_  
  30. #define _SHELL_H_  
  31. /****************************************************************************** 
  32. ********************************* 檔案引用部分 ******************************** 
  33. ******************************************************************************/  
  34. #include "stdint.h"         //包含uint8_t等資料型別  
  35. #include "stdbool.h"        //包含Bool型別  
  36. #include "stdio.h"          //包含printf支援  
  37.   
  38. /****************************************************************************** 
  39. ********************************* 引數巨集定義 ********************************* 
  40. ******************************************************************************/  
  41. //版本定義  
  42. #define SHELL_VER           2       //Shell版本  
  43. #ifndef SHELL_LED_MAX               //LED實體數量  
  44.   #define SHELL_LED_MAX     4  
  45. #endif  
  46.   
  47. //緩衝大小配置  
  48. #define SHELL_RX_MAX        (256+32)        //shell指令接收緩衝大小  
  49. #define SHELL_TX_MAX        (512)           //shell指令傳送緩衝大小  
  50.   
  51. /****************************************************************************** 
  52. ********************************* 數 據 聲 明 ********************************* 
  53. ******************************************************************************/  
  54. /*———————*  
  55. *     Shell接收 
  56. *———————-*/  
  57. //接收資料  
  58. extern volatile uint16_t   shell_rx_rdy;                    //0:空閒,非零:忙,使用者讀為非零後清零  
  59. extern volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1];   //接收緩衝  
  60.   
  61. /****************************************************************************** 
  62. ********************************* 函 數 聲 明 ********************************* 
  63. ******************************************************************************/  
  64. /*———————*  
  65. *    輸出函式 
  66. *———————-*/  
  67. //除錯Shell的介面數量  
  68. #if     (6 == SHELL_LED_MAX)  
  69.   extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,  
  70.                                 uint16_t led2_cfg,uint16_t led3_cfg,  
  71.                                 uint16_t led4_cfg,uint16_t led5_cfg);  
  72. #elif   (5 == SHELL_LED_MAX)  
  73.   extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,  
  74.                                 uint16_t led2_cfg,uint16_t led3_cfg,  
  75.                                 uint16_t led4_cfg);  
  76. #elif   (4 == SHELL_LED_MAX)  
  77.   extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,  
  78.                                 uint16_t led2_cfg,uint16_t led3_cfg);  
  79. #elif   (3 == SHELL_LED_MAX)  
  80.   extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,  
  81.                                 uint16_t led2_cfg);  
  82. #elif   (2 == SHELL_LED_MAX)  
  83.   extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg);  
  84. #elif   (1 == SHELL_LED_MAX)  
  85.   extern void shell_GPIO_Config(uint16_t led0_cfg);  
  86. #endif  
  87.   
  88. //檢測引數合法性  
  89. #if ((SHELL_LED_MAX > 6) || (SHELL_LED_MAX == 0))  
  90.   #error SHELL_LED_MAX is invaild!  
  91. #endif  
  92.   
  93. //初始化Shell  
  94. extern void shell_Init(uint32_t baud);          //模組初始化  
  95. extern void shell_SendStr(void * ptStr);        //傳送以’\0’結束的字串  
  96. extern void shell_SendHex(void * ptHex,uint16_t size);  //傳送指定個數的資料  
  97.   
  98. /*———————*  
  99. *    LEDx測試訊號定義 
  100. *———————-*/  
  101. extern void Ledx_config(uint8_t led_id,uint16_t msg_id);    //設定LED的配置訊號  
  102. extern uint16_t Ledx_read(uint8_t led_id);                  //讀取LED的配置訊號(失敗返回0)  
  103. extern  void Ledx_on (uint16_t msg_id);             //傳送LED開訊息  
  104. extern  void Ledx_off(uint16_t msg_id);             //傳送LED關訊息  
  105. extern  void Ledx_div(uint16_t msg_id);             //傳送LED取反訊息  
  106.   
  107. /*———————*  
  108. *     時基延時函式 
  109. *———————-*/  
  110. extern void Delay_LibInit(void);  
  111. extern void DlyTime_us(uint16_t us);  
  112. extern void DlyTime_ms(uint16_t ms);  
  113. extern void DlyWait_base(volatile uint64_t * ptCnt);    //標記為等待的基點時間  
  114. extern uint32_t DlyWait_lost(volatile uint64_t * ptCnt);//判斷逝去的時間(us)  
  115.   
  116. /*———————*  
  117. *     輔助判斷指令 
  118. *———————-*/  
  119. extern bool StrComp(void * buffer,void * StrCmd);   //字串匹配比較函式  
  120.   
  121. /*———————*  
  122. *       Shell服務 
  123. *———————-*/  
  124. //在main.c函式while()中判斷shell_rx_rdy是否為非零,為非零才執行以下程式  
  125. extern void Shell_Invalid_Service(void); //指令未處理服務(會處理shell_rx_rdy訊號)  
  126.   
  127. /****************************************************************************** 
  128. ***********************************   END  ************************************ 
  129. ******************************************************************************/  
  130. #endif  

3.shell.c

[cpp] view
plain
 copy

  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作組 
  4. ** 
  5. **———————————File Info———————————— 
  6. ** File Name:               shell.c 
  7. ** Last modified Date:      2014/3/5 16:43:59 
  8. ** Last Version:            V2   
  9. ** Description:             none 
  10. ** 
  11. **—————————————————————————— 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2014/3/5 16:43:58 
  14. ** Version:                 V2 
  15. ** Descriptions:            適合於STM32 
  16. **—————————————————————————— 
  17. ** Libraries:               STM32F10x_StdPeriph_Driver 
  18. ** version                  V3.5 
  19. *******************************************************************************/  
  20.   
  21. /****************************************************************************** 
  22. 更新說明: 
  23. ******************************************************************************/  
  24.   
  25. /****************************************************************************** 
  26. *********************************  應 用 資 料 ******************************** 
  27. ******************************************************************************/  
  28.   
  29. /****************************************************************************** 
  30. ********************************* 檔案引用部分 ******************************** 
  31. ******************************************************************************/  
  32. #include "shell.h"      //包含Shell介面檔案  
  33.   
  34. //是否使用擴充套件的Shell介面  
  35. #ifdef SHELL_HAL_EXT  
  36.   #include "shell_hal.h"    //本地的Shell檔案  
  37. #else  
  38.   #include "console.h"      //標準的Shell檔案  
  39. #endif  
  40.   
  41. /****************************************************************************** 
  42. ********************************* Shell.h定義 ********************************* 
  43. ******************************************************************************/  
  44. /*———————*  
  45. *     Shell 收發標記 
  46. *———————-*/  
  47. volatile uint16_t   shell_rx_rdy = 0;                       //0:空閒,非零:忙  
  48. volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1]="\0";   //接收緩衝  
  49.   
  50. /****************************************************************************** 
  51. ********************************* 本 地 數 據 ********************************* 
  52. ******************************************************************************/  
  53. /*———————*  
  54. *     Shell緩衝定義 
  55. *———————-*/  
  56. //接收  
  57. static volatile uint16_t    shell_rx_index = 0;             //資料接收標記  
  58.   
  59. //傳送  
  60. static volatile uint8_t     shell_tx_buff[SHELL_TX_MAX+1]="\0";  
  61. static volatile uint16_t    shell_tx_size  = 0;             //0:空閒,非零:忙  
  62. static volatile uint16_t    shell_tx_index = 0;             //傳送資料標記  
  63.   
  64. /*———————*  
  65. *     LED控制訊號 
  66. *———————-*/  
  67. static volatile uint16_t    msg_led_cfg[SHELL_LED_MAX];     //配置訊號  
  68.   
  69. /*———————*  
  70. *    延時模組定義 
  71. *———————-*/  
  72. static volatile uint64_t    TimeDlyCnt = 0;                 //用於輔助的延時計數值  
  73.   
  74. /****************************************************************************** 
  75. ********************************* 函 數 聲 明 ********************************* 
  76. ******************************************************************************/  
  77. /****************************************************************************** 
  78. / 函式功能:初始化GPIO口(串列埠和四個LED燈配置) 
  79. / 修改日期:none 
  80. / 輸入引數:none 
  81. / 輸出引數:none 
  82. / 使用說明:none 
  83. ******************************************************************************/  
  84. #if     (6 == SHELL_LED_MAX)  
  85.     void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,  
  86.                             uint16_t led2_cfg,uint16_t led3_cfg,  
  87.                             uint16_t led4_cfg,uint16_t led5_cfg)  
  88. #elif   (5 == SHELL_LED_MAX)  
  89.     void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,  
  90.                             uint16_t led2_cfg,uint16_t led3_cfg,  
  91.                             uint16_t led4_cfg)  
  92. #elif   (4 == SHELL_LED_MAX)  
  93.     void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,  
  94.                             uint16_t led2_cfg,uint16_t led3_cfg)  
  95. #elif   (3 == SHELL_LED_MAX)  
  96.     void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,  
  97.                             uint16_t led2_cfg)  
  98. #elif   (2 == SHELL_LED_MAX)  
  99.     void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg)  
  100. #elif   (1 == SHELL_LED_MAX)  
  101.     void shell_GPIO_Config(uint16_t led0_cfg)  
  102. #endif  
  103. {  
  104.     GPIO_InitTypeDef GPIO_InitStruct;  
  105.       
  106.     /* 配置串列埠 ———————————————————*/  
  107.     // 開啟在APB2上的GPIO口外設時鐘  
  108.     CONSOLE_GPIO_RCC_INIT();    //開啟GPIO口的時鐘  
  109.   
  110.     // 配置TX引腳  
  111.     GPIO_InitStruct.GPIO_Pin    = CONSOLE_TX_PIN;  
  112.     GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_AF_PP;  
  113.     GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;  
  114.     GPIO_Init(CONSOLE_TX_PORT,  &GPIO_InitStruct);  
  115.   
  116.     // 配置RX引腳  
  117.     GPIO_InitStruct.GPIO_Pin    = CONSOLE_RX_PIN;  
  118.     GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IPU;  
  119.     GPIO_Init(CONSOLE_RX_PORT,  &GPIO_InitStruct);  
  120.   
  121.     //鎖定GPIO口,防止其他更改  
  122.     GPIO_PinLockConfig(CONSOLE_TX_PORT,CONSOLE_TX_PIN);  
  123.     GPIO_PinLockConfig(CONSOLE_RX_PORT,CONSOLE_RX_PIN);  
  124.       
  125.     /* 配置LEDx ———————————————————*/  
  126.     LEDx_GPIO_RCC_INIT();  
  127.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  
  128.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;  
  129.       
  130.     //根據定義配置四個LED  
  131.   #if (SHELL_LED_MAX > 0)  
  132.     GPIO_InitStruct.GPIO_Pin    = LED0_PIN;  
  133.     GPIO_Init(LED0_PORT,   &GPIO_InitStruct);  
  134.     GPIO_PinLockConfig(LED0_PORT,LED0_PIN);  
  135.     msg_led_cfg[0] = led0_cfg;  
  136.     LED0_OFF();  
  137.   #endif  
  138.   #if (SHELL_LED_MAX > 1)  
  139.     GPIO_InitStruct.GPIO_Pin    = LED1_PIN;  
  140.     GPIO_Init(LED1_PORT,   &GPIO_InitStruct);  
  141.     GPIO_PinLockConfig(LED1_PORT,LED1_PIN);  
  142.     msg_led_cfg[1] = led1_cfg;  
  143.     LED1_OFF();  
  144.   #endif  
  145.   #if (SHELL_LED_MAX > 2)  
  146.     GPIO_InitStruct.GPIO_Pin    = LED2_PIN;  
  147.     GPIO_Init(LED2_PORT,   &GPIO_InitStruct);  
  148.     GPIO_PinLockConfig(LED2_PORT,LED2_PIN);  
  149.     msg_led_cfg[2] = led2_cfg;  
  150.     LED2_OFF();  
  151.   #endif  
  152.   #if (SHELL_LED_MAX > 3)  
  153.     GPIO_InitStruct.GPIO_Pin    = LED3_PIN;  
  154.     GPIO_Init(LED3_PORT,   &GPIO_InitStruct);  
  155.     GPIO_PinLockConfig(LED3_PORT,LED3_PIN);  
  156.     msg_led_cfg[3] = led3_cfg;  
  157.     LED3_OFF();  
  158.   #endif   
  159.   #if (SHELL_LED_MAX > 4)  
  160.     GPIO_InitStruct.GPIO_Pin    = LED4_PIN;  
  161.     GPIO_Init(LED4_PORT,   &GPIO_InitStruct);  
  162.     GPIO_PinLockConfig(LED4_PORT,LED4_PIN);  
  163.     msg_led_cfg[4] = led4_cfg;  
  164.     LED4_OFF();  
  165.   #endif   
  166.   #if (SHELL_LED_MAX > 5)  
  167.     GPIO_InitStruct.GPIO_Pin    = LED5_PIN;  
  168.     GPIO_Init(LED5_PORT,   &GPIO_InitStruct);  
  169.     GPIO_PinLockConfig(LED5_PORT,LED5_PIN);  
  170.     msg_led_cfg[5] = led5_cfg;  
  171.     LED5_OFF();  
  172.   #endif   
  173. }  
  174.   
  175. /****************************************************************************** 
  176. / 函式功能:串列埠初始化,使用中斷單位元組接收資料 
  177. / 修改日期:none 
  178. / 輸入引數:baud 波特率 
  179. / 輸出引數:none 
  180. / 使用說明:none 
  181. ******************************************************************************/  
  182. void shell_Init(uint32_t baud)  
  183. {  
  184.     USART_InitTypeDef   USART_InitStructure;  
  185.     NVIC_InitTypeDef    NVIC_UART_Cfg;  //UART中斷向量  
  186.       
  187.     //————————— 先定義好資料結構 —————————  
  188.     //定義好USART結構體  
  189.     USART_InitStructure.USART_BaudRate      = baud;  
  190.     USART_InitStructure.USART_WordLength    = USART_WordLength_8b;  
  191.     USART_InitStructure.USART_StopBits      = USART_StopBits_1;  
  192.     USART_InitStructure.USART_Parity        = USART_Parity_No ;  
  193.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  194.     USART_InitStructure.USART_Mode          = USART_Mode_Tx | USART_Mode_Rx;  
  195.     USART_InitStructure.USART_BaudRate = USART_InitStructure.USART_BaudRate;    //防止編譯報錯  
  196.       
  197.     //定義好NVIC:UART中斷  
  198.     NVIC_UART_Cfg.NVIC_IRQChannel = CONSOLE_IRQn;  
  199.     NVIC_UART_Cfg.NVIC_IRQChannelPreemptionPriority = 1;  
  200.     NVIC_UART_Cfg.NVIC_IRQChannelSubPriority = CONSOLE_UART_PRIO;  
  201.     NVIC_UART_Cfg.NVIC_IRQChannelCmd = ENABLE;  
  202.     NVIC_UART_Cfg.NVIC_IRQChannel = NVIC_UART_Cfg.NVIC_IRQChannel;              //防止編譯報錯  
  203.       
  204.     //模式配置  
  205.     //————————— 中斷方式收發資料 —————————-  
  206.     CONSOLE_UART_RCC_INIT();                                //開啟USART的時鐘  
  207.     USART_Cmd(CONSOLE, DISABLE);                            //關閉UART  
  208.       
  209.     USART_Init(CONSOLE, &USART_InitStructure);              //初始化串列埠  
  210.       
  211.     USART_ITConfig(CONSOLE, USART_IT_RXNE, ENABLE);  
  212.     USART_ITConfig(CONSOLE, USART_IT_IDLE, ENABLE);  
  213.       
  214.     USART_Cmd(CONSOLE, ENABLE);  
  215.       
  216.     NVIC_Init(&NVIC_UART_Cfg);                              //配置好NVIC  
  217. }  
  218.   
  219. /****************************************************************************** 
  220. / 函式功能:Delay延時庫初始化(需要1us的計數精度,和50ms的溢位計數) 
  221. / 修改日期:2014/5/1 21:02:58 
  222. / 輸入引數:none 
  223. / 輸出引數:none 
  224. / 使用說明:(限STM32F40X的TIM2,TIM3,TIM4,TIM5) 
  225. ******************************************************************************/  
  226. void Delay_LibInit(void)  
  227. {  
  228.     TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;  
  229.     NVIC_InitTypeDef            NVIC_InitStructure;  
  230.       
  231.     //開啟TIM2時鐘  
  232.     TIMEDly_RCC_INIT();  
  233.   
  234.     /* Enable the TIMx gloabal Interrupt */  
  235.     NVIC_InitStructure.NVIC_IRQChannel                  = TIMEDly_IRQn;  
  236.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;  
  237.     NVIC_InitStructure.NVIC_IRQChannelSubPriority       = 0;    //由於是時基,需要使用最高優先順序  
  238.     NVIC_InitStructure.NVIC_IRQChannelCmd               = ENABLE;  
  239.     NVIC_Init(&NVIC_InitStructure);  
  240.     
  241.     /* Time base configuration */  
  242.     TIM_TimeBaseStructure.TIM_Period    = 65000;  
  243.     TIM_TimeBaseStructure.TIM_Prescaler     = (SystemCoreClock/1000000)-1;  
  244.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;  
  245.     TIM_TimeBaseStructure.TIM_CounterMode    = TIM_CounterMode_Up;  
  246.   
  247.     TIM_TimeBaseInit(TIMEDly, &TIM_TimeBaseStructure);  
  248.      
  249.     /* TIM Interrupts enable */  
  250.     TIM_ITConfig(TIMEDly,TIM_IT_Update, ENABLE);  
  251.   
  252.     /* TIMx enable counter */  
  253.     TIM_Cmd(TIMEDly, ENABLE);  
  254. }  
  255.   
  256. /****************************************************************************** 
  257. / 函式功能:等待一個us延時 
  258. / 修改日期:2014/5/1 21:02:58 
  259. / 輸入引數:none 
  260. / 輸出引數:none 
  261. / 使用說明:none 
  262. ******************************************************************************/  
  263. void DlyTime_us(uint16_t us)  
  264. {  
  265.    uint64_t this_cnt,over_cnt,tmp_val;  
  266.      
  267.     //得到當前的準確時間  
  268.     do  
  269.     {  
  270.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  271.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  272.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  273.             (TIMEDly->SR    & TIM_IT_Update)    )  
  274.         {  
  275.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  276.             TimeDlyCnt  +=  65000;    
  277.         }  
  278.         tmp_val = TIMEDly->CNT + TimeDlyCnt;   
  279.     }  
  280.     while(this_cnt != tmp_val);  
  281.     over_cnt = this_cnt + us;       //得到目標延時時間  
  282.       
  283.     //延時函式  
  284.     do  
  285.     {  
  286.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  287.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  288.             (TIMEDly->SR    & TIM_IT_Update)    )  
  289.         {  
  290.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  291.             TimeDlyCnt  +=  65000;    
  292.         }  
  293.           
  294.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  295.     }  
  296.     while(this_cnt < over_cnt);  
  297. }  
  298.   
  299. /****************************************************************************** 
  300. / 函式功能:等待一個ms延時 
  301. / 修改日期:2014/5/1 21:02:58 
  302. / 輸入引數:none 
  303. / 輸出引數:none 
  304. / 使用說明:none 
  305. ******************************************************************************/  
  306. void DlyTime_ms(uint16_t ms)  
  307. {  
  308.    uint64_t this_cnt,over_cnt,tmp_val;  
  309.      
  310.     //得到當前的準確時間  
  311.     do  
  312.     {  
  313.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  314.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  315.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  316.             (TIMEDly->SR    & TIM_IT_Update)    )  
  317.         {  
  318.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  319.             TimeDlyCnt  +=  65000;    
  320.         }  
  321.         tmp_val = TIMEDly->CNT + TimeDlyCnt;   
  322.     }  
  323.     while(this_cnt != tmp_val);  
  324.     over_cnt = this_cnt + (uint32_t)ms*1000;  
  325.       
  326.     //延時函式  
  327.     do  
  328.     {  
  329.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  330.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  331.             (TIMEDly->SR    & TIM_IT_Update)    )  
  332.         {  
  333.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  334.             TimeDlyCnt  +=  65000;    
  335.         }  
  336.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  337.     }  
  338.     while(this_cnt < over_cnt);  
  339. }  
  340.   
  341. /****************************************************************************** 
  342. / 函式功能:標記時間起點 
  343. / 修改日期:2014/5/1 21:02:58 
  344. / 輸入引數:none 
  345. / 輸出引數:none 
  346. / 使用說明:none 
  347. ******************************************************************************/  
  348. void DlyWait_base(volatile uint64_t * ptCnt)  
  349. {  
  350.     uint64_t this_cnt,tmp_val;  
  351.       
  352.     //得到當前的準確時間  
  353.     do  
  354.     {  
  355.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  356.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  357.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  358.             (TIMEDly->SR    & TIM_IT_Update)    )  
  359.         {  
  360.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  361.             TimeDlyCnt  +=  65000;    
  362.         }  
  363.         tmp_val = TIMEDly->CNT + TimeDlyCnt;   
  364.     }  
  365.     while(this_cnt != tmp_val);  
  366.     *ptCnt = this_cnt;  
  367. }  
  368.   
  369. /****************************************************************************** 
  370. / 函式功能:檢測從起點開始已逝去的時間(最大1個小時) 
  371. / 修改日期:2014/5/1 21:02:58 
  372. / 輸入引數:none 
  373. / 輸出引數:返回0表示時間到,返回非零表示時間未到 
  374. / 使用說明:none 
  375. ******************************************************************************/  
  376. uint32_t DlyWait_lost(volatile uint64_t * ptCnt)  
  377. {  
  378.     uint64_t this_cnt,tmp_val;  
  379.       
  380.     //得到當前的準確時間  
  381.     do  
  382.     {  
  383.         this_cnt = TIMEDly->CNT + TimeDlyCnt;  
  384.         if( (TIMEDly->SR    & TIM_IT_Update)    &&  
  385.             (TIMEDly->SR    & TIM_IT_Update)    &&  
  386.             (TIMEDly->SR    & TIM_IT_Update)    )  
  387.         {  
  388.             TIMEDly->SR =   (uint16_t)~TIM_IT_Update;  
  389.             TimeDlyCnt  +=  65000;   
  390.         }  
  391.         tmp_val = TIMEDly->CNT + TimeDlyCnt;   
  392.     }  
  393.     while(this_cnt != tmp_val);  
  394.       
  395.     //計算已逝去的時間  
  396.     if(*ptCnt <= this_cnt)  
  397.     {  
  398.         tmp_val = this_cnt – *ptCnt;  
  399.         if(tmp_val > (65536UL*65536UL-1))  
  400.                 return (uint32_t)(65536UL*65536UL-1);  
  401.         else    return (uint32_t)tmp_val;  
  402.     }  
  403.     else  
  404.     {  
  405.         *ptCnt = this_cnt;  
  406.         return 0;         
  407.     }  
  408. }  
  409.   
  410. /****************************************************************************** 
  411. / 函式功能:中斷支援函式(限STM32F40X的TIM2,TIM3,TIM4,TIM5) 
  412. / 修改日期:2014/5/1 21:02:58 
  413. / 輸入引數:none 
  414. / 輸出引數:none 
  415. / 使用說明:none 
  416. ******************************************************************************/   
  417. void TIMEDly_IRQHandler(void)  
  418. {  
  419.     //簡單寫法  
  420.     if( TIMEDly->SR & TIM_IT_Update )  
  421.     {  
  422.         TIMEDly->SR = (uint16_t)~TIM_IT_Update;  
  423.         TimeDlyCnt += 65000;  
  424.         //Ledx_div(3);        //時基訊號  
  425.     }  
  426. }  
  427.   
  428. /****************************************************************************** 
  429. / 函式功能:printf支援函式 
  430. / 修改日期:none 
  431. / 輸入引數:none 
  432. / 輸出引數:none 
  433. / 使用說明:none 
  434. ******************************************************************************/  
  435. PUTCHAR_PROTOTYPE  
  436. {  
  437.     Ledx_on(11);  
  438.     /* Loop until the end of transmission */  
  439.     while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );  
  440.       
  441.     /* Place your implementation of fputc here */  
  442.     /* e.g. write a character to the USART */  
  443.     CONSOLE->DR = ch;  
  444.       
  445.     /* Loop until the end of transmission */  
  446.     //while( (CONSOLE->SR & USART_FLAG_TC) == RESET );  
  447.     Ledx_off(11);  
  448.     return ch;  
  449. }  
  450.   
  451. /****************************************************************************** 
  452. / 函式功能:字串傳送函式 
  453. / 修改日期:none 
  454. / 輸入引數:none 
  455. / 輸出引數:none 
  456. / 使用說明:none 
  457. ******************************************************************************/  
  458. void shell_SendStr(void * ptAsc)  
  459. {                                   //中斷方式  
  460.     //————————— 中斷方式收發資料 —————————-  
  461.     uint16_t        i,size;  
  462.     uint8_t         *ptDst;  
  463.     uint8_t const   *ptSrc;     //源資料只讀不寫  
  464.       
  465.     //計算字串的長度  
  466.     ptSrc = (uint8_t const *)ptAsc;  
  467.     size  = 0;  
  468.     while(*ptSrc++){size++;}  
  469.       
  470.     //判斷字串是否超過緩衝  
  471.     Ledx_on(11);  
  472.     if(size > SHELL_TX_MAX)  
  473.     {  
  474.         //關閉中斷髮送方式  
  475.         shell_tx_index = 0;  
  476.         shell_tx_size  = 0;  
  477.         CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //關閉傳送完畢中斷  
  478.           
  479.         ptSrc = (uint8_t const *)ptAsc;  
  480.         while(size–)  
  481.         {  
  482.             while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );  
  483.             CONSOLE->DR = *ptSrc++;  
  484.         }  
  485.         Ledx_off(11);  
  486.     }  
  487.     else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )  
  488.     {  
  489.         //如果未啟用非空中斷則,啟用非空中斷髮送資料  
  490.         //複製資料  
  491.         ptDst = (uint8_t *)shell_tx_buff;  
  492.         ptSrc = (uint8_t const *)ptAsc;  
  493.         for(i=0; i<size; i++)  
  494.             *ptDst++ = *ptSrc++;  
  495.           
  496.         //啟動傳送中斷  
  497.         shell_tx_index = 0;  
  498.         shell_tx_size  = size;  
  499.         CONSOLE->CR1 |= USART_CR1_TXEIE;        //啟動傳送非空中斷          
  500.     }  
  501. }  
  502.   
  503. /****************************************************************************** 
  504. / 函式功能:傳送Hex資料函式 
  505. / 修改日期:none 
  506. / 輸入引數:none 
  507. / 輸出引數:none 
  508. / 使用說明:none 
  509. ******************************************************************************/  
  510. void shell_SendHex(void * ptHex,uint16_t size)  
  511. {                                  //中斷方式  
  512.     //————————— 中斷方式收發資料 —————————-  
  513.     uint16_t        i;  
  514.     uint8_t         *ptDst;  
  515.     uint8_t const   *ptSrc;     //源資料只讀不寫  
  516.   
  517.     Ledx_on(11);  
  518.     if(size > SHELL_TX_MAX)  
  519.     {  
  520.         //關閉中斷髮送方式  
  521.         shell_tx_index = 0;  
  522.         shell_tx_size  = 0;  
  523.         CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //關閉傳送完畢中斷  
  524.           
  525.         //直接傳送資料  
  526.         ptSrc = (uint8_t const *)ptHex;  
  527.         while(size–)  
  528.         {  
  529.             while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );  
  530.             CONSOLE->DR = *ptSrc++;  
  531.         }  
  532.         Ledx_off(11);   
  533.     }  
  534.     else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )  
  535.     {  
  536.         //如果未啟用非空中斷則,啟用非空中斷髮送資料  
  537.         //複製資料  
  538.         ptDst = (uint8_t *)shell_tx_buff;  
  539.         ptSrc = (uint8_t const *)ptHex;     
  540.         for(i=0; i<size; i++)  
  541.             *ptDst++ = *ptSrc++;  
  542.           
  543.         //啟動傳送中斷  
  544.         shell_tx_index = 0;  
  545.         shell_tx_size  = size;  
  546.         CONSOLE->CR1 |= USART_CR1_TXEIE;        //啟動傳送非空中斷       
  547.     }  
  548. }  
  549.   
  550. /****************************************************************************** 
  551. / 函式功能:中斷服務程式 
  552. / 修改日期:none 
  553. / 輸入引數:none 
  554. / 輸出引數:none 
  555. / 使用說明:none 
  556. ******************************************************************************/  
  557. void CONSOLE_IRQHandler(void)  
  558. {  
  559.     uint8_t     rxd_reg,txd_reg;  
  560.     uint16_t    isr_reg;  
  561.                                        //中斷配置  
  562.     //————————— 中斷方式收發資料 —————————-  
  563.     isr_reg = CONSOLE->SR;  
  564.     //接收中斷  
  565.     if( (CONSOLE->CR1 & USART_CR1_RXNEIE) && (isr_reg & USART_SR_RXNE) )  
  566.     {  
  567.         rxd_reg = CONSOLE->DR;  
  568.         Ledx_on(12);  
  569.         if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到位元組,重置接收指標  
  570.         else  
  571.         {  
  572.             if( shell_rx_index < SHELL_RX_MAX)  
  573.             {  
  574.                 shell_rx_buff[shell_rx_index] = rxd_reg;  
  575.                 shell_rx_index++;  
  576.             }  
  577.             else  
  578.             {  
  579.                 shell_rx_index = 0;  
  580.                 Ledx_off(12);      
  581.             }  
  582.         }  
  583.     }  
  584.       
  585.     if( (CONSOLE->CR1 & USART_CR1_IDLEIE) && (isr_reg & USART_SR_IDLE) )  
  586.     {  
  587.         CONSOLE->SR;  
  588.         CONSOLE->DR;  
  589.         if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到空閒,重置接收指標  
  590.         else  
  591.         {  
  592.             if( (shell_rx_index >=2) && (‘\r’ == shell_rx_buff[shell_rx_index-2]) &&  
  593.                 (‘\n’ == shell_rx_buff[shell_rx_index-1])   )       //以"\r\n"結尾  
  594.             {  
  595.                 shell_rx_rdy = shell_rx_index;  
  596.                 shell_rx_index = 0;  
  597.                 Ledx_off(12);  
  598.             }  
  599.             else if( (shell_rx_index > 0) && (‘\b’ == shell_rx_buff[shell_rx_index-1]) )  //以\b結尾  
  600.             {  
  601.                 shell_rx_index = shell_rx_index <2? 0:shell_rx_index-2;  
  602.                 printf(" \b");      //傳送輔助刪除          
  603.             }   
  604.         }   
  605.     }  
  606.       
  607.     //傳送非空中斷      
  608.     if( (CONSOLE->CR1 & USART_CR1_TXEIE) && (isr_reg & USART_SR_TXE ) )  
  609.     {  
  610.         if(shell_tx_size && (shell_tx_index < shell_tx_size) )  
  611.         {  
  612.             txd_reg = shell_tx_buff[shell_tx_index++];  
  613.             CONSOLE->DR = txd_reg;  //傳送資料  
  614.         }  
  615.         else  
  616.         {  
  617.             //關閉非空中斷  
  618.             shell_tx_index = 0;  
  619.             shell_tx_size = 0;  
  620.             CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //關閉傳送完畢中斷   
  621.             Ledx_off(11);   
  622.         }           
  623.     }  
  624. }  
  625.   
  626.   
  627. /****************************************************************************** 
  628. / 函式功能:指令(ASCII或HEX指令)未處理訊息回執 
  629. / 修改日期:2013/9/12 20:25:45 
  630. / 輸入引數:none 
  631. / 輸出引數:none 
  632. / 使用說明:一位元組一位元組接收資料,拼裝為指令 
  633. ******************************************************************************/  
  634. void Shell_Invalid_Service(void)  
  635. {  
  636.     int         tx_len,i,led_id,msg_id;  
  637.     uint8_t *   ptSrc;  
  638.     uint8_t *   ptDst;  
  639.     uint8_t     tmp_buff[64];  
  640.       
  641.     //指令識別  
  642.     if(2 > shell_rx_rdy)  
  643.     {  
  644.         shell_rx_buff[0]  = 0;  
  645.         return;  
  646.     }  
  647.     else if( (‘\r’ == shell_rx_buff[shell_rx_rdy-2]) && (‘\n’ == shell_rx_buff[shell_rx_rdy-1]) )  
  648.     {  
  649.         ptSrc = (uint8_t *)shell_rx_buff;  
  650.         if(2 == shell_rx_rdy)  
  651.         {  
  652.             //填寫資料  
  653.             tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT:OK!\r\n");  
  654.           
  655.             //傳送資料  
  656.             shell_SendHex(tmp_buff,tx_len);     //傳送資料      
  657.         }  
  658.         else if(StrComp(ptSrc,"led rd\r\n"))   //顯示LED的訊號配置  
  659.         {  
  660.             //填寫資料  
  661.             tx_len = (uint16_t)sprintf((void *)tmp_buff,  
  662.           #if     (6 == SHELL_LED_MAX)  
  663.                 "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d  LED5=%d\r\n",  
  664.                 msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],  
  665.                 msg_led_cfg[3],msg_led_cfg[4],msg_led_cfg[5]);  
  666.           #elif   (5 == SHELL_LED_MAX)  
  667.                 "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d\r\n",  
  668.                 msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],  
  669.                 msg_led_cfg[3],msg_led_cfg[4]);  
  670.           #elif   (4 == SHELL_LED_MAX)  
  671.                 "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d\r\n",  
  672.                 msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],  
  673.                 msg_led_cfg[3]);  
  674.           #elif   (3 == SHELL_LED_MAX)  
  675.                 "->LED0=%d  LED1=%d  tLED2=%d\r\n",  
  676.                 msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2]);  
  677.           #elif   (2 == SHELL_LED_MAX)  
  678.                 "->LED0=%d  LED1=%d\r\n",  
  679.                 msg_led_cfg[0],msg_led_cfg[1]);  
  680.           #elif   (1 == SHELL_LED_MAX)  
  681.                 "->LED0=%d\r\n",  
  682.                 msg_led_cfg[0]);  
  683.           #endif          
  684.             //傳送資料  
  685.             shell_SendHex(tmp_buff,tx_len);     //傳送資料          
  686.         }  
  687.         else if(StrComp(ptSrc,"led wr "))      //設定LED的訊號配置  
  688.         {  
  689.             if(2 != sscanf((void *)ptSrc,"%*s%*s%d=%d",&led_id,&msg_id) )goto ERROR_LOOP;  
  690.             if( (led_id>(SHELL_LED_MAX-1)) || (msg_id >65535) )goto ERROR_LOOP;  
  691.   
  692.             Ledx_config((uint8_t)led_id,(uint16_t)msg_id);  //配置訊號   
  693.             //填寫資料  
  694.             tx_len = (uint16_t)sprintf((void *)tmp_buff,  
  695.                 "->LED[%d]_Msg=%d\r\n",led_id,msg_led_cfg[led_id]);  
  696.   
  697.             //傳送資料  
  698.             shell_SendHex(tmp_buff,tx_len);     //傳送資料     
  699.         }  
  700.         else goto ERROR_LOOP;  
  701.     }  
  702.     else  
  703.     {  
  704. ERROR_LOOP:  
  705.         //填寫指令碼  
  706.         tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT: Cmd Error:\t\"");  
  707.           
  708.         //計算地址,填寫資料,填寫尾部  
  709.         ptDst = tmp_buff + tx_len;  
  710.         ptSrc = (uint8_t *)shell_rx_buff;  
  711.         if(shell_rx_rdy > 32)  
  712.         {  
  713.             for(i=0; i<32; i++)  
  714.             {   
  715.                 if( (*ptSrc > 126) || (*ptSrc < 32) )  
  716.                 {  
  717.                     *ptDst++ = ‘?’;  
  718.                      ptSrc++;     
  719.                 }  
  720.                 else  
  721.                 {  
  722.                     *ptDst++ = *ptSrc++;   
  723.                 }   
  724.             }  
  725.             *(ptDst-2) = ‘-‘;  
  726.             *(ptDst-1) = ‘>’;  
  727.             tx_len += 32;  
  728.         }  
  729.         else  
  730.         {  
  731.             for(i=0; i<shell_rx_rdy; i++)  
  732.             {   
  733.                 *ptDst++ = *ptSrc++;  
  734.                 tx_len++;   
  735.             }  
  736.             *(ptDst-2) = ‘<‘;  
  737.             *(ptDst-1) = ‘-‘;  
  738.         }  
  739.         tx_len += (uint16_t)sprintf((void *)ptDst,"\"\r\n");  
  740.     
  741.         //傳送資料  
  742.         shell_SendHex(tmp_buff,tx_len);  //傳送資料  
  743.     }  
  744.       
  745.     //清除資料返回程式  
  746.     shell_rx_buff[0]  = 0;  
  747.     shell_rx_rdy      = 0;  
  748. }  
  749.   
  750. /****************************************************************************** 
  751. / 函式功能:字串測試匹配指令 
  752. / 修改日期:2014/3/5 19:30:22 
  753. / 輸入引數:none 
  754. / 輸出引數:none 
  755. / 使用說明:none 
  756. ******************************************************************************/  
  757. bool StrComp(void * buffer,void * StrCmd)  
  758. {  
  759.     uint8_t i;  
  760.     uint8_t * ptBuf;  
  761.     uint8_t * ptCmd;  
  762.       
  763.     ptBuf = (uint8_t *)buffer;  
  764.     ptCmd = (uint8_t *)StrCmd;  
  765.     for(i=0; i<255; i++)  
  766.     {  
  767.         if(ptCmd[i])  
  768.         {  
  769.             if(ptBuf[i] != ptCmd[i])return false;  
  770.         }  
  771.         else   
  772.         {  
  773.             if(i)return i;  
  774.             else return false;      
  775.         }  
  776.     }  
  777.     return false;  
  778. }  
  779.   
  780. /****************************************************************************** 
  781. / 函式功能:開啟LED訊號 
  782. / 修改日期:none 
  783. / 輸入引數:none 
  784. / 輸出引數:none 
  785. / 使用說明:none 
  786. ******************************************************************************/  
  787. void Ledx_on(uint16_t msg_id)  
  788. {  
  789.   #if (SHELL_LED_MAX > 0)  
  790.     if(msg_id == msg_led_cfg[0])LED0_ON();  
  791.   #endif  
  792.   #if (SHELL_LED_MAX > 1)  
  793.     if(msg_id == msg_led_cfg[1])LED1_ON();  
  794.   #endif  
  795.   #if (SHELL_LED_MAX > 2)  
  796.     if(msg_id == msg_led_cfg[2])LED2_ON();  
  797.   #endif  
  798.   #if (SHELL_LED_MAX > 3)  
  799.     if(msg_id == msg_led_cfg[3])LED3_ON();  
  800.   #endif  
  801.   #if (SHELL_LED_MAX > 4)  
  802.     if(msg_id == msg_led_cfg[4])LED4_ON();  
  803.   #endif  
  804.   #if (SHELL_LED_MAX > 5)  
  805.     if(msg_id == msg_led_cfg[5])LED5_ON();  
  806.   #endif  
  807. }  
  808.   
  809. /****************************************************************************** 
  810. / 函式功能:關閉LED訊號 
  811. / 修改日期:none 
  812. / 輸入引數:none 
  813. / 輸出引數:none 
  814. / 使用說明:none 
  815. ******************************************************************************/  
  816. void Ledx_off(uint16_t msg_id)  
  817. {  
  818.   #if (SHELL_LED_MAX > 0)  
  819.     if(msg_id == msg_led_cfg[0])LED0_OFF();  
  820.   #endif  
  821.   #if (SHELL_LED_MAX > 1)  
  822.     if(msg_id == msg_led_cfg[1])LED1_OFF();  
  823.   #endif  
  824.   #if (SHELL_LED_MAX > 2)  
  825.     if(msg_id == msg_led_cfg[2])LED2_OFF();  
  826.   #endif  
  827.   #if (SHELL_LED_MAX > 3)  
  828.     if(msg_id == msg_led_cfg[3])LED3_OFF();  
  829.   #endif  
  830.   #if (SHELL_LED_MAX > 4)  
  831.     if(msg_id == msg_led_cfg[4])LED4_OFF();  
  832.   #endif  
  833.   #if (SHELL_LED_MAX > 5)  
  834.     if(msg_id == msg_led_cfg[5])LED5_OFF();  
  835.   #endif  
  836. }  
  837.   
  838. /****************************************************************************** 
  839. / 函式功能:取反LED訊號 
  840. / 修改日期:none 
  841. / 輸入引數:none 
  842. / 輸出引數:none 
  843. / 使用說明:none 
  844. ******************************************************************************/  
  845. void Ledx_div(uint16_t msg_id)  
  846. {  
  847.   #if (SHELL_LED_MAX > 0)  
  848.     if(msg_id == msg_led_cfg[0])LED0_DIV();  
  849.   #endif  
  850.   #if (SHELL_LED_MAX > 1)  
  851.     if(msg_id == msg_led_cfg[1])LED1_DIV();  
  852.   #endif  
  853.   #if (SHELL_LED_MAX > 2)  
  854.     if(msg_id == msg_led_cfg[2])LED2_DIV();  
  855.   #endif  
  856.   #if (SHELL_LED_MAX > 3)  
  857.     if(msg_id == msg_led_cfg[3])LED3_DIV();  
  858.   #endif  
  859.   #if (SHELL_LED_MAX > 4)  
  860.     if(msg_id == msg_led_cfg[4])LED4_DIV();  
  861.   #endif  
  862.   #if (SHELL_LED_MAX > 5)  
  863.     if(msg_id == msg_led_cfg[5])LED5_DIV();  
  864.   #endif  
  865. }  
  866.   
  867. /****************************************************************************** 
  868. / 函式功能:配置LED訊號 
  869. / 修改日期:none 
  870. / 輸入引數:none 
  871. / 輸出引數:none 
  872. / 使用說明:none 
  873. ******************************************************************************/  
  874. void Ledx_config(uint8_t led_id,uint16_t msg_id)  
  875. {  
  876.     if(0 == led_id)     {LED0_OFF();msg_led_cfg[0]=msg_id;}  
  877.   #if(SHELL_LED_MAX > 1)       
  878.     else if(1 == led_id){LED1_OFF();msg_led_cfg[1]=msg_id;}  
  879.   #endif  
  880.   #if(SHELL_LED_MAX > 2)  
  881.     else if(2 == led_id){LED2_OFF();msg_led_cfg[2]=msg_id;}  
  882.   #endif  
  883.   #if(SHELL_LED_MAX > 3)  
  884.     else if(3 == led_id){LED3_OFF();msg_led_cfg[3]=msg_id;}  
  885.   #endif  
  886.   #if(SHELL_LED_MAX > 4)  
  887.     else if(4 == led_id){LED4_OFF();msg_led_cfg[4]=msg_id;}  
  888.   #endif  
  889.   #if(SHELL_LED_MAX > 5)  
  890.     else if(5 == led_id){LED5_OFF();msg_led_cfg[5]=msg_id;}  
  891.   #endif   
  892. }  
  893.   
  894. /****************************************************************************** 
  895. / 函式功能:讀取LED的配置訊號 
  896. / 修改日期:none 
  897. / 輸入引數:none 
  898. / 輸出引數:none 
  899. / 使用說明:none 
  900. ******************************************************************************/  
  901. uint16_t Ledx_read(uint8_t led_id)  
  902. {  
  903.     if(0 == led_id)     return msg_led_cfg[0];  
  904.   #if(SHELL_LED_MAX > 1)  
  905.     else if(1 == led_id)return msg_led_cfg[1];  
  906.   #endif  
  907.   #if(SHELL_LED_MAX > 2)  
  908.     else if(2 == led_id)return msg_led_cfg[2];  
  909.   #endif  
  910.   #if(SHELL_LED_MAX > 3)  
  911.     else if(3 == led_id)return msg_led_cfg[3];  
  912.   #endif  
  913.   #if(SHELL_LED_MAX > 4)  
  914.     else if(4 == led_id)return msg_led_cfg[4];  
  915.   #endif  
  916.   #if(SHELL_LED_MAX > 5)  
  917.     else if(5 == led_id)return msg_led_cfg[5];  
  918.   #endif   
  919.     else return 0;  
  920. }  
  921.   
  922. /****************************************************************************** 
  923. ***********************************   END  ************************************ 
  924. ******************************************************************************/  

四. shell使用

以MDK為例:

1. 將shell.c等檔案加入工程

2. 包含Shell.h,並外部宣告shell服務程式

[cpp] view
plain
 copy

  1. /****************************************************************************** 
  2. *********************************Shell 函式聲 明 ****************************** 
  3. ******************************************************************************/  
  4. extern void Shell_SPI_Service(void);  
  5. extern void Shell_RTC_Service(void);  
  6. extern void Shell_WIZ_Service(void);  
  7. extern void Shell_UPAN_Service(void);  
  8. extern void Shell_IAP_Service(uint8_t const this_ver);  
[cpp] view
plain
 copy

  1. shell_GPIO_Config(30,10,46,1);  //shell介面和四個LED燈的訊號配置  
  2. shell_Init(460800);     //初始化shell控制檯  

3. 在main,c的大迴圈中新增以下程式碼

[cpp] view
plain
 copy

  1. //Shell構架的控制檯服務  
  2. if(shell_rx_rdy)  
  3. {  
  4.     Shell_IAP_Service(SOFT_VER);    //IAP模組指令處理  
  5.     Shell_SPI_Service();            //SPI_FLASH模組指令處理  
  6.     Shell_WIZ_Service();            //網絡卡模組的指令處理   
  7.     Shell_RTC_Service();            //RTC模組的指令處理  
  8.     Shell_MCU_Service();            //MCU雜項功能指令處理  
  9.     Shell_VLSI_Service();           //音效卡模組的指令處理  
  10.     Shell_UPAN_Service();           //U盤模組的指令處理  
  11.     Shell_Invalid_Service();        //指令無效的預設處理  
  12. }  

4. 編譯下載檔案到STM32,完成後位元組在超級終端上敲擊Enter就會顯示AT:OK!的字樣表示可以正常通訊

注意事項: 
1. 開啟超級終端的本地回顯功能
2. 有些終端工具輸入Enter’時只輸出(\r碼) 如SecureCRT,這時需要將Enter對映按鍵(\r\n),winXP的超級終端輸入Enter是輸出(\r\n兩個碼值的)

五. RTC Shell服務檔案示例

這裡展示一個Shell服務的檔案模板寫法:

[cpp] view
plain
 copy

  1. /*********************************Copyright (c)********************************* 
  2. **                                
  3. **                                 FIVE工作組 
  4. ** 
  5. **———————————File Info———————————— 
  6. ** File Name:               rtc_shell.c 
  7. ** Last modified Date:      2014/3/5 9:27:49 
  8. ** Last Version:            V2.0   
  9. ** Description:             檔案操作命令解釋,需要Console Shell V2以上支援 
  10. ** 
  11. **—————————————————————————— 
  12. ** Created By:              wanxuncpx 
  13. ** Created date:            2014/3/5 9:28:31 
  14. ** Version:                 V2.0 
  15. ** Descriptions:            none 
  16. **—————————————————————————— 
  17. ** HW_CMU:                  ANSIC 
  18. ** Libraries:               NONE 
  19. ** version                  NONE 
  20. *******************************************************************************/  
  21.   
  22. /****************************************************************************** 
  23. 更新說明: 
  24. ******************************************************************************/  
  25.   
  26. /****************************************************************************** 
  27. *********************************  編 譯 控 制 ******************************** 
  28. ******************************************************************************/  
  29. #define RTC_SHELL       //註釋掉時遮蔽iap shell功能  
  30.   
  31. /****************************************************************************** 
  32. ********************************* 檔案引用部分 ******************************** 
  33. ******************************************************************************/  
  34. /*———————*  
  35. *     檔案包含 
  36. *———————-*/  
  37. //基礎支援檔案  
  38. #include "shell.h"          //Shell支援檔案,含bool,uint8_t..以及串列埠資料收發操作  
  39. #include "rtc.h"         //命令控制支援檔案  
  40.   
  41. /*———————*  
  42. *     Shell版本判斷 
  43. *———————-*/  
  44. #ifdef SHELL_VER  
  45.   #if (SHELL_VER < 2)  
  46.     #error "shell版本太低"  
  47.   #endif  
  48. #else  
  49.     #error "未找到Shell檔案,或shell版本資訊"  
  50. #endif  
  51.   
  52. /****************************************************************************** 
  53. ********************************* 輸出函式功能 ******************************** 
  54. ******************************************************************************/  
  55. /*———————*  
  56. *       輸出函式功能 
  57. *———————-*/  
  58. #ifdef RTC_SHELL  
  59.   extern void Shell_RTC_Service(void);  
  60. #else  
  61.   void Shell_RTC_Service(void){;}  
  62. #endif  
  63.   
  64. /*———————*  
  65. *       輸入函式 
  66. *———————-*/  
  67. //none  
  68.   
  69. /****************************************************************************** 
  70. ********************************* 數 據 聲 明 ********************************* 
  71. ******************************************************************************/  
  72. #ifdef RTC_SHELL  
  73. /*———————*  
  74. *        
  75. *———————-*/  
  76. //命令幫助檔案  
  77. const char RTC_HelpMsg[] =  
  78.     "[RTC contorls]\r\n"  
  79.     " rtc help\t\t- help.\r\n"  
  80.     " rtc rd info\t\t- Read RTC info.\r\n"  
  81.     " rtc rd time\t\t- Read RTC date and time.\r\n"  
  82.     " rtc wr time <Hour>:<Minute>:<Second>    – Write time.\r\n"  
  83.     " rtc wr date <Year>-<Month>-<Day> <Week> – Warning Week=[1..7]\r\n"  
  84.     "\r\n";  
  85.       
  86. /****************************************************************************** 
  87. ********************************* 函 數 聲 明 ********************************* 
  88. ******************************************************************************/  
  89.   
  90. /****************************************************************************** 
  91. / 函式功能:檔案系統Shel指令處理 
  92. / 修改日期:2013/9/10 19:04:15 
  93. / 輸入引數:輸入當前的程式版本 
  94. / 輸出引數:none 
  95. / 使用說明:none 
  96. ******************************************************************************/  
  97. void Shell_RTC_Service(void)  
  98. {  
  99.     uint8_t     *ptRxd;         //用於接收指令處理  
  100.     //uint8_t     *ptTxd;         //方便用於指令傳送  
  101.     int         i,j,k,l;  
  102.     //int         tx_len,drv;  
  103.     //uint32_t    u32_arg[4];  
  104.     uint16_t    retval;  
  105.     uint8_t     arg[32];  
  106.     uint32_t    tmp_time;  
  107.   
  108.     //指令初級過濾  
  109.     //————————————————————————–  
  110.     //格式:<->[cmd bytes]<CRLF>  即"-[cmd bytes]\r\n"  
  111.     //指令必須以"-"開始, 以"\r\n"結束  
  112.     i = shell_rx_rdy;  
  113.     if( (i < 2) || (‘\r’ != shell_rx_buff[i-2]) || (‘\n’ != shell_rx_buff[i-1]))return;  
  114.       
  115.     //長度和字首過濾  
  116.     ptRxd = (uint8_t *)shell_rx_buff;  
  117.     if( (‘ ‘ != shell_rx_buff[3]) || (‘r’ != shell_rx_buff[0]) || (i < 6) ||   
  118.         (‘t’ != shell_rx_buff[1]) || (‘c’ != shell_rx_buff[2]) )  return;  
  119.           
  120.     //處理指令  
  121.     //————————————————————————–  
  122.     ptRxd += 4;  
  123.     if(StrComp(ptRxd,"rd time"))    //按包讀取指令  
  124.     {  
  125.         RTC_Sprintf_CurrTime((void *)arg);    
  126.         printf("Time:%s\r\n",arg);   
  127.     }  
  128.     else if(StrComp(ptRxd,"rd info\r\n"))      //讀取RTC資訊  
  129.     {  
  130.         //列印當前時間和上次復位時間  
  131.         RTC_Sprintf_CurrTime((void *)arg);   
  132.         printf("->Time:%s\tResetCounter:%d\r\n",arg,RESET_CNT);  
  133.         RTC_Sprintf_ResetCurr((void *)arg,&tmp_time);   
  134.         printf("\tCurrReset:%s\tRun: %d Days, %d hour, %d minute\r\n",  
  135.             arg,tmp_time/(24*60),(tmp_time%(24*60))/60,tmp_time%60 );   
  136.         RTC_Sprintf_ResetLast((void *)arg,&tmp_time);   
  137.         printf("\tNextReset:%s\tRun: %d Days, %d hour, %d minute\r\n",  
  138.             arg,tmp_time/(24*60),(tmp_time%(24*60))/60,tmp_time%60 );      
  139.     }  
  140.     else if(StrComp(ptRxd,"wr time "))      //寫時間  
  141.     {  
  142.         retval = sscanf((void*)shell_rx_buff,"%*s%*s%*s%d:%d:%d",&i,&j,&k);  
  143.         if(3 != retval)return;   //沒有接收到3個輸入資料,直接退出  
  144.         if(RTC_TimeWrite((uint8_t)i,(uint8_t)j,(uint8_t)k) )  
  145.         {  
  146.             RTC_Sprintf_CurrTime((void *)arg);  
  147.             printf("->CurrTime:%s\r\n",arg);      
  148.         }  
  149.         else  
  150.         {  
  151.             printf("->Error Time Input!\r\n");  
  152.             shell_rx_rdy = 0;       //不用觸發錯誤指令顯示   
  153.             return;     
  154.         }  
  155.     }  
  156.     else if(StrComp(ptRxd,"wr date "))      //寫日期  
  157.     {  
  158.         retval = sscanf((void*)shell_rx_buff,"%*s%*s%*s%d-%d-%d %d",&i,&j,&k,&l);  
  159.         if(4 != retval)return;   //沒有接收到4個輸入資料,直接退出  
  160.         if(RTC_DateWrite((uint16_t)i,(uint8_t)j,(uint8_t)k,(uint8_t)l))  
  161.         {  
  162.             RTC_Sprintf_CurrTime((void *)arg);  
  163.             printf("->CurrTime:%s\r\n",arg);      
  164.         }  
  165.         else  
  166.         {  
  167.             printf("->Error Date Input!\r\n");  
  168.             shell_rx_rdy = 0;       //shell_rx_rdy為0,表示指令已被處理完畢,否者下個Shell服務繼續呼叫  
  169.             return;      
  170.         }  
  171.     }  
  172.     else if(StrComp(ptRxd,"help\r\n"))      //指令幫助  
  173.     {  
  174.         shell_SendStr((void *)RTC_HelpMsg);  
  175.     }  
  176.     else return;  
  177.       
  178.     //退出處理  
  179.     //————————————————————————–  
  180.     shell_rx_rdy = 0;   //shell_rx_rdy為0,表示指令已被處理完畢,否者下個Shell服務繼續呼叫  
  181. }  
  182.   
  183. /****************************************************************************** 
  184. ***********************************   END  ************************************ 
  185. ******************************************************************************/  
  186. #endif