![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
lguancho
Joined: 08 Sep 2003 Posts: 5
|
Winpenny RS485 Source Code Question |
Posted: Fri Feb 18, 2005 2:58 am |
|
|
Hi, all. I am trying to port and test Winpenny's RS485 code from Pic16F to Pic18F452. I redefine the register addresses (PORTX, TRISX etc) in the header file. The code could be compiled, and I am trying to test it in with a chip, sending some command string to my PC (turn on the serial port monitor in CCS IDE). I keep receiving a series of '0' , instead of some "Hello" string.
I find that the problem lies with the setup() and configurecom() function. When I disables these functions, and use CCS #use Rs232() fuction, I can receive without any problem.
Could anyone help to see what I have done wrong on the setup() and configurecom()
Code: |
#define MASTER
#include <18F452.h>
#use delay(clock=20000000)
#fuses HS,NOLVP,NOWDT,PUT
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,errors, enable=PIN_C5)
#include "D:\rs485net\Include\reg18F452.h"
#include "D:\rs485net\Include\rs485.h"
#include <stdlib.h>
#include "D:\rs485net\Include\lcd873b.h"
#include "D:\rs485net\lcd873b.c" // Keypad LCD routine
#include "D:\rs485net\Rs485.c" // RS485 protocol driver
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
char cTest[10];
//**************************************************
// Timer Interrupt service routine
//**************************************************
#INT_RTCC
clock_isr()
{
TMR0L = TMR0_RELOAD; // Reload PICs timer
BIT_CLEAR( INTCON, TMR0IF ); // Clear interrupt flag
}
//**************************************************
// USART interrupt service routine
//**************************************************
#INT_RDA
void UsartInterrupt(void)
{
while ( BIT_TEST( PIR1, RCIF ) ) // If USART RX Interrupt
{
TMR0L = TMR0_RELOAD; //TMR0_RELOAD
cRs485RxChar = getc(); //RCREG;
if ( !( RCSTA & 6 ) ) // Then if no errors
{ // Process received character
Rs485Decode(); // Decode RS485 network trafic
bit_set( RCSTA, CREN ); // Enable receiver.
}
else
{
bit_clear( RCSTA, CREN ); // Clear any errors
cRs485RxChar = getc(); // =RCREG
cRs485RxChar = getc(); // =RCREG
bit_set( RCSTA, CREN ); // Enable receiver.
}
bit_clear( PIR1, RCIF );
}
}
void main(void)
{
char cPacketReady;
char cLenOfData;
char cCmd, c;
//Setup(); // Enable interrupts
//BIT_CLEAR( INTCON, TMR0IE ); // Timer interrupts off
/*
#ifndef MASTER
LcdWrite("Waiting........");
#else
LcdWrite("Sending message");
#endif
*/
// Just setup the network address
//write_eeprom( NET_ADDRESS_HIGH, 0x10 );
//write_eeprom( NET_ADDRESS_LOW, 0x10 );
//cOurAddrHigh = read_eeprom( NET_ADDRESS_HIGH );
//cOurAddressLow = read_eeprom( NET_ADDRESS_LOW );
while ( 1 )
{
cOurAddrHigh = 'A'; //0x10;
cOurAddrLow = 'A'; //0x10;
Rs485Initialise( cOurAddrHigh,cOurAddrLow );
#ifdef MASTER
cTest[0] = 'H';
cTest[1] = 'e';
cTest[2] = 'l';
cTest[3] = 'l';
cTest[4] = 'o';
cTest[5] = 13;
ClearLine2();
LcdWrite("GET DATA PKT");
Rs485SendPacket( SENSOR_GET_DATA, 5, &cTest[0] );
delay_ms(2500);
delay_ms(2500);
delay_ms(2500);
delay_ms(2500);
/*
ClearLine2();
LcdWrite("POLL PKT");
Rs485SendPacket( SENSOR_POLL_CMD, 0, &cTest[0] );
delay_ms(2500);
delay_ms(2500);
delay_ms(2500);
delay_ms(2500);
*/
/*
cOurAddrHigh = 0x10;
cOurAddrLow = 0x18;
// Send a packet to another node
Rs485Initialise( cOurAddrHigh,cOurAddrLow );
Rs485SendPacket( SENSOR_POLL_CMD, 0, &cTest[0] );
delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
*/
#endif
/*
cPacketReady = Rs485Process();
if ( cPacketReady )
{
Rs485GetPacket( &cCmd, &cLenOfData, &cTest[0] );
delay_ms(10000);
Rs485SendPacket(cCmd, cLenOfData, &cTest[0] );
/*
ClearLine2();
LcdWrite( "CMD: " );
BinToHexAscii( cCmd );
LcdWrite( ' ' );
if ( cLenOfData != 0 )
{
for ( c=0; c<cLenOfData; c++ ) LcdWrite( cTest[c] );
}
//Rs485SendPacket( SENSOR_ACK, 0, NULL );
delay_ms(255);
Rs485Initialise(cOurAddrHigh,cOurAddrLow);
ClearLine1();
LcdWrite("Waiting........");
}
*/
}
}
//**************************
// Setup Hardware
//**************************
void Setup(void)
{
T0CON = 0xC4; // 8Bit TMR0 prescal = enable, rate = 1:32
INTCON = 0; // disable global interupts
// ADCON1 = 0x07; // Disable ADC
TRISA = PortAConfig; // 0b00111111 for slave
TRISB = PortBConfig; // 0b00000000 for slave
TRISC = PortCConfig; // 0b00000000
TRISD = PortDConfig;
TRISE = PortEConfig;
//PORTC = 0xFF;
LCDSetup(); // Setup the LCD Display
//ConfigureComms(); /* Configure USART for Asyncronous Comms */
//BIT_SET(INTCON,GIE);
}
//*******************************************************/
//* Configure PIC18F452 USART for communications */
//* */
//* Asynchronous mode */
//* 8 data bits ( For other rates see PIC16F8XX Data ) */
//* 1 stop bits */
//* No Parity */
//* */
//*******************************************************/
void ConfigureComms(void)
{
// SPBRG = 64; // Set Baud rate 19,200 20MHz clock
SPBRG = 129; // 9600 Baud at 20MHz
BIT_CLEAR( TXSTA, TX9 ); // 8 bit transmit mode
BIT_SET( TXSTA, BRGH ); // BRGH = 1 High speed mode- Note smaller baud rate error%
BIT_CLEAR( TXSTA, SYNC ); // Asyncronous mode;
BIT_SET( TXSTA, TXEN ); // Enable Transmitter
PIR1 = 0x00; // Clear all interrupt flags including AUSART TX & RX
BIT_SET( PIE1,TXIE ); // Enable Transmit Interrupts
BIT_SET( PIE1,RCIE ); // Enable Receive Interrupts
BIT_SET( INTCON, PEIE ); // Enable all Peripheral Interrupts
BIT_SET( RCSTA, CREN ); // Enable continuous receive
BIT_CLEAR( RCSTA, RX9 ); // 8 bit receive mode
BIT_SET( RCSTA, SPEN ); // Enable Serial port
}
|
Question 2: Inside the serial rx ISR, the TMR0 is loaded with a value of 255 (defined by TMR0_Reload). I don't understand this? Could someone help to explain the purposes of this timer function within the rx ISR?
Warmest Regards
lguancho |
|
![](templates/subSilver/images/spacer.gif) |
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Feb 18, 2005 9:16 am |
|
|
Just a guess. But it sounds like you have the wrong level. Try an inverter in there. or you could try the invert option on a non-hardware-uart pin.
That would great fast little test.
I use a max 1480BCPI to a PIC18F452.
RO_bar goes to a 3k pull-up and an inverter and then to RC7 (inverter needed)
BUT
RC6 goes right to DI.. ( no inverter neede) |
|
![](templates/subSilver/images/spacer.gif) |
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Fri Feb 18, 2005 9:25 am |
|
|
as for the ISR, just another guess.
But when you have 1/2 duplex wiring.
ie:1 set of differential pair.
You need to switch over from the PC talking to when the PIC is talking. So you need to know when the bus is idle. i did this with a timmer. Thus when PC is talking, the PIC is RX'ing and you reset the timer .
PC talking...
rx a char and set timer=255
rx a char and set timer=255
...
When PC stops talking
timer=254,253,252,......0 and int on rollover. Set bus_idle=TRUE and
now the PIC can talk. |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Feb 18, 2005 9:53 am |
|
|
It is not working probably due to not configuring one of the registers correctly. Make sure you are handling the enable pin for the transceiver. The timer0 does nothing according to the source that I looked at. |
|
![](templates/subSilver/images/spacer.gif) |
lguancho
Joined: 08 Sep 2003 Posts: 5
|
|
Posted: Mon Feb 21, 2005 4:27 am |
|
|
Hi,all. I include the header file for the 18F452 and RS485.c and Rs385.h
[code]
void Setup(void);
void ConfigureComms(void);
// EEPROM addresses
#define NET_ADDRESS_HIGH 0
#define NET_ADDRESS_LOW 1
#ifndef MASTER
// PORT Configuration For Slave
#define PortAConfig 0x3F
#define PortBConfig 0x00
#define PortCConfig 0x00
#define PortDConfig 0x00
#define PortEConfig 0x00
#else
// PORT Configuration // For Master
#define PortAConfig 0x00
#define PortBConfig 0x00
#define PortCConfig 0x0f
#define PortDConfig 0x00
#define PortEConfig 0x00
#endif
//*********************************************************************
#define TMR0_RELOAD 255 // TMR0 reload value
//#define TMR0_RELOAD 248 // TMR0 reload value
#BYTE PORTA = 0xF80
#BYTE PORTB = 0xF81
#BYTE PORTC = 0xF82
#BYTE PORTD = 0xF83
#BYTE PORTE = 0xF84
#BYTE LATA = 0xF89
#BYTE LATB = 0xF8A
#BYTE LATC = 0xF8B
#BYTE LATD = 0xF8C
#BYTE LATE = 0xF8D
#BYTE TRISA = 0xF92
#BYTE TRISB = 0xF93
#BYTE TRISC = 0xF94
#BYTE TRISD = 0xF95
#BYTE TRISE = 0xF96
#BYTE PIE1 = 0xF9D
#BYTE PIR1 = 0xF9E
#BYTE IPR1 = 0xF9F
#BYTE PIE2 = 0xFA0
#BYTE PIR2 = 0xFA1
#BYTE IPR2 = 0xFA2
#BYTE RCSTA = 0xFAB
#BYTE TXSTA = 0xFAC
#BYTE TXREG = 0xFAD
#BYTE RCREG = 0xFAE
#BYTE SPBRG = 0xFAF
#BYTE T3CON = 0xFB1
#BYTE TMR3L = 0xFB2
#BYTE TMR3H = 0xFB3
#BYTE CCP2CON = 0xFBA
#BYTE CCPR2L = 0xFBB
#BYTE CCPR2H = 0xFBC
#BYTE CCP1CON = 0xFBD
#BYTE CCPR1L = 0xFBE
#BYTE CCPR1H = 0xFBF
#BYTE ADCON1 = 0xFC1
#BYTE ADCON2 = 0xFC2
#BYTE ADRESL = 0xFC3
#BYTE ADRESH = 0xFC4
#BYTE SSPCON2 = 0xFC5
#BYTE SSPCON1 = 0xFC6
#BYTE SSPSTAT = 0xFC7
#BYTE SSPADD = 0xFC8
#BYTE SSPBUF = 0xFC9
#BYTE T2CON = 0xFCA
#BYTE PR2 = 0xFCB
#BYTE TMR2 = 0xFCC
#BYTE T1CON = 0xFCD
#BYTE TMR1L = 0xFCE
#BYTE TMR1H = 0xFCF
#BYTE RCON = 0xFD0
#BYTE WDTCON = 0xFD1
#BYTE LVDCON = 0xFD2
#BYTE OSCCON = 0xFD3
#BYTE T0CON = 0xFD5
#BYTE TMR0L = 0xFD6
#BYTE TMR0H = 0xFD7
#BYTE STATUS = 0xFD8
#BYTE FSR2L = 0xFD9
#BYTE FSR2H = 0xFDA
#BYTE PLUSW2 = 0xFDB
#BYTE PREINC2 = 0xFDC
#BYTE POSTDEC2 = 0xFDD
#BYTE POSTINC2 = 0xFDE
#BYTE INDF2 = 0xFDF
#BYTE BSR = 0xFE0
#BYTE FSR1L = 0xFE1
#BYTE FSR1H = 0xFE2
#BYTE PLUSW1 = 0xFE3
#BYTE PREINC1 = 0xFE4
#BYTE POSTDEC1 = 0xFE5
#BYTE POSTINC1 = 0xFE6
#BYTE INDF1 = 0xFE7
#BYTE WREG = 0xFE8
#BYTE FSR0L = 0xFE9
#BYTE FSR0H = 0xFEA
#BYTE PLUSW0 = 0xFEB
#BYTE PREINC0 = 0xFEC
#BYTE POSTDEC0 = 0xFED
#BYTE POSTINC0 = 0xFEE
#BYTE INDF0 = 0xFEF
#BYTE INTCON3 = 0xFF0
#BYTE INTCON2 = 0xFF1
#BYTE INTCON = 0xFF2
#BYTE PRODL = 0xFF3
#BYTE PRODH = 0xFF4
#BYTE TABLAT = 0xFF5
#BYTE TBLPTRL = 0xFF6
#BYTE TBLPTRH = 0xFF7
#BYTE TBLPTRU = 0xFF8
#BYTE PCL = 0xFF9
#BYTE PCLATH = 0xFFA
#BYTE PCLATU = 0xFFB
#BYTE STKPTR = 0xFFC
#BYTE TOSL = 0xFFD
#BYTE TOSH = 0xFFE
#BYTE TOSU = 0xFFF
// INTCON BITS
#define GIE 7
#define PEIE 6
#define TMR0IE 5
#define INT0IE 4
#define RBIE 3
#define TMR0IF 2
#define INT0IF 1
#define RBIF 0
// USART TXSTA Register bits
#define CSCR 7
#define TX9 6
#define TXEN 5
#define SYNC 4
#define BRGH 2
#define TRMT 1
#define TX9D 0
// USART RCSTA Register bits
#define SPEN 7
#define RX9 6
#define SREN 5
#define CREN 4
#define ADDEN 3
#define FERR 2
#define OERR 1
#define RX9D 0
#define TRMT_MASK 2
// Bits of STATUS register
#define NEGATIVE 4
#define OV 3 // Overflow
#define ZERO 2
#define DIG_CARRY 1
#define CARRY 0
// Bits of PIE1
#define PSPIE 7
#define ADIE 6
#define RCIE 5
#define TXIE 4
#define SSPIE 3
#define CCP1IE 2
#define TMR2IE 1
#define TMR1IE 0
// Bits of SSPSTAT
#define SMP 7
#define CKE 6
#define D_A 5
//#define P 4 // Cause compiler error because of identifier s
//#define S 3
#define R_W 2
#define UA 1
#define BF 0
#define R_W_MASK 0x04
// Bits of PIR1
#define PSPIF 7
#define ADIF 6
#define RCIF 5
#define TXIF 4
#define SSPIF 3
#define CCP1IF 2
#define TMR2IF 1
#define TMR1IF 0
#define SSPIF_MASK 0x08
// Bits of SSPCON2
#define GCEN 7
#define ACKSTAT 6
#define ACKDT 5
#define ACKEN 4
#define RCEN 3
#define PEN 2
#define RSEN 1
#define SEN 0
// Bits of RCON - Note: PCON for Pic16F877
#define IPEN 7
#define RI 4
#define TO 3
#define PD 2
#define POR 1
#define BOR 0
// Bits of INTCON2
#define RBPU 7
#define INTEDG0 6
#define INTEDG1 5
#define INTEDG2 4
#define TMR01P 2
#define RBIP 0
// Bits of T0CON Note - OPTION_REG for PIC16
#define TMR0ON 7 //
#define T08BIT 6
#define T0CS 5
#define T0SE 4
#define PSA 3
#define T0PS2 2 //PS2
#define T0PS1 1 //PS1
#define T0PS0 0 //PS0
[/code]
RS485.C Listing
[code]
//**************************************************************************
// Rs495.c
// RS485 network protocol
//
// Version 1.0 beta
//
// Processor: PIC16F87x
//
// Network packet protocol:
//
// STX ( 0x02 )
// NET ADDRESS HIGH
// NET ADDRESS LOW
// PAYLOAD LENGTH
// COMMAND
// DATA ( Optional )
// CRC HIGH
// CRC LOW
//
//
//
//
//
// By: J.Winpenny
// j.winpenny@ukonline.co.uk
//
//**************************************************************************
//#include "D:\rs485net\Include\Rs485.h"
//#include <lcd.c>
//#include "D:\rs485net\Include\lcd873b.h"
//struct
//{
static char cOurAddrHigh;
static char cOurAddrLow;
static char cRs485RxChar;
static char cRS485State;
static char cStart;
static char cNetAddrHigh, cNetAddrLow;
static char cLenExpected;
static char cCommand;
static char c485Buf[64];
static char cRxCrcHigh, cRxCrcLow;
static char cCalcCrcHigh, cCalcCrcLow;
static char cBufPtr;
static char cError;
static char cCrcTmp, cCrcTmp5, cCrcTmp4, cCrcTmp3, cCrcTmp2;
//} RS485_Protocol;
//****************************************************************************
// void Rs485Initialise(void)
//
// Initialise RS485 network driver Note- No Change
//****************************************************************************
void Rs485Initialise(char cAddrHigh, char cAddrLow)
{
cOurAddrHigh = cAddrHigh;
cOurAddrLow = cAddrLow;
cRS485State = PKT_WAIT_START;
BIT_CLEAR( RS485_CONTROL, OUTPUTS_ON ); // Disable driver
BIT_SET( PIE1, RCIE ); // Enable Receive Interrupt
}
//****************************************************************************
// char PacketForUs(void)
//
// Decide if packet valid and destined for this node.
// Ignore invalid packets and packets for other nodes Note: No Change
//
//****************************************************************************
#separate
char Rs485Process(void)
{
char cOurPkt, cPktReady;
cOurPkt = FALSE;
cPktReady = FALSE;
disable_interrupts(GLOBAL);
if ( cRS485State == PKT_COMPLETE )
{
if ( ( cNetAddrHigh == cOurAddrHigh )&& // valid and destined for this node
( cNetAddrLow == cOurAddrLow ) )
{
cOurPkt = TRUE;
}
else
{
ClearLine2();
LcdWrite("traffic"); // Network traffic for other nodes
delay_ms(200);
}
cRS485State = PostValidatePacket(); // Validate packet CRC
if ( (cRS485State == PKT_INVALID)||(cRS485State == PKT_VALID) )
{
// Reject invalid packets
if ( cRS485State == PKT_INVALID ) // NAK our invalid packets
{
ClearLine2();
if ( cError == BAD_CRC ) LcdWrite("Bad CRC");
else if ( cError == BAD_LENGTH ) LcdWrite("Bad length");
delay_ms(200);
//if ( cOurPkt ) Rs485SendPacket( SENSOR_NAK, 0, NULL );
cRS485State = PKT_WAIT_START;
}
else if ( cRS485State == PKT_VALID ) // If packet valid
{ // and destined for this node
if ( cOurPkt ) cPktReady = TRUE;
else cRS485State = PKT_WAIT_START;
}
}
}
enable_interrupts(GLOBAL);
return cPktReady;
}
//****************************************************************************
// void Rs485Decode(void)
//
// Decode an incomming packet on the RS485 network
//
// Expecting:
// START,
// NETWORK ADDRESS_HIGH,
// NETWORK ADDRESS_LOW,
// PAYLOAD LENGTH,
// COMMAND,
// optional DATA,
// CRC HIGH,
// CRC LOW Note: No Change
//
//****************************************************************************
#separate
char Rs485Decode( void )
{
switch ( cRS485State )
{
case PKT_WAIT_START: cStart = cRs485RxChar;
if ( cRs485RxChar == PKT_START ) // Check for the start of packet byte
{
cRS485State++;
}
break;
case PKT_WAIT_ADDR_HIGH: cNetAddrHigh = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_ADDR_LOW: cNetAddrLow = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_LEN: cLenExpected = cRs485RxChar;
if ( cLenExpected > sizeof(c485Buf) )
{
cRS485State = PKT_INVALID;
cError = BAD_LENGTH;
}
else
{
cBufPtr = 0;
cRS485State++;
}
break;
case PKT_CMD: cCommand = cRs485RxChar;
if ( PacketHasPayload() ) cRS485State = PKT_WAIT_DATA;
else cRS485State = PKT_WAIT_CRC_HIGH;
break;
case PKT_WAIT_DATA: c485Buf[cBufPtr] = cRs485RxChar;
cBufPtr++;
if ( cBufPtr == cLenExpected ) // If last byte of data received
{
cRS485State++; // next byet is the CRC high byte
}
break;
case PKT_WAIT_CRC_HIGH: cRxCrcHigh = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_CRC_LOW: cRxCrcLow = cRs485RxChar;
cRS485State = PKT_COMPLETE;
break;
case PKT_COMPLETE: break; // Idle state
case PKT_VALID: break; // Idle state
case PKT_INVALID: break; // Idle state
default: cRS485State = PKT_WAIT_START;
break;
}
return cRS485State;
}
//****************************************************************************
// void Rs485SendPacket( char cAddr, char cCmd, char cLen, char *cData )
//
// Send a packet over the RS485 link
//
// Input: NETWORK_ADDRESS, COMMAND, PAYLOAD_LENGTH, optional DATA
// Note: No Change
//****************************************************************************
void Rs485SendPacket( char cCmd, char cLen, char *cData )
{
char c, d;
BIT_CLEAR( PIE1, RCIE ); // Disable Receive Interrupt
BIT_SET( RS485_CONTROL, OUTPUTS_ON ); // Enable driver
delay_ms(1); // Line turnarround time
cCalcCrcHigh = 0xff; // Clear CRC
cCalcCrcLow = 0xff;
// Send some NULL preamblesfopr receiving UART
//for ( c=0; c < NUM_TX_PREAMBLE; c++ ) Rs485SendChar( 0x00 );
Rs485UpdateCrc( PKT_START );
Rs485SendChar( PKT_START ); // Send packet start character
Rs485UpdateCrc( cOurAddrHigh );
Rs485SendChar( cOurAddrHigh ); // Send address high
Rs485UpdateCrc( cOurAddrLow );
Rs485SendChar( cOurAddrLow ); // Send address low
Rs485UpdateCrc( cLen );
Rs485SendChar( cLen ); // Send length
Rs485UpdateCrc( cCmd );
Rs485SendChar( cCmd ); // Send command
if ( cLen != 0 ) // If payload not empty send data
{
for ( c = 0; c < cLen; c++ )
{
d = cData[c];
Rs485UpdateCrc( d );
}
for ( c = 0; c < cLen; c++ )
{
d = cData[c];
Rs485SendChar( d ); // Send data
}
}
Rs485SendChar(cCalcCrcHigh);
Rs485SendChar(cCalcCrcLow);
delay_ms(1);
BIT_CLEAR( RS485_CONTROL, OUTPUTS_ON ); // Disable driver
BIT_SET( PIE1, RCIE ); // Enable Receive Interrupt
}
//****************************************************************************
// void Rs485GetPacket( char *cCommand, char cLen, char *cData )
//
// Pass packet to main application
//
//****************************************************************************
void Rs485GetPacket( char *cCom, char *cLen, char *cData )
{
char c;
*cCom = cCommand;
*cLen = cLenExpected;
for ( c=0; c < cLenExpected;c++ ) cData[c] = c485Buf[c];
cData[cLenExpected] = 0x00; // Termninate
}
/*************************************************************************
* Example Table Driven CRC16 Routine using 4-bit message chunks
*
* By Ashley Roll
* Digital Nemesis Pty Ltd
* www.digitalnemesis.com
* ash@digitalnemesis.com
*
* The following is an example of implementing a restricted size CRC16
* table lookup. No optimisation as been done so the code is clear and
* easy to understand.
*
* Test Vector: "123456789" (character string, no quotes)
* Generated CRC: 0x29B1
*
* Modified for CCS compiler by J.Winpenny
*************************************************************************/
/*
* CRC16 Lookup tables (High and Low Byte) for 4 bits per iteration.
*/
const char CRC16_LookupHigh[16] = {
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1
};
const char CRC16_LookupLow[16] = {
0x00, 0x21, 0x42, 0x63, 0x84, 0xA5, 0xC6, 0xE7,
0x08, 0x29, 0x4A, 0x6B, 0x8C, 0xAD, 0xCE, 0xEF
};
/*
* Before each message CRC is generated, the CRC register must be
* initialised by calling this function
*/
void CRC16_Init( void )
{
// Initialise the CRC to 0xFFFF for the CCITT specification
cCalcCrcHigh = 0xFF;
cCalcCrcLow = 0xFF;
}
/*
* Process 4 bits of the message to update the CRC Value.
*
* Note that the data must be in the low nibble of val.
*/
void CRC16_Update4Bits( char val )
{
char t;
// Step one, extract the Most significant 4 bits of the CRC register
t = cCalcCrcHigh >> 4;
// XOR in the Message Data into the extracted bits
t = t ^ val;
// Shift the CRC Register left 4 bits
cCalcCrcHigh = (cCalcCrcHigh << 4) | (cCalcCrcLow >> 4);
cCalcCrcLow = cCalcCrcLow << 4;
// Do the table lookups and XOR the result into the CRC Tables
cCalcCrcHigh = cCalcCrcHigh ^ CRC16_LookupHigh[t];
cCalcCrcLow = cCalcCrcLow ^ CRC16_LookupLow[t];
}
/*
* Process one Message Byte to update the current CRC Value
*/
void Rs485UpdateCrc( char cVal )
{
CRC16_Update4Bits( cVal >> 4 ); // High nibble first
CRC16_Update4Bits( cVal & 0x0F ); // Low nibble
}
//****************************************************************************
// void Rs485SendChar( char c )
//
// Driver level of RS485 protocol
// Output character on RS485 driver
// // Include line turn around time
//****************************************************************************
void Rs485SendChar( char c )
{
putc(c);
// TXREG = c; // Load data to send
// while ( !( TXSTA & TRMT_MASK )); // Wait for TX Empty
}
//****************************************************************************
// char PostValidatePacket(void)
//
// Verify the CRC on the last packet received
//
// Check if the CRC is correct
// and return the updated state as the result
//
//****************************************************************************
char PostValidatePacket(void)
{
char c, d;
CRC16_Init();
Rs485UpdateCrc(PKT_START);
Rs485UpdateCrc(cNetAddrHigh);
Rs485UpdateCrc(cNetAddrLow);
Rs485UpdateCrc(cLenExpected);
Rs485UpdateCrc(cCommand);
if ( PacketHasPayload() ) // If the packet has a payload,
{ // then include the data in the CRC.
for ( c = 0; c < cLenExpected; c++ )
{
d = c485Buf[c];
Rs485UpdateCrc( d );
}
}
// Check if the CRC is correct
// and return the updated state as the result
if ( (cRxCrcHigh == cCalcCrcHigh)&&(cRxCrcLow == cCalcCrcLow) )
{
cRS485State = PKT_VALID;
}
else
{
cError = BAD_CRC;
cRS485State = PKT_INVALID;
ClearLine2();
BinToHexAscii(cRxCrcHigh );
BinToHexAscii(cRxCrcLow );
LcdWrite(' ');
BinToHexAscii(cCalcCrcHigh);
BinToHexAscii(cCalcCrcHigh);
delay_ms(255);
delay_ms(255);
delay_ms(255);
delay_ms(255);
}
return cRS485State;
}
//****************************************************************************
// char GetPacketCmdType(void)
//
// Check packet command type
// Return TRUE if packet has a data payload.
//
//****************************************************************************
char PacketHasPayload(void)
{
if ( cCommand == SENSOR_GET_DATA ) return TRUE;
else return FALSE;
}
//****************************************************************************
// void BinToHexAscii( char c )
//
// Contributed by: Nick De Smith
//
//****************************************************************************
void BinToHexAscii( char c )
{
const char hexMap[17] = "0123456789ABCDEF";
LcdWrite( hexMap[(c >> 4) & 0xF] );
LcdWrite( hexMap[(c & 0xF)] );
}
[/code]
[code]
#separate
char Rs485Process(void);
void Rs485Initialise(char cAddrHigh, char cAddrLow);
#separate
char Rs485Decode( void );
void Rs485UpdateCrc(char cVal );
void CRC16_Init( void );
void CRC16_Update4Bits( char val );
void Rs485SendPacket( char cCmd, char cLen, char *cData );
void Rs485GetPacket( char *cCom, char *cLen, char *cData );
void Rs485SendChar( char c );
char PostValidatePacket(void);
char PacketHasPayload(void);
void BinToHexAscii( char c );
//#define NULL 0
// Configurables
#define RS485_CONTROL PORTC
#define OUTPUTS_ON 5 //decimal 0b0000 0101
#define NUM_TX_PREAMBLE 3
// Protocol defines
#define PKT_START 0x23 // packet start for master
#define SPKT_START 0x21 // slave packet start
// States of packet decoder state machine
#define PKT_WAIT_START 0
#define PKT_WAIT_ADDR_HIGH 1
#define PKT_WAIT_ADDR_LOW 2
#define PKT_WAIT_LEN 3
#define PKT_CMD 4
#define PKT_WAIT_DATA 5
#define PKT_WAIT_CRC_HIGH 6
#define PKT_WAIT_CRC_LOW 7
#define PKT_COMPLETE 8
#define PKT_VALID 9
#define PKT_INVALID 255
// Error codes
#define BAD_LENGTH 1
#define BAD_CRC 2
// Packet types
#define SENSOR_POLL_CMD 0xA1
#define SENSOR_PING_SYNC 0xA2
#define SENSOR_CONFIG 0xA3
#define SENSOR_GET_DATA 0xA4
#define SENSOR_ACK 0xB0
#define SENSOR_NAK 0xC0
[/code] |
|
![](templates/subSilver/images/spacer.gif) |
lguancho
Joined: 08 Sep 2003 Posts: 5
|
|
Posted: Mon Feb 21, 2005 4:28 am |
|
|
Hi,all. I include the header file for the 18F452 and RS485.c and Rs385.h
[code]
void Setup(void);
void ConfigureComms(void);
// EEPROM addresses
#define NET_ADDRESS_HIGH 0
#define NET_ADDRESS_LOW 1
#ifndef MASTER
// PORT Configuration For Slave
#define PortAConfig 0x3F
#define PortBConfig 0x00
#define PortCConfig 0x00
#define PortDConfig 0x00
#define PortEConfig 0x00
#else
// PORT Configuration // For Master
#define PortAConfig 0x00
#define PortBConfig 0x00
#define PortCConfig 0x0f
#define PortDConfig 0x00
#define PortEConfig 0x00
#endif
//*********************************************************************
#define TMR0_RELOAD 255 // TMR0 reload value
//#define TMR0_RELOAD 248 // TMR0 reload value
#BYTE PORTA = 0xF80
#BYTE PORTB = 0xF81
#BYTE PORTC = 0xF82
#BYTE PORTD = 0xF83
#BYTE PORTE = 0xF84
#BYTE LATA = 0xF89
#BYTE LATB = 0xF8A
#BYTE LATC = 0xF8B
#BYTE LATD = 0xF8C
#BYTE LATE = 0xF8D
#BYTE TRISA = 0xF92
#BYTE TRISB = 0xF93
#BYTE TRISC = 0xF94
#BYTE TRISD = 0xF95
#BYTE TRISE = 0xF96
#BYTE PIE1 = 0xF9D
#BYTE PIR1 = 0xF9E
#BYTE IPR1 = 0xF9F
#BYTE PIE2 = 0xFA0
#BYTE PIR2 = 0xFA1
#BYTE IPR2 = 0xFA2
#BYTE RCSTA = 0xFAB
#BYTE TXSTA = 0xFAC
#BYTE TXREG = 0xFAD
#BYTE RCREG = 0xFAE
#BYTE SPBRG = 0xFAF
#BYTE T3CON = 0xFB1
#BYTE TMR3L = 0xFB2
#BYTE TMR3H = 0xFB3
#BYTE CCP2CON = 0xFBA
#BYTE CCPR2L = 0xFBB
#BYTE CCPR2H = 0xFBC
#BYTE CCP1CON = 0xFBD
#BYTE CCPR1L = 0xFBE
#BYTE CCPR1H = 0xFBF
#BYTE ADCON1 = 0xFC1
#BYTE ADCON2 = 0xFC2
#BYTE ADRESL = 0xFC3
#BYTE ADRESH = 0xFC4
#BYTE SSPCON2 = 0xFC5
#BYTE SSPCON1 = 0xFC6
#BYTE SSPSTAT = 0xFC7
#BYTE SSPADD = 0xFC8
#BYTE SSPBUF = 0xFC9
#BYTE T2CON = 0xFCA
#BYTE PR2 = 0xFCB
#BYTE TMR2 = 0xFCC
#BYTE T1CON = 0xFCD
#BYTE TMR1L = 0xFCE
#BYTE TMR1H = 0xFCF
#BYTE RCON = 0xFD0
#BYTE WDTCON = 0xFD1
#BYTE LVDCON = 0xFD2
#BYTE OSCCON = 0xFD3
#BYTE T0CON = 0xFD5
#BYTE TMR0L = 0xFD6
#BYTE TMR0H = 0xFD7
#BYTE STATUS = 0xFD8
#BYTE FSR2L = 0xFD9
#BYTE FSR2H = 0xFDA
#BYTE PLUSW2 = 0xFDB
#BYTE PREINC2 = 0xFDC
#BYTE POSTDEC2 = 0xFDD
#BYTE POSTINC2 = 0xFDE
#BYTE INDF2 = 0xFDF
#BYTE BSR = 0xFE0
#BYTE FSR1L = 0xFE1
#BYTE FSR1H = 0xFE2
#BYTE PLUSW1 = 0xFE3
#BYTE PREINC1 = 0xFE4
#BYTE POSTDEC1 = 0xFE5
#BYTE POSTINC1 = 0xFE6
#BYTE INDF1 = 0xFE7
#BYTE WREG = 0xFE8
#BYTE FSR0L = 0xFE9
#BYTE FSR0H = 0xFEA
#BYTE PLUSW0 = 0xFEB
#BYTE PREINC0 = 0xFEC
#BYTE POSTDEC0 = 0xFED
#BYTE POSTINC0 = 0xFEE
#BYTE INDF0 = 0xFEF
#BYTE INTCON3 = 0xFF0
#BYTE INTCON2 = 0xFF1
#BYTE INTCON = 0xFF2
#BYTE PRODL = 0xFF3
#BYTE PRODH = 0xFF4
#BYTE TABLAT = 0xFF5
#BYTE TBLPTRL = 0xFF6
#BYTE TBLPTRH = 0xFF7
#BYTE TBLPTRU = 0xFF8
#BYTE PCL = 0xFF9
#BYTE PCLATH = 0xFFA
#BYTE PCLATU = 0xFFB
#BYTE STKPTR = 0xFFC
#BYTE TOSL = 0xFFD
#BYTE TOSH = 0xFFE
#BYTE TOSU = 0xFFF
// INTCON BITS
#define GIE 7
#define PEIE 6
#define TMR0IE 5
#define INT0IE 4
#define RBIE 3
#define TMR0IF 2
#define INT0IF 1
#define RBIF 0
// USART TXSTA Register bits
#define CSCR 7
#define TX9 6
#define TXEN 5
#define SYNC 4
#define BRGH 2
#define TRMT 1
#define TX9D 0
// USART RCSTA Register bits
#define SPEN 7
#define RX9 6
#define SREN 5
#define CREN 4
#define ADDEN 3
#define FERR 2
#define OERR 1
#define RX9D 0
#define TRMT_MASK 2
// Bits of STATUS register
#define NEGATIVE 4
#define OV 3 // Overflow
#define ZERO 2
#define DIG_CARRY 1
#define CARRY 0
// Bits of PIE1
#define PSPIE 7
#define ADIE 6
#define RCIE 5
#define TXIE 4
#define SSPIE 3
#define CCP1IE 2
#define TMR2IE 1
#define TMR1IE 0
// Bits of SSPSTAT
#define SMP 7
#define CKE 6
#define D_A 5
//#define P 4 // Cause compiler error because of identifier s
//#define S 3
#define R_W 2
#define UA 1
#define BF 0
#define R_W_MASK 0x04
// Bits of PIR1
#define PSPIF 7
#define ADIF 6
#define RCIF 5
#define TXIF 4
#define SSPIF 3
#define CCP1IF 2
#define TMR2IF 1
#define TMR1IF 0
#define SSPIF_MASK 0x08
// Bits of SSPCON2
#define GCEN 7
#define ACKSTAT 6
#define ACKDT 5
#define ACKEN 4
#define RCEN 3
#define PEN 2
#define RSEN 1
#define SEN 0
// Bits of RCON - Note: PCON for Pic16F877
#define IPEN 7
#define RI 4
#define TO 3
#define PD 2
#define POR 1
#define BOR 0
// Bits of INTCON2
#define RBPU 7
#define INTEDG0 6
#define INTEDG1 5
#define INTEDG2 4
#define TMR01P 2
#define RBIP 0
// Bits of T0CON Note - OPTION_REG for PIC16
#define TMR0ON 7 //
#define T08BIT 6
#define T0CS 5
#define T0SE 4
#define PSA 3
#define T0PS2 2 //PS2
#define T0PS1 1 //PS1
#define T0PS0 0 //PS0
[/code]
RS485.C Listing
[code]
//**************************************************************************
// Rs495.c
// RS485 network protocol
//
// Version 1.0 beta
//
// Processor: PIC16F87x
//
// Network packet protocol:
//
// STX ( 0x02 )
// NET ADDRESS HIGH
// NET ADDRESS LOW
// PAYLOAD LENGTH
// COMMAND
// DATA ( Optional )
// CRC HIGH
// CRC LOW
//
//
//
//
//
// By: J.Winpenny
// j.winpenny@ukonline.co.uk
//
//**************************************************************************
//#include "D:\rs485net\Include\Rs485.h"
//#include <lcd.c>
//#include "D:\rs485net\Include\lcd873b.h"
//struct
//{
static char cOurAddrHigh;
static char cOurAddrLow;
static char cRs485RxChar;
static char cRS485State;
static char cStart;
static char cNetAddrHigh, cNetAddrLow;
static char cLenExpected;
static char cCommand;
static char c485Buf[64];
static char cRxCrcHigh, cRxCrcLow;
static char cCalcCrcHigh, cCalcCrcLow;
static char cBufPtr;
static char cError;
static char cCrcTmp, cCrcTmp5, cCrcTmp4, cCrcTmp3, cCrcTmp2;
//} RS485_Protocol;
//****************************************************************************
// void Rs485Initialise(void)
//
// Initialise RS485 network driver Note- No Change
//****************************************************************************
void Rs485Initialise(char cAddrHigh, char cAddrLow)
{
cOurAddrHigh = cAddrHigh;
cOurAddrLow = cAddrLow;
cRS485State = PKT_WAIT_START;
BIT_CLEAR( RS485_CONTROL, OUTPUTS_ON ); // Disable driver
BIT_SET( PIE1, RCIE ); // Enable Receive Interrupt
}
//****************************************************************************
// char PacketForUs(void)
//
// Decide if packet valid and destined for this node.
// Ignore invalid packets and packets for other nodes Note: No Change
//
//****************************************************************************
#separate
char Rs485Process(void)
{
char cOurPkt, cPktReady;
cOurPkt = FALSE;
cPktReady = FALSE;
disable_interrupts(GLOBAL);
if ( cRS485State == PKT_COMPLETE )
{
if ( ( cNetAddrHigh == cOurAddrHigh )&& // valid and destined for this node
( cNetAddrLow == cOurAddrLow ) )
{
cOurPkt = TRUE;
}
else
{
ClearLine2();
LcdWrite("traffic"); // Network traffic for other nodes
delay_ms(200);
}
cRS485State = PostValidatePacket(); // Validate packet CRC
if ( (cRS485State == PKT_INVALID)||(cRS485State == PKT_VALID) )
{
// Reject invalid packets
if ( cRS485State == PKT_INVALID ) // NAK our invalid packets
{
ClearLine2();
if ( cError == BAD_CRC ) LcdWrite("Bad CRC");
else if ( cError == BAD_LENGTH ) LcdWrite("Bad length");
delay_ms(200);
//if ( cOurPkt ) Rs485SendPacket( SENSOR_NAK, 0, NULL );
cRS485State = PKT_WAIT_START;
}
else if ( cRS485State == PKT_VALID ) // If packet valid
{ // and destined for this node
if ( cOurPkt ) cPktReady = TRUE;
else cRS485State = PKT_WAIT_START;
}
}
}
enable_interrupts(GLOBAL);
return cPktReady;
}
//****************************************************************************
// void Rs485Decode(void)
//
// Decode an incomming packet on the RS485 network
//
// Expecting:
// START,
// NETWORK ADDRESS_HIGH,
// NETWORK ADDRESS_LOW,
// PAYLOAD LENGTH,
// COMMAND,
// optional DATA,
// CRC HIGH,
// CRC LOW Note: No Change
//
//****************************************************************************
#separate
char Rs485Decode( void )
{
switch ( cRS485State )
{
case PKT_WAIT_START: cStart = cRs485RxChar;
if ( cRs485RxChar == PKT_START ) // Check for the start of packet byte
{
cRS485State++;
}
break;
case PKT_WAIT_ADDR_HIGH: cNetAddrHigh = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_ADDR_LOW: cNetAddrLow = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_LEN: cLenExpected = cRs485RxChar;
if ( cLenExpected > sizeof(c485Buf) )
{
cRS485State = PKT_INVALID;
cError = BAD_LENGTH;
}
else
{
cBufPtr = 0;
cRS485State++;
}
break;
case PKT_CMD: cCommand = cRs485RxChar;
if ( PacketHasPayload() ) cRS485State = PKT_WAIT_DATA;
else cRS485State = PKT_WAIT_CRC_HIGH;
break;
case PKT_WAIT_DATA: c485Buf[cBufPtr] = cRs485RxChar;
cBufPtr++;
if ( cBufPtr == cLenExpected ) // If last byte of data received
{
cRS485State++; // next byet is the CRC high byte
}
break;
case PKT_WAIT_CRC_HIGH: cRxCrcHigh = cRs485RxChar;
cRS485State++;
break;
case PKT_WAIT_CRC_LOW: cRxCrcLow = cRs485RxChar;
cRS485State = PKT_COMPLETE;
break;
case PKT_COMPLETE: break; // Idle state
case PKT_VALID: break; // Idle state
case PKT_INVALID: break; // Idle state
default: cRS485State = PKT_WAIT_START;
break;
}
return cRS485State;
}
//****************************************************************************
// void Rs485SendPacket( char cAddr, char cCmd, char cLen, char *cData )
//
// Send a packet over the RS485 link
//
// Input: NETWORK_ADDRESS, COMMAND, PAYLOAD_LENGTH, optional DATA
// Note: No Change
//****************************************************************************
void Rs485SendPacket( char cCmd, char cLen, char *cData )
{
char c, d;
BIT_CLEAR( PIE1, RCIE ); // Disable Receive Interrupt
BIT_SET( RS485_CONTROL, OUTPUTS_ON ); // Enable driver
delay_ms(1); // Line turnarround time
cCalcCrcHigh = 0xff; // Clear CRC
cCalcCrcLow = 0xff;
// Send some NULL preamblesfopr receiving UART
//for ( c=0; c < NUM_TX_PREAMBLE; c++ ) Rs485SendChar( 0x00 );
Rs485UpdateCrc( PKT_START );
Rs485SendChar( PKT_START ); // Send packet start character
Rs485UpdateCrc( cOurAddrHigh );
Rs485SendChar( cOurAddrHigh ); // Send address high
Rs485UpdateCrc( cOurAddrLow );
Rs485SendChar( cOurAddrLow ); // Send address low
Rs485UpdateCrc( cLen );
Rs485SendChar( cLen ); // Send length
Rs485UpdateCrc( cCmd );
Rs485SendChar( cCmd ); // Send command
if ( cLen != 0 ) // If payload not empty send data
{
for ( c = 0; c < cLen; c++ )
{
d = cData[c];
Rs485UpdateCrc( d );
}
for ( c = 0; c < cLen; c++ )
{
d = cData[c];
Rs485SendChar( d ); // Send data
}
}
Rs485SendChar(cCalcCrcHigh);
Rs485SendChar(cCalcCrcLow);
delay_ms(1);
BIT_CLEAR( RS485_CONTROL, OUTPUTS_ON ); // Disable driver
BIT_SET( PIE1, RCIE ); // Enable Receive Interrupt
}
//****************************************************************************
// void Rs485GetPacket( char *cCommand, char cLen, char *cData )
//
// Pass packet to main application
//
//****************************************************************************
void Rs485GetPacket( char *cCom, char *cLen, char *cData )
{
char c;
*cCom = cCommand;
*cLen = cLenExpected;
for ( c=0; c < cLenExpected;c++ ) cData[c] = c485Buf[c];
cData[cLenExpected] = 0x00; // Termninate
}
/*************************************************************************
* Example Table Driven CRC16 Routine using 4-bit message chunks
*
* By Ashley Roll
* Digital Nemesis Pty Ltd
* www.digitalnemesis.com
* ash@digitalnemesis.com
*
* The following is an example of implementing a restricted size CRC16
* table lookup. No optimisation as been done so the code is clear and
* easy to understand.
*
* Test Vector: "123456789" (character string, no quotes)
* Generated CRC: 0x29B1
*
* Modified for CCS compiler by J.Winpenny
*************************************************************************/
/*
* CRC16 Lookup tables (High and Low Byte) for 4 bits per iteration.
*/
const char CRC16_LookupHigh[16] = {
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1
};
const char CRC16_LookupLow[16] = {
0x00, 0x21, 0x42, 0x63, 0x84, 0xA5, 0xC6, 0xE7,
0x08, 0x29, 0x4A, 0x6B, 0x8C, 0xAD, 0xCE, 0xEF
};
/*
* Before each message CRC is generated, the CRC register must be
* initialised by calling this function
*/
void CRC16_Init( void )
{
// Initialise the CRC to 0xFFFF for the CCITT specification
cCalcCrcHigh = 0xFF;
cCalcCrcLow = 0xFF;
}
/*
* Process 4 bits of the message to update the CRC Value.
*
* Note that the data must be in the low nibble of val.
*/
void CRC16_Update4Bits( char val )
{
char t;
// Step one, extract the Most significant 4 bits of the CRC register
t = cCalcCrcHigh >> 4;
// XOR in the Message Data into the extracted bits
t = t ^ val;
// Shift the CRC Register left 4 bits
cCalcCrcHigh = (cCalcCrcHigh << 4) | (cCalcCrcLow >> 4);
cCalcCrcLow = cCalcCrcLow << 4;
// Do the table lookups and XOR the result into the CRC Tables
cCalcCrcHigh = cCalcCrcHigh ^ CRC16_LookupHigh[t];
cCalcCrcLow = cCalcCrcLow ^ CRC16_LookupLow[t];
}
/*
* Process one Message Byte to update the current CRC Value
*/
void Rs485UpdateCrc( char cVal )
{
CRC16_Update4Bits( cVal >> 4 ); // High nibble first
CRC16_Update4Bits( cVal & 0x0F ); // Low nibble
}
//****************************************************************************
// void Rs485SendChar( char c )
//
// Driver level of RS485 protocol
// Output character on RS485 driver
// // Include line turn around time
//****************************************************************************
void Rs485SendChar( char c )
{
putc(c);
// TXREG = c; // Load data to send
// while ( !( TXSTA & TRMT_MASK )); // Wait for TX Empty
}
//****************************************************************************
// char PostValidatePacket(void)
//
// Verify the CRC on the last packet received
//
// Check if the CRC is correct
// and return the updated state as the result
//
//****************************************************************************
char PostValidatePacket(void)
{
char c, d;
CRC16_Init();
Rs485UpdateCrc(PKT_START);
Rs485UpdateCrc(cNetAddrHigh);
Rs485UpdateCrc(cNetAddrLow);
Rs485UpdateCrc(cLenExpected);
Rs485UpdateCrc(cCommand);
if ( PacketHasPayload() ) // If the packet has a payload,
{ // then include the data in the CRC.
for ( c = 0; c < cLenExpected; c++ )
{
d = c485Buf[c];
Rs485UpdateCrc( d );
}
}
// Check if the CRC is correct
// and return the updated state as the result
if ( (cRxCrcHigh == cCalcCrcHigh)&&(cRxCrcLow == cCalcCrcLow) )
{
cRS485State = PKT_VALID;
}
else
{
cError = BAD_CRC;
cRS485State = PKT_INVALID;
ClearLine2();
BinToHexAscii(cRxCrcHigh );
BinToHexAscii(cRxCrcLow );
LcdWrite(' ');
BinToHexAscii(cCalcCrcHigh);
BinToHexAscii(cCalcCrcHigh);
delay_ms(255);
delay_ms(255);
delay_ms(255);
delay_ms(255);
}
return cRS485State;
}
//****************************************************************************
// char GetPacketCmdType(void)
//
// Check packet command type
// Return TRUE if packet has a data payload.
//
//****************************************************************************
char PacketHasPayload(void)
{
if ( cCommand == SENSOR_GET_DATA ) return TRUE;
else return FALSE;
}
//****************************************************************************
// void BinToHexAscii( char c )
//
// Contributed by: Nick De Smith
//
//****************************************************************************
void BinToHexAscii( char c )
{
const char hexMap[17] = "0123456789ABCDEF";
LcdWrite( hexMap[(c >> 4) & 0xF] );
LcdWrite( hexMap[(c & 0xF)] );
}
[/code]
[code]
#separate
char Rs485Process(void);
void Rs485Initialise(char cAddrHigh, char cAddrLow);
#separate
char Rs485Decode( void );
void Rs485UpdateCrc(char cVal );
void CRC16_Init( void );
void CRC16_Update4Bits( char val );
void Rs485SendPacket( char cCmd, char cLen, char *cData );
void Rs485GetPacket( char *cCom, char *cLen, char *cData );
void Rs485SendChar( char c );
char PostValidatePacket(void);
char PacketHasPayload(void);
void BinToHexAscii( char c );
//#define NULL 0
// Configurables
#define RS485_CONTROL PORTC
#define OUTPUTS_ON 5 //decimal 0b0000 0101
#define NUM_TX_PREAMBLE 3
// Protocol defines
#define PKT_START 0x23 // packet start for master
#define SPKT_START 0x21 // slave packet start
// States of packet decoder state machine
#define PKT_WAIT_START 0
#define PKT_WAIT_ADDR_HIGH 1
#define PKT_WAIT_ADDR_LOW 2
#define PKT_WAIT_LEN 3
#define PKT_CMD 4
#define PKT_WAIT_DATA 5
#define PKT_WAIT_CRC_HIGH 6
#define PKT_WAIT_CRC_LOW 7
#define PKT_COMPLETE 8
#define PKT_VALID 9
#define PKT_INVALID 255
// Error codes
#define BAD_LENGTH 1
#define BAD_CRC 2
// Packet types
#define SENSOR_POLL_CMD 0xA1
#define SENSOR_PING_SYNC 0xA2
#define SENSOR_CONFIG 0xA3
#define SENSOR_GET_DATA 0xA4
#define SENSOR_ACK 0xB0
#define SENSOR_NAK 0xC0
[/code] |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|