一种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. #ifndef _SHELL_HAL_
  27. #define _SHELL_HAL_
  28. /******************************************************************************
  29. ********************************* 文件引用部分 ********************************
  30. ******************************************************************************/
  31. //包含库文件
  32. #include "stm32f10x.h"
  33. #include "stm32f10x_gpio.h"
  34. #include "stm32f10x_rcc.h"
  35. #include "stm32f10x_tim.h"
  36. /******************************************************************************
  37. ******************************** 可 配 置 参 数 *******************************
  38. ******************************** MNCS_IMAGE图像板 *****************************
  39. ******************************************************************************/
  40. /*---------------------*
  41. *     UART端口配置
  42. *----------------------*/
  43. //IO配置
  44. #define CONSOLE                 USART3
  45. #define CONSOLE_TX_PORT         GPIOB
  46. #define CONSOLE_TX_PIN          GPIO_Pin_10
  47. #define CONSOLE_RX_PORT         GPIOB
  48. #define CONSOLE_RX_PIN          GPIO_Pin_11
  49. //时钟配置
  50. #define CONSOLE_GPIO_RCC_INIT() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE)
  51. #define CONSOLE_UART_RCC_INIT() RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE)
  52. //中断优先级
  53. #define CONSOLE_UART_PRIO       7       //建议[0..15]
  54. //中断向量配置
  55. #define CONSOLE_IRQn            USART3_IRQn;
  56. #define CONSOLE_IRQHandler      USART3_IRQHandler
  57. /*---------------------*
  58. *     四个LED定义
  59. *----------------------*/
  60. #define LED0_VALID              1           //非零表示使能对应的LED,0:无效
  61. #define LED0_PORT               GPIOB
  62. #define LED0_PIN                GPIO_Pin_13
  63. #define LED1_VALID              1           //非零表示使能对应的LED,0:无效
  64. #define LED1_PORT               GPIOB
  65. #define LED1_PIN                GPIO_Pin_15
  66. #define LED2_VALID              0           //非零表示使能对应的LED,0:无效
  67. #define LED2_PORT               GPIOA
  68. #define LED2_PIN                GPIO_Pin_11
  69. #define LED3_VALID              0           //非零表示使能对应的LED,0:无效
  70. #define LED3_PORT               GPIOA
  71. #define LED3_PIN                GPIO_Pin_11
  72. #define LED4_VALID              0           //非零表示使能对应的LED,0:无效
  73. #define LED4_PORT               GPIOA
  74. #define LED4_PIN                GPIO_Pin_11
  75. #define LED5_VALID              0           //非零表示使能对应的LED,0:无效
  76. #define LED5_PORT               GPIOA
  77. #define LED5_PIN                GPIO_Pin_11
  78. /*---------------------*
  79. *        时基BASE
  80. *----------------------*/
  81. #define TIMEDly                 TIM4
  82. #define TIMEDly_IRQn            TIM4_IRQn
  83. #define TIMEDly_IRQHandler      TIM4_IRQHandler
  84. //时钟配置
  85. #define TIMEDly_RCC_INIT()      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  86. //初始化LGPIO口
  87. #define LEDx_GPIO_RCC_INIT()    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE)
  88. //------------------------------------------------------------------------------
  89. /******************************************************************************
  90. ******************************* 以下参数无需更改 ******************************
  91. ******************************************************************************/
  92. /*---------------------*
  93. *  注意以下区域无需用户更改
  94. *----------------------*/
  95. #if LED0_VALID
  96. #define LED0_ON()             (LED0_PORT->BRR  = LED0_PIN)
  97. #define LED0_OFF()            (LED0_PORT->BSRR = LED0_PIN)
  98. #define LED0_DIV()            (LED0_PORT->ODR  ^= LED0_PIN)
  99. #else
  100. #define LED0_ON()             __NOP()
  101. #define LED0_OFF()            __NOP()
  102. #define LED0_DIV()            __NOP()
  103. #endif
  104. #if LED1_VALID
  105. #define LED1_ON()             (LED1_PORT->BRR  = LED1_PIN)
  106. #define LED1_OFF()            (LED1_PORT->BSRR = LED1_PIN)
  107. #define LED1_DIV()            (LED1_PORT->ODR ^= LED1_PIN)
  108. #else
  109. #define LED1_ON()             __NOP()
  110. #define LED1_OFF()            __NOP()
  111. #define LED1_DIV()            __NOP()
  112. #endif
  113. #if LED2_VALID
  114. #define LED2_ON()             (LED2_PORT->BRR  = LED2_PIN)
  115. #define LED2_OFF()            (LED2_PORT->BSRR = LED2_PIN)
  116. #define LED2_DIV()            (LED2_PORT->ODR ^= LED2_PIN)
  117. #else
  118. #define LED2_ON()             __NOP()
  119. #define LED2_OFF()            __NOP()
  120. #define LED2_DIV()            __NOP()
  121. #endif
  122. #if LED3_VALID
  123. #define LED3_ON()             (LED3_PORT->BRR  = LED3_PIN)
  124. #define LED3_OFF()            (LED3_PORT->BSRR = LED3_PIN)
  125. #define LED3_DIV()            (LED3_PORT->ODR ^= LED3_PIN)
  126. #else
  127. #define LED3_ON()             __NOP()
  128. #define LED3_OFF()            __NOP()
  129. #define LED3_DIV()            __NOP()
  130. #endif
  131. #if LED4_VALID
  132. #define LED4_ON()             (LED4_PORT->BSRR = LED4_PIN)
  133. #define LED4_OFF()            (LED4_PORT->BRR  = LED4_PIN)
  134. #define LED4_DIV()            (LED4_PORT->ODR ^= LED4_PIN)
  135. #else
  136. #define LED4_ON()             __NOP()
  137. #define LED4_OFF()            __NOP()
  138. #define LED4_DIV()            __NOP()
  139. #endif
  140. #if LED5_VALID
  141. #define LED5_ON()             (LED5_PORT->BSRR = LED5_PIN)
  142. #define LED5_OFF()            (LED5_PORT->BRR  = LED5_PIN)
  143. #define LED5_DIV()            (LED5_PORT->ODR ^= LED5_PIN)
  144. #else
  145. #define LED5_ON()             __NOP()
  146. #define LED5_OFF()            __NOP()
  147. #define LED5_DIV()            __NOP()
  148. #endif
  149. /******************************************************************************
  150. ******************************* printf支持文件 ********************************
  151. ******************************************************************************/
  152. /* Private function prototypes -----------------------------------------------*/
  153. #ifdef __GNUC__
  154. /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
  155. set to ‘Yes‘) calls __io_putchar() */
  156. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  157. #else
  158. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  159. #endif /* __GNUC__ */
  160. /******************************************************************************
  161. ***********************************   END  ************************************
  162. ******************************************************************************/
  163. #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. #ifndef _SHELL_H_
  27. #define _SHELL_H_
  28. /******************************************************************************
  29. ********************************* 文件引用部分 ********************************
  30. ******************************************************************************/
  31. #include "stdint.h"         //包含uint8_t等数据类型
  32. #include "stdbool.h"        //包含Bool类型
  33. #include "stdio.h"          //包含printf支持
  34. /******************************************************************************
  35. ********************************* 参数宏定义 *********************************
  36. ******************************************************************************/
  37. //版本定义
  38. #define SHELL_VER           2       //Shell版本
  39. #ifndef SHELL_LED_MAX               //LED实体数量
  40. #define SHELL_LED_MAX     4
  41. #endif
  42. //缓冲大小配置
  43. #define SHELL_RX_MAX        (256+32)        //shell指令接收缓冲大小
  44. #define SHELL_TX_MAX        (512)           //shell指令发送缓冲大小
  45. /******************************************************************************
  46. ********************************* 数 据 声 明 *********************************
  47. ******************************************************************************/
  48. /*---------------------*
  49. *     Shell接收
  50. *----------------------*/
  51. //接收数据
  52. extern volatile uint16_t   shell_rx_rdy;                    //0:空闲,非零:忙,用户读为非零后清零
  53. extern volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1];   //接收缓冲
  54. /******************************************************************************
  55. ********************************* 函 数 声 明 *********************************
  56. ******************************************************************************/
  57. /*---------------------*
  58. *    输出函数
  59. *----------------------*/
  60. //调试Shell的接口数量
  61. #if     (6 == SHELL_LED_MAX)
  62. extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
  63. uint16_t led2_cfg,uint16_t led3_cfg,
  64. uint16_t led4_cfg,uint16_t led5_cfg);
  65. #elif   (5 == SHELL_LED_MAX)
  66. extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
  67. uint16_t led2_cfg,uint16_t led3_cfg,
  68. uint16_t led4_cfg);
  69. #elif   (4 == SHELL_LED_MAX)
  70. extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
  71. uint16_t led2_cfg,uint16_t led3_cfg);
  72. #elif   (3 == SHELL_LED_MAX)
  73. extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg,
  74. uint16_t led2_cfg);
  75. #elif   (2 == SHELL_LED_MAX)
  76. extern void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg);
  77. #elif   (1 == SHELL_LED_MAX)
  78. extern void shell_GPIO_Config(uint16_t led0_cfg);
  79. #endif
  80. //检测参数合法性
  81. #if ((SHELL_LED_MAX > 6) || (SHELL_LED_MAX == 0))
  82. #error SHELL_LED_MAX is invaild!
  83. #endif
  84. //初始化Shell
  85. extern void shell_Init(uint32_t baud);          //模块初始化
  86. extern void shell_SendStr(void * ptStr);        //发送以‘\0‘结束的字符串
  87. extern void shell_SendHex(void * ptHex,uint16_t size);  //发送指定个数的数据
  88. /*---------------------*
  89. *    LEDx测试信号定义
  90. *----------------------*/
  91. extern void Ledx_config(uint8_t led_id,uint16_t msg_id);    //设置LED的配置信号
  92. extern uint16_t Ledx_read(uint8_t led_id);                  //读取LED的配置信号(失败返回0)
  93. extern  void Ledx_on (uint16_t msg_id);             //发送LED开消息
  94. extern  void Ledx_off(uint16_t msg_id);             //发送LED关消息
  95. extern  void Ledx_div(uint16_t msg_id);             //发送LED取反消息
  96. /*---------------------*
  97. *     时基延时函数
  98. *----------------------*/
  99. extern void Delay_LibInit(void);
  100. extern void DlyTime_us(uint16_t us);
  101. extern void DlyTime_ms(uint16_t ms);
  102. extern void DlyWait_base(volatile uint64_t * ptCnt);    //标记为等待的基点时间
  103. extern uint32_t DlyWait_lost(volatile uint64_t * ptCnt);//判断逝去的时间(us)
  104. /*---------------------*
  105. *     辅助判断指令
  106. *----------------------*/
  107. extern bool StrComp(void * buffer,void * StrCmd);   //字符串匹配比较函数
  108. /*---------------------*
  109. *       Shell服务
  110. *----------------------*/
  111. //在main.c函数while()中判断shell_rx_rdy是否为非零,为非零才执行以下程序
  112. extern void Shell_Invalid_Service(void); //指令未处理服务(会处理shell_rx_rdy信号)
  113. /******************************************************************************
  114. ***********************************   END  ************************************
  115. ******************************************************************************/
  116. #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. #include "shell.h"      //包含Shell接口文件
  30. //是否使用扩展的Shell接口
  31. #ifdef SHELL_HAL_EXT
  32. #include "shell_hal.h"    //本地的Shell文件
  33. #else
  34. #include "console.h"      //标准的Shell文件
  35. #endif
  36. /******************************************************************************
  37. ********************************* Shell.h定义 *********************************
  38. ******************************************************************************/
  39. /*---------------------*
  40. *     Shell 收发标记
  41. *----------------------*/
  42. volatile uint16_t   shell_rx_rdy = 0;                       //0:空闲,非零:忙
  43. volatile uint8_t    shell_rx_buff[SHELL_RX_MAX+1]="\0";   //接收缓冲
  44. /******************************************************************************
  45. ********************************* 本 地 数 据 *********************************
  46. ******************************************************************************/
  47. /*---------------------*
  48. *     Shell缓冲定义
  49. *----------------------*/
  50. //接收
  51. static volatile uint16_t    shell_rx_index = 0;             //数据接收标记
  52. //发送
  53. static volatile uint8_t     shell_tx_buff[SHELL_TX_MAX+1]="\0";
  54. static volatile uint16_t    shell_tx_size  = 0;             //0:空闲,非零:忙
  55. static volatile uint16_t    shell_tx_index = 0;             //发送数据标记
  56. /*---------------------*
  57. *     LED控制信号
  58. *----------------------*/
  59. static volatile uint16_t    msg_led_cfg[SHELL_LED_MAX];     //配置信号
  60. /*---------------------*
  61. *    延时模块定义
  62. *----------------------*/
  63. static volatile uint64_t    TimeDlyCnt = 0;                 //用于辅助的延时计数值
  64. /******************************************************************************
  65. ********************************* 函 数 声 明 *********************************
  66. ******************************************************************************/
  67. /******************************************************************************
  68. / 函数功能:初始化GPIO口(串口和四个LED灯配置)
  69. / 修改日期:none
  70. / 输入参数:none
  71. / 输出参数:none
  72. / 使用说明:none
  73. ******************************************************************************/
  74. #if     (6 == SHELL_LED_MAX)
  75. void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
  76. uint16_t led2_cfg,uint16_t led3_cfg,
  77. uint16_t led4_cfg,uint16_t led5_cfg)
  78. #elif   (5 == SHELL_LED_MAX)
  79. void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
  80. uint16_t led2_cfg,uint16_t led3_cfg,
  81. uint16_t led4_cfg)
  82. #elif   (4 == SHELL_LED_MAX)
  83. void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
  84. uint16_t led2_cfg,uint16_t led3_cfg)
  85. #elif   (3 == SHELL_LED_MAX)
  86. void shell_GPIO_Config( uint16_t led0_cfg,uint16_t led1_cfg,
  87. uint16_t led2_cfg)
  88. #elif   (2 == SHELL_LED_MAX)
  89. void shell_GPIO_Config(uint16_t led0_cfg,uint16_t led1_cfg)
  90. #elif   (1 == SHELL_LED_MAX)
  91. void shell_GPIO_Config(uint16_t led0_cfg)
  92. #endif
  93. {
  94. GPIO_InitTypeDef GPIO_InitStruct;
  95. /* 配置串口 ---------------------------------------------------------*/
  96. // 打开在APB2上的GPIO口外设时钟
  97. CONSOLE_GPIO_RCC_INIT();    //打开GPIO口的时钟
  98. // 配置TX引脚
  99. GPIO_InitStruct.GPIO_Pin    = CONSOLE_TX_PIN;
  100. GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_AF_PP;
  101. GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;
  102. GPIO_Init(CONSOLE_TX_PORT,  &GPIO_InitStruct);
  103. // 配置RX引脚
  104. GPIO_InitStruct.GPIO_Pin    = CONSOLE_RX_PIN;
  105. GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_IPU;
  106. GPIO_Init(CONSOLE_RX_PORT,  &GPIO_InitStruct);
  107. //锁定GPIO口,防止其他更改
  108. GPIO_PinLockConfig(CONSOLE_TX_PORT,CONSOLE_TX_PIN);
  109. GPIO_PinLockConfig(CONSOLE_RX_PORT,CONSOLE_RX_PIN);
  110. /* 配置LEDx ---------------------------------------------------------*/
  111. LEDx_GPIO_RCC_INIT();
  112. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  113. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
  114. //根据定义配置四个LED
  115. #if (SHELL_LED_MAX > 0)
  116. GPIO_InitStruct.GPIO_Pin    = LED0_PIN;
  117. GPIO_Init(LED0_PORT,   &GPIO_InitStruct);
  118. GPIO_PinLockConfig(LED0_PORT,LED0_PIN);
  119. msg_led_cfg[0] = led0_cfg;
  120. LED0_OFF();
  121. #endif
  122. #if (SHELL_LED_MAX > 1)
  123. GPIO_InitStruct.GPIO_Pin    = LED1_PIN;
  124. GPIO_Init(LED1_PORT,   &GPIO_InitStruct);
  125. GPIO_PinLockConfig(LED1_PORT,LED1_PIN);
  126. msg_led_cfg[1] = led1_cfg;
  127. LED1_OFF();
  128. #endif
  129. #if (SHELL_LED_MAX > 2)
  130. GPIO_InitStruct.GPIO_Pin    = LED2_PIN;
  131. GPIO_Init(LED2_PORT,   &GPIO_InitStruct);
  132. GPIO_PinLockConfig(LED2_PORT,LED2_PIN);
  133. msg_led_cfg[2] = led2_cfg;
  134. LED2_OFF();
  135. #endif
  136. #if (SHELL_LED_MAX > 3)
  137. GPIO_InitStruct.GPIO_Pin    = LED3_PIN;
  138. GPIO_Init(LED3_PORT,   &GPIO_InitStruct);
  139. GPIO_PinLockConfig(LED3_PORT,LED3_PIN);
  140. msg_led_cfg[3] = led3_cfg;
  141. LED3_OFF();
  142. #endif
  143. #if (SHELL_LED_MAX > 4)
  144. GPIO_InitStruct.GPIO_Pin    = LED4_PIN;
  145. GPIO_Init(LED4_PORT,   &GPIO_InitStruct);
  146. GPIO_PinLockConfig(LED4_PORT,LED4_PIN);
  147. msg_led_cfg[4] = led4_cfg;
  148. LED4_OFF();
  149. #endif
  150. #if (SHELL_LED_MAX > 5)
  151. GPIO_InitStruct.GPIO_Pin    = LED5_PIN;
  152. GPIO_Init(LED5_PORT,   &GPIO_InitStruct);
  153. GPIO_PinLockConfig(LED5_PORT,LED5_PIN);
  154. msg_led_cfg[5] = led5_cfg;
  155. LED5_OFF();
  156. #endif
  157. }
  158. /******************************************************************************
  159. / 函数功能:串口初始化,使用中断单字节接收数据
  160. / 修改日期:none
  161. / 输入参数:baud 波特率
  162. / 输出参数:none
  163. / 使用说明:none
  164. ******************************************************************************/
  165. void shell_Init(uint32_t baud)
  166. {
  167. USART_InitTypeDef   USART_InitStructure;
  168. NVIC_InitTypeDef    NVIC_UART_Cfg;  //UART中断向量
  169. //--------------------------- 先定义好数据结构 ---------------------------
  170. //定义好USART结构体
  171. USART_InitStructure.USART_BaudRate      = baud;
  172. USART_InitStructure.USART_WordLength    = USART_WordLength_8b;
  173. USART_InitStructure.USART_StopBits      = USART_StopBits_1;
  174. USART_InitStructure.USART_Parity        = USART_Parity_No ;
  175. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  176. USART_InitStructure.USART_Mode          = USART_Mode_Tx | USART_Mode_Rx;
  177. USART_InitStructure.USART_BaudRate = USART_InitStructure.USART_BaudRate;    //防止编译报错
  178. //定义好NVIC:UART中断
  179. NVIC_UART_Cfg.NVIC_IRQChannel = CONSOLE_IRQn;
  180. NVIC_UART_Cfg.NVIC_IRQChannelPreemptionPriority = 1;
  181. NVIC_UART_Cfg.NVIC_IRQChannelSubPriority = CONSOLE_UART_PRIO;
  182. NVIC_UART_Cfg.NVIC_IRQChannelCmd = ENABLE;
  183. NVIC_UART_Cfg.NVIC_IRQChannel = NVIC_UART_Cfg.NVIC_IRQChannel;              //防止编译报错
  184. //模式配置
  185. //--------------------------- 中断方式收发数据 ----------------------------
  186. CONSOLE_UART_RCC_INIT();                                //打开USART的时钟
  187. USART_Cmd(CONSOLE, DISABLE);                            //关闭UART
  188. USART_Init(CONSOLE, &USART_InitStructure);              //初始化串口
  189. USART_ITConfig(CONSOLE, USART_IT_RXNE, ENABLE);
  190. USART_ITConfig(CONSOLE, USART_IT_IDLE, ENABLE);
  191. USART_Cmd(CONSOLE, ENABLE);
  192. NVIC_Init(&NVIC_UART_Cfg);                              //配置好NVIC
  193. }
  194. /******************************************************************************
  195. / 函数功能:Delay延时库初始化(需要1us的计数精度,和50ms的溢出计数)
  196. / 修改日期:2014/5/1 21:02:58
  197. / 输入参数:none
  198. / 输出参数:none
  199. / 使用说明:(限STM32F40X的TIM2,TIM3,TIM4,TIM5)
  200. ******************************************************************************/
  201. void Delay_LibInit(void)
  202. {
  203. TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
  204. NVIC_InitTypeDef            NVIC_InitStructure;
  205. //开启TIM2时钟
  206. TIMEDly_RCC_INIT();
  207. /* Enable the TIMx gloabal Interrupt */
  208. NVIC_InitStructure.NVIC_IRQChannel                  = TIMEDly_IRQn;
  209. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0;
  210. NVIC_InitStructure.NVIC_IRQChannelSubPriority       = 0;    //由于是时基,需要使用最高优先级
  211. NVIC_InitStructure.NVIC_IRQChannelCmd               = ENABLE;
  212. NVIC_Init(&NVIC_InitStructure);
  213. /* Time base configuration */
  214. TIM_TimeBaseStructure.TIM_Period    = 65000;
  215. TIM_TimeBaseStructure.TIM_Prescaler     = (SystemCoreClock/1000000)-1;
  216. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  217. TIM_TimeBaseStructure.TIM_CounterMode    = TIM_CounterMode_Up;
  218. TIM_TimeBaseInit(TIMEDly, &TIM_TimeBaseStructure);
  219. /* TIM Interrupts enable */
  220. TIM_ITConfig(TIMEDly,TIM_IT_Update, ENABLE);
  221. /* TIMx enable counter */
  222. TIM_Cmd(TIMEDly, ENABLE);
  223. }
  224. /******************************************************************************
  225. / 函数功能:等待一个us延时
  226. / 修改日期:2014/5/1 21:02:58
  227. / 输入参数:none
  228. / 输出参数:none
  229. / 使用说明:none
  230. ******************************************************************************/
  231. void DlyTime_us(uint16_t us)
  232. {
  233. uint64_t this_cnt,over_cnt,tmp_val;
  234. //得到当前的准确时间
  235. do
  236. {
  237. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  238. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  239. (TIMEDly->SR    & TIM_IT_Update)    &&
  240. (TIMEDly->SR    & TIM_IT_Update)    )
  241. {
  242. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  243. TimeDlyCnt  +=  65000;
  244. }
  245. tmp_val = TIMEDly->CNT + TimeDlyCnt;
  246. }
  247. while(this_cnt != tmp_val);
  248. over_cnt = this_cnt + us;       //得到目标延时时间
  249. //延时函数
  250. do
  251. {
  252. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  253. (TIMEDly->SR    & TIM_IT_Update)    &&
  254. (TIMEDly->SR    & TIM_IT_Update)    )
  255. {
  256. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  257. TimeDlyCnt  +=  65000;
  258. }
  259. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  260. }
  261. while(this_cnt < over_cnt);
  262. }
  263. /******************************************************************************
  264. / 函数功能:等待一个ms延时
  265. / 修改日期:2014/5/1 21:02:58
  266. / 输入参数:none
  267. / 输出参数:none
  268. / 使用说明:none
  269. ******************************************************************************/
  270. void DlyTime_ms(uint16_t ms)
  271. {
  272. uint64_t this_cnt,over_cnt,tmp_val;
  273. //得到当前的准确时间
  274. do
  275. {
  276. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  277. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  278. (TIMEDly->SR    & TIM_IT_Update)    &&
  279. (TIMEDly->SR    & TIM_IT_Update)    )
  280. {
  281. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  282. TimeDlyCnt  +=  65000;
  283. }
  284. tmp_val = TIMEDly->CNT + TimeDlyCnt;
  285. }
  286. while(this_cnt != tmp_val);
  287. over_cnt = this_cnt + (uint32_t)ms*1000;
  288. //延时函数
  289. do
  290. {
  291. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  292. (TIMEDly->SR    & TIM_IT_Update)    &&
  293. (TIMEDly->SR    & TIM_IT_Update)    )
  294. {
  295. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  296. TimeDlyCnt  +=  65000;
  297. }
  298. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  299. }
  300. while(this_cnt < over_cnt);
  301. }
  302. /******************************************************************************
  303. / 函数功能:标记时间起点
  304. / 修改日期:2014/5/1 21:02:58
  305. / 输入参数:none
  306. / 输出参数:none
  307. / 使用说明:none
  308. ******************************************************************************/
  309. void DlyWait_base(volatile uint64_t * ptCnt)
  310. {
  311. uint64_t this_cnt,tmp_val;
  312. //得到当前的准确时间
  313. do
  314. {
  315. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  316. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  317. (TIMEDly->SR    & TIM_IT_Update)    &&
  318. (TIMEDly->SR    & TIM_IT_Update)    )
  319. {
  320. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  321. TimeDlyCnt  +=  65000;
  322. }
  323. tmp_val = TIMEDly->CNT + TimeDlyCnt;
  324. }
  325. while(this_cnt != tmp_val);
  326. *ptCnt = this_cnt;
  327. }
  328. /******************************************************************************
  329. / 函数功能:检测从起点开始已逝去的时间(最大1个小时)
  330. / 修改日期:2014/5/1 21:02:58
  331. / 输入参数:none
  332. / 输出参数:返回0表示时间到,返回非零表示时间未到
  333. / 使用说明:none
  334. ******************************************************************************/
  335. uint32_t DlyWait_lost(volatile uint64_t * ptCnt)
  336. {
  337. uint64_t this_cnt,tmp_val;
  338. //得到当前的准确时间
  339. do
  340. {
  341. this_cnt = TIMEDly->CNT + TimeDlyCnt;
  342. if( (TIMEDly->SR    & TIM_IT_Update)    &&
  343. (TIMEDly->SR    & TIM_IT_Update)    &&
  344. (TIMEDly->SR    & TIM_IT_Update)    )
  345. {
  346. TIMEDly->SR =   (uint16_t)~TIM_IT_Update;
  347. TimeDlyCnt  +=  65000;
  348. }
  349. tmp_val = TIMEDly->CNT + TimeDlyCnt;
  350. }
  351. while(this_cnt != tmp_val);
  352. //计算已逝去的时间
  353. if(*ptCnt <= this_cnt)
  354. {
  355. tmp_val = this_cnt - *ptCnt;
  356. if(tmp_val > (65536UL*65536UL-1))
  357. return (uint32_t)(65536UL*65536UL-1);
  358. else    return (uint32_t)tmp_val;
  359. }
  360. else
  361. {
  362. *ptCnt = this_cnt;
  363. return 0;
  364. }
  365. }
  366. /******************************************************************************
  367. / 函数功能:中断支持函数(限STM32F40X的TIM2,TIM3,TIM4,TIM5)
  368. / 修改日期:2014/5/1 21:02:58
  369. / 输入参数:none
  370. / 输出参数:none
  371. / 使用说明:none
  372. ******************************************************************************/
  373. void TIMEDly_IRQHandler(void)
  374. {
  375. //简单写法
  376. if( TIMEDly->SR & TIM_IT_Update )
  377. {
  378. TIMEDly->SR = (uint16_t)~TIM_IT_Update;
  379. TimeDlyCnt += 65000;
  380. //Ledx_div(3);        //时基信号
  381. }
  382. }
  383. /******************************************************************************
  384. / 函数功能:printf支持函数
  385. / 修改日期:none
  386. / 输入参数:none
  387. / 输出参数:none
  388. / 使用说明:none
  389. ******************************************************************************/
  390. PUTCHAR_PROTOTYPE
  391. {
  392. Ledx_on(11);
  393. /* Loop until the end of transmission */
  394. while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
  395. /* Place your implementation of fputc here */
  396. /* e.g. write a character to the USART */
  397. CONSOLE->DR = ch;
  398. /* Loop until the end of transmission */
  399. //while( (CONSOLE->SR & USART_FLAG_TC) == RESET );
  400. Ledx_off(11);
  401. return ch;
  402. }
  403. /******************************************************************************
  404. / 函数功能:字符串发送函数
  405. / 修改日期:none
  406. / 输入参数:none
  407. / 输出参数:none
  408. / 使用说明:none
  409. ******************************************************************************/
  410. void shell_SendStr(void * ptAsc)
  411. {                                   //中断方式
  412. //--------------------------- 中断方式收发数据 ----------------------------
  413. uint16_t        i,size;
  414. uint8_t         *ptDst;
  415. uint8_t const   *ptSrc;     //源数据只读不写
  416. //计算字符串的长度
  417. ptSrc = (uint8_t const *)ptAsc;
  418. size  = 0;
  419. while(*ptSrc++){size++;}
  420. //判断字符串是否超过缓冲
  421. Ledx_on(11);
  422. if(size > SHELL_TX_MAX)
  423. {
  424. //关闭中断发送方式
  425. shell_tx_index = 0;
  426. shell_tx_size  = 0;
  427. CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
  428. ptSrc = (uint8_t const *)ptAsc;
  429. while(size--)
  430. {
  431. while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
  432. CONSOLE->DR = *ptSrc++;
  433. }
  434. Ledx_off(11);
  435. }
  436. else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )
  437. {
  438. //如果未启用非空中断则,启用非空中断发送数据
  439. //复制数据
  440. ptDst = (uint8_t *)shell_tx_buff;
  441. ptSrc = (uint8_t const *)ptAsc;
  442. for(i=0; i<size; i++)
  443. *ptDst++ = *ptSrc++;
  444. //启动发送中断
  445. shell_tx_index = 0;
  446. shell_tx_size  = size;
  447. CONSOLE->CR1 |= USART_CR1_TXEIE;        //启动发送非空中断
  448. }
  449. }
  450. /******************************************************************************
  451. / 函数功能:发送Hex数据函数
  452. / 修改日期:none
  453. / 输入参数:none
  454. / 输出参数:none
  455. / 使用说明:none
  456. ******************************************************************************/
  457. void shell_SendHex(void * ptHex,uint16_t size)
  458. {                                  //中断方式
  459. //--------------------------- 中断方式收发数据 ----------------------------
  460. uint16_t        i;
  461. uint8_t         *ptDst;
  462. uint8_t const   *ptSrc;     //源数据只读不写
  463. Ledx_on(11);
  464. if(size > SHELL_TX_MAX)
  465. {
  466. //关闭中断发送方式
  467. shell_tx_index = 0;
  468. shell_tx_size  = 0;
  469. CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
  470. //直接发送数据
  471. ptSrc = (uint8_t const *)ptHex;
  472. while(size--)
  473. {
  474. while( (CONSOLE->SR & USART_FLAG_TXE) == RESET );
  475. CONSOLE->DR = *ptSrc++;
  476. }
  477. Ledx_off(11);
  478. }
  479. else if( !(CONSOLE->CR1 & USART_CR1_TXEIE) )
  480. {
  481. //如果未启用非空中断则,启用非空中断发送数据
  482. //复制数据
  483. ptDst = (uint8_t *)shell_tx_buff;
  484. ptSrc = (uint8_t const *)ptHex;
  485. for(i=0; i<size; i++)
  486. *ptDst++ = *ptSrc++;
  487. //启动发送中断
  488. shell_tx_index = 0;
  489. shell_tx_size  = size;
  490. CONSOLE->CR1 |= USART_CR1_TXEIE;        //启动发送非空中断
  491. }
  492. }
  493. /******************************************************************************
  494. / 函数功能:中断服务程序
  495. / 修改日期:none
  496. / 输入参数:none
  497. / 输出参数:none
  498. / 使用说明:none
  499. ******************************************************************************/
  500. void CONSOLE_IRQHandler(void)
  501. {
  502. uint8_t     rxd_reg,txd_reg;
  503. uint16_t    isr_reg;
  504. //中断配置
  505. //--------------------------- 中断方式收发数据 ----------------------------
  506. isr_reg = CONSOLE->SR;
  507. //接收中断
  508. if( (CONSOLE->CR1 & USART_CR1_RXNEIE) && (isr_reg & USART_SR_RXNE) )
  509. {
  510. rxd_reg = CONSOLE->DR;
  511. Ledx_on(12);
  512. if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到字节,重置接收指针
  513. else
  514. {
  515. if( shell_rx_index < SHELL_RX_MAX)
  516. {
  517. shell_rx_buff[shell_rx_index] = rxd_reg;
  518. shell_rx_index++;
  519. }
  520. else
  521. {
  522. shell_rx_index = 0;
  523. Ledx_off(12);
  524. }
  525. }
  526. }
  527. if( (CONSOLE->CR1 & USART_CR1_IDLEIE) && (isr_reg & USART_SR_IDLE) )
  528. {
  529. CONSOLE->SR;
  530. CONSOLE->DR;
  531. if(shell_rx_rdy)shell_rx_index = 0;     //忙模式收到空闲,重置接收指针
  532. else
  533. {
  534. if( (shell_rx_index >=2) && (‘\r‘ == shell_rx_buff[shell_rx_index-2]) &&
  535. (‘\n‘ == shell_rx_buff[shell_rx_index-1])   )       //以"\r\n"结尾
  536. {
  537. shell_rx_rdy = shell_rx_index;
  538. shell_rx_index = 0;
  539. Ledx_off(12);
  540. }
  541. else if( (shell_rx_index > 0) && (‘\b‘ == shell_rx_buff[shell_rx_index-1]) )  //以\b结尾
  542. {
  543. shell_rx_index = shell_rx_index <2? 0:shell_rx_index-2;
  544. printf(" \b");      //发送辅助删除
  545. }
  546. }
  547. }
  548. //发送非空中断
  549. if( (CONSOLE->CR1 & USART_CR1_TXEIE) && (isr_reg & USART_SR_TXE ) )
  550. {
  551. if(shell_tx_size && (shell_tx_index < shell_tx_size) )
  552. {
  553. txd_reg = shell_tx_buff[shell_tx_index++];
  554. CONSOLE->DR = txd_reg;  //发送数据
  555. }
  556. else
  557. {
  558. //关闭非空中断
  559. shell_tx_index = 0;
  560. shell_tx_size = 0;
  561. CONSOLE->CR1 &= ~USART_CR1_TXEIE;        //关闭发送完毕中断
  562. Ledx_off(11);
  563. }
  564. }
  565. }
  566. /******************************************************************************
  567. / 函数功能:指令(ASCII或HEX指令)未处理消息回执
  568. / 修改日期:2013/9/12 20:25:45
  569. / 输入参数:none
  570. / 输出参数:none
  571. / 使用说明:一字节一字节接收数据,拼装为指令
  572. ******************************************************************************/
  573. void Shell_Invalid_Service(void)
  574. {
  575. int         tx_len,i,led_id,msg_id;
  576. uint8_t *   ptSrc;
  577. uint8_t *   ptDst;
  578. uint8_t     tmp_buff[64];
  579. //指令识别
  580. if(2 > shell_rx_rdy)
  581. {
  582. shell_rx_buff[0]  = 0;
  583. return;
  584. }
  585. else if( (‘\r‘ == shell_rx_buff[shell_rx_rdy-2]) && (‘\n‘ == shell_rx_buff[shell_rx_rdy-1]) )
  586. {
  587. ptSrc = (uint8_t *)shell_rx_buff;
  588. if(2 == shell_rx_rdy)
  589. {
  590. //填写数据
  591. tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT:OK!\r\n");
  592. //发送数据
  593. shell_SendHex(tmp_buff,tx_len);     //发送数据
  594. }
  595. else if(StrComp(ptSrc,"led rd\r\n"))   //显示LED的信号配置
  596. {
  597. //填写数据
  598. tx_len = (uint16_t)sprintf((void *)tmp_buff,
  599. #if     (6 == SHELL_LED_MAX)
  600. "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d  LED5=%d\r\n",
  601. msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
  602. msg_led_cfg[3],msg_led_cfg[4],msg_led_cfg[5]);
  603. #elif   (5 == SHELL_LED_MAX)
  604. "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d  LED4=%d\r\n",
  605. msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
  606. msg_led_cfg[3],msg_led_cfg[4]);
  607. #elif   (4 == SHELL_LED_MAX)
  608. "->LED0=%d  LED1=%d  tLED2=%d  LED3=%d\r\n",
  609. msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2],
  610. msg_led_cfg[3]);
  611. #elif   (3 == SHELL_LED_MAX)
  612. "->LED0=%d  LED1=%d  tLED2=%d\r\n",
  613. msg_led_cfg[0],msg_led_cfg[1],msg_led_cfg[2]);
  614. #elif   (2 == SHELL_LED_MAX)
  615. "->LED0=%d  LED1=%d\r\n",
  616. msg_led_cfg[0],msg_led_cfg[1]);
  617. #elif   (1 == SHELL_LED_MAX)
  618. "->LED0=%d\r\n",
  619. msg_led_cfg[0]);
  620. #endif
  621. //发送数据
  622. shell_SendHex(tmp_buff,tx_len);     //发送数据
  623. }
  624. else if(StrComp(ptSrc,"led wr "))      //设置LED的信号配置
  625. {
  626. if(2 != sscanf((void *)ptSrc,"%*s%*s%d=%d",&led_id,&msg_id) )goto ERROR_LOOP;
  627. if( (led_id>(SHELL_LED_MAX-1)) || (msg_id >65535) )goto ERROR_LOOP;
  628. Ledx_config((uint8_t)led_id,(uint16_t)msg_id);  //配置信号
  629. //填写数据
  630. tx_len = (uint16_t)sprintf((void *)tmp_buff,
  631. "->LED[%d]_Msg=%d\r\n",led_id,msg_led_cfg[led_id]);
  632. //发送数据
  633. shell_SendHex(tmp_buff,tx_len);     //发送数据
  634. }
  635. else goto ERROR_LOOP;
  636. }
  637. else
  638. {
  639. ERROR_LOOP:
  640. //填写指令码
  641. tx_len = (uint16_t)sprintf((void *)tmp_buff,"\r\nAT: Cmd Error:\t\"");
  642. //计算地址,填写数据,填写尾部
  643. ptDst = tmp_buff + tx_len;
  644. ptSrc = (uint8_t *)shell_rx_buff;
  645. if(shell_rx_rdy > 32)
  646. {
  647. for(i=0; i<32; i++)
  648. {
  649. if( (*ptSrc > 126) || (*ptSrc < 32) )
  650. {
  651. *ptDst++ = ‘?‘;
  652. ptSrc++;
  653. }
  654. else
  655. {
  656. *ptDst++ = *ptSrc++;
  657. }
  658. }
  659. *(ptDst-2) = ‘-‘;
  660. *(ptDst-1) = ‘>‘;
  661. tx_len += 32;
  662. }
  663. else
  664. {
  665. for(i=0; i<shell_rx_rdy; i++)
  666. {
  667. *ptDst++ = *ptSrc++;
  668. tx_len++;
  669. }
  670. *(ptDst-2) = ‘<‘;
  671. *(ptDst-1) = ‘-‘;
  672. }
  673. tx_len += (uint16_t)sprintf((void *)ptDst,"\"\r\n");
  674. //发送数据
  675. shell_SendHex(tmp_buff,tx_len);  //发送数据
  676. }
  677. //清除数据返回程序
  678. shell_rx_buff[0]  = 0;
  679. shell_rx_rdy      = 0;
  680. }
  681. /******************************************************************************
  682. / 函数功能:字符串测试匹配指令
  683. / 修改日期:2014/3/5 19:30:22
  684. / 输入参数:none
  685. / 输出参数:none
  686. / 使用说明:none
  687. ******************************************************************************/
  688. bool StrComp(void * buffer,void * StrCmd)
  689. {
  690. uint8_t i;
  691. uint8_t * ptBuf;
  692. uint8_t * ptCmd;
  693. ptBuf = (uint8_t *)buffer;
  694. ptCmd = (uint8_t *)StrCmd;
  695. for(i=0; i<255; i++)
  696. {
  697. if(ptCmd[i])
  698. {
  699. if(ptBuf[i] != ptCmd[i])return false;
  700. }
  701. else
  702. {
  703. if(i)return i;
  704. else return false;
  705. }
  706. }
  707. return false;
  708. }
  709. /******************************************************************************
  710. / 函数功能:打开LED信号
  711. / 修改日期:none
  712. / 输入参数:none
  713. / 输出参数:none
  714. / 使用说明:none
  715. ******************************************************************************/
  716. void Ledx_on(uint16_t msg_id)
  717. {
  718. #if (SHELL_LED_MAX > 0)
  719. if(msg_id == msg_led_cfg[0])LED0_ON();
  720. #endif
  721. #if (SHELL_LED_MAX > 1)
  722. if(msg_id == msg_led_cfg[1])LED1_ON();
  723. #endif
  724. #if (SHELL_LED_MAX > 2)
  725. if(msg_id == msg_led_cfg[2])LED2_ON();
  726. #endif
  727. #if (SHELL_LED_MAX > 3)
  728. if(msg_id == msg_led_cfg[3])LED3_ON();
  729. #endif
  730. #if (SHELL_LED_MAX > 4)
  731. if(msg_id == msg_led_cfg[4])LED4_ON();
  732. #endif
  733. #if (SHELL_LED_MAX > 5)
  734. if(msg_id == msg_led_cfg[5])LED5_ON();
  735. #endif
  736. }
  737. /******************************************************************************
  738. / 函数功能:关闭LED信号
  739. / 修改日期:none
  740. / 输入参数:none
  741. / 输出参数:none
  742. / 使用说明:none
  743. ******************************************************************************/
  744. void Ledx_off(uint16_t msg_id)
  745. {
  746. #if (SHELL_LED_MAX > 0)
  747. if(msg_id == msg_led_cfg[0])LED0_OFF();
  748. #endif
  749. #if (SHELL_LED_MAX > 1)
  750. if(msg_id == msg_led_cfg[1])LED1_OFF();
  751. #endif
  752. #if (SHELL_LED_MAX > 2)
  753. if(msg_id == msg_led_cfg[2])LED2_OFF();
  754. #endif
  755. #if (SHELL_LED_MAX > 3)
  756. if(msg_id == msg_led_cfg[3])LED3_OFF();
  757. #endif
  758. #if (SHELL_LED_MAX > 4)
  759. if(msg_id == msg_led_cfg[4])LED4_OFF();
  760. #endif
  761. #if (SHELL_LED_MAX > 5)
  762. if(msg_id == msg_led_cfg[5])LED5_OFF();
  763. #endif
  764. }
  765. /******************************************************************************
  766. / 函数功能:取反LED信号
  767. / 修改日期:none
  768. / 输入参数:none
  769. / 输出参数:none
  770. / 使用说明:none
  771. ******************************************************************************/
  772. void Ledx_div(uint16_t msg_id)
  773. {
  774. #if (SHELL_LED_MAX > 0)
  775. if(msg_id == msg_led_cfg[0])LED0_DIV();
  776. #endif
  777. #if (SHELL_LED_MAX > 1)
  778. if(msg_id == msg_led_cfg[1])LED1_DIV();
  779. #endif
  780. #if (SHELL_LED_MAX > 2)
  781. if(msg_id == msg_led_cfg[2])LED2_DIV();
  782. #endif
  783. #if (SHELL_LED_MAX > 3)
  784. if(msg_id == msg_led_cfg[3])LED3_DIV();
  785. #endif
  786. #if (SHELL_LED_MAX > 4)
  787. if(msg_id == msg_led_cfg[4])LED4_DIV();
  788. #endif
  789. #if (SHELL_LED_MAX > 5)
  790. if(msg_id == msg_led_cfg[5])LED5_DIV();
  791. #endif
  792. }
  793. /******************************************************************************
  794. / 函数功能:配置LED信号
  795. / 修改日期:none
  796. / 输入参数:none
  797. / 输出参数:none
  798. / 使用说明:none
  799. ******************************************************************************/
  800. void Ledx_config(uint8_t led_id,uint16_t msg_id)
  801. {
  802. if(0 == led_id)     {LED0_OFF();msg_led_cfg[0]=msg_id;}
  803. #if(SHELL_LED_MAX > 1)
  804. else if(1 == led_id){LED1_OFF();msg_led_cfg[1]=msg_id;}
  805. #endif
  806. #if(SHELL_LED_MAX > 2)
  807. else if(2 == led_id){LED2_OFF();msg_led_cfg[2]=msg_id;}
  808. #endif
  809. #if(SHELL_LED_MAX > 3)
  810. else if(3 == led_id){LED3_OFF();msg_led_cfg[3]=msg_id;}
  811. #endif
  812. #if(SHELL_LED_MAX > 4)
  813. else if(4 == led_id){LED4_OFF();msg_led_cfg[4]=msg_id;}
  814. #endif
  815. #if(SHELL_LED_MAX > 5)
  816. else if(5 == led_id){LED5_OFF();msg_led_cfg[5]=msg_id;}
  817. #endif
  818. }
  819. /******************************************************************************
  820. / 函数功能:读取LED的配置信号
  821. / 修改日期:none
  822. / 输入参数:none
  823. / 输出参数:none
  824. / 使用说明:none
  825. ******************************************************************************/
  826. uint16_t Ledx_read(uint8_t led_id)
  827. {
  828. if(0 == led_id)     return msg_led_cfg[0];
  829. #if(SHELL_LED_MAX > 1)
  830. else if(1 == led_id)return msg_led_cfg[1];
  831. #endif
  832. #if(SHELL_LED_MAX > 2)
  833. else if(2 == led_id)return msg_led_cfg[2];
  834. #endif
  835. #if(SHELL_LED_MAX > 3)
  836. else if(3 == led_id)return msg_led_cfg[3];
  837. #endif
  838. #if(SHELL_LED_MAX > 4)
  839. else if(4 == led_id)return msg_led_cfg[4];
  840. #endif
  841. #if(SHELL_LED_MAX > 5)
  842. else if(5 == led_id)return msg_led_cfg[5];
  843. #endif
  844. else return 0;
  845. }
  846. /******************************************************************************
  847. ***********************************   END  ************************************
  848. ******************************************************************************/

