嵌入式技术论坛
直播中

剑寒九州

8年用户 654经验值
私信 关注
[问答]

怎样能够让finsh调试串口和上位机通讯的串口进行共用呢

怎样能够让finsh调试串口和上位机通讯的串口进行共用,而不是通过输入特定指令进入通讯模式,大家做产品时都是怎么去协调的呢? RT-Thread串口终端finsh和用户自定义串口协议共用一个物理串口如何去实现呢?

回帖(9)

麻酱

2022-8-1 10:52:34
是因为板子串口资源不够吗?一般都会单独留出来一个串口作为控制台调试使用,如果实在不够用可以把Finsh控制台给关了,这样能多出来一个串口供用户使用,

Finsh 控制台线程的名字是 “tshell”,线程的处理函数名称为 finsh_thread_entry(),位置位于文件 rt-thread/components/finsh/shell.c 中。该线程处理函数的逻辑如下,阻塞的从串口设备中读取数据,读取到一行后从命令表中查找并执行相应的命令。

void finsh_thread_entry(void *parameter)
{
    ... ...
    while (1)
    {
        ch = (int)finsh_getchar();  // 从串口中读取数据,阻塞
        if (ch < 0)
        {
            continue;
        }
        ... ...
        /* handle end of line, break */
        if (ch == 'r' || ch == 'n')
        {
#ifdef FINSH_USING_HISTORY
            shell_push_history(shell);
#endif
            if (shell->echo_mode)
                rt_kprintf("n");
            msh_exec(shell->line, shell->line_position);    // 执行相应的命令
            rt_kprintf(FINSH_PROMPT);
            memset(shell->line, 0, sizeof(shell->line));
            shell->line_curpos = shell->line_position = 0;
            continue;
        }
        ... ...
    } /* end of device read */
}
如果非要实现用户串口和控制台串口共有的话可以考虑从这里面入手,比如说用户串口使用时有特殊的结尾字符,或者特殊的报头等情况,程序判断到特殊的报头或者报尾后执行用户的代码而不去执行相应的命令。
举报

剑寒九州

2022-8-1 10:52:47
感谢回复,经过一段时间的摸索,参考AT组件里面的写法,确实是可以实现的,具体重点部分代码附上:

/**
* @file app_factory_task.c
* @author your name (you@domain.com)
* @Brief
* @version 0.1
* @date 2022-03-20
*
* @copyright Copyright (c) 2022
*
*/
#define LOG_TAG                        "factory"
#define LOG_LVL                        LOG_LVL_INFO
#include
#include "app_factory_task.h"
#include
#include
#define FACTORY_ESC_KEY                0x1B
static rt_device_t console;
static struct rt_semaphore console_rx_notice;
static rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size) = RT_NULL;
static rt_uint16_t odev_oflag = 0;
static char console_getchar(void)
{
    char ch;
    rt_sem_take(&console_rx_notice, RT_WAITING_FOREVER);
    return ch;
}
static void console_putchar(char ch)
{
    rt_device_write(console, 0, &ch, 1);
}
static rt_err_t console_getchar_rx_ind(rt_device_t dev, rt_size_t size)
{
    rt_uint8_t ch;
    rt_size_t i;
    for (i = 0; i < size; i++)
    {
        /* read a char */
        if (rt_device_read(dev, 0, &ch, 1))
        {
            rt_sem_release(&console_rx_notice);
        }
    }
    return RT_EOK;
}
void factory_port_init(void)
{
    rt_base_t int_lvl;
    rt_sem_init(&console_rx_notice, "factory_rx", 0, RT_IPC_FLAG_FIFO);
    int_lvl = rt_hw_interrupt_disable();
    console = rt_console_get_device();
    if (console)
    {
        /* backup RX indicate */
        odev_rx_ind = console->rx_indicate;
        odev_oflag = console->open_flag;
        console->open_flag &= ~RT_DEVICE_FLAG_STREAM;
        rt_device_set_rx_indicate(console, console_getchar_rx_ind);
    }
    rt_hw_interrupt_enable(int_lvl);
}
void factory_port_deinit(void)
{
    rt_base_t int_lvl;
    rt_device_t console;
    int_lvl = rt_hw_interrupt_disable();
    console = rt_console_get_device();
    if (console && odev_rx_ind)
    {
        /* restore RX indicate */
        console->open_flag |= RT_DEVICE_FLAG_STREAM;
        rt_device_set_rx_indicate(console, odev_rx_ind);
    }
    rt_hw_interrupt_enable(int_lvl);
    rt_sem_detach(&console_rx_notice);
}
static void factory_cfg(int argc, char **argv)
{
    char ch;
    factory_port_init();
    rt_kprintf("======== Start to factory mode to config board ========n");
    rt_kprintf("Config software will control console. Press 'ESC' to exit.n");
    /* process user input */
    while (FACTORY_ESC_KEY != (ch = console_getchar()))
    {
        //TO DO parse the protocol for upper software
        console_putchar(ch);
    }
    factory_port_deinit();
}
MSH_CMD_EXPORT(factory_cfg, Factory mode to config board);
MSH_CMD_EXPORT_ALIAS(factory_cfg, P0, Factory mode to config board);
举报

剑寒九州

2022-8-1 10:53:08
一般都是单独拿出来一个串口做其他功能开发是吧,我是不太想去改动RT-Thread源码的东西
举报

麻酱

2022-8-1 10:53:15
通常是这么用的,也比较方便。
举报

剑寒九州

2022-8-1 10:53:23
还是打算用两个串口去实现好了,免得给自己制造更多的麻烦
举报

fansz

2022-8-1 10:53:30
如果是jlink仿真器可以开启jlink RTT打印 社区有软件包,可以不占用串口 用swd接口 速度比串口还快很多
举报

安德森大

2022-8-1 10:53:41
我想到的是通过协议格式区分,但应该会改动源码,楼上说的jlink rtt是个好主意
举报

laisvl

2022-8-1 10:53:53
之前我在nano上有这么用过,通过判断 自己的协议中是否包含了 “admin” 来切换到shell,默认使用自己的协议

if(huart==&PC_HUART)
{
    switch(ring->mode)
    {
        case MODE_SHELL:
            rt_sem_release(app_sem.shell_rx);
            break;
        case MODE_PROTOCOL:
            rt_sem_release(app_sem.PROTO_PC[0]);
            MidUart_put_char(ring,0);    //每帧后面补一个0
            if (!rt_strcmp((char*)&ring->buff[ring->head], ADMIN))
            {
                MID_USART_RingModeSet(MODE_SHELL);
            }               
            break;
    }
}
原理很简单,就是不给shell信号量就行了
举报

laisvl

2022-8-1 10:54:00
第二种方法:可以取消finsh线程的初始化,在特定的命令下才开启finsh的线程也行
举报

更多回帖

发帖
×
20
完善资料,
赚取积分