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

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

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

基于serialX串口驅(qū)動(dòng)移植freemodbus

冬至子 ? 來源:出出啊 ? 作者:出出啊 ? 2023-10-13 14:54 ? 次閱讀

關(guān)于 serialX
之前,筆者寫過多篇 serialX 的文章,已經(jīng)把它的原理和理念完完全全明明白白講了,包括它的優(yōu)勢以及使用它需要注意的方面和可能遇到的問題。

到目前為止,筆者只介紹了 finsh/msh 使用 serialX ,實(shí)現(xiàn)了中斷接收中斷發(fā)送模式打開串口設(shè)備,這次嘗試讓筆者堅(jiān)信了即便使用 DMA 收發(fā)也能在 finsh 里應(yīng)付自如。今天我們嘗試一下在 freemodbus 里使用 serialX 。

注:筆者寫過文章,討論在控制臺(tái)或者 finsh 里完全的中斷收發(fā)或者完全的 DMA 收發(fā)會(huì)有哪些問題。有興趣的大家可以找找看。

測試環(huán)境
筆者手里有一塊兒 NK-980IOT V1.0 的開發(fā)板,這是去年 rt-thread 論壇搞的測評(píng)活動(dòng)送的。一方面,它吃灰很久了,另一方面,serialX 的驅(qū)動(dòng)很久沒新增了。趁此機(jī)會(huì),筆者把 NUC980 的 serialX 驅(qū)動(dòng)加上,然后在此基礎(chǔ)上調(diào)試出 console 和 finsh,最后移植 freemodbus 試試會(huì)遇到什么問題。

NUC980 serialX 驅(qū)動(dòng)
之前,筆者介紹 serialX 的時(shí)候,曾詳細(xì)的講解過 struct rt_uart_ops 接口中的每一個(gè)函數(shù)的功能。完全按照每一個(gè)函數(shù)功能定義去做,后面的事情就是水到渠成的。

花了小半天的時(shí)間從 drv_uart.c 改成 drv_uartX.c 。

然后使用 serialX 中提供的 測試程序 serialX_test.c 簡單測試了一下,收發(fā)回環(huán)沒發(fā)現(xiàn)嚴(yán)重問題(沒有數(shù)據(jù)丟失,沒有數(shù)據(jù)錯(cuò)誤)。

啟用控制臺(tái)和 finsh 。改成“中斷收發(fā)讀寫”模式,試了幾個(gè)命令,打印結(jié)果完整。

可以說,驗(yàn)證了這次寫的驅(qū)動(dòng)還是很不錯(cuò)的,是成功的。

啟用 freemodbus
env 環(huán)境里啟用 freemodbus,打開 modbus master 并添加 master 的測試程序。
使用命令 pkgs --update 下載 freemodbus 源碼。

打開項(xiàng)目后,我們可以看到 “sample_mb_master.c” “port” 開頭的以及幾個(gè) “mb” 開頭的?!眘ample_mb_master.c” 文件是測試樣例程序,”port” 開頭的文件是 freemodbus 在 rt-thread 系統(tǒng)上的接口,剩余的是 freemodbus 的核心程序。

這里面 “sample_mb_master.c” “portserial_m.c” 這兩個(gè)文件是今天我們最關(guān)心的。我們可以打開看看這倆文件都做了啥。

“sample_mb_master.c”
這個(gè)文件的主要工作是創(chuàng)建了兩個(gè)線程。

一個(gè)用來循環(huán)調(diào)用 eMBMasterPoll 函數(shù),這個(gè)函數(shù)是 freemodbus 工作引擎。不循環(huán)執(zhí)行這個(gè)函數(shù) freemodbus 跑不起來。

另一個(gè)模式應(yīng)用層線程,用來發(fā)送多寄存器寫請(qǐng)求(在這個(gè)樣例程序里只用這個(gè)來做演示)。

