Implementation method of open source serial port oscilloscope for embedded microcontroller

Share an open source QT serial port oscilloscope, which is completely open source and supports serial port, TCP, waveform display, and communication protocols.

Sailor Project function description

picture

Serial port debugging assistant function

  • Supports the basic sending and receiving functions of the traditional serial port debugging assistant, and can refresh a large amount of data without lagging.

  • Supports saving received data

  • Supports the setting of up to 200 editable instructions and is used for multiple sendings

  • Support timer sending

  • Support newline character replacement timestamp function

  • Supports more Chinese encoding formats

  • It is worth noting that it supports simple serial port debugging on Linux

  • Support loading csv table data to 200 editable instructions

  • Supports saving and restarting recovery of some window configurations (provided you do not delete the configuration file)

Instructions

Note that QT's built-in text display window will cause software lag after loading a large amount of data. The current solution is to set a display buffer. During the data refresh phase (i.e., the serial port receiving data phase), if you need to maintain the refresh state (i.e., real-time Display the received data), only the contents of the display buffer are displayed. You can use the mouse to move the scroll bar up to stop data refresh. At the same time, when you move the scroll bar up to a certain extent, all data will start to be loaded. If you want to To trigger real-time refresh of data status, just move the scroll bar to the lowest end and ensure that data is received.

Since the saved data is the data of the display interface, if it is in the refresh state, all data cannot be saved. The correct way is to close the serial port, move the scroll bar to the top, load all the data, and then save the window data.

TCPServer interface

picture

picture

picture

picture

picture

SEASKY serial communication protocol

The communication method is a serial port, configured with a baud rate of 115200, 8 data bits, 1 stop bit, no hardware flow control, and no parity bit.

1. Communication protocol format

Frame header Equipment type Device ID Data ID end of frame
protocol_header(4-byte) equipment_type(2-byte) equipment_id (2-byte) data_id(2-byte) frame_tail(2-byte, CRC16, whole packet check)

2. Detailed definition of frame header

picture

3. Serial communication protocol

int parse_protocol(protocol_struct* pProtocol,uint16_t parseDataLen)
{
    //解析数据,使用前需提前缓冲 pProtocol->message_st.pData
    int ret = -1;
    uint16_t pos_offset;
    frame_struct* pFrameStruct = &pProtocol->frame_st;
    message_struct* pMessageStruct = &pProtocol->message_st;
    if (check_protocol_heade(pMessageStruct->pData) == PROTOCOL_RESULT_OK)
    {
        //更新帧头数据
        pFrameStruct->header.sof            = pMessageStruct->pData[0];
        //获取data段的数据长度
        pFrameStruct->header.data_length    = (pMessageStruct->pData[2] << 8) | (pMessageStruct->pData[1]);
        pFrameStruct->header.crc_check      = pMessageStruct->pData[3];
        //获取此次数据包长度
        pMessageStruct->data_len = pFrameStruct->header.data_length + PROTOCOL_DATA_OFFSET + 2;
        //计算解析后得到的 data_union 数据长度
        pFrameStruct->frame_user.cmd_data.data_len = (pFrameStruct->header.data_length) / sizeof(data_union);
        if(pMessageStruct->data_len<=parseDataLen)
        {
            if (pMessageStruct->data_len <= pMessageStruct->max_data_len)
            {
                if(CRC16_Check_Sum(&pMessageStruct->pData[0], pMessageStruct->data_len) != 0)
                {
                    pFrameStruct->frame_user.equipment_type = (pMessageStruct->pData[5]<<8) | (pMessageStruct->pData[4]);
                    pFrameStruct->frame_user.equipment_id   = (pMessageStruct->pData[7] << 8) | (pMessageStruct->pData[6]);
                    pFrameStruct->frame_user.data_id        = (pMessageStruct->pData[9] << 8) | (pMessageStruct->pData[8]);
                    //拷贝 data段 指定长度数据
                    ret = (int)memcpy(&pFrameStruct->frame_user.cmd_data.pData[0], &pMessageStruct->pData[PROTOCOL_DATA_OFFSET], pFrameStruct->header.data_length);
                    pos_offset = pFrameStruct->header.data_length + PROTOCOL_DATA_OFFSET;
                    pFrameStruct->frame_tail = (pMessageStruct->pData[pos_offset+1] << 8) | (pMessageStruct->pData[pos_offset]);
                    return PROTOCOL_RESULT_OK;
                }
                else
                {
                    //待解析BUFF超过预定解析数据容量,避免内存越界
                    PROTOCOL_ERROR_PRINTF("parse_protocol->>CRC16_Check_Sum err!\n");
                    return PROTOCOL_RESULT_CHECK_FRAME_ERR;
                }
            }
            else
            {
                //待解析BUFF超过预定解析数据容量,避免内存越界
                PROTOCOL_ERROR_PRINTF("parse_protocol->>data_len[%d] > max_data_len[%d]!\n",
                    pMessageStruct->data_len,
                    pMessageStruct->max_data_len);
                return PROTOCOL_RESULT_OUT_OF_LEN;
            }
        }
        else
        {
            //通过包头计算,还未收到完整的数据包
//            PROTOCOL_ERROR_PRINTF("parse_protocol->>data_len[%d] > max_data_len[%d]!\n",
//                pMessageStruct->data_len,
//                pMessageStruct->max_data_len);
            return PROTOCOL_RESULT_OUT_OF_LEN;
        }
    }
    else
    {
        //待解析BUFF超过预定解析数据容量,避免内存越界
        PROTOCOL_ERROR_PRINTF("parse_protocol->>check_protocol_heade err!\n");
        return PROTOCOL_RESULT_CHECK_HEAD_ERR;
    }
    PROTOCOL_DEBUG_PRINTF("parse_protocol->>check_protocol_heade ok!\n");
    return PROTOCOL_RESULT_ERR;
}

Software screenshot

picture

picture

picture

picture

Project open source address:

https://github.com/SEASKY-Master/vSailorProject

Guess you like

Origin blog.csdn.net/weixin_41114301/article/details/133198155