|
|
View previous topic :: View next topic |
Author |
Message |
mesuty Guest
|
RS422 comm slowing down the CPU |
Posted: Thu Apr 21, 2005 1:11 am |
|
|
Hi friends;
The code below is for a 30 node PIC18F452 connected to a PC via 4 wire RS422 system. System is working perfectly except.
1) When I set the adress , the CPU is getting correct address numbre. Say , If I give 0x01 as the node number , it is answering all the calls to node 0x01. But when I use the printf ("#%2X\r\n",RS485_ID) to read adress back , it is giving 0xD9 instead of 0x01.
2) After a couple of minutes of communication , total system is slowing down in communication, nearly 10-20 times.
Each message sent from PC contains @@nnCCPP+0x0d
where @@=header
nn : Node number
CC : Command
PP : Param value if needed.
CR (0x0d)
Do you think Should I rewrite the comms routines?.
Can somebody give me a ASCII charecter based example to broadcast just 5-6 bytes of data to subscribers of line.
Note. My compiler is PCWH 3.221
All ideas are wellcome.
Code: |
#include <18F452.h>
#device adc=8
#use delay(clock=16000000)
#fuses NOWDT,WDT128,HS, PROTECT, NOOSCSEN, BROWNOUT, BORV20, NOPUT, STVREN, NODEBUG, NOLVP, NOWRT, NOWRTD, NOWRTB, NOWRTC, NOCPD, NOCPB, NOEBTR, NOEBTRB
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9,ENABLE=PIN_C1,stream=PC)
#ZERO_RAM
int RS485_ID;
char inbuf[12]=" ";
byte gethex(char digit) {
if(digit<='9')
return(digit-'0');
else
return((toupper(digit)-'A')+10);
}
#int_RDA
RDA_isr()
{
int a,b;
gets(inbuf);
//output_high(PIN_C1);
//puts(inbuf);
if(inbuf[0]=='@' && inbuf[1]=='@') // @@ message header
{
if (inbuf[2]=='G' && inbuf[3]=='M') //GLOBAL SET metre sayac
{
metre_hedef=256*(inbuf[4])*16+gethex(inbuf[5]) + (inbuf[6])*16+gethex(inbuf[7]);
}
if (inbuf[2]=='G' && inbuf[3]=='R') //GLOBAL RUN
{
WM_RUN=1;
}
if (inbuf[2]=='G' && inbuf[3]=='S') //GLOBAL STOP
{
WM_RUN=0;
}
// Adres set procedure @@ AS NN ,(00..FF)
// During address set , node number not required.
if (inbuf[2]=='A' && inbuf[3]=='S')
{
RS485_ID=gethex((inbuf[4])*16+gethex(inbuf[5]));
write_eeprom (0,RS485_ID);
output_high(PIN_C1);
delay_ms(100); // EEpromda yazma tamamlanana dek bekle
printf ("#%2X\r\n",RS485_ID-208);
output_low(PIN_C1);
}
//If message blongs to this CPU
if (RS485_ID==gethex((inbuf[2])*16+gethex(inbuf[3])))
{ //output_high(PIN_C1);
switch (inbuf[4])
{
case 'M': { if (inbuf[5]=='S')//Metre counter value
{
metre_hedef=256*(inbuf[6])*16+gethex(inbuf[7]) + (inbuf[8])*16+gethex(inbuf[9]);
#IF (DEBUG==TRUE)
#ENDIF
}
Break;}
case 'W' : { if (inbuf[5]=='R')// Wax motor run
{
WM_RUN=1;
}
if (inbuf[5]=='S') // Wax motor Stop
{
WM_RUN=0;
}
}
Break;
case 'S' :{ if (inbuf[5]=='S') // Status send (inquiry)
{
}
printf("#%2X%c\r\n",RS485_ID-208,ST_stat); //Node status
Break;
}
}
}
}
//Clear comm buffer
for (a=0;a++;a<12) {
inbuf[a]=' ';
}
}
void INIT_MCU()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16|RTCC_8_bit);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
RS485_ID=read_eeprom(0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
set_tris_a(0b00111111); // All in
set_tris_b(0b11001111);
set_tris_c(0b10110000);
set_tris_d(0b00000000);
set_tris_e(0b00000000);
}
void main()
{
INIT_MCU();
MPC_Reset();
init_vars();
enable_interrupts(INT_RDA); // open serial port
ST_stat='R'; // Status :=AFTER_RESET
While(1)
{
//Normal tasks
}
} |
|
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Apr 21, 2005 6:23 am |
|
|
See this line
Code: | enable_interrupts(INT_TIMER1);
|
I don't see an interrupt handler for it. This will cause your program to constantly run the interrupt handler and run dog slow. |
|
|
TSchultz
Joined: 08 Sep 2003 Posts: 66 Location: Toronto, Canada
|
|
Posted: Thu Apr 21, 2005 6:52 am |
|
|
You really need to reduce the code in your serial interrupt handler. You should just receive, maybe validate, the packet, then once you have the full packet set a flag so a handler in the main loop can decode and process the packet.
Here is the code I run for RS485, it is a custom prototocol but should be easy to follow. The code has been fairly well optimized (I think).
Code: | /****************************************************************************
Interrupt routine to receive data using internal USART.
Routine handles all aspects of packet collection and validation.
NewData is set when a complete and valid packet has been received if;
- BOF must be valid
- ID must be ours, or global id
- number of bytes must match LEN field
- FCS must be valid, will be zero if correct
- EOF must be found after FCS character
- all bytes must be received within allowed timeframe (see timer ISR routine)
*****************************************************************************/
#INT_RDA
void isr_RXSerial( void ) {
static byte FCS, c;
if( kbhit() ) { //test to make sure byte is in buffer, ISR may have been called erroneously
c = getc(); //get byte from buffer
if ( !serialA_Working ) { //Are we already getting a packet?
serialA_Working = ( c == BOF ); //if BOF then we are getting a packet
serialA_Timeout = false; //clear timeout
serialA_Bytes = 0; //we have no data bytes yet
serialA_GoodData = 0;
PacketErr++; //Assume packet is bad until verified
} else {
serialA.Buffer[serialA_Bytes] = c; //put character in buffer
serialA_Working = ( serialA_Bytes++ < SERIAL_BUFFER_SIZE ); //don't exceed buffer size
if (serialA_Bytes == 1) {
serialA_Working = ( ClientID == c ) || ( GlobalID == c ); // If ID no good then discard remaining chars
serialA_Reply = ( ClientID == c ); // Allow reply if ID is ClientID, don't reply if GlobalID
FCS = c; //set FSC with first byte
} else if ( serialA_Bytes <= serialA.Data.LEN + 1 ) {
FCS ^= c; //Still getting data bytes so accumulate FSC
} else if ( c == EOF ) { //Check EOF
if( FCS == 0 ){
PacketErr--; //FSC is valid so packet is not in error
serialA_GoodData = 1;
}
serialA_NewData = 1; //( FCS == 0 ); //If FSC is good then we have good packet
serialA_Working = false; //We are no longer getting data
PacketsRX++; //Increment good packet count
} else {
serialA_Working = false; // data receive error so stop grabbing data
}
}
}
}
|
In my main loop I then check for serialA_NewData, it true then I have a good packet to work with. The only other thing not in the code above is a timeout which is handled in a timer irq, it just clears SerialA_Working which aborts the current RX.
Hope this helps some. |
|
|
|
|
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
|