四. 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. #define RTC_SHELL       //注释掉时屏蔽iap shell功能
  28. /******************************************************************************
  29. ********************************* 文件引用部分 ********************************
  30. ******************************************************************************/
  31. /*---------------------*
  32. *     文件包含
  33. *----------------------*/
  34. //基础支持文件
  35. #include "shell.h"          //Shell支持文件,含bool,uint8_t..以及串口数据收发操作
  36. #include "rtc.h"         //命令控制支持文件
  37. /*---------------------*
  38. *     Shell版本判断
  39. *----------------------*/
  40. #ifdef SHELL_VER
  41. #if (SHELL_VER < 2)
  42. #error "shell版本太低"
  43. #endif
  44. #else
  45. #error "未找到Shell文件,或shell版本信息"
  46. #endif
  47. /******************************************************************************
  48. ********************************* 输出函数功能 ********************************
  49. ******************************************************************************/
  50. /*---------------------*
  51. *       输出函数功能
  52. *----------------------*/
  53. #ifdef RTC_SHELL
  54. extern void Shell_RTC_Service(void);
  55. #else
  56. void Shell_RTC_Service(void){;}
  57. #endif
  58. /*---------------------*
  59. *       输入函数
  60. *----------------------*/
  61. //none
  62. /******************************************************************************
  63. ********************************* 数 据 声 明 *********************************
  64. ******************************************************************************/
  65. #ifdef RTC_SHELL
  66. /*---------------------*
  67. *
  68. *----------------------*/
  69. //命令帮助文件
  70. const char RTC_HelpMsg[] =
  71. "[RTC contorls]\r\n"
  72. " rtc help\t\t- help.\r\n"
  73. " rtc rd info\t\t- Read RTC info.\r\n"
  74. " rtc rd time\t\t- Read RTC date and time.\r\n"
  75. " rtc wr time <Hour>:<Minute>:<Second>    - Write time.\r\n"
  76. " rtc wr date <Year>-<Month>-<Day> <Week> - Warning Week=[1..7]\r\n"
  77. "\r\n";
  78. /******************************************************************************
  79. ********************************* 函 数 声 明 *********************************
  80. ******************************************************************************/
  81. /******************************************************************************
  82. / 函数功能:文件系统Shel指令处理
  83. / 修改日期:2013/9/10 19:04:15
  84. / 输入参数:输入当前的程序版本
  85. / 输出参数:none
  86. / 使用说明:none
  87. ******************************************************************************/
  88. void Shell_RTC_Service(void)
  89. {
  90. uint8_t     *ptRxd;         //用于接收指令处理
  91. //uint8_t     *ptTxd;         //方便用于指令发送
  92. int         i,j,k,l;
  93. //int         tx_len,drv;
  94. //uint32_t    u32_arg[4];
  95. uint16_t    retval;
  96. uint8_t     arg[32];
  97. uint32_t    tmp_time;
  98. //指令初级过滤
  99. //--------------------------------------------------------------------------
  100. //格式:<->[cmd bytes]<CRLF>  即"-[cmd bytes]\r\n"
  101. //指令必须以"-"开始, 以"\r\n"结束
  102. i = shell_rx_rdy;
  103. if( (i < 2) || (‘\r‘ != shell_rx_buff[i-2]) || (‘\n‘ != shell_rx_buff[i-1]))return;
  104. //长度和前缀过滤
  105. ptRxd = (uint8_t *)shell_rx_buff;
  106. if( (‘ ‘ != shell_rx_buff[3]) || (‘r‘ != shell_rx_buff[0]) || (i < 6) ||
  107. (‘t‘ != shell_rx_buff[1]) || (‘c‘ != shell_rx_buff[2]) )  return;
  108. //处理指令
  109. //--------------------------------------------------------------------------
  110. ptRxd += 4;
  111. if(StrComp(ptRxd,"rd time"))    //按包读取指令
  112. {
  113. RTC_Sprintf_CurrTime((void *)arg);
  114. printf("Time:%s\r\n",arg);
  115. }
  116. else if(StrComp(ptRxd,"rd info\r\n"))      //读取RTC信息
  117. {
  118. //打印当前时间和上次复位时间
  119. RTC_Sprintf_CurrTime((void *)arg);
  120. printf("->Time:%s\tResetCounter:%d\r\n",arg,RESET_CNT);
  121. RTC_Sprintf_ResetCurr((void *)arg,&tmp_time);
  122. printf("\tCurrReset:%s\tRun: %d Days, %d hour, %d minute\r\n",
  123. arg,tmp_time/(24*60),(tmp_time%(24*60))/60,tmp_time%60 );
  124. RTC_Sprintf_ResetLast((void *)arg,&tmp_time);
  125. printf("\tNextReset:%s\tRun: %d Days, %d hour, %d minute\r\n",
  126. arg,tmp_time/(24*60),(tmp_time%(24*60))/60,tmp_time%60 );
  127. }
  128. else if(StrComp(ptRxd,"wr time "))      //写时间
  129. {
  130. retval = sscanf((void*)shell_rx_buff,"%*s%*s%*s%d:%d:%d",&i,&j,&k);
  131. if(3 != retval)return;   //没有接收到3个输入数据,直接退出
  132. if(RTC_TimeWrite((uint8_t)i,(uint8_t)j,(uint8_t)k) )
  133. {
  134. RTC_Sprintf_CurrTime((void *)arg);
  135. printf("->CurrTime:%s\r\n",arg);
  136. }
  137. else
  138. {
  139. printf("->Error Time Input!\r\n");
  140. shell_rx_rdy = 0;       //不用触发错误指令显示
  141. return;
  142. }
  143. }
  144. else if(StrComp(ptRxd,"wr date "))      //写日期
  145. {
  146. retval = sscanf((void*)shell_rx_buff,"%*s%*s%*s%d-%d-%d %d",&i,&j,&k,&l);
  147. if(4 != retval)return;   //没有接收到4个输入数据,直接退出
  148. if(RTC_DateWrite((uint16_t)i,(uint8_t)j,(uint8_t)k,(uint8_t)l))
  149. {
  150. RTC_Sprintf_CurrTime((void *)arg);
  151. printf("->CurrTime:%s\r\n",arg);
  152. }
  153. else
  154. {
  155. printf("->Error Date Input!\r\n");
  156. shell_rx_rdy = 0;       //shell_rx_rdy为0,表示指令已被处理完毕,否者下个Shell服务继续调用
  157. return;
  158. }
  159. }
  160. else if(StrComp(ptRxd,"help\r\n"))      //指令帮助
  161. {
  162. shell_SendStr((void *)RTC_HelpMsg);
  163. }
  164. else return;
  165. //退出处理
  166. //--------------------------------------------------------------------------
  167. shell_rx_rdy = 0;   //shell_rx_rdy为0,表示指令已被处理完毕,否者下个Shell服务继续调用
  168. }
  169. /******************************************************************************
  170. ***********************************   END  ************************************
  171. ******************************************************************************/
  172. #endif

