/* * 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: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $ */ #include "port.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- static variables ---------------------------------*/ static eMBParity eCurrParity; /* ----------------------- functions ---------------------------------*/ UCHAR CalcParity( UCHAR ucData ); /* ----------------------- Start implementation -----------------------------*/ void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) { /* If xRXEnable enable serial receive interrupts. If xTxENable enable * transmitter empty interrupts. */ if(xRxEnable == TRUE) { set_bit(rcsta, CREN); set_bit(pie1, RCIE); //485 status determined by xTxEnable state } else { clear_bit(pie1, RCIE); clear_bit(rcsta, CREN); //485 status determined by xTxEnable state } if(xTxEnable == TRUE) { set_bit(pie1, TXIE); TRANSMIT_ON_485(); //Allow time for bus to turn around. delay_10us(1); } else { clear_bit(pie1, TXIE); //Bad way to do this, but wait for TX complete while(txsta.TRMT == 0); RECEIVE_ON_485(); } //Enable peripheral and global ints set_bit(intcon, GIEL); // set_bit(intcon, GIEH); } BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { BOOL ucReturn; /* prevent compiler warning. */ (void)ucPORT; /* Only supporting RTU so always 8 data bits */ (void)ucDataBits; set_bit(rcsta, SPEN); //Int priority low clear_bit(ipr1, RCIP); clear_bit(ipr1, TXIP); // Make sure serial pins are NOT digital outputs set_bit(trisb, 1); set_bit(trisb, 4); // Turn off A/D for serial pins set_bit(adcon1, 5); set_bit(adcon1, 6); baudctl = 0x08; //Set BRG16 bit //Set 16 bit baudrate count spbrg = (4000000/(16*ulBaudRate)) - 1; //Save parity since it is generated programatically eCurrParity = eParity; //Since RTU only, for tx parity will be on 9th data bit or // 9th data bit set to 0 to be 2nd stop bit set_bit(txsta, TX9); set_bit(rcsta, RX9); if(eParity == MB_PAR_NONE) { //Do not receive 9th bit in case sender doesn't have 2 stop bits. clear_bit(rcsta, RX9); //Clear 9th data bit for case of no parity to do 2 stop bits. clear_bit(txsta, TX9D); } //Leave transmit enabled set_bit(txsta, TXEN); vMBPortSerialEnable( FALSE, FALSE ); 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. */ /* We need to generate TX parity, if enabled */ switch(eCurrParity) { case MB_PAR_EVEN: if(CalcParity(ucByte) == 0 ) { clear_bit(txsta, TX9D); } else { set_bit(txsta, TX9D); } break; case MB_PAR_ODD: if(CalcParity(ucByte) == 0 ) { set_bit(txsta, TX9D); } else { clear_bit(txsta, TX9D); } break; } //Write the data byte txreg = ucByte; return TRUE; } BOOL xMBPortSerialGetByte( CHAR * pucByte ) { /* Return the byte in the UARTs receive buffer. This function is called * by the protocol stack */ *pucByte = rcreg; return TRUE; } void vMBPortClose( void ) { } /****************************************************************************** * Name: CalcParity * Description: Calculates parity of ucData * Uses: * * Returns: Parity of ucData in bit 0 of returned UCHAR: 0 = even, 1 = odd * * NOTE: For TX of 9 bit Even Parity, send the bit returned here in the 9th bit. * For TX of 9 bit Odd Parity, send the complement of the returned bit in the 9th bit. * For RX of 9 Bit Even Parity, parity is good if returned bit matches 9th RX bit. * For RX of 9 bit Odd Parity, parity is good if returned bit is complement of 9th RX bit. *****************************************************************************/ UCHAR CalcParity( UCHAR ucData ) { asm { movf _ucData, W ;8-bit parity ;This routine will leave the parity of ucData in _ucData.0 ;while blenderizing most of the rest of _ucData swapf _ucData, W ;x = abcdefgh w = efghabcd xorwf _ucData, F ;x = abcdefgh w = efghabcd rrcf _ucData, W ;x = abcdefgh w = -abcdefg xorwf _ucData, F ;x = abcdefgh w = -abcdefg ; at this point, the parity for half the bits ; (a, b, e, and f) is in bit 2 of X, and the ; parity for the other half (bits c, d, g, and h) ; is in bit 0 of X. btfsc _ucData, 2 ; if the parity of (a,b,e,f) is 0, ; then the parity of (a,b,c,d,e,f,g,h) ; is equal to the parity of (c,d,g,h)... ; which is already in bit 0, so skip ahead. incf _ucData, F ; otherwise, the parity of (a,b,e,f) is 1, ; so the parity of (a,b,c,d,e,f,g,h) is ; NOT equal to the parity of (c,d,g,h). ; invert bit 0. ; at this point, bit 0 of _ucData contains the parity of ; (a,b,c,d,e,f,g,h). } return ucData & 0x01; }
Copyright © 2006 SourceBoost Technologies