0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

modbus在rtthread上的應(yīng)用

CHANBAEK ? 來源:小陳學不停 ? 作者:小陳學不停 ? 2023-01-12 16:45 ? 次閱讀

1 背景
最近有一個modbus通信協(xié)議的需求,借此機會總結(jié)一下modbus在rtthread上的應(yīng)用。

2 RS485
2.1 簡介
RS485通信接口一般應(yīng)用在物聯(lián)網(wǎng)自動化場景,只有2根線,工作在半雙工模式。

圖片

2.2 與RS232對比

圖片

2.3 正點原子開發(fā)板上的應(yīng)用電路

圖片

RS485低電平是接收模式,高電平是發(fā)送模式,在發(fā)送函數(shù)中發(fā)送之前切換為發(fā)送狀態(tài),發(fā)送完后切換為接收狀態(tài)

3 modbus
3.1 1.5T和3.5T
modbus協(xié)議規(guī)定字節(jié)間隔為1.5個字符,幀間隔為3.5個字符若串口通信參數(shù)設(shè)置為(注:開始位固定為1):數(shù)據(jù)位8,奇偶校驗位1,停止位1,波特率9600bps,
則傳輸一個字符(即1個字節(jié))的時間為:(1+8+1+1)/9600=0.00114583s=1.1454583ms
1.5字符間隔=1.5x1.1454583ms=1.71818745ms
3.5字符間隔=3.5x1.1454583ms=4.00910405ms

38400bps,則傳輸一個字符(即1個字節(jié))的時間為:
(1+8+1+1)/38400=0.00028645=0.286ms
1.5字符間隔=1.5x0.286ms=0.4ms
3.5字符間隔=3.5x0.286ms=1ms

3.2 libmodbus
libmodbus是一個基于C語言實現(xiàn)的Modbus驅(qū)動庫,作者是Stephane,支持Linux, Mac OS X, FreeBSD, QNX and Win32操作系統(tǒng),主要應(yīng)用在PC上,用來開發(fā)上位機,也可以對源代碼進行交叉編譯,以適配更多的平臺,比如ARM Linux。 源代碼開源,遵循 LGPL-2.1 許可。

4 相關(guān)代碼
該版本不需要支持select和poll機制
4.1 宏定義
#define _RESPONSE_TIMEOUT 500000
#define _BYTE_TIMEOUT 5000
#define HAVE_DECL_TIOCM_RTS 1

4.2 初始化