更多全新视频: www.makeru.com.cn/?t=12                      嵌入式学习交流群:561213221

原文地址:https://www.cnblogs.com/huan-huan/p/8488024.html

时间: 2024-10-10 20:18:30

一种STM32的串口控制台的实现(非常实用)的相关文章

STM32的串口采用DMA方式接收数据测试(转)

STM32的串口采用DMA方式接收数据测试 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.   参考链接:http://www.amobbs.com/forum.PHP?mod=viewthread&tid=5511863&highlight=dma%E6%8E%A5%E6%94%B6   环境: 主机:WINXP 开发环境:MDK4.23 MCU:STM32F103CBT6 说明: 串口可以配置成用DMA的方式接收数据,不过DMA需要定长才

关于STM32 USART(串口)发送数据丢失第一帧的真实原因探索

自我介绍 为什么要写个自我介绍?俗话说,光说不练假把式,光练不说傻把式, 因为本人一直很自负,感觉什么东西都可以很快上手(当然非对口专业知识要求高的技能除外),如果我不把这自负表现出来,感觉会憋出内伤. 本人于2015年毕业于电子科技大学,开始的理想是进入一家国外的游戏公司,但理想很丰满,现实很骨感,给育碧.2k Game.Gameloft.EA都投了简历,但都被无情pass掉了(在此吐槽一下,这些公司真的是想在校园里招本科生吗?明明是研究生的计算机图形学却成了这些公司对本科生的要求).后来毕业