“portserial_m.c”
這個(gè)文件里是串口設(shè)備操作相關(guān)的。比如初始化、打開、關(guān)閉,寫數(shù)據(jù)到串口設(shè)備,從串口設(shè)備讀數(shù)據(jù)等等。

xMBMasterPortSerialInit
筆者第一次打開這個(gè)文件,滿眼看到的 serial->config. serial->ops->configure 等操作把我驚呆了。

初始化過程最后創(chuàng)建了子線程 serial_soft_trans_irq ,它的工作就是發(fā)送數(shù)據(jù)。

serial_soft_trans_irq
發(fā)送子線程入口函數(shù),這個(gè)函數(shù)只關(guān)心 EVENT_SERIAL_TRANS_START 事件,接收到事件后調(diào)用 xMBMasterRTUTransmitFSM 函數(shù),如果數(shù)據(jù)沒發(fā)送完,調(diào)用 xMBMasterPortSerialPutByte->xMBMasterPortSerialPutByte 往串口寫 1 個(gè)字節(jié)數(shù)據(jù)。循環(huán)執(zhí)行直到把所有需要發(fā)送的數(shù)據(jù)寫完。

第一次測試
經(jīng)過簡單瀏覽后,筆者想盡快運(yùn)行程序,做進(jìn)一步觀察。

計(jì)算機(jī)端,筆者用一個(gè) Qt5 寫的 modbus slave 終端。如果一切順利,NK-980IOT 開發(fā)板上發(fā)的多寄存器寫請(qǐng)求會(huì)對(duì) Qt5 modbus slave 終端里的數(shù)據(jù)修改,并界面上顯示到數(shù)據(jù)變化。

很幸運(yùn),筆者這一步也很順利。

進(jìn)一步測試
因?yàn)樽詭У?master 樣例程序僅僅測試了一個(gè)多寄存器寫,而且,我們可以看到原來只對(duì) eMBMasterReqWriteMultipleHoldingRegister 返回錯(cuò)誤代碼計(jì)數(shù),并沒有區(qū)分判斷會(huì)出現(xiàn)哪種錯(cuò)誤,我們把這個(gè)錯(cuò)誤碼處理一下

rt_uint32_t err_no = 0, err_reg = 0, err_arg = 0, err_data = 0, err_tout = 0;
switch (error_code) {
case MB_MRE_NO_ERR:
    err_no++;
break;
case MB_MRE_NO_REG:
    err_reg++;
break;
case MB_MRE_ILL_ARG:
    err_arg++;
break;
case MB_MRE_REV_DATA:
    err_data++;
break;
case MB_MRE_TIMEDOUT:
    err_tout++;
break;
default:
    rt_kprintf("n:%d; r:%d; a:%d; d:%d; t:%dn", err_no, err_reg, err_arg, err_data, err_tout);
break;
}

這幾種返回碼,只有 MB_MRE_NO_ERR 是正常和完美的,如果出現(xiàn)其它幾個(gè)都是有問題的。

筆者經(jīng)過關(guān)閉 slave 端,可以測試出現(xiàn) MB_MRE_TIMEDOUT 。但是,經(jīng)常還會(huì)出現(xiàn) MB_MRE_REV_DATA 這個(gè)錯(cuò)誤?。?!

MB_MRE_REV_DATA 錯(cuò)誤跟蹤
這個(gè)錯(cuò)誤字面含義是,有接收數(shù)據(jù),但是接收的數(shù)據(jù)有異常!我們上面的測試只有一個(gè)“多寄存器寫”,master 發(fā)寫請(qǐng)求了以后,只有可能收到成功響應(yīng)(MB_MRE_NO_ERR),或者錯(cuò)誤響應(yīng)信息(MB_MRE_NO_REG MB_MRE_ILL_ARG)。不應(yīng)該會(huì)出現(xiàn) slave 給 master 主動(dòng)發(fā)請(qǐng)求的。

