本帖最后由 qinyunti 于 2025-1-25 21:34 编辑

【电子DIY】DIY行车记录仪为游戏机之主控软件开发(4)移植标准输入输出和SHELL

一. 前言

前面我们已经实现了串口的收发接口,为了方便后续调试和交互我们就来移植标准输入输出实现以及简单的SHELL。

代码见:https://github.com/qinyunti/py32f403-nes.git

添加以下文件

image.png


二. Xprintf移植

参考公众号文章

https://mp.weixin.qq.com/s/y4MHV3cd4T0b51L5M4J5Xg?token=1631959641&lang=zh_CN


适配输入输出接口

<pre>static void xprintf_out_port(int ch)
  • {
  •     uint8_t val = ch;
  •     uart_send(0,&val,1);
  • }

  • static int xprintf_in_port(void)
  • {
  •     uint32_t len;
  •     uint8_t val;
  •     do
  •     {
  •         len = uart_read(0,&val,1);
  •     }while(len == 0);
  •     return val;
  • }</pre>
  • 复制代码

    初始化时,设置接口即可

        xdev_out(xprintf_out_port);

    xdev_in(xprintf_in_port);


    Xprintf.h中一些宏控制是否支持浮点等。


    三. Shell移植

    参考公众号文章

    https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg?token=1631959641&lang=zh_CN

    实现底层收发接口

    <pre>uint32_t shell_read(uint8_t *buff, uint32_t len)
  • {
  •         return uart_read(0,buff,len);
  • }

  • void shell_write(uint8_t *buff, uint32_t len)
  • {
  •         uart_send(0,buff,len);
  • }</pre>
  • 复制代码

    设置接口

    <pre>shell_set_itf(shell_read, shell_write, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);</pre>
    复制代码

    任务中循环调用s h e l l _ e x e c ( );即可

    <pre>static void shell_task(void *arg)
  • {   
  •     (void)arg;
  •           xprintf("shell task start.\r\n");
  •         
  •     while(1)
  •     {
  •         shell_e x e c();
  •         vTaskDelay((1*1000/configTICK_RATE_HZ));
  •     }
  • }
  • </pre>
  • 复制代码

    四. 测试


    <pre>#include <string.h>
  • #include "py32f4xx_hal.h"
  • #include "py32f403_hal_rcc.h"

  • #include "uart.h"

  • #include "FreeRTOS.h"
  • #include "task.h"
  • #include "xprintf.h"
  • #include "shell.h"
  • #include "shell_func.h"

  • static void clk_out(void)
  • {
  •         /* PA8 AF0 MCO*/
  •         GPIO_InitTypeDef  GPIO_InitStruct;
  •         __HAL_RCC_GPIOA_CLK_ENABLE();                  

  •         GPIO_InitStruct.Pin = GPIO_PIN_8;
  •         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;            
  •         GPIO_InitStruct.Pull = GPIO_PULLUP;                 
  •         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;         
  •         GPIO_InitStruct.Alternate = GPIO_AF0_MCO;        
  •         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);  

  •         HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1);
  •        
  • }

  • static void clk_init(void)
  • {
  •         RCC_OscInitTypeDef  RCC_OscInitStruct;
  •         RCC_OscInitStruct.HSEFreq = RCC_HSE_16_32MHz;
  •         RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  •         RCC_OscInitStruct.HSI48MState = RCC_HSI48M_ON;
  •         RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  •         RCC_OscInitStruct.LSEDriver = RCC_LSEDRIVE_HIGH;
  •         RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  •         RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  •         RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  •         RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  •         RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  •         RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  •         HAL_RCC_OscConfig(&RCC_OscInitStruct);
  •        
  •         RCC_ClkInitTypeDef  RCC_ClkInitStruct;
  •         RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  •         RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  •         RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  •         RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  •         RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  •         HAL_RCC_ClockConfig(&RCC_ClkInitStruct, 5);
  •        
  •         SystemCoreClockUpdate();
  • }

  • static void xprintf_out_port(int ch)
  • {
  •     uint8_t val = ch;
  •     uart_send(0,&val,1);
  • }

  • static int xprintf_in_port(void)
  • {
  •     uint32_t len;
  •     uint8_t val;
  •     do
  •     {
  •         len = uart_read(0,&val,1);
  •     }while(len == 0);
  •     return val;
  • }


  • static void shell_task(void *arg)
  • {   
  •     (void)arg;
  •           xprintf("shell task start.\r\n");
  •        
  •     while(1)
  •     {
  •         shell_e x e c();
  •         vTaskDelay((1*1000/configTICK_RATE_HZ));
  •     }
  • }

  • uint32_t shell_read(uint8_t *buff, uint32_t len)
  • {
  •         return uart_read(0,buff,len);
  • }

  • void shell_write(uint8_t *buff, uint32_t len)
  • {
  •         uart_send(0,buff,len);
  • }

  • static void shell_task_init(void)
  • {
  •                 TaskHandle_t xHandle;
  •     xdev_out(xprintf_out_port);
  •     xdev_in(xprintf_in_port);
  •     shell_set_itf(shell_read, shell_write, (shell_cmd_cfg*)g_shell_cmd_list_ast, 1);
  •     /* 创建任务,执行shell */
  •           xTaskCreate( shell_task, "shell", 512, NULL, 1, &xHandle );
  • }

  • int main(void)
  • {
  •         HAL_Init();
  •         clk_init();
  •         clk_out();
  •         uart_init(0,115200);
  •         uart_init(1,115200);
  •         shell_task_init();
  •        
  •         vTaskStartScheduler();
  • }
  • </pre>
  • 复制代码

    输入help可以看到支持的命令

    image.png

    五. 总结

    以上我们移植了标准输入输出实现xprintf,以及简单的shell,可以方便的进行打印调试,命令行交互。