STM32之串口通信

一.RS232通信协议 1.概念 个人计算机上的通讯接口之一,由电子工业协会(Electronic Industries Association,EIA) 所制定的异步传输标准接口. 2.电气特性 逻辑1(MARK): -3V--15V 逻辑0(SPACE):  +3-+15V 3.接口 实现全双工异步通信只需要三根线:RX.TX和GND. 二.常见COMS电平转RS232电平的芯片--MAX3232 1.逻辑输入与逻辑输出特性 2.RS232接口端输入特性 3.RS232接口端输出特性 三.S

14. 串口控制台建立

14. 串口控制台建立 串口控制台建立这一节的主要有三个内容: 1.控制台框架搭建 1.1控制台的分类介绍: 1.1.1菜单型控制台:就是选中设置好的数字或者字母选项后执行相应功能的控制台: 例如刚进入uboot之后的界面,就是菜单型控制台: 等待我们输入命令,来执行相应的操作.例如上面,如果此时我们输入1,就是进行Format the nand Flash的操作: 1.1.2解析型控制台:在上面的菜单型控制台里,选择5:Exit to command line:后会出现: 就进入了解析型控制台

linux内核打印数据到串口控制台,printk数据不打印问题

linux内核打印数据到串口控制台问题 原文来源:http://i.cnblogs.com/EditPosts.aspx?opt=1 1.查看当前控制台的打印级别 cat /proc/sys/kernel/printk 4    4    1    7 其中第一个“4”表示内核打印函数printk的打印级别,只有级别比他高的信息才能在控制台上打印出来,既 0-3级别的信息 2.修改打印 echo "新的打印级别  4    1    7" >/proc/sys/kernel/pr

