目录
9.00 uC/Modbus程序流程
本节描述了由Modbus通道接收和响应的消息所采取的途径。每个通道包含4个缓存区以及用于管理这些缓存区的变量,如图9-1所示。
图9-1,uC/Modbus Buffer管理
9.01 uC/Modbus-S,ASCII Rx与Tx
遵循以下提供的代码可能是有用的。
MB_CommRxTxISR_Handler() – mb_bsp.c
UART上接收的字符由MB_CommRxTxISR_Handler()处理,除非UART的Rx和Tx分别有单独的中断。这种情况下,函数将调用MB_CommRxISR_Handler()。从UART提取已接收的字符并传递给MB_RxByte()进行处理。
MB_RxByte() – mb.c
MB_RxByte()决定接收的字符需要传递给ASCII还是RTU进行处理。如果是ASCII,字符将传递给MB_ASCII_RxByte()。
MB_ASCII_RxByte() – mb.c
MB_ASCII_RxByte()将接收到的字符放置到 .RxBuf[]。如果接收的字符是“冒号”(即,‘:’),会将指针复位为 .RxBuf[]头部,因为这表示接到了主机的新消息。如果接收到的是“换行”(即,0x0A),将会通知Rx Task,接收的消息发往与通道匹配的节点地址。通过调用MB_OS_RxSignal() (mb_os.c)通知任务。
MB_OS_RxTask() – mb_os.c
所有的Modbus通信都由一个名为MB_OS_RxTask()的Rx任务来处理。该任务等待MB_ASCII_RxByte()向其发送消息。消息实际上是一个指向接收到消息的Modbus通道的指针。MB_OS_RxTask()调用MB_RxTask() (mb.c)进而调用MBS_RxTask() (mbs_core.c)。MBS_RxTask()决定消息是ASCII或RTU消息,并调用MBS_ASCII_Task() (mbs_core.C)或MBS_RTU_Task() (mbs_core.C),分别对接收到的消息进行实际处理。
MBS_ASCII_Task() – mbs_core.c
此时,我们收到了一条来自Modbus主机的消息,该消息指向通道的节点地址。但是,我们不知道消息是否有效。MBS_ASCII_Task()调用MB_ASCII_Rx() (mb.c)将ASCII格式转换为二进制格式。转换后的消息存放在.RxFrameData[]中。
MBS_ASCII_Task()然后调用MB_ASCII_RxCalcLRC()确定接收到的作为消息一部分的LRC是否与计算的LRC一致。注意,LRC是通过将接收到的消息中除冒号外的所有ASCII字符相加来计算的,LRC与CR/LF然后进行两个补充。也就是,LRC仅包含由Modbus主机发送的节点地址、功能码与数据。
如果有一个有效的消息,然后调用MBS_FCxx_Handler()解析接收的消息并向主机返回应答。
应答通过MB_ASCII_Tx()发送到主机。
MBS_FCxx_Handler() – mbs_core.c
此函数通过查看接收消息中的“功能码”来确定主机的内容,从而调用相应的Modbus功能码处理函数:MBS_FC??_???()。应答已二进制格式存放在.TxFrameData[]缓存中。
MB_ASCII_Tx() – mb.c
当需要向Modbus主机发送应答时调用该函数。MB_ASCII_Tx()将存放在.TxFrameData[]中的应答转换为ASCII。转换后的数据存放在.TxBuf[]中。
通过调用MB_ASCII_TxCalcLRC()来计算传出帧的LRC。注意,LRC是通过将接收到的消息中除冒号外的所有ASCII字符相加来计算的,LRC与CR/LF然后进行两个补充。也就是,LRC仅包含发送给Modbus主机的节点地址、功能码与数据。
MB_ASCII_Tx()然后调用MB_Tx()设置发送。
MB_Tx() – mb.c
通过调用该函数向Modbus主机发送消息。在这里,我们只是将 .TxBufPtr指向 .TxBuf[]的起始位置,通过调用MB_TxByte()(mb.c)传输第一个字节来“启动”传输中断。注意,在多数情况下,传输中断仅在一个字符传输完成后发生。
MB_TxByte() – mb.c
MB_TxByte()转而调用MB_CommTx1() (mb_bsp.c),后者向UART发送一个字节并使能Tx中断。
9.02 uC/Modbus-S,RTU Rx与Tx
遵循以下提供的代码可能是有用的。
MB_CommRxTxISR_Handler() – mb_bsp.c
UART上接收的字节由MB_CommRxTxISR_Handler()处理,除非UART的Rx和Tx分别有单独的中断。这种情况下,函数将调用MB_CommRxISR_Handler()。从UART提取已接收的字节并传递给MB_RxByte()进行处理。
MB_RxByte() – mb.c
MB_RxByte()决定接收的至字节需要传递给ASCII还是RTU进行处理。如果是ASCII,字符将传递给MB_RTU_RxByte()。
MB_RTU_RxByte() – mb.c
MB_RTU_RxByte()将接收到的字节放入 .RxBuf[]。因为在RTU模式中,帧分割是通过时间实现的,MB_RTU_RxByte()会重置通道的RTU定时器,表示还未收到帧结束标志。接收的字节存放在接收缓存.RxBuf[]中。完整帧的信号通过该通道的RTU计时器超时来完成(请参阅通信中的MB_RTU_TmrUpdate())。
MB_OS_RxTask() – mb_os.c
所有的Modbus通信都由一个名为MB_OS_RxTask()的Rx任务来处理。该任务等待RTU定时器发出的指示已接收到完整帧的消息。消息实际上是一个指向接收到消息的Modbus通道的指针。MB_OS_RxTask()调用MB_RxTask() (mb.c)进而调用MBS_RxTask() (mbs_core.c)。MBS_RxTask()决定消息是ASCII或RTU消息,并调用MBS_ASCII_Task() (mbs_core.C)或MBS_RTU_Task() (mbs_core.C),分别对接收到的消息进行实际处理。
MBS_RTU_Task() – mbs_core.c
此时,我们收到了一条来自Modbus主机的消息,该消息指向通道的节点地址。但是,我们不知道消息是否有效。MBS_RTU_Task()调用MB_RTU_Rx() (mb.c)将接收的数据从.RxBuf[]中复制到.RxFrameData[]中。
MBS_RTU_Task()然后调用MB_RTU_RxCalcLRC()确定接收到的作为消息一部分的CRC是否与计算的CRC一致。注意,CRC是通过将接收到的消息中除CRC本身的所有字节进行CRC计算得到的,也就是,CRC仅包含由Modbus主机发送的节点地址、功能码与数据。
如果有一个有效的消息,然后调用MBS_FCxx_Handler()解析接收的消息并向主机返回应答。
应答通过MB_RTU_Tx()发送到主机。
MBS_FCxx_Handler() – mbs_core.c
此函数通过查看接收消息中的“功能码”来确定主机的内容,从而调用相应的Modbus功能码处理函数:MBS_FC??_???()。应答已二进制格式存放在.TxFrameData[]缓存中。
MB_RTU_Tx() – mb.c
当需要向Modbus主机发送应答时调用该函数。MB_RTU_Tx()将存放在.TxFrameData[]中的应答复制到.TxBuf[]中。
通过调用MB_RTU_TxCalcCRC()来计算传出帧的CRC。注意,CRC是通过将接收到的消息中除CRC本身的所有字节进行CRC计算得到的,也就是,CRC仅包含发送到Modbus主机的节点地址、功能码与数据。
MB_RTU_Tx()然后调用MB_Tx()设置发送。
MB_Tx() – mb.c
通过调用该函数向Modbus主机发送消息。在这里,我们只是将 .TxBufPtr指向 .TxBuf[]的起始位置,通过调用MB_TxByte()(mb.c)传输第一个字节来“启动”传输中断。注意,在多数情况下,传输中断仅在一个字符传输完成后发生。
MB_TxByte() – mb.c
MB_TxByte()转而调用MB_CommTx1() (mb_bsp.c),后者向UART发送一个字节并使能Tx中断。
9.03 uC/Modbus-M,ASCII Rx与Tx
遵循以下提供的代码可能是有用的。
MBM_FC??_????() – mbm_core.c
Modbus主机应用调用MBM_FC??_????()向从机发送命令。该函数生成一个命令帧,通过调用MBM_TxCmd()发送。
MBM_TxCmd() – mbm_core.c
该函数根据主机通道配置为ASCII或RTU分别调用MB_ASCII_Tx() 或 MB_RTU_Tx()。
MB_ASCII_Tx() – mb.c
在ASCII模式,调用该函数将命令发送至Modbus从机。MB_ASCII_Tx()将.TxFrameData[]中的命令转换为ASCII格式,转换后的数据存储在.TxBuf[]中。
通过调用MB_ASCII_TxCalcLRC()来计算传出帧的LRC。注意,LRC是通过将接收到的消息中除冒号外的所有ASCII字符相加来计算的,LRC与CR/LF然后进行两个补充。也就是,LRC仅包含由Modbus主机发送的节点地址、功能码与数据。
MB_ASCII_Tx()然后调用MB_Tx()设置传输。
MB_Tx() – mb.c
调用该函数向Modbus从机发送消息。在这里,我们只是将 .TxBufPtr指向 .TxBuf[]的起始位置,通过调用MB_TxByte()(mb.c)传输第一个字节来“启动”传输中断。注意,在多数情况下,传输中断仅在一个字符传输完成后发生。
MB_TxByte() – mb.c
MB_TxByte()转而调用MB_CommTx1() (mb_bsp.c),后者向UART发送一个字节并使能Tx中断。
MB_OS_Wait() – mb_os.c
命令发送完成后,MBM_FC??_???()调用MB_OS_Wait()等待从机的应答,后者会附带一个超时时间。如果超时时间(见MB_CfgCh())内未接收到应答将会刷新Rx缓存区。如果接收到应答,将调用MBM_RxReply()处理应答。
MB_CommRxTxISR_Handler() – mb_bsp.c
UART上接收的字符由MB_CommRxTxISR_Handler()处理,除非UART的Rx和Tx分别有单独的中断。这种情况下,函数将调用MB_CommRxISR_Handler()。从UART提取已接收的字符并传递给MB_RxByte()进行处理。
MB_RxByte() – mb.c
MB_RxByte()决定接收的字符需要传递给ASCII还是RTU进行处理。如果是ASCII,字符将传递给MB_ASCII_RxByte()。
MB_ASCII_RxByte() – mb.c
MB_ASCII_RxByte()将接收到的字符放置到 .RxBuf[]中。如果接收的字符是“冒号”(即,‘:’),会将指针复位为 .RxBuf[]头部,因为这表示接到了主机的新消息。如果接收到的是“换行”(即,0x0A)表示应答接收完成,将会调用MB_OS_RxSignal() (mb_os.c),将唤醒向从机发送命令的任务,MBM_FC??_???()函数将恢复(在B_OS_RxWait()调用之后)。
MBM_RxReply() – mbm_core.c
MBM_RxReply()确定通道被配置为ASCII或RTU并分别调用MB_ASCII_Rx()或MB_RTU_Rx()接收数据包。
MB_ASCII_Rx() – mb.c
MB_ASCII_Rx()确定接收到的数据包是否包含正确的格式和校验和。如果接收到有效的数据包,MB_ASCII_Rx()返回到MBM_RxReply()然后返回至MBM_FC??_???()函数。
MBM_FC??_???() – mbm_core.c
MBM_FC??_???()解析应答并向调用方返回请求的信息。
9.04 uC/Modbus-M,RTU Rx与Tx
遵循以下提供的代码可能是有用的。
MBM_FC??_????() – mbm_core.c
Modbus主机应用调用MBM_FC??_????()向从机发送命令。该函数生成一个命令帧,通过调用MBM_TxCmd()发送。
MBM_TxCmd() – mbm_core.c
该函数根据主机通道配置为ASCII或RTU分别调用MB_ASCII_Tx() 或 MB_RTU_Tx()。
MB_RTU_Tx() – mb.c
需要向Modbus从机发送命令时调用该函数。MB_RTU_Tx()将.TxFrameData[]中的命令复制到.TxBuf[]中。
通过调用MB_RTU_TxCalcCRC()来计算传出帧的CRC。注意,CRC是通过将接收到的消息中除CRC本身的所有字节进行CRC计算得到的,也就是,CRC仅包含发送到Modbus主机的节点地址、功能码与数据。
MB_RTU_Tx()然后调用MB_Tx()设置传输。
MB_Tx() – mb.c
调用该函数向Modbus从机发送消息。在这里,我们只是将 .TxBufPtr指向 .TxBuf[]的起始位置,通过调用MB_TxByte()(mb.c)传输第一个字节来“启动”传输中断。注意,在多数情况下,传输中断仅在一个字符传输完成后发生。
MB_TxByte() – mb.c
MB_TxByte()转而调用MB_CommTx1(),后者向UART发送一个字节并使能Tx中断。
MB_OS_Wait() – mb_os.c
命令发送完成后,MBM_FC??_???()调用MB_OS_Wait()等待从机的应答,后者会附带一个超时时间。如果超时时间(见MB_CfgCh())内未接收到应答将会刷新Rx缓存区。如果接收到应答,将调用MBM_RxReply()处理应答。
MB_CommRxTxISR_Handler() – mb_bsp.c
UART上接收的字符由MB_CommRxTxISR_Handler()处理,除非UART的Rx和Tx分别有单独的中断。这种情况下,函数将调用MB_CommRxISR_Handler()。从UART提取已接收的字符并传递给MB_RxByte()进行处理。
MB_RxByte() – mb.c
MB_RxByte()决定接收的字符需要传递给ASCII还是RTU进行处理。如果是RTU,字符将传递给MB_RTU_RxByte()。
MB_RTU_RxByte() – mb.c
MB_RTU_RxByte()将接收到的字符放置到 .RxBuf[]中。因为在RTU模式中,帧分割是通过时间实现的,MB_RTU_RxByte()会重置通道的RTU定时器,表示还未收到帧结束标志。接收的字节存放在接收缓存.RxBuf[]中。完整帧的信号通过该通道的RTU计时器超时来完成(请参阅mb.c中的MB_RTU_TmrUpdate())。
MBM_RxReply() – mbm_core.c
MBM_RxReply()确定通道被配置为ASCII或RTU并分别调用MB_ASCII_Rx()或MB_RTU_Rx()接收数据包。
MB_RTU_Rx() – mb.c
MB_RTU_Rx()确定接收到的数据包是否包含正确的格式和校验和。如果接收到有效的数据包,MB_RTU_Rx()返回到MBM_RxReply()然后返回至MBM_FC??_???()函数。
MBM_FC??_???() – mbm_core.c
MBM_FC??_???()解析应答并向调用方返回请求的信息。
10.00首字母缩写、缩写和助记符
uC/Modbus包含一些首字母缩写,缩写和助记符,如表10-1。
This … |
Means … |
An |
Analog |
App |
Application |
Buf |
Buffer |
Cfg |
Configuration |
Ch |
Channel |
Comm |
Communication |
Ctr |
Counter |
DI |
Discrete Input |
Dis |
Disable |
DO |
Discrete Output |
En |
Enable |
Err |
Error |
FC |
Function Code |
FP |
Floating Point |
Id |
Identifier |
In |
Input |
Init |
Initialization |
ISR |
Interrupt Service Routine |
Ix |
Index |
MB |
Modbus |
MBM |
Modbus Master |
MBS |
Modbus Slave |
Nbr |
Number |
OS |
Operating System |
Out |
Output |
Pkt |
Packet |
Prio |
Priority |
Rd |
Read |
Reg |
Register |
RTU |
Remote Terminal Unit |
Rx |
Receive |
Stk |
Stack |
Tmr |
Timer |
Tx |
Transmit |
Val |
Value |
Wr |
Write |