Freemodbus通信,串口接收模式改为DMA接收模式。

本文介绍了如何将Freemodbus从机协议栈的串口接收模式由中断改为DMA,以解决大数据量传输时对MCU资源的浪费问题。通过对posterial.c、porttimer.c、mbrtu.c和port.h等文件的修改,实现了串口的DMA接收功能,并在定时器中断中进行超时判断和状态机切换。原有的发送和接收缓冲区使用了volatile关键字,通过标志位处理发送和接收冲突。
摘要由CSDN通过智能技术生成

相信老铁们,在实际项目开发中,当使用Freemodbus从机协议栈时,会遇到一个问题,就是网上大多数对于该协议栈的移植,在数据接收这块,使用的大都是串口中断接收模式。这样做会有一个问题,如果一条Modbus总线上有若干个从机,一个个从机接收到主机的数据请求时,返回的数据长度大于1kBytes,会有一个问题,总线上其他的从机都处于串口中断接收模式,这样的话,在这段时间内,其他的从机是处于忙碌状态。可想而知对于MCU的CPU是一种浪费。那么对于现在网上大家常用的stm32,大家在实际项目中,都有可能用到Modbus通信协议,要么是自己写,要么是移植人家的。我在实际项目总,为了省事,直接移植人家的freemodbus,做从机协议栈来使用。但是对它的数据接收模式做了一些修改,具体修改看下文代码。


 posterial.c文件:该文件实现对串口的底层配置和发送实现

/*
 * FreeModbus Libary: STM32 Port
 * Copyright (C) 2013 Armink <armink.ztl@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: portserial.c,v 1.60 2013/08/13 15:07:05 Armink $
 */
 
/* ----------------------- Platform includes --------------------------------*/ 
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"


/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
//static void prvvUARTRxISR(void);

/* -------------------------- golobal function ------------------------------*/
unsigned char * exportPoint(unsigned short * length);
void  MB_DMAchannelInit (void);

extern volatile UCHAR  ucRTUBuf[7*1024];

/* ----------------------- Start implementation -----------------------------*/
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
	
	if (xRxEnable)
	{	
		//USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_RXNE, ENABLE);
		SLAVE_RS485_RECEIVE_MODE;
	}
	else
	{
		SLAVE_RS485_SEND_MODE;
		//USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_RXNE, DISABLE);
	}
	if (xTxEnable)
	{
		USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_TXE, ENABLE);
	}
	else
	{
		USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_TXE, DISABLE);
	}
}

void vMBPortClose(void)
{
	USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_TXE | USART_IT_RXNE, DISABLE);
	USART_Cmd(MODBUS_RS485_SERIAL_PORT, DISABLE);
}

 
/* 默认一个从机 串口3 波特率可设置  奇偶检验可设置. */
BOOL 
xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
		eMBParity eParity)
{	
    OS_CPU_SR  cpu_sr;


	GPIO_InitTypeDef 					GPIO_InitStructure;
	USART_InitTypeDef 					USART_InitStructure;
    NVIC_InitTypeDef					NVIC_InitStructure;

	
	/* -------------------时钟初始化------------------------------------. */
	//RCC_APB2PeriphClockCmd(MODBUS_RS485_CONTRL_RCC, ENABLE);
	RCC_APB2PeriphClockCmd(MODBUS_PORT_SERIAL_RCC | 
	           MODBUS_RS485_CONTRL_RCC, ENABLE);
	
												
	/* -----------------------IO初始化---------------------------------. */
	
	/* USART1_TX -----.*/
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = MODBUS_PORT_SERIAL_TX_PIN;
	GPIO_Init(MODBUS_PORT_SERIAL_TX_GPIO,&GPIO_InitStructure);
	
	/* USART1_RX------.*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = MODBUS_PORT_SERIAL_RX_PIN;
	GPIO_Init(MODBUS_PORT_SERIAL_RX_GPIO, &GPIO_InitStructure);
	
	/* 配置485发送和接收模----------.*/
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = MODBUS_RS485_CONTRL_PIN;
	GPIO_Init(MODBUS_RS485_CONTRL_GPIO, &GPIO_InitStructure);
	 
	
	/* 串口初始化 ---------------. */
	USART_InitStructure.USART_BaudRate = ulBaudRate;

	switch (eParity)
	{
		case MB_PAR_NONE:  
		USART_InitStructure.USART_Parity = USART_Parity_No;
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;
		break;
		
		case MB_PAR_ODD:  
		USART_InitStructure.USART_Parity = USART_Parity_Odd;
		USART_InitStructure.USART_WordLength = USART_WordLength_9b;
		break;
		
		case MB_PAR_EVEN:  
		USART_InitStructure.USART_Parity = USART_Parity_Even;
		USART_InitStructure.USART_WordLength = USART_WordLength_9b;
		break;
		
		default:
		return FALSE;
	}

	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_HardwareFlowControl =
	USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	
	if (ucPORT != 1)
		return FALSE;
 
	OS_ENTER_CRITICAL();

	USART_Init(MODBUS_RS485_SERIAL_PORT, &USART_InitStructure);
	//USART_ITConfig(MODBUS_RS485_SERIAL_PORT, USART_IT_RXNE, ENABLE);
	USART_Cmd(MODBUS_RS485_SERIAL_PORT, ENABLE);
    USART_ClearFlag(MODBUS_RS485_SERIAL_PORT,USART_FLAG_TC);
    USART_DMACmd(MODBUS_RS485_SERIAL_PORT,USART_DMAReq_Rx,ENABLE);   

	 
		/* ------------------中断初始化-----------------------------
	*设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
	-----------------------------------------------------------. */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel = MB_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
    OS_EXIT_CRITICAL();

    MB_DMAchannelInit();
	
	return TRUE;
}