嵌入式 02 STM32 07串口通信

STM32串口通信(F1系列包含3个USART和2个UART) 一.单片机与PC机串行通信研究目的和意义: 单片机自诞生以来以其性能稳定,价格低廉.功能强大.在智能仪器.工业装备以及日用电子消费产品中得到了广泛的应用.在单片机的输入输出控制中,除直接接上小键盘和LCD显示屏等方法外,一般都通过串口和上位机PC进行通信.这样不仅能够实现远程控制,而且能够利用PC机强大的数据处理功能以及友好的控制界面.在一般的利用PC机对单片机进行控制的场合,都是采用操作系统作为上位机的平台,其优点是界面友好,编程

[国嵌攻略][057][串口控制台建立]

控制台分类 1.菜单型控制台,通过选择菜单来执行命令 2.解析型控制台,通过输入命令来执行命令 printf().scanf()函数移植 1.函数采用变参 2.打印信息到串口 3.关键在于把变参转换成字符串,相关函数需要从Linux内核或标准C库中移植 va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); /***********************************************

tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——移植u-boot.bin(打印串口控制台)

在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的信息打印. 在上节.我们看到调用 relocate_code 重定位.在 u-boot 的帮助文档 doc/README.arm-relocation 中对重定位有说明. u-boot 为了生成位置无关码,在链接时指定了-pie 选项,这个选项在 u-boot-2014.04/arch/arm/config.mk 中指定: 当使用-pie 选项后.链接器会生成一个修正表(fixup  tables).在终于的二进制文件 u-boot

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植u-boot.bin(打印串口控制台)

在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的打印信息. 在上节,我们看到调用 relocate_code 重定位.在 u-boot 的帮助文档 doc/README.arm-relocation 中对重定位有说明.u-boot 为了生成位置无关码,在链接时指定了-pie 选项,这个选项在 u-boot-2014.04/arch/arm/config.mk 中指定: 当使用-pie 选项后,链接器会生成一个修正表(fixup  tables),在最终的二进制文件 u-boot.