热度 25
2013-11-26 15:07
4459 次阅读|
0 个评论
FreeMODBUS一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议.。 FreeMODBUS最新版本V1.5。下载地址:http://www.freemodbus.org/index.php?idx=5 下面进行的移植基于STM8S单片机的官方固件库 1、物理层接口文件修改(具体应修改接口文件portserial.c及porttimer.c) portserial.c文件中: void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )函数设置串口状态。当xRxEnable为真时,应使能串口接收及接收中断。在RS485通讯系统中,还要注意将RS485接口芯片设为接收使能状态;当xTxEnable为真时,应使能串口发送及发送中断。在RS485通讯系统中,还要注意将RS485接口芯片设为发送使能状态。void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) //控制串口的收发中断 { if(TRUE==xRxEnable) { UART1_ITConfig(UART1_IT_RXNE, ENABLE); } else { UART1_ITConfig(UART1_IT_RXNE, DISABLE); } if(TRUE==xTxEnable) { UART1_ITConfig(UART1_IT_TXE,ENABLE); } else { UART1_ITConfig(UART1_IT_TXE, DISABLE); } } BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )函数初始化串行通讯端口。参数ucPORT可以忽略;参数ulBaudRate是通讯端口的波特率,应根据此数值设置所使用硬件端口的波特率;参数ucDataBits为通讯时所使用的数据位宽,注意,若使用RTU模式,则有ucDataBits=8,若使用ASCII模式,则有ucDataBits=7,应根据此参数设置所使用硬件端口的数据位宽;eParity为校验方式,eParity=MB_PAR_NONE为无校验,此时硬件端口应设置为无校验方式及两个停止位,eParity=MB_PAR_ODD为奇校验,此时硬件端口应设置为奇校验方式及一个停止位,eParity= MB_PAR_EVEN为偶校验,此时硬件端口应设置为偶校验方式及一个停止位。函数返回值务必为TRUE。 BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { UART1_WordLength_TypeDef databit; UART1_Parity_TypeDef parity; UART1_DeInit(); if(8==ucDataBits) { databit = UART1_WORDLENGTH_8D; } else { databit = UART1_WORDLENGTH_9D; } if(MB_PAR_NONE == eParity) { parity = UART1_PARITY_NO; } else if(MB_PAR_ODD == eParity) { parity = UART1_PARITY_ODD; } else { parity = UART1_PARITY_EVEN; } UART1_Init((uint32_t)ulBaudRate,databit, UART1_STOPBITS_1, parity, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE); /* ENABLE the USARTx */ UART1_ITConfig(UART1_IT_TXE, ENABLE); return TRUE; } BOOL xMBPortSerialPutByte( CHAR ucByte )通讯端口发送一字节数据函数。在此函数中编写发送一字节数据的函数。注意,由于使用的是中断发送,故只需将数据放到发送寄存器即可。函数返回值务必为TRUE。 BOOLxMBPortSerialPutByte( CHAR ucByte ) { UART1_SendData8(ucByte); return TRUE; } BOOL xMBPortSerialGetByte( CHAR * pucByte )通讯端口接收一字节数据函数。在此函数中编写接收的函数。由于使用的是中断接收,只需将接收寄存器的值放到* pucByte即可。函数返回值务必为TRUE。 BOOL xMBPortSerialGetByte( CHAR * pucByte ) { *pucByte = UART1_ReceiveData8(); return TRUE; } void prvvUARTRxISR( void )和void prvvUARTTxReadyISR( void )无需修改。 portserial.c文件修改 BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )初始化超时定时器播函数。根据所使用的硬件初始化超时定时器,使之能产生中断时间为usTim1Timerout50us*50us的中断,本例移植采用单片机的TIM4定时器。函数返回值务必为TRUE。 BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) { /* TIM4 configuration: - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter clock used is 16 MHz / 128 = 125 000 Hz - With 125 000 Hz we can generate time base: max time base is 2.048 ms if TIM4_PERIOD = 255 -- (255 + 1) / 125000 = 2.048 ms min time base is 0.016 ms if TIM4_PERIOD = 1 -- ( 1 + 1) / 125000 = 0.016 ms -- 16us - In this example we need to generate a time base equal to 50us so TIM4_PERIOD = (0.00005 * 125000 - 1) = 5 */ /* Time base configuration */ TIM4_TimeBaseInit(TIM4_PRESCALER_128, 5); /* Clear TIM4 update flag */ TIM4_ClearFlag(TIM4_FLAG_UPDATE); /* Enable update interrupt */ TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); /* enable interrupts */ // enableInterrupts(); /* Enable TIM4 */ TIM4_Cmd(ENABLE); return TRUE;; } void vMBPortTimersEnable( )使能超时定时器函数。需在此函数中清除中断标志位、清零定时器计数值,并重新使能定时器中断。 void vMBPortTimersEnable( ) //打开时钟 { /* Clear TIM4 update flag */ TIM4_ClearFlag(TIM4_FLAG_UPDATE); /* Enable update interrupt */ TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); TIM4_SetCounter(0x00); /* Enable TIM4 */ TIM4_Cmd(ENABLE); } void vMBPortTimersDisable( )关闭超时定时器函数。在此函数中清零定时器计数值,并关闭定时器中断。 void vMBPortTimersDisable( ) //关闭时钟 { TIM4_Cmd(DISABLE); TIM4_SetCounter(0x00); TIM4_ITConfig(TIM4_IT_UPDATE, DISABLE); TIM4_ClearFlag(TIM4_FLAG_UPDATE); } void prvvTIMERExpiredISR( void )函数不需修改。 2、 应用层回函数的修改 在应用层,用户需要定义所需要使用的寄存器,并修改对应的回函数。 eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )输入寄存器回函数。* pucRegBuffer为协议中所需的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。 eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; if( ( usAddress = REG_INPUT_START ) ( usAddress + usNRegs = REG_INPUT_START + REG_INPUT_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegInputStart ); while( usNRegs 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )保持寄存器回函数。* pucRegBuffer为要协议中的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。 eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; u16 *PRT=(u16*)pucRegBuffer; if( ( usAddress = REG_HOLDING_START ) ( usAddress + usNRegs = REG_HOLDING_START + REG_HOLDING_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegHoldingStart ); switch ( eMode ) { case MB_REG_READ: while( usNRegs 0 ) { //// *PRT++ = __REV16(usRegHoldingBuf ); //数据序转 REV16.W *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf 8 ); *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf 0xFF ); iRegIndex++; usNRegs--; } break; case MB_REG_WRITE: while( usNRegs 0 ) { //// usRegHoldingBuf = __REV16(*PRT++); //数据序转 REV16.W usRegHoldingBuf = *pucRegBuffer++ 8; usRegHoldingBuf |= *pucRegBuffer++; iRegIndex++; usNRegs--; } } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )读/写开关寄存器 函数。* pucRegBuffer为要添加到协议中的数据,usAddress为地址,usNCoils为要访问的个数,eMode为访问类型(MB_REG_READ为读状态,MB_REG_WRITE为写)。用户应根据要访问的地址usAddress将相应的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的地址usAddress放到相应地址中。 eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { ( void )pucRegBuffer; ( void )usAddress; ( void )usNCoils; ( void )eMode; return MB_ENOREG; } eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )读开关寄存器函数。 eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { ( void )pucRegBuffer; ( void )usAddress; ( void )usNDiscrete; return MB_ENOREG; }