- /*
- * FreeModbus Libary: BARE Port
- * Copyright (C) 2006 Christian Walter <wolti@sil.at>
- *
- * 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$
- */
- #ifndef _PORT_H
- #define _PORT_H
- #include <assert.h>
- #include <inttypes.h>
- #define INLINE inline
- #define PR_BEGIN_EXTERN_C extern "C" {
- #define PR_END_EXTERN_C }
- // 关全局中断
- #define ENTER_CRITICAL_SECTION() __asm volatile ("cpsid i" : : : "memory")
- // 开全局中断
- #define EXIT_CRITICAL_SECTION() __asm volatile ("cpsie i" : : : "memory")
- typedef uint8_t BOOL;
- typedef unsigned char UCHAR;
- typedef char CHAR;
- typedef uint16_t USHORT;
- typedef int16_t SHORT;
- typedef uint32_t ULONG;
- typedef int32_t LONG;
- #ifndef TRUE
- #define TRUE 1
- #endif
- #ifndef FALSE
- #define FALSE 0
- #endif
- /*------------------------------------USART相关宏定义-------------------------------*/
- #define MODBUS_USART_PORT USART1
- #define MODBUS_USART_IRQn USART1_IRQn
- #define MODBUS_USART_IRQHandler USART1_IRQHandler
- #define MODBUS_USART_PERIPH DDL_RCM_APB_PERIPHERAL_USART1
- #define MODBUS_USART_CLOCK_API DDL_RCM_EnableAPBPeripheral
- #define MODBUS_USART_GPIO_PERIPH DDL_RCM_AHB_PERIPHERAL_GPIO
- #define MODBUS_USART_GPIO_CLOCK_API DDL_RCM_EnableAHBPeripheral
- #define MODBUS_USART_TX_PORT GPIOB
- #define MODBUS_USART_TX_PIN DDL_GPIO_PIN_9
- #define MODBUS_USART_TX_AF DDL_GPIO_AF_0
- #define MODBUS_USART_RX_PORT GPIOB
- #define MODBUS_USART_RX_PIN DDL_GPIO_PIN_6
- #define MODBUS_USART_RX_AF DDL_GPIO_AF_0
- #define MODBUS_USART_DE_PORT GPIOB
- #define MODBUS_USART_DE_PIN DDL_GPIO_PIN_11
- #define MODBUS_USART_DE_AF DDL_GPIO_AF_1
- /*------------------------------------TIMER相关宏定义-------------------------------*/
- #define MODBUS_TIME_PORT TMR1
- #define MODBUS_TIME_IRQn TMR1_IRQn
- #define MODBUS_TIME_IRQHandler TMR1_IRQHandler
- #define MODBUS_TIME_PERIPH DDL_RCM_APB_PERIPHERAL_TMR1
- #define MODBUS_TIME_CLOCK_API DDL_RCM_EnableAPBPeripheral
- extern void __myaeabi_assert(const char *expr, const char *file, int line);
- #define myassert(e) ((e) ? (void)0 : __myaeabi_assert(#e, __FILE__, __LINE__))
- #endif
2.串口移植
- /*
- * FreeModbus Libary: BARE Port
- * Copyright (C) 2006 Christian Walter <wolti@sil.at>
- *
- * 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$
- */
- #include "port.h"
- #include "main.h"
- /* ----------------------- Modbus includes ----------------------------------*/
- #include "mb.h"
- #include "mbport.h"
- /* ----------------------- static functions ---------------------------------*/
- static void prvvUARTTxReadyISR( void );
- static void prvvUARTRxISR( void );
- static void MODBUS_USART_IRQHandler(void);
- /* ----------------------- Start implementation -----------------------------*/
- void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
- {
- /* If xRXEnable enable serial receive interrupts. If xTxENable enable
- * transmitter empty interrupts.
- */
- /* If xRXEnable enable serial receive interrupts. If xTxENable enable
- * transmitter empty interrupts.
- */
-
- if (xRxEnable)
- {
- DDL_USART_EnableIT_RXNE(MODBUS_USART_PORT);//使能接收中断
- DDL_USART_ClearFlag_RXNE(MODBUS_USART_PORT);//清除中断标志
- }
- else
- {
- DDL_USART_DisableIT_RXNE(MODBUS_USART_PORT);//失能接收中断;
- }
-
- if (xTxEnable)
- {
- DDL_USART_EnableIT_TC(MODBUS_USART_PORT);//使能发送中断
- DDL_USART_ClearFlag_TC(MODBUS_USART_PORT);//清除中断标志
- }
- else
- {
- DDL_USART_DisableIT_TC(MODBUS_USART_PORT);//失能发送中断
- }
- }
- void vMBPortClose( void )
- {
- DDL_USART_Disable(MODBUS_USART_PORT); //关闭usart
- }
- BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
- {
- DDL_GPIO_InitTypeDef GPIO_InitStruct = {0U};
- DDL_USART_InitTypeDef USART_InitStruct = {0U};
- /* 配置时钟 */
- DDL_RCM_Unlock();
- MODBUS_USART_CLOCK_API(MODBUS_USART_PERIPH);
- MODBUS_USART_GPIO_CLOCK_API(MODBUS_USART_GPIO_PERIPH);
- DDL_RCM_Lock();
- /* MODBUS_USART_PORT 配置接收发送引脚*/
- GPIO_InitStruct.Pin = MODBUS_USART_TX_PIN;
- GPIO_InitStruct.Mode = DDL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = DDL_GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.OutputType = DDL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = DDL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = MODBUS_USART_TX_AF;
- DDL_GPIO_Init(MODBUS_USART_TX_PORT, &GPIO_InitStruct);
-
- GPIO_InitStruct.Pin = MODBUS_USART_RX_PIN;
- GPIO_InitStruct.Mode = DDL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = DDL_GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.OutputType = DDL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = DDL_GPIO_PULL_NO;
- GPIO_InitStruct.Alternate = MODBUS_USART_RX_AF;
- DDL_GPIO_Init(MODBUS_USART_RX_PORT, &GPIO_InitStruct);
-
- /* MODBUS_USART_PORT DE*/
- GPIO_InitStruct.Pin = MODBUS_USART_DE_PIN;
- GPIO_InitStruct.Mode = DDL_GPIO_MODE_ALTERNATE;
- GPIO_InitStruct.Speed = DDL_GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.OutputType = DDL_GPIO_OUTPUT_PUSHPULL;
- GPIO_InitStruct.Pull = DDL_GPIO_PULL_UP;
- GPIO_InitStruct.Alternate = MODBUS_USART_DE_AF;
- DDL_GPIO_Init(MODBUS_USART_DE_PORT, &GPIO_InitStruct);
- /* MODBUS_USART_PORT 配置 */
- USART_InitStruct.BaudRate = ulBaudRate;
- if (eParity == MB_PAR_NONE)
- {
- USART_InitStruct.Parity = DDL_USART_PARITY_NONE; //不进行奇偶位检测
- }
- else if (eParity == MB_PAR_EVEN)
- {
- USART_InitStruct.Parity = DDL_USART_PARITY_EVEN; //进行偶位检测
- }
- else
- {
- USART_InitStruct.Parity = DDL_USART_PARITY_ODD; //进行奇位检测
- }
-
- if (ucDataBits == 9)
- {
- USART_InitStruct.DataWidth = DDL_USART_DATAWIDTH_9B; //发送数据为9位
- }
- else
- {
- USART_InitStruct.DataWidth = DDL_USART_DATAWIDTH_8B; //发送数据为8位
- }
-
- USART_InitStruct.StopBits = DDL_USART_STOPBITS_1;
- USART_InitStruct.TransferDirection = DDL_USART_DIRECTION_TX_RX;
- USART_InitStruct.HardwareFlowControl = DDL_USART_HWCONTROL_NONE;
- USART_InitStruct.OverSampling = DDL_USART_OVERSAMPLING_16;
- DDL_USART_Init(MODBUS_USART_PORT, &USART_InitStruct);
- /* RS485 DE Mode Configuration */
- /* Calculation for DE deassertion time (DEDT): */
- /* DEDT time = DEDT value * (bit time / oversampling rate) */
- /* Bit time = 1 / Baud rate */
- /* Oversampling rate = 16 (DDL_USART_OVERSAMPLING_16) */
- /* Assuming Baud rate = 115200: */
- /* Bit time = 1 / 115200 ≈ 8.68 us */
- /* DEDT time = 16 * (8.68 us / 16) = 8.68 us */
- DDL_USART_SetDEDeassertionTime(MODBUS_USART_PORT, 0x10);
- /* Calculation for DE assertion time (DEAT): */
- /* DEAT time = 16 * (8.68 us / 16) = 8.68 us */
- DDL_USART_SetDEAssertionTime(MODBUS_USART_PORT, 0x10);
- /* Enable USART DE Mode */
- DDL_USART_EnableDEMode(MODBUS_USART_PORT);
- /* USART Enable */
- DDL_USART_Enable(MODBUS_USART_PORT);
- /* Redirect the interrupt service function to the USART_Receive_Isr function. */
- DDL_Interrupt_Register(MODBUS_USART_IRQn, USART1_IRQHandler);
- /* Enable NVIC Interrupt */
- DDL_NVIC_EnableIRQRequest(MODBUS_USART_IRQn,1,0);
-
- return TRUE;
- }
- BOOL xMBPortSerialPutByte( CHAR ucByte )
- {
- /* Put a byte in the UARTs transmit buffer. This function is called
- * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
- * called. */
- DDL_USART_TransmitData8(MODBUS_USART_PORT,ucByte);//发送一个字节
- return TRUE;
- }
- BOOL xMBPortSerialGetByte( CHAR * pucByte )
- {
- /* Return the byte in the UARTs receive buffer. This function is called
- * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
- */
-
- *pucByte = DDL_USART_ReceiveData8(MODBUS_USART_PORT); //接收一个字节
- //DDL_USART_TransmitData8(USART1,*pucByte );
- return TRUE;
- }
- /* Create an interrupt handler for the transmit buffer empty interrupt
- * (or an equivalent) for your target processor. This function should then
- * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
- * a new character can be sent. The protocol stack will then call
- * xMBPortSerialPutByte( ) to send the character.
- */
- static void prvvUARTTxReadyISR( void )
- {
- pxMBFrameCBTransmitterEmpty( );
- }
- /* Create an interrupt handler for the receive interrupt for your target
- * processor. This function should then call pxMBFrameCBByteReceived( ). The
- * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
- * character.
- */
- static void prvvUARTRxISR( void )
- {
- pxMBFrameCBByteReceived( );
- }
- /*****************************************************************************
- * 函数名:MODBUS_USART_PORT_IRQHandler
- * 功 能:串口中断服务函数
- * 输 入:
- * 无
- * 输 出:
- * 无
- ****************************************************************************/
- void MODBUS_USART_IRQHandler(void)
- {
- //#if SYSTEM_SUPPORT_OS
- // OSIntEnter();
- //#endif
-
- if (DDL_USART_IsActiveFlag_RXNE(MODBUS_USART_PORT) == SET) //接收中断
- {
- prvvUARTRxISR();
- DDL_USART_ClearFlag_RXNE(MODBUS_USART_PORT);
- }
-
- if (DDL_USART_IsActiveFlag_TC(MODBUS_USART_PORT) == SET) //发送中断
- {
- prvvUARTTxReadyISR();
- DDL_USART_ClearFlag_TC(MODBUS_USART_PORT);
- }
- //#if SYSTEM_SUPPORT_OS
- // OSIntExit();
- //#endif
- }
- void __myaeabi_assert(const char *expr, const char *file, int line) {
- // 例如通过串口输出断言信息
- //printf("Assertion failed: %s, file %s, line %d\n", expr, file, line);
- //while (1); // 死循环或触发看门狗
- }
- /***********************************文件结束***********************************/
3.定时器移植
- /*
- * FreeModbus Libary: BARE Port
- * Copyright (C) 2006 Christian Walter <wolti@sil.at>
- *
- * 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$
- */
- /* ----------------------- Platform includes --------------------------------*/
- #include "port.h"
- #include "main.h"
- /* ----------------------- Modbus includes ----------------------------------*/
- #include "mb.h"
- #include "mbport.h"
- /* ----------------------- static functions ---------------------------------*/
- static void prvvTIMERExpiredISR( void );
- static void MODBUS_TIME_IRQHandler(void);
- //当波特率 > 19200bps时,采用定时器时钟固定为1750us ,
- //当波特率 < 19200bps时,定时器时钟为3.5个字符传输时间长
- /* ----------------------- Start implementation -----------------------------*/
- BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )
- {
- DDL_TMR_InitTypeDef TMR_InitStruct = {0U};
- uint16_t PrescalerValue;
- //时基频率 / (1 + Prescaler) = 20KHz
- PrescalerValue = (uint16_t)((SystemCoreClock / 2400) - 1);
- /* Config Clock */
- DDL_RCM_Unlock();
- MODBUS_TIME_CLOCK_API(MODBUS_TIME_PERIPH);
- DDL_RCM_Lock();
- /* Config MODBUS_TIME_PORT */
- /* Calculation details: */
- /* Main clock frequency: 120 MHz */
- /* Timer frequency after prescaler: 120 MHz / (Prescaler + 1) = 1 MHz (1 us per count) */
- /* Auto-reload value: 999 (Timer counts 1000 cycles before an update event) */
- /* Update event period: 1000*1 us = 1 ms */
- /* Therefore, TMR1 generates an update interrupt every 1 millisecond. */
-
- TMR_InitStruct.Prescaler = PrescalerValue;
- TMR_InitStruct.CounterMode = DDL_TMR_COUNTERMODE_UP;
- TMR_InitStruct.Autoreload = (uint16_t)usTim1Timerout50us;
- TMR_InitStruct.ClockDivision = DDL_TMR_CLOCKDIVISION_DIV1;
- TMR_InitStruct.RepetitionCounter = 0x00000000U;
- DDL_TMR_Init(MODBUS_TIME_PORT, &TMR_InitStruct);
- /* Enable MODBUS_TIME_PORT Interrupt */
- DDL_TMR_EnableIT_UPDATE(MODBUS_TIME_PORT);
- DDL_Interrupt_Register(MODBUS_TIME_IRQn, MODBUS_TIME_IRQHandler);
- DDL_NVIC_EnableIRQRequest(MODBUS_TIME_IRQn, 0, 0);
- /* Enable MODBUS_TIME_PORT*/
- DDL_TMR_EnableCounter(MODBUS_TIME_PORT);
- return TRUE;
- }
- inline void vMBPortTimersEnable( )
- {
- /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
- DDL_TMR_ClearFlag_UPDATE(MODBUS_TIME_PORT);
- DDL_TMR_EnableIT_UPDATE(MODBUS_TIME_PORT);
- DDL_TMR_SetCounter(MODBUS_TIME_PORT,0x00000000);
- DDL_TMR_EnableCounter(MODBUS_TIME_PORT);
-
- }
- inline void vMBPortTimersDisable( )
- {
- DDL_TMR_ClearFlag_UPDATE(MODBUS_TIME_PORT);
- DDL_TMR_DisableIT_UPDATE(MODBUS_TIME_PORT);
- DDL_TMR_SetCounter(MODBUS_TIME_PORT,0x00000000);
- DDL_TMR_DisableCounter(MODBUS_TIME_PORT);
- }
- /* Create an ISR which is called whenever the timer has expired. This function
- * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
- * the timer has expired.
- */
- static void prvvTIMERExpiredISR( void )
- {
- ( void )pxMBPortCBTimerExpired( );
- }
- /*****************************************************************************
- * 函数名:MODBUS_TIME_PORT_IRQHandler
- * 功 能:定时器中断服务函数
- * 输 入:
- * 无
- * 输 出:
- * 无
- ****************************************************************************/
- void MODBUS_TIME_IRQHandler(void)
- {
- #if SYSTEM_SUPPORT_OS
- OSIntEnter();
- #endif
-
- if (DDL_TMR_IsActiveFlag_UPDATE(MODBUS_TIME_PORT) == SET)
- {
- DDL_TMR_ClearFlag_UPDATE(MODBUS_TIME_PORT);
- prvvTIMERExpiredISR();
- }
-
- #if SYSTEM_SUPPORT_OS
- OSIntExit();
- #endif
- }
- /* ----------------------- start implementation -----------------------------*/
- void vMBPortTimersDelay(USHORT usTimeOutMS)
- {
- (void)usTimeOutMS; // 避免编译器警告
- // 如果只使用RTU模式,此函数无需任何操作
- return;
- }
5.modbus控制GPIO点亮LED
- eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,eMBRegisterMode eMode )
- {
- eMBErrorCode eStatus = MB_ENOERR;
- int iNCoils = ( int )usNCoils;
- unsigned short usBitOffset;
- /* Check if we have registers mapped at this block. */
- if( ( usAddress >= REG_COILS_START ) && ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_NREGS*8) )
- {
- usBitOffset = ( unsigned short )( usAddress - REG_COILS_START );
-
- switch ( eMode )
- {
- /* Read current values and pass to protocol stack. */
- case MB_REG_READ:
- while( iNCoils > 0 )
- {
- *pucRegBuffer++ = xMBUtilGetBits(ucRegCoilsBuf,usBitOffset,(unsigned char)( iNCoils >8 ? 8 :iNCoils ));
- iNCoils -= 8;
- usBitOffset += 8;
- }
-
- break;
- /* Update current register values. */
- case MB_REG_WRITE:
- while( iNCoils > 0 )
- {
- xMBUtilSetBits(ucRegCoilsBuf, usBitOffset, (unsigned char)(iNCoils > 8 ? 8:iNCoils),*pucRegBuffer++ );
- iNCoils -= 8;
- usBitOffset += 8;
- }
- uint8_t temp = ucRegCoilsBuf[0];
- ///////////////////////////////////////////////////
- //编写自己的逻辑代码
- if(temp & 0x01)
- {
- DDL_GPIO_ResetOutputPin(GPIOA,DDL_GPIO_PIN_1);
- }
- else
- {
- DDL_GPIO_SetOutputPin(GPIOA,DDL_GPIO_PIN_1);
- }
-
- if((temp >> 1) &0x01)
- {
- DDL_GPIO_ResetOutputPin(GPIOA,DDL_GPIO_PIN_2);
- }
- else
- {
- DDL_GPIO_SetOutputPin(GPIOA,DDL_GPIO_PIN_2);
- }
- /////////////////////////////////////////////////
- break;
- }
- }
- else
- {
- eStatus = MB_ENOREG;
- }
-
- return eStatus;
- }
三、测试