int rc = 0; 
    uint8_t mb_reply[MODBUS_TCP_MAX_ADU_LENGTH];
    uint16_t tab_reg[64] = {0};
    char dev_name[32] ="/dev/uart2";
    
    #ifndef RT_USING_POSIX_STDIO
        sprintf(dev_name,"%s","uart2");
    #endif
    
    ctx = modbus_new_rtu(dev_name, 115200, 'N', 8, 1);
    rt_kprintf("ctx =[%x]\\n",ctx);
    modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
    modbus_rtu_set_rts(ctx, RS485_RE, MODBUS_RTU_RTS_UP);
    modbus_set_slave(ctx, CONFIG_SLAVE_ID); /* 設(shè)置從機地址 */
    modbus_set_debug(ctx,1);
    modbus_set_response_timeout(ctx, 0, 1000000);
    mb_mapping = modbus_mapping_new(0, 0, CONFIG_REG_HOLD_MAX, 0);
    if (mb_mapping == RT_NULL)
    {
        rt_kprintf("modbus_mapping_new failed! \\n");
        modbus_free(ctx);
        return;
    }

    mb_mapping->tab_registers[0] = 'R';
    mb_mapping->tab_registers[1] = 'T';
    mb_mapping->tab_registers[2] = '-';
    mb_mapping->tab_registers[3] = 'T';
    mb_mapping->tab_registers[4] = 'h';
    mb_mapping->tab_registers[5] = 'r';
    mb_mapping->tab_registers[6] = 'e';
    mb_mapping->tab_registers[7] = 'a';
    mb_mapping->tab_registers[8] = 'd';
    mb_mapping->tab_registers[0x0b] = 0x1234;
    #ifndef RT_USING_POSIX_STDIO
    rt_sem_init(&ctx->rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    #endif
    modbus_connect(ctx);
    int num = 0;

4.3 接收處理
_modbus_receive_msg
兼容了兩種不同的方式

4.3.1 方式1 檢查串口隊列是否有數(shù)據(jù)或者是否滿
select實際上是讓線程進入睡眠,直到有事件響應(yīng)就喚醒,同時檢查串口隊列中是否有數(shù)據(jù)。
4.3.1.1 接收處理函數(shù)

int rc;
    #ifdef RT_USING_POSIX_STDIO
    fd_set rset;
    #else
    uint8_t *rset;
    #endif
    struct timeval tv;
    struct timeval *p_tv;
    int length_to_read;
    int msg_length = 0;
    _step_t step;


    if (ctx->debug) {
        if (msg_type == MSG_INDICATION) {
            rt_kprintf("Waiting for a indication...\\n");
        } else {
            rt_kprintf("Waiting for a confirmation...\\n");
        }
    }

    /* Add a file descriptor to the set */
    #ifdef RT_USING_POSIX_STDIO
    FD_ZERO(&rset);
    FD_SET(ctx->s, &rset);
    #endif

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_SLAVE_ID;

    length_to_read = ctx->backend->header_length + 1;

    if (msg_type == MSG_INDICATION) 
    {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } 
    else 
    {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }

     length_to_read = ctx->backend->header_length + 1;


    if (msg_type == MSG_INDICATION) {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } else {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }


    while (length_to_read != 0) 
    {
        uint32_t get_tick = rt_tick_get();

        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);

        rt_kprintf("takes ms=[%d]\\n",rt_tick_get() - get_tick);

        if (rc == -1) 
        {
            _error_print(ctx, "select");

            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) 
            {
                int saved_errno = errno;


                if (errno == ETIMEDOUT) {
                    _sleep_response_timeout(ctx);
                    modbus_flush(ctx);
                } else if (errno == EBADF) {
                    modbus_close(ctx);
                    modbus_connect(ctx);
                }
                errno = saved_errno;
            }

            return -1;
        } 

        rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);

        if (rc == 0) 
        {
            errno = ECONNRESET;
            rc = -1;
        }


        if (rc == -1) {
            _error_print(ctx, "read");
            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
                (errno == ECONNRESET || errno == ECONNREFUSED ||
                 errno == EBADF)) {
                int saved_errno = errno;
                modbus_close(ctx);
                modbus_connect(ctx);
                /* Could be removed by previous calls */
                errno = saved_errno;
            }
            return -1;
        }


        /* Display the hex code of each character received */
        if (ctx->debug) {
            int i;
            for (i=0; i < rc; i++)
                printf("<%.2X>", msg[msg_length + i]);
        }
        
        /* Sums bytes received */
        msg_length += rc;
        /* Computes remaining bytes */
        length_to_read -= rc;

        if (length_to_read == 0) 
        {
            switch (step) 
            {
            case _STEP_SLAVE_ID:
            {
                if (CONFIG_SLAVE_ID != msg[0])
                {
                    break;  
                }
                else
                {
                    step = _STEP_FUNCTION;
                }
            }
            case _STEP_FUNCTION:
            {
                length_to_read = compute_meta_length_after_function(
                    msg[ctx->backend->header_length],
                    msg_type);
                if (length_to_read != 0) {
                    step = _STEP_META;
                } /* else switches straight to the next step */
            }
            break;

            case _STEP_META:
                length_to_read = compute_data_length_after_meta(
                    ctx, msg, msg_type);
                if ((msg_length + length_to_read) > (int)ctx->backend->max_adu_length) {
                    errno = EMBBADDATA;
                    _error_print(ctx, "too many data");
                    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }


        if (length_to_read > 0 &&
            (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
            /* If there is no character in the buffer, the allowed timeout
               interval between two consecutive bytes is defined by
               byte_timeout */
            tv.tv_sec = ctx->byte_timeout.tv_sec;
            tv.tv_usec = ctx->byte_timeout.tv_usec;
            p_tv = &tv;
        } 
        /* else timeout isn't set again, the full response must be read before
           expiration of response timeout (for CONFIRMATION only) */
    }

    if (ctx->debug)
        rt_kprintf("\\n");

    return ctx->backend->check_integrity(ctx, msg, msg_length);

4.3.1.2從串口設(shè)備讀數(shù)據(jù)

4.3.1.2 從串口設(shè)備讀數(shù)據(jù)_modbus_rtu_recv
#if defined(_WIN32)
    return win32_ser_read(&((modbus_rtu_t *)ctx->backend_data)->w_ser, rsp, rsp_length);
#else
#ifdef RT_USING_POSIX_STDIO
        return read(ctx->s, rsp, rsp_length);
#else
        return rt_device_read(ctx->dev, 0,rsp, rsp_length);
#endif

4.3.1.3 檢查串口隊列

int poll_get(modbus_t *ctx)
{
    int mask = 0;
            rt_base_t level;
            struct rt_serial_rx_fifo* rx_fifo;

            //rt_poll_add(&(device->wait_queue), req);
        struct rt_serial_device *serial; 
        serial = (struct rt_serial_device *)ctx->dev;

            rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx;


            level = rt_hw_interrupt_disable();
            if ((rx_fifo->get_index != rx_fifo->put_index) || (rx_fifo->get_index == rx_fifo->put_index && rx_fifo->is_full == RT_TRUE))
            {
              mask = 1;
            } 

            rt_hw_interrupt_enable(level);
              
    return mask;
}


static int _modbus_rtu_select(modbus_t *ctx, void *rset,
                              struct timeval *tv, int length_to_read)
{
    int s_rc;
#if defined(_WIN32)
    s_rc = win32_ser_select(&((modbus_rtu_t *)ctx->backend_data)->w_ser,
                            length_to_read, tv);
    if (s_rc == 0) {
        errno = ETIMEDOUT;
        return -1;
    }


    if (s_rc < 0) {
        return -1;
    }
#else
#ifdef RT_USING_POSIX_STDIO
    fd_set *new_rset = (fd_set *)rset;
    while ((s_rc = select(ctx->s+1, new_rset, NULL, NULL, tv)) == -1) {
        if (errno == EINTR) {
            if (ctx->debug) {
                fprintf(stderr, "A non blocked signal was caught\\n");
            }
            /* Necessary after an error */
            FD_ZERO(new_rset);
            FD_SET(ctx->s, new_rset);
        } else {
            return -1;
        }
    }


#else
    uint32_t msec = 0;

    if (tv)
    {
        msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
    }
    else
    {
        msec = 1000;
    }

    uint32_t ms_delay_ivt = 10;

    uint32_t get_tick = rt_tick_get();

    if (msec < ms_delay_ivt)
    { 
        ms_delay_ivt = msec;
    }

    while (1)
    {
        s_rc = poll_get(ctx); 

        if ((s_rc) || ((rt_tick_get() - get_tick)>msec))
        {
            break;  
        }
        rt_thread_mdelay(ms_delay_ivt); 
    } 
#endif 
    if (s_rc == 0) 
    {
        /* Timeout */
        errno = ETIMEDOUT;
        return -1;
    }
#endif

4.3.2 方式2
4.3.2.1 直接等待接收數(shù)據(jù)
不使用先select后rec的方式,而是直接等待接收串口數(shù)據(jù)

int rc;
    #ifdef RT_USING_POSIX_STDIO
    fd_set rset;
    #else
    uint8_t *rset;
    #endif
    struct timeval tv;
    struct timeval *p_tv;
    int length_to_read;
    int msg_length = 0;
    _step_t step;


    if (ctx->debug) {
        if (msg_type == MSG_INDICATION) {
            rt_kprintf("Waiting for a indication...\\n");
        } else {
            rt_kprintf("Waiting for a confirmation...\\n");
        }
    }

    /* Add a file descriptor to the set */
    #ifdef RT_USING_POSIX_STDIO
    FD_ZERO(&rset);
    FD_SET(ctx->s, &rset);
    #endif

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_SLAVE_ID;

    length_to_read = ctx->backend->header_length + 1;

    if (msg_type == MSG_INDICATION) 
    {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } 
    else 
    {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }

     length_to_read = ctx->backend->header_length + 1;


    if (msg_type == MSG_INDICATION) {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } else {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }


    while (length_to_read != 0) 
    {


          uint32_t msec = 0;

           if (p_tv)
          {
            msec = (p_tv->tv_sec * 1000) + (p_tv->tv_usec / 1000);
          } 
          else
          {
             msec = 500; 
          } 
            uint32_t i = 0; 
            uint32_t tick = rt_tick_get(); 
            while (rt_tick_get() <= (tick + rt_tick_from_millisecond(msec)) && i < (length_to_read))
            {
                i += _rym_read_data(ctx, msg + msg_length,length_to_read);
                //rt_thread_mdelay(5);
            }

            rt_kprintf("i=%d\\r\\n",i);
            rc = i;  

        if (rc == 0) 
        {
            errno = ECONNRESET;
            rc = -1;
        }


        if (rc == -1) {
            _error_print(ctx, "read");
            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
                (errno == ECONNRESET || errno == ECONNREFUSED ||
                 errno == EBADF)) {
                int saved_errno = errno;
                modbus_close(ctx);
                modbus_connect(ctx);
                /* Could be removed by previous calls */
                errno = saved_errno;
            }
            return -1;
        }


        /* Display the hex code of each character received */
        if (ctx->debug) {
            int i;
            for (i=0; i < rc; i++)
                printf("<%.2X>", msg[msg_length + i]);
        }


        /* Sums bytes received */
        msg_length += rc;
        /* Computes remaining bytes */
        length_to_read -= rc;

        if (length_to_read == 0) 
        {
            switch (step) 
            {
            case _STEP_SLAVE_ID:
            {
                if (CONFIG_SLAVE_ID != msg[0])
                {
                    break;  
                }
                else
                {
                    step = _STEP_FUNCTION;
                }
            }
            case _STEP_FUNCTION:
            {
                length_to_read = compute_meta_length_after_function(
                    msg[ctx->backend->header_length],
                    msg_type);
                if (length_to_read != 0) {
                    step = _STEP_META;
                } /* else switches straight to the next step */
            }
            break;

            case _STEP_META:
                length_to_read = compute_data_length_after_meta(
                    ctx, msg, msg_type);
                if ((msg_length + length_to_read) > (int)ctx->backend->max_adu_length) {
                    errno = EMBBADDATA;
                    _error_print(ctx, "too many data");
                    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }


        if (length_to_read > 0 &&
            (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
            /* If there is no character in the buffer, the allowed timeout
               interval between two consecutive bytes is defined by
               byte_timeout */
            tv.tv_sec = ctx->byte_timeout.tv_sec;
            tv.tv_usec = ctx->byte_timeout.tv_usec;
            p_tv = &tv;
        } 
        /* else timeout isn't set again, the full response must be read before
           expiration of response timeout (for CONFIRMATION only) */
    }

    if (ctx->debug)
        rt_kprintf("\\n");

    return ctx->backend->check_integrity(ctx, msg, msg_length);

4.3.2.2 超時等待接收

static rt_size_t _rym_read_data(modbus_t *ctx,rt_uint8_t *buf,rt_size_t len)
{
    /* we should already have had the code */ 
    rt_size_t readlen = 0;


    do
    {
        readlen += rt_device_read(ctx->dev,
                                  0, buf + readlen, len - readlen);
        if (readlen >= len)
            return readlen;
    }
    while (rt_sem_take(&ctx->rx_sem, 5) == RT_EOK);


    return readlen;
}

4.4 應(yīng)用部分

while (1)
    {
        if (0 == send_type)
        {
            rc = modbus_receive(ctx, mb_reply);

            if (rc > 0)
            {
                modbus_reply(ctx, mb_reply, rc, mb_mapping);
                uint8_t idx=0;
                rt_kprintf("check [",mb_mapping->tab_registers[0x0b]);
                for(idx=0; idx<0xFC; idx++)
                {
                    rt_kprintf("[%04x] ",mb_mapping->tab_registers[idx]);

                    if (idx%16==0)
                    {
                       rt_kprintf("\\n");
                    }
                }
                rt_kprintf("]\\n");
           }
        }
        else
        {
            memset(tab_reg, 0, 64 * 2);
            int regs = modbus_read_registers(ctx, 0, 20, tab_reg);
            rt_kprintf("[%4d][read num = %d]", num, regs);
            num++;
            int i;
            for (i = 0; i < 20; i++)
            {
                rt_kprintf("<%#x>", tab_reg[i]);
            }
            rt_kprintf("\\n");
            rt_thread_mdelay(2000);
        }
    }
    modbus_close(ctx);
    modbus_free(ctx);
}


static int rtu_test_init(void)
{
    rt_pin_mode(RS485_RE, PIN_MODE_OUTPUT);
    rt_thread_t tid;
    tid = rt_thread_create("mb_test",
                           mb_slave_thread, RT_NULL,
                           2048,
                           12, 10);
    if (tid != RT_NULL)
        rt_thread_startup(tid);


    return RT_EOK;
}


INIT_APP_EXPORT(rtu_test_init);


int cmd_modbus_send(int argc, char **argv)
{
        uint16_t set_addr = strtoul(argv[1], 0, 16); 
        uint16_t set_data = strtoul(argv[2], 0, 16); 

        send_type = 1;

         //int 
        int res = modbus_write_register(ctx, set_addr,set_data);

        rt_kprintf("res = [%d]\\n",res);


    return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_modbus_send, mod,mod [addr][data]);

5 測試
5.1 從機測試
5.1.1 上位機
使用modbus poll上位機進行測試,從機地址是0x30,讀取保持寄存器地址是0x100,個數(shù)是100

圖片

圖片

5.1.2 日志

Sending request using RTS signal
check [[0052] 
[0054] [002d] [0054] [0068] [0072] [0065] [0061] [0064] [0000] [0000] [1234] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] 
[0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] [0000] ]
Waiting for a indication...
takes ms=[710]
takes ms=[0]
takes ms=[0]
<30><03><01><00><00><64><41><30><03><01><00><00><64><41>
[30][03][C8][00][52][00][54][00][2D][00][54][00][68][00][72][00][65][00][61][00][64][00][00][00][00][12][34][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][00][F2][BC]
Sending request using RTS signal

5.2 主機測試
5.2.1 上位機
使用Modbus Slave上位機,從機地址是0x30,讀取保持寄存器地址是0,個數(shù)是20

圖片

圖片

5.2.2 日志

rst rc=[20]
[ 629][read num = 20]<1><100><3><4><5><6><7><8><9><77><0><0><0><0><0><0><0><0><0>
[30][03][00][00][00][14][41][E4]
Sending request using RTS signal
Waiting for a confirmation...
takes ms=[237]
takes ms=[0]
takes ms=[1]
<00><61><30><03><28><00><01><01><00><00><03><00><04><00><05><00><06><00><07><00><08><00><09><00><0A><00><7B><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><72>
rst rc=[20]
[ 630][read num = 20]<1><100><3><4><5><6><7><8><9><7b><0><0><0><0><0><0><0><0><0>
[30][03][00][00][00][14][41][E4]
Sending request using RTS signal
Waiting for a confirmation...
takes ms=[226]
takes ms=[0]
takes ms=[1]
<30><03><28><00><01><01><00><00><03><00><04><00><05><00><06><00><07><00><08><00><09><00><0A><00><80><00><00><00><00><00><00><00>
rst rc=[20]
[ 631][read num = 20]<1><100><3><4><5><6><7><8><9><80><0><0><0><0><0><0><0><0><0>
[30][03][00][00][00][14][41][E4]
Sending request using RTS signal
Waiting for a confirmation...
takes ms=[227]
takes ms=[0]
<00><00><00><00><00><00><00><00><00><00><00><30><03><28>takes ms=[0]
<00><01><01><00><00><03><00><04><00><05><00><06><00><07><00><08><00><09><00><0A><00><84><00><00><00><00><00><00><00><00><00><00>
rst rc=[20]
[ 632][read num = 20]<1><100><3><4><5><6><7><8><9><84><0><0><0><0><0><0><0><0><0>
[30][03][00][00][00][14][41][E4]
Sending request using RTS signal
Waiting for a confirmation...
takes ms=[236]
takes ms=[0]
takes ms=[0]
<00><00><00><00><00><00><00><00><56><30><03><28><00><01><01><00><00><03><00><04><00><05><00><06><00><07><00><08><00><09><00><0A><00><89><00><00><00><00><00><00><00><00><00><00><00><00><00>
rst rc=[20]
[ 633][read num = 20]<1><100><3><4><5><6><7><8><9><89><0><0><0><0><0><0><0><0><0>

6 總結(jié)
6.1modbus的應(yīng)用場景非常廣泛,無論在哪個領(lǐng)域都會有它的身影,所以掌握它是很有必要的,還是需要多做點項目多應(yīng)用,多多刻意地練習。

6.2 主機模式下接收不穩(wěn)定,有時校驗不通過
看了下代碼,應(yīng)該是解碼方式的問題,后續(xù)再優(yōu)化一下解碼步驟

  • 通信協(xié)議
    +關(guān)注

    關(guān)注

    28

    文章

    810

    瀏覽量

    40120
  • RS485
    +關(guān)注

    關(guān)注

    39

    文章

    1127

    瀏覽量

    81768
  • MODBUS
    +關(guān)注

    關(guān)注

    28

    文章

    1718

    瀏覽量

    76419
  • RS232
    +關(guān)注

    關(guān)注

    13

    文章

    728

    瀏覽量

    93909
  • RTThread
    +關(guān)注

    關(guān)注

    7

    文章

    132

    瀏覽量

    40684
收藏 人收藏

    評論

    相關(guān)推薦

    使用rtthread移植qboot工程的學習筆記

    學習rtthread,配置qboot時的過程;記錄一下自己使用rtthread studio配置qboot和app工程的制作過程.
    的頭像 發(fā)表于 06-12 09:55 ?6815次閱讀
    使用<b class='flag-5'>rtthread</b>移植qboot工程的學習筆記

    RT-Thread Studio配置rtthread CANFD驅(qū)動來控制M3508電機

    本文旨在RT-Thread Studio配置rtthread CANFD驅(qū)動來控制M3508電機,不涉及任何原理 開發(fā)環(huán)境:RT-Thread Studio v2.2.6
    發(fā)表于 10-08 11:44 ?1072次閱讀
    <b class='flag-5'>在</b>RT-Thread Studio<b class='flag-5'>上</b>配置<b class='flag-5'>rtthread</b> CANFD驅(qū)動來控制M3508電機

    linux下搭建rtthread_qemu系統(tǒng)

    RT-Thread源碼的獲取方式有多種,可以是官網(wǎng)瀏覽器下載、云盤下載、git獲取,強烈推薦git,因為使用git可以很方便的切換各種版本的rtthread
    的頭像 發(fā)表于 11-21 14:40 ?1317次閱讀
    <b class='flag-5'>在</b>linux下搭建<b class='flag-5'>rtthread</b>_qemu系統(tǒng)

    介紹Modbus協(xié)議STM32平臺的移植

    協(xié)議STM32平臺的移植。1.1 freemodbus介紹??freemodbus是一個奧地利人寫的Modbus協(xié)議。它是一個針對嵌入式應(yīng)用的一個免費(自由)的通用MODBUS協(xié)議
    發(fā)表于 01-14 06:57

    rtthread-nano3.1.3添加pm組件FinSH控制臺就輸入不了怎么解決

    rtthread-nano3.1.3版本添加了pm組件,但是添加之后FinSH 控制臺就輸入不了了,未添加pm組件之前都是可以用的
    發(fā)表于 04-21 09:32

    rtthread smart可以使用device框架嗎

    rtthread smart發(fā)布出來很久了,一直沒時間玩,最近在rtthread開發(fā)使用device框架感覺太爽太省心了。然后突然想到,如果在rt smart跑同樣這套代碼,dev
    發(fā)表于 05-05 14:14

    介紹一個支持從主機的多實例modbus

    SMALL_MODBUS_PORT_H#define SMALL_MODBUS_PORT_H/**RTTHREAD PORT*/#define SMALL_MODBUS_RTTHREAD
    發(fā)表于 08-17 14:42

    有沒有哪位道友RTThread內(nèi)核移植modbus_tcp成功的啊

    有沒有哪位道友,成功的使用過agile_modbus協(xié)議棧的modbus_tcp啊,我看官方給的DEMO都是基于posix接口寫的,但是本人不太清除posix接口。有沒有哪位道友RTThre
    發(fā)表于 11-09 14:27

    Modbus TCPARM工控板的使用

    Modbus TCPARM工控板的使用 本文主要介紹ZLG/Modbus TCP 用戶接口及具體使用方法
    發(fā)表于 04-07 16:41 ?31次下載

    Modbus UARTARM工控板的使用

    Modbus UARTARM工控板的使用本文主要介紹ZLG/Modbus UART 用戶接口及具體使用方法
    發(fā)表于 04-07 16:44 ?71次下載

    Modbus TCPARM工控板的使用

    Modbus 協(xié)議是應(yīng)用于電子控制器的一種通用語言。Modbus/TCP 則是運行在TCP/IPModbus 報文傳輸協(xié)議。通過此協(xié)議
    發(fā)表于 07-19 15:03 ?256次下載

    RTThread操作系統(tǒng)的調(diào)度設(shè)計原理是怎樣的

    電子發(fā)燒友網(wǎng)站提供《RTThread操作系統(tǒng)的調(diào)度設(shè)計原理是怎樣的.pdf》資料免費下載
    發(fā)表于 11-26 17:24 ?26次下載
    <b class='flag-5'>RTThread</b>操作系統(tǒng)的調(diào)度設(shè)計原理是怎樣的

    華大單片機移植RTThread操作系統(tǒng)

    3.1.新建華大單片機最小系統(tǒng)工程模板,這里不展開3.2.Keil MDK加入Rtthread代碼3.3添加rtthread源碼到工程中3.4 添加完成的樣子3.5 移植后需要修改部分東西才能讓系統(tǒng)真正跑起來。。4.測試例子5
    發(fā)表于 11-17 17:21 ?51次下載
    華大單片機移植<b class='flag-5'>RTThread</b>操作系統(tǒng)

    rtthread套娃移植

    和大家分享下將基于rtthread的項目移植到其他平臺的經(jīng)驗。背景最近做了一個物聯(lián)網(wǎng)項目移植。原先的項目使用的硬件平臺為stm32f401+sim800c(mcu + 2G modem),軟件平臺為
    發(fā)表于 12-20 19:45 ?13次下載
    <b class='flag-5'>rtthread</b>套娃移植