1 獲取組件代碼
-
直接通過(guò)env中
- github下載
2 導(dǎo)入
通過(guò)env導(dǎo)入將自動(dòng)添加文件错敢,組件代碼在RTT\components\net\freemodbus\modbus目錄下,可以直接使用斑司,而通過(guò)git下載的代碼需要手動(dòng)加入怯疤,首先進(jìn)入FreeModbus_Slave-Master-RTT-STM32-1.1\FreeModbus目錄却盘,modbus文件夾是協(xié)議相關(guān)文件,port文件夾是移植相關(guān)文件。還需要在rtconfig中添加配置
#define RT_USING_MODBUS
#define RT_MODBUS_MASTER_RTU //這里使用的是RTU
3 移植
目前使用stm32f103鉴竭,無(wú)需移植晤愧,之后更新補(bǔ)充該章節(jié)
3.1定時(shí)器
不同波特率定時(shí)時(shí)間計(jì)算:
1.freemodbus一幀的結(jié)束是通過(guò)串口3.5位傳輸?shù)臅r(shí)間來(lái)判斷的,當(dāng)串口的波特率大于19200時(shí)超時(shí)時(shí)間是固定為1750us大莫,當(dāng)串口通信的波特率小于等于19200時(shí),就有一個(gè)計(jì)算公式官份,用來(lái)計(jì)算超時(shí)時(shí)間只厘。
2.串口可以設(shè)置成以下模式
起始位1bit + 數(shù)據(jù)位8bit + 停止位1bit
起始位1bit + 數(shù)據(jù)位8bit + 停止位2bit
起始位1bit + 數(shù)據(jù)位8bit + 校驗(yàn)位1bit + 停止位1bit
起始位1bit + 數(shù)據(jù)位8bit + 校驗(yàn)位1bit + 停止位2bit
位數(shù)10 11 12 烙丛,取中間值11
3.5位時(shí)間的計(jì)算:1位傳輸時(shí)間是 1/BaudRate(s),1字節(jié)就是 11* 1/BaudRate(s) 羔味,定時(shí)器溢出時(shí)間3.511 1/BaudRate(s)河咽,轉(zhuǎn)成整數(shù)運(yùn)算711 1/BaudRate2(s)
定時(shí)配置是50us計(jì)一次數(shù),假設(shè)為X次赋元,則得出計(jì)算公式50X(us) = 711 1/BaudRate2(s)忘蟹,推出X = 7220000UL/BaudRate 2,將X設(shè)置到定時(shí)器的計(jì)數(shù)值搁凸,將定時(shí)器配置成50us計(jì)數(shù)一次,x50us就會(huì)溢出中斷媚值。
這里說(shuō)明一下在定時(shí)器初始化中超時(shí)時(shí)間計(jì)算的代碼
(50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1
其中usT35TimeOut50us變量由函數(shù)傳入,是由波特率計(jì)算出的超時(shí)時(shí)間护糖,單位是us褥芒,轉(zhuǎn)化成ms,除以1000嫡良,然后再轉(zhuǎn)化成街拍數(shù)锰扶,乘上 RT_TICK_PER_SECOND/1000,最后的+1是為了至少大于超時(shí)時(shí)間寝受,因?yàn)榍懊孓D(zhuǎn)化小數(shù)被去掉了的坷牛。
這里要注意一下是,如果RT_TICK_PER_SECOND最好是調(diào)高一些很澄,例程中給的是10000京闰。
4 使用
4.1 運(yùn)行協(xié)議棧
需要建立一個(gè)線程,下列例子是參考的例程代碼
#define thread_ModbusMasterPoll_Prio 9
static rt_uint8_t thread_ModbusMasterPoll_stack[512];
struct rt_thread thread_ModbusMasterPoll;
void thread_entry_ModbusMasterPoll(void* parameter)
{
eMBMasterInit(MB_RTU, 3, 115200, MB_PAR_EVEN);
eMBMasterEnable();
while (1)
{
eMBMasterPoll();
rt_thread_delay(1);
}
}
int main()
{
rt_thread_init(&thread_ModbusMasterPoll, "MBMasterPoll",
thread_entry_ModbusMasterPoll, RT_NULL, thread_ModbusMasterPoll_stack,
sizeof(thread_ModbusMasterPoll_stack), thread_ModbusMasterPoll_Prio,5);
rt_thread_startup(&thread_ModbusMasterPoll);
}
4.2 讀寫
4.2.1 freemodebus功能字說(shuō)明
4.2.2 讀寫API
函數(shù)均返回eMBMasterReqErrCode 類型數(shù)據(jù)甩苛,當(dāng)返回值等于MB_MRE_NO_ERR時(shí)則表示操作失敗
功能 | 保持寄存器API函數(shù) |
---|---|
單寫 | eMBMasterReqWriteHoldingRegister( 從機(jī)地址忙干,寄存器地址,無(wú)符號(hào)16位數(shù)據(jù)浪藻,超時(shí)時(shí)間); |
多寫 | eMBMasterReqWriteMultipleHoldingRegister(從機(jī)地址捐迫,寄存器地址,寫寄存器數(shù)爱葵,數(shù)據(jù)首地址施戴,超時(shí)時(shí)間) |
多讀 | eMBMasterReqReadHoldingRegister(從機(jī)地址,寄存器地址萌丈,讀取數(shù)量赞哗,超時(shí)時(shí)間) |
讀寫 | eMBMasterReqReadWriteMultipleHoldingRegister(從機(jī)地址,讀寄存器地址辆雾,讀寄存器數(shù)量肪笋,寫數(shù)據(jù)首地址,寫寄存器地址,寫寄存器數(shù)量藤乙,超時(shí)時(shí)間) |
功能 | 輸入寄存器API函數(shù) |
---|---|
多讀 | eMBMasterReqReadInputRegister(從機(jī)地址猜揪,讀寄存器地址,讀寄存器數(shù)量坛梁,超時(shí)時(shí)間) |
功能 | 線圈API函數(shù) |
---|---|
單寫 | eMBMasterReqWriteCoil(從機(jī)地址而姐,寫線圈地址,寫線圈數(shù)量划咐,超時(shí)時(shí)間) |
多寫 | eMBMasterReqWriteMultipleCoils(從機(jī)地址拴念,寫線圈起始地址,寫線圈數(shù)量褐缠,寫數(shù)據(jù)首地址政鼠,超時(shí)時(shí)間) |
多讀 | eMBMasterReqReadCoils(從機(jī)地址,讀線圈地址队魏,讀線圈數(shù)量缔俄,超時(shí)時(shí)間) |
功能 | 離散輸入API函數(shù) |
---|---|
多讀 | eMBMasterReqReadDiscreteInputs(從機(jī)地址,讀離散輸入地址器躏,讀離散輸入數(shù)量,超時(shí)時(shí)間) |
例如
//執(zhí)行
if(MB_MRE_NO_ERR == eMBMasterReqReadHoldingRegister(1,3,1,1))
//則串口輸出 01 03 00 03 00 01 74 0A
函數(shù)的超時(shí)時(shí)間是等待發(fā)送的時(shí)間蟹略,并不是發(fā)送完成等待應(yīng)答的時(shí)間登失,單位是毫秒
4.2.3 讀數(shù)據(jù)存儲(chǔ)
由user_mb_app_m.c和user_mb_app.c來(lái)管理,數(shù)據(jù)被分類保存在數(shù)組中挖炬。
從機(jī)默認(rèn)使用 一維數(shù)組 作為緩存區(qū)數(shù)據(jù)結(jié)構(gòu)揽浙,主機(jī)可以存儲(chǔ)所有網(wǎng)內(nèi)從機(jī)的數(shù)據(jù),所以主機(jī)采用 二維數(shù)組 對(duì)所有從機(jī)節(jié)點(diǎn)數(shù)據(jù)進(jìn)行存儲(chǔ)意敛。二維數(shù)組的列號(hào)代表寄存器馅巷、線圈及離散量地址,行號(hào)代表從機(jī)節(jié)點(diǎn)ID草姻,但需要做減一處理钓猬,例如usMRegHoldBuf[2][1]代表從機(jī)ID為 3,保持寄存器地址為 1 的從機(jī)數(shù)據(jù)撩独。
文件中的函數(shù)是協(xié)議內(nèi)部使用敞曹,并不是用來(lái)讀buffer的,也就如果需要讀buffer數(shù)據(jù)综膀,可以先這么處理:
讀從機(jī)地址為1.寄存器地址為3的數(shù)據(jù)
extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
rt_kprintf("Receive success reg %d",usMRegHoldBuf[0][3]);
4.3 使用例程
//main.c
#include <rtthread.h>
#include "user_mb_app.h"
#define thread_ModbusMasterPoll_Prio 9
#define thread_MDtest_Prio 10
static rt_uint8_t thread_ModbusMasterPoll_stack[512];
static rt_uint8_t thread_MDtest_stack[512];
struct rt_thread thread_ModbusMasterPoll;
struct rt_thread thread_MDtest;
void thread_entry_ModbusMasterPoll(void* parameter)
{
eMBMasterInit(MB_RTU, 3, 115200, MB_PAR_EVEN);
eMBMasterEnable();
while (1)
{
eMBMasterPoll();
rt_thread_delay(1);
}
}
USHORT usModbusUserData[10]={1,2,3,4,5,6,7,8,9,0};
UCHAR temp[2];
void mbMasterThreadEntry(void * para)
{
rt_thread_mdelay(5000);
while (1)
{
// if(MB_MRE_NO_ERR == eMBMasterReqReadInputRegister(1, 3, 2, 1)) //這里的超時(shí)時(shí)等待獲取信號(hào)量的時(shí)間 01 04 00 03 00 02 81 CB
// if(MB_MRE_NO_ERR == eMBMasterReqWriteHoldingRegister(1,3,usModbusUserData[0],1)) // 01 06 00 03 00 01 B8 0A
if(MB_MRE_NO_ERR == eMBMasterReqReadHoldingRegister(1,3,1,1))
{
//eMBMasterRegHoldingCB(temp,3,1,MB_REG_READ);
//rt_kprintf("Receive success reg 3= %d\n",((uint16_t)temp[0])<<8 + temp[1] );
extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
rt_kprintf("Receive success reg %d",usMRegHoldBuf[0][3]);
}
else
{
rt_kprintf(" poll failed\n");
}
rt_thread_mdelay(10000);
}
}
int main(void)
{
/* user app entry */
rt_thread_init(&thread_ModbusMasterPoll, "MBMasterPoll",
thread_entry_ModbusMasterPoll, RT_NULL, thread_ModbusMasterPoll_stack,
sizeof(thread_ModbusMasterPoll_stack), thread_ModbusMasterPoll_Prio,5);
rt_thread_startup(&thread_ModbusMasterPoll);
rt_thread_init(&thread_MDtest, "MBtest",
mbMasterThreadEntry, RT_NULL, thread_MDtest_stack,
sizeof(thread_MDtest_stack), thread_MDtest_Prio,5);
rt_thread_startup(&thread_MDtest);
return 0;
}
5 參考
https://blog.csdn.net/weixin_42867108/article/details/82227635
https://github.com/armink/FreeModbus_Slave-Master-RTT-STM32
https://blog.csdn.net/byxdaz/article/details/77979114
6 附件
度盤(nfjc)