為了觀察 slave 端接收和發(fā)送數(shù)據(jù),筆者計(jì)劃把 slave 端的調(diào)試打開,檢查一下它是不是回復(fù)響應(yīng)出現(xiàn)錯(cuò)誤了。

因?yàn)楣P者的 slave 端是 Qt 寫的,當(dāng)前使用的這個(gè) exe 是很久之前用 Qt5.9 版本編譯出來的。筆者需要重新編譯一下這個(gè) exe 程序(現(xiàn)在安裝的版本有 Qt5.12 Qt5.15 兩個(gè))。編譯出來新程序之后,筆者得到如下調(diào)試信息(無論是 Qt5.12 還是 Qt5.15),

qt.modbus.lowlevel: (RTU server) Received ADU: "01100000000408000f0049000200003574"
qt.modbus: (RTU server) Request PDU: 0x100000000408000f004900020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"
qt.modbus.lowlevel: (RTU server) Received ADU: "011000000004080013004b000200009175"
qt.modbus: (RTU server) Request PDU: 0x1000000004080013004b00020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"
qt.modbus.lowlevel: (RTU server) Received ADU: "011000000004080027004d000200006cb6"
qt.modbus: (RTU server) Request PDU: 0x1000000004080027004d00020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"

slave 斷得到了完整正確的 ADU,響應(yīng)的 ADU 也是正常的。接下來再回過頭看看開發(fā)板接收響應(yīng) ADU 時(shí)得到的數(shù)據(jù)是什么。
在 eMBMasterRTUReceive 函數(shù)體內(nèi) if 條件語句之前添加一句代碼 od_mem((unsigned int)ucMasterRTURcvBuf, (unsigned int)ucMasterRTURcvBuf + usMasterRcvBufferPos);。這句代碼將在控制臺(tái)打印輸出接收到的 ADU 。

筆者看到了很多 “01040004 70F9C1” “01040004 70F9F9” 或者其它數(shù)據(jù),但是正確的應(yīng)該是 “01100000 0004C1CA”,很多次才出現(xiàn)一次正確的。為什么從串口發(fā)出去的數(shù)據(jù)是正確的,能被遠(yuǎn)端正常接收,遠(yuǎn)端響應(yīng)回來的數(shù)據(jù)就出現(xiàn)接收錯(cuò)誤了?!

為了確定開發(fā)板和驅(qū)動(dòng)工作還是正常的,筆者又切換到 serialX 的測試程序,用收發(fā)回環(huán)測試一遍沒有問題,再測試 freemodbus 接收仍然異常!

修改 xMBMasterPortSerialInit
前邊筆者說過,當(dāng)看到 serial->config. serial->ops->configure 等操作時(shí)驚呆了。這一步,讓上帝的歸上帝吧。

serial_dev = rt_device_find(uart_name);
if(serial_dev == RT_NULL)
{
    /* can not find uart */
    return FALSE;
}
/* set serial configure parameter */
uart_conf.baud_rate = ulBaudRate;
/* set serial configure */
rt_device_control(serial_dev, RT_DEVICE_CTRL_CONFIG, &uart_conf);
/* open serial device */
if (!rt_device_open(serial_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)) {
    rt_device_set_rx_indicate(serial_dev, serial_rx_ind);
} else {
    return FALSE;
}

全局變量 static struct rt_serial_device *serial; 改成 static rt_device_t serial_dev = RT_NULL;。所有使用 serial 這個(gè)變量的地方全換成使用 serial_dev 。

這樣修改了以后,一切變得明朗了起來。

總結(jié)

除了上面提到的那個(gè)問題,筆者還遇到一種情況,slave 端接收串口數(shù)據(jù)經(jīng)常出現(xiàn)斷幀,而且字符接收間隔長達(dá) 10+ms 。這種情況,當(dāng)筆者將 rt_device_write(serial_dev, 0, pucByte, 1); 改成 rt_device_write(serial_dev, 0, pucByte, sz); 后得到解決。但是,之后再也沒復(fù)現(xiàn)。

