[APM32F4] 【APM32F411V Tiny Board测评】+串口shell移植nr_micro_shell和letter_shell

[复制链接]
 楼主| WoodData 发表于 2024-5-22 11:31 | 显示全部楼层 |阅读模式
本帖最后由 WoodData 于 2024-5-22 15:00 编辑

上期已经搞定了APM32F411的串口通信,本期就移植一下串口shell,方便命令控制。目前shell比较好的有nr_micao_shell和letter shell这2种。其中nr_micro_shell比较简单,只是基本的shell命令。
而letter shell相对复杂一些,但是功能也更多。有用户权限控制和密码控制。

下面就开始我的移植过程。由于之前也移植到其他平台MCU,所以本次移植也非常简单了。
首先下载nr_micao_shell和letter shell的代码,添加到keil工程中。加入头文件路径。
1.png
然后就是实现串口发送接收。接收要使用中断模式,使用FIFO缓存接收,防止数据丢失。
串口初始化和发送接收:
  1. void APM_TINY_COMInit(USART_T * com, uint32_t baud)
  2. {
  3.     GPIO_Config_T GPIO_configStruct;
  4.     USART_Config_T usartConfigStruct;

  5.     GPIO_ConfigStructInit(&GPIO_configStruct);
  6.     if (USART1 == com)
  7.     {
  8.         /* Enable GPIO clock */
  9.         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
  10.         RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
  11.         
  12.         /* Connect PXx to USARTx_Tx */
  13.         GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_9, GPIO_AF_USART1);
  14.         /* Connect PXx to USARTx_Rx */
  15.         GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10, GPIO_AF_USART1);
  16.         /* Configure USART Tx as alternate function push-pull */
  17.         GPIO_configStruct.mode = GPIO_MODE_AF;
  18.         GPIO_configStruct.pin  = GPIO_PIN_9;
  19.         GPIO_configStruct.speed = GPIO_SPEED_50MHz;
  20.         GPIO_Config(GPIOA, &GPIO_configStruct);
  21.         /* Configure USART Rx as input floating */
  22.         GPIO_configStruct.mode = GPIO_MODE_AF;
  23.         GPIO_configStruct.pin  = GPIO_PIN_10;
  24.         GPIO_Config(GPIOA, &GPIO_configStruct);
  25.     }
  26.     else if (USART2 == com)
  27.     {
  28.         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
  29.         RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USART2);
  30.         
  31.         /* Connect PXx to USARTx_Tx */
  32.         GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_2, GPIO_AF_USART2);
  33.         /* Connect PXx to USARTx_Rx */
  34.         GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_3, GPIO_AF_USART2);
  35.         /* Configure USART Tx as alternate function push-pull */
  36.         GPIO_configStruct.mode = GPIO_MODE_AF;
  37.         GPIO_configStruct.pin  = GPIO_PIN_2;
  38.         GPIO_configStruct.speed = GPIO_SPEED_50MHz;
  39.         GPIO_Config(GPIOA, &GPIO_configStruct);
  40.         /* Configure USART Rx as input floating */
  41.         GPIO_configStruct.mode = GPIO_MODE_AF;
  42.         GPIO_configStruct.pin  = GPIO_PIN_3;
  43.         GPIO_Config(GPIOA, &GPIO_configStruct);
  44.     }
  45.    
  46.     /* USART1 configuration */
  47.     usartConfigStruct.baudRate = baud;
  48.     usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
  49.     usartConfigStruct.mode = USART_MODE_TX_RX;
  50.     usartConfigStruct.parity = USART_PARITY_NONE;
  51.     usartConfigStruct.stopBits = USART_STOP_BIT_1;
  52.     usartConfigStruct.wordLength = USART_WORD_LEN_8B;
  53.     /* USART configuration */
  54.     USART_Config(com, &usartConfigStruct);
  55.    
  56.     /* Enable USART1 RXBNEinterrput */
  57.     USART_EnableInterrupt(com,USART_INT_RXBNE);
  58.     USART_ClearStatusFlag(com,USART_FLAG_RXBNE);
  59.     NVIC_EnableIRQRequest(USART1_IRQn,1,0);
  60.    
  61.     /* Enable USART */
  62.     USART_Enable(com);
  63. }

  64. void shell_usart_init(void)
  65. {
  66.     APM_TINY_COMInit(USART1,115200);
  67.    
  68. #ifdef UART_SHELL
  69. #if UART_SHELL == 1
  70.     userShellInit(); //LETTER_SHELL
  71. #elif UART_SHELL == 2
  72.     shell_init();   //NR_MICRO_SHELL
  73. #endif
  74. #endif
  75. }
fifo结构体定义

  1. typedef struct fifo_buffer
  2. {
  3.     volatile uint32_t    read_i;
  4.     volatile uint32_t    write_i;
  5.     uint8_t     buff[128];
  6. }fifo_buffer;

  7. extern fifo_buffer  shell_uart_rx;
接收数据处理:
  1. void shell_usart_loop(void)
  2. {
  3.     if(shell_uart_rx.read_i != shell_uart_rx.write_i)
  4.     {
  5. #ifdef UART_SHELL
  6.         #if UART_SHELL == 1
  7.             shellHandler(&shell, shell_uart_rx.buff[shell_uart_rx.read_i++]); //letter shell
  8.         #elif UART_SHELL == 2
  9.             shell(shell_uart_rx.buff[shell_uart_rx.read_i++]);
  10.         #endif
  11. #endif
  12.         shell_uart_rx.read_i &= 0x7f;
  13.     }
  14. }

  15. void USART1_IRQHandler(void)
  16. {
  17.     uint32_t ch;
  18.    
  19.     if(USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET)
  20.     {
  21.         ch = USART_RxData(USART1);
  22.         if(((shell_uart_rx.write_i+1)&0x7f) != shell_uart_rx.read_i)
  23.         {
  24.             shell_uart_rx.buff[shell_uart_rx.write_i++] = ch & 0xff;
  25.             shell_uart_rx.write_i &= 0x7f;
  26.         }
  27.         USART_ClearStatusFlag(USART1,USART_FLAG_RXBNE);
  28.     }
  29. }