BOOL xMBPortSerialPutByte(CHAR ucByte)
{
	USART_SendData(MODBUS_RS485_SERIAL_PORT, ucByte);
	/* add by frank 2019 -3-11. */
	while(USART_GetFlagStatus(MODBUS_RS485_SERIAL_PORT, USART_FLAG_TC) == RESET){};
	return TRUE;
}

BOOL xMBP
### 回答1: FreemodbusFree Modbus)是一个开源的Modbus通信协议库,它提供了在嵌入式系统中实现Modbus通信协议的功能。DMA(Direct Memory Access)是一种用于数据传输的技术,通过DMA可以在不占用CPU资源的情况下实现高速数据传输。那么关于FreemodbusDMA接收,可以简单描述如下: 在使用Freemodbus中实现DMA接收的过程中,首先需要配置DMA通道,并将接收数据的缓冲区地址指定给DMA。当设备接收Modbus通信的数据时,数据会被直接传送到DMA所指定的缓冲区中。由于DMA的特性,数据传输过程中不需要CPU进行干预,可以充分利用CPU的空闲时间进行其他的任务处理。 在DMA接收数据后,我们可以通过相应的回调函数或中断来处理接收到的数据。可以根据需要解析Modbus通信协议的相关字段,以获取所需的数据内容。同时,还可以进一步处理和响应Modbus通信的命令。 使用FreemodbusDMA接收,可以有效提高数据传输的效率,减轻CPU的负担。同时,由于使用了硬件DMA传输数据,可以减少数据传输的延迟,提高数据接收的可靠性。 需要注意的是,在使用FreemodbusDMA接收时,需要了解并配置相关的硬件和参数,以确保数据的正确接收和处理。同时,还需要合理设计和布置系统资源,以充分发挥DMA技术的优势。 总而言之,FreemodbusDMA接收是一种在嵌入式系统中实现高效Modbus通信的方法。通过配置DMA通道,并指定接收缓冲区地址,可以实现无CPU干预的高速数据接收。这种方式可以提高系统的实时性和稳定性,适用于对数据传输效率和可靠性有较高要求的应用场景。 ### 回答2: Freemodbus是一种开源的Modbus通信协议栈,它能够在多种嵌入式系统上实现Modbus通信功能。DMA(直接内存访问)是一种特殊的数据传输方式,它可以实现数据的高效率传输,减轻CPU的负担。 在Freemodbus中使用DMA接收数据,需要首先配置DMA通道的参数。通过设置DMA的源地址、目标地址和数据长度等参数,将接收到的数据传输到指定的缓冲区中。接收到的数据可以是Modbus从机设备发送过来的Modbus数据帧。 在数据传输过程中,DMA控制器负责直接从外设读取数据,并将数据存储到指定的缓冲区中,而不需要CPU的介入。这样就能够实现数据的快速传输,提高系统的效率。 在Freemodbus中,通过配置串口的接收中断触发方式,当接收到完整的Modbus数据帧时,会触发DMA传输完成中断。在中断服务程序中,可以对接收到的数据进行处理,例如解析Modbus数据帧中的功能码和数据内容等。 使用DMA接收数据可以提高数据传输的效率,减少CPU的负担。在高速、大数据量的Modbus通信场景中,尤其适用。但需要注意的是,在使用DMA接收数据时,需要合理配置DMA的参数,确保数据传输的准确性和完整性。 总而言之,Freemodbus可以通过配置DMA实现数据的高速接收,提高系统的效率和性能。这为Modbus通信在嵌入式系统中的应用提供了更多的选择和改进的可能性。 ### 回答3: FreeModbus 是一种开源的 Modbus 通信协议栈,用于将数据在 Modbus 从站设备与主站设备之间进行传输和通信DMA(直接内存访问)是一种数据传输方式,允许在不使用 CPU 的情况下,将数据直接传输到内存中。 对于 FreeModbusDMA 接收是指在数据传输过程中,使用 DMA 控制器将接收到的数据直接传输到内存中,而无需 CPU 的干预。通过使用 DMA,可以显著提高数据传输的效率和速度,并减轻 CPU 的负担。 在 FreeModbus 中,DMA 接收需要进行一定的配置和设置。首先,需要配置 DMA 控制器以启用接收功能,并指定数据传输的源和目的地。然后,需要设置接收缓冲区的地址,并设置缓冲区的大小,以确保接收到的数据不会超出缓冲区的容量。 一旦 DMA 接收配置完成,当有数据从 Modbus 从站设备传输到主站设备时,DMA 控制器会自动将数据传输到指定的内存地址中。一旦数据传输完成,可以通过检查接收缓冲区中的数据来获取接收到的数据。 使用 DMA 接收可以有效地减少 CPU 在数据传输过程中的参与,提高整体系统的性能和效率。因此,在使用 FreeModbus 进行通信时,使用 DMA 接收是一种值得考虑的方法。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值