得益于 serialX 的框架理念,我們可以從“一個(gè)字節(jié)一個(gè)字節(jié)的寫”提升到“寫一批字節(jié)”。而且放到發(fā)送緩存里的數(shù)據(jù),無論使用中斷發(fā)送還是 DMA 發(fā)送都不會(huì)對(duì)應(yīng)用層帶來任何壓力。

另一方面,讀 modbus ADU 的時(shí)候,其實(shí)也可以“讀一批字節(jié)”。不是一個(gè)字節(jié)中斷,read 一個(gè)字節(jié),下一個(gè)接收字節(jié)中斷,再 read 一個(gè)字節(jié)…

freemodbus 還有很多可圈可點(diǎn)的地方。但是拿它來驗(yàn)證 serialX 驅(qū)動(dòng)可能是最簡單的一個(gè)了。

最后,筆者把修改過后的 ‘portserial_m.c’ 文件上傳上來,但是請(qǐng)大家注意,不止這一個(gè)文件需要修改,但是其它修改都是因?yàn)檫@個(gè)文件引起的。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5253

    瀏覽量

    119206
  • 緩存器
    +關(guān)注

    關(guān)注

    0

    文章

    63

    瀏覽量

    11624
  • 串口驅(qū)動(dòng)
    +關(guān)注

    關(guān)注

    2

    文章

    81

    瀏覽量

    18503
  • FreeModbus
    +關(guān)注

    關(guān)注

    0

    文章

    16

    瀏覽量

    4413
  • serialX
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    799
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    單線串口共陰極LED驅(qū)動(dòng)控制電路—AiP1652

    單線串口共陰極LED驅(qū)動(dòng)控制電路—AiP1652
    的頭像 發(fā)表于 09-09 10:02 ?121次閱讀
    單線<b class='flag-5'>串口</b>共陰極LED<b class='flag-5'>驅(qū)動(dòng)</b>控制電路—AiP1652

    串口驅(qū)動(dòng)分析之serial driver

    前兩節(jié)我們介紹串口驅(qū)動(dòng)的框架和tty core部分。這節(jié)我們介紹和硬件緊密相關(guān)的串口驅(qū)動(dòng)部分。
    的頭像 發(fā)表于 09-04 14:23 ?119次閱讀
    <b class='flag-5'>串口</b><b class='flag-5'>驅(qū)動(dòng)</b>分析之serial driver

    基于STM32的E01和E01C驅(qū)動(dòng)移植

    移植到常見的MCU型號(hào)STM32F103C8T6,實(shí)現(xiàn)基本的無線通信。電腦端的串口調(diào)試助手操作和顯示數(shù)據(jù)收發(fā)。(可以稍加修改,適用于其他STM32系列的MCU)硬
    的頭像 發(fā)表于 08-30 12:35 ?132次閱讀
    基于STM32的E01和E01C<b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>移植</b>

    STC串口驅(qū)動(dòng)調(diào)試程序

    STC的串口驅(qū)動(dòng)調(diào)試程序。
    發(fā)表于 07-08 14:23 ?2次下載

    第二講:單片機(jī)STC89C52+RA8889驅(qū)動(dòng)控制彩屏 代碼移植介紹

    介紹51單片機(jī)如何移植RA8889的代碼進(jìn)行彩屏驅(qū)動(dòng)與控制
    的頭像 發(fā)表于 06-04 10:36 ?592次閱讀
    第二講:單片機(jī)STC89C52+RA8889<b class='flag-5'>驅(qū)動(dòng)</b>控制彩屏 代碼<b class='flag-5'>移植</b>介紹

    IAR for STM8做freemodbus,怎么都編譯不過去了?

    之前一直使用的是IAR for STM8開發(fā)平臺(tái)版本是6.1.6.1880, 可是最近做freemodbus,怎么都編譯不過去了!懷疑版本低還是庫函數(shù)加載的不對(duì)呢?
    發(fā)表于 05-11 06:18

    請(qǐng)問stm32cube ide如何編譯底層庫?

    把之前在mdk5中編譯正常的freemodbus 移植到 cube ide 后,無法編譯通過。 看debug 是 無法編譯m3的底層庫的方法。cmsis_gcc.h D
    發(fā)表于 04-10 07:35

    usb轉(zhuǎn)串口線怎么使用 usb轉(zhuǎn)串口串口轉(zhuǎn)usb的區(qū)別

    )進(jìn)行通信。因此,通過使用USB轉(zhuǎn)串口線,可以將現(xiàn)代計(jì)算機(jī)與串口設(shè)備連接起來,實(shí)現(xiàn)數(shù)據(jù)傳輸和通信。 在使用USB轉(zhuǎn)串口線之前,需要先安裝適當(dāng)?shù)?b class='flag-5'>驅(qū)動(dòng)程序。這些
    的頭像 發(fā)表于 01-22 14:56 ?3279次閱讀

    【AWTK開源智能串口屏方案】HMI端程序移植編譯及運(yùn)行

    本篇文章介紹一下AWTK開源智能串口屏方案的串口屏端(即HMI端)的編譯運(yùn)行步驟,并介紹如何將HMI端移植到Linux或STM32平臺(tái)或RTOS平臺(tái),以及如何配置資源文件。引言:AWTK-HMI
    的頭像 發(fā)表于 01-18 08:24 ?691次閱讀
    【AWTK開源智能<b class='flag-5'>串口</b>屏方案】HMI端程序<b class='flag-5'>移植</b>編譯及運(yùn)行

    移植uart驅(qū)動(dòng)至μc/cosIII中,PC串口無輸出顯示的原因?如何解決?

    剛接觸uc/cosIII,由于開發(fā)需要,有關(guān)驅(qū)動(dòng)移植的問題需向你們請(qǐng)教,希望能得到你們的幫忙,謝謝! 環(huán)境:win7 + IAR7.70.2 + Jlink + ADSP-CM408F-EZKIT
    發(fā)表于 01-11 08:12

    臺(tái)達(dá)串口DVP系列驅(qū)動(dòng)如何使用?

    詳細(xì)介紹如何使用臺(tái)達(dá)串口DVP系列驅(qū)動(dòng)
    發(fā)表于 12-29 11:06 ?0次下載

    如何將FreeMODBUS協(xié)議棧移植到AT32F43x單片機(jī)方法

    電子發(fā)燒友網(wǎng)站提供《如何將FreeMODBUS協(xié)議棧移植到AT32F43x單片機(jī)方法.pdf》資料免費(fèi)下載
    發(fā)表于 12-18 11:15 ?0次下載
    如何將<b class='flag-5'>FreeMODBUS</b>協(xié)議棧<b class='flag-5'>移植</b>到AT32F43x單片機(jī)方法

    如何將FreeMODBUS協(xié)議棧移植到AT32F43x單片機(jī)

    本應(yīng)用筆記介紹了如何將FreeMODBUS協(xié)議棧移植到AT32F43x單片機(jī)方法。本文檔提供的源代碼演示了使用Modbus的應(yīng)用程序。單片機(jī)作為Modbus從機(jī),可通過RS485或RS232與上位機(jī)相連,與Modbus Poll調(diào)試工具(Modbus主機(jī))進(jìn)行通訊。
    發(fā)表于 10-26 06:18

    STM32 USB虛擬串口驅(qū)動(dòng)

    電子發(fā)燒友網(wǎng)站提供《STM32 USB虛擬串口驅(qū)動(dòng).rar》資料免費(fèi)下載
    發(fā)表于 10-09 15:25 ?92次下載
    STM32 USB虛擬<b class='flag-5'>串口</b><b class='flag-5'>驅(qū)動(dòng)</b>

    freemodbus可用在主機(jī)上嗎?

    freemodbus可用在主機(jī)上么
    發(fā)表于 10-09 06:40