目录
9.00 uC/Modbus程序流程
9.01 uC/Modbus-S,ASCII Rx与Tx
9.02 uC/Modbus-S,RTU Rx与Tx
9.03 uC/Modbus-M,ASCII Rx与Tx
9.04 uC/Modbus-M,RTU Rx与Tx
10.00首字母缩写、缩写和助记符
本节描述了由Modbus通道接收和响应的消息所采取的途径。每个通道包含4个缓存区以及用于管理这些缓存区的变量,如图9-1所示。
图9-1,uC/Modbus Buffer管理
遵循以下提供的代码可能是有用的。
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中断。
遵循以下提供的代码可能是有用的。
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中断。
遵循以下提供的代码可能是有用的。
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??_???()解析应答并向调用方返回请求的信息。
遵循以下提供的代码可能是有用的。
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??_???()解析应答并向调用方返回请求的信息。
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 |