帖子太长,接着上一篇帖子:
串口助手测试modbus
(2)测试命令,测试读多个输入寄存器的值,即eMBFuncReadInputRegister 发送地址为:0A ,发送命令代码为04,寄存器开始地址为00 00 (GPIOA),寄存器个数为0001(GPIOA) 发送0a 04 00 00 00 01 30 B1,无反应,无任何数据返回。 看一下出现这个问题可能的原因。一是modbus接收不到数据帧,这个通过debug已经排除,可以接收到CRC验证码正确的数据帧,那么一定是modbus不能发送数据,先看看简单串口能不能发送数据,在main里通过USART1Write()进行测试发现发送没问题。 在上一节的分析可以看出,只有满足两个条件MB协议栈才可以返回数据,一是当接收的数据处理完调用了 eMBRTUSend(&STATE_RX_IDLE)—>STATE_TX_XMIT 使接收状态机进入STATE_TX_XMIT状态;二是 串口发送完成中断 ,从而调用发送状态机进行发送数据。那么先验证第一条,在eMBPoll:peMBFrameSendCur 位置设置断点,看看有没有调用 eMBRTUSend 。可以看到确实可以满足这一条件,由 eMBRTUSend 触发STATE_TX_XMIT状态。
排除了这一可能,会不会进不到 串口发送完成中断 中断呢?同样在中断函数中设置断点查看仿真结果。果然问题出现在无法进入中断语句去调用发送状态机,那么这个中断触发需要满足什么条件呢? //发生发送完成中断 if(USART_GetITStatus(USART1, USART_IT_TC) == SET) { prvvUARTTxReadyISR(); //清除中断标志 USART_ClearITPendingBit(USART1, USART_IT_TC); } 网上搜了一下,发现在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束。当USART_DR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,所有位发送结束时(送出停止位后)硬件会设置TC标志。 试试改成USART_IT_TXE这个标准来引发中断,果然就好用了! 发送0a 04 00 00 0001 30 B1,返回0A 04 02 00 00 1C F1 那么为什么可以进入USART_IT_TXE中断就不能进入USART_IT_TC中断呢? 原来在vMBPortSerialEnable中断控制使能函数中控制的是USART_ITConfig(USART1, USART_IT_TXE, ENABLE)这个中断,并不是USART_IT_TC这个中断,没有使能进了中断才怪呢。 究其USART_IT_TC,即Transmission Complete,需要先发送一个字节后才进入中断,这里称为“发送后中断”。原来是发送完数据引发中断去处理一些事情的意思,而USART_IT_TXE,即发送寄存器空中断,当使能TXEIE后,只要Tx DR空了,就会产生中断。所以,发送完字符串后必须关掉,否则会导致重复进入中断。这也是和TC不同之处。 数据是返回来了,但是读取GPIOA的数据怎么是全0呢,这显然不正确,再回到eMBRegInputCB()函数中去看一下,接收的地址怎么从1开始而不是设定的从0开始?去eMBFuncReadInputRegister看一下,原来不知道什么原因解析完地址以后出现了usRegAddress++,百度看别人也有类似的问题导致通信格式不正确,注释即可。 到这里关于freemodbus RTU在STM32上的移植就算结束了,移植的工作不多,但想把协议栈是如何工作的搞清楚需要花一点时间,本文如有错误和不妥的地方还希望请多交流指正。
|