在main中调用,2个shell是通过宏定义选择编译。
2.png

接下来是修改nr_micro_shell配置移植,主要修改nr_micro_shell_config.h配置。
关键的串口部分:
3.png

letter shell的修改主要在port部分,shell_port.c文件内

  1. #include "shell_cfg_user.h"
  2. #include "shell_uart.h"
  3. #include "shell.h"


  4. Shell shell;
  5. char shellBuffer[512];


  6. /**
  7. * [url=home.php?mod=space&uid=247401]@brief[/url] 用户shell写
  8. *
  9. * @param data 数据
  10. * @param len 数据长度
  11. *
  12. * [url=home.php?mod=space&uid=266161]@return[/url] short 实际写入的数据长度
  13. */
  14. short userShellWrite(char *data, unsigned short len)
  15. {
  16.     for(uint32_t i=0;i<len;i++)
  17.         USART_PutChar(data[i]);
  18.     return len;
  19. }


  20. /**
  21. * [url=home.php?mod=space&uid=247401]@brief[/url] 用户shell读
  22. *
  23. * @param data 数据
  24. * @param len 数据长度
  25. *
  26. * [url=home.php?mod=space&uid=266161]@return[/url] short 实际读取到
  27. */
  28. short userShellRead(char *data, unsigned short len)
  29. {
  30.     uint32_t rlen = 0;
  31.     for(uint32_t i=0;i<len;i++)
  32.     {
  33.         if(shell_uart_rx.read_i != shell_uart_rx.write_i)
  34.         {
  35.             data[rlen++] = shell_uart_rx.buff[shell_uart_rx.read_i++];
  36.             shell_uart_rx.read_i &= 0x7f;
  37.         }
  38.     }
  39.     return rlen;
  40. }

  41. /**
  42. * @brief 用户shell上锁
  43. *
  44. * @param shell shell
  45. *
  46. * @return int 0
  47. */
  48. int userShellLock(Shell *shell)
  49. {
  50.     return 0;
  51. }

  52. /**
  53. * @brief 用户shell解锁
  54. *
  55. * @param shell shell
  56. *
  57. * @return int 0
  58. */
  59. int userShellUnlock(Shell *shell)
  60. {
  61.     return 0;
  62. }

  63. /**
  64. * @brief 用户shell初始化
  65. *
  66. */
  67. void userShellInit(void)
  68. {
  69.     shell.write = userShellWrite;
  70.     shell.read = userShellRead;
  71. //    shell.lock = userShellLock;
  72. //    shell.unlock = userShellUnlock;
  73.     shellInit(&shell, shellBuffer, 512);

  74. }
配置在shell_cfg_user.h文件内。

下面来编译烧录测试一下。首先选择nr_micro_shell。定义#define UART_SHELL  2
4.png

再来测试一下letter shell。定义#define UART_SHELL  1。然后编译下载测试。
5.png



代码工程:
游客,如果您要查看本帖隐藏内容请回复







lemonhub 发表于 2024-5-22 14:23 | 显示全部楼层
本帖最后由 lemonhub 于 2024-5-22 14:41 编辑

学习学习,之前移植的时候,有部分功能没有成功,工程里面缺少shell_uart文件
 楼主| WoodData 发表于 2024-5-22 15:01 | 显示全部楼层
lemonhub 发表于 2024-5-22 14:23
学习学习,之前移植的时候,有部分功能没有成功,工程里面缺少shell_uart文件 ...

哦,重新上传了附近,缺的补上了
szt1993 发表于 2024-5-23 16:49 | 显示全部楼层
shell—uart对于shell文本支持怎样?
 楼主| WoodData 发表于 2024-5-23 17:36 | 显示全部楼层
szt1993 发表于 2024-5-23 16:49
shell—uart对于shell文本支持怎样?

什么文本??
piaozi2008 发表于 2024-8-13 19:07 | 显示全部楼层
支持楼主2
chenjun89 发表于 2024-8-13 19:38 来自手机 | 显示全部楼层
这两个shell楼主更推荐用哪个?
 楼主| WoodData 发表于 2024-8-13 22:45 | 显示全部楼层
chenjun89 发表于 2024-8-13 19:38
这两个shell楼主更推荐用哪个?

看你需求了,我一般只用nr_micro_shell就够了。如果需要用户控制和密码控制的用lettershell
binbin3944 发表于 2024-8-22 22:58 | 显示全部楼层
journey111222 发表于 2025-2-13 09:09 | 显示全部楼层
看看代码
幻影书记 发表于 2025-3-28 14:47 | 显示全部楼层
学习了。
听楼主的,先考虑一下nr_micro_shell
前些天看了letter_shell,确实觉得有点复杂了。
jobszheng 发表于 2025-3-29 09:44 | 显示全部楼层
学习了一遍,还是要自己开发。
感觉还是有点复杂,自己写的话冗余代码会少很多
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

4778

帖子

28

粉丝
快速回复 在线客服 返回列表 返回顶部

127

主题

4778

帖子

28

粉丝
快速回复 在线客服 返回列表 返回顶部