Every processor has its own special interrupt-handling quirks.
Microchip's PIC18F4331 page
has links to an errata document and
the PIC18F4331 datasheet.
In particular, the datasheet has some good tips in
section 20
"Enhanced universal synchronous asynchronous receiver transmitter (EUSART)"
and even more particularly,
the 3 steps listed in section 20.0
and the 10 steps of
"To set up an Asynchronous Reception"
in section 20.3.2.
I've changed a few things that look like they might help:
// WARNING: untested code
int main(void){
//***********************Initializing Values****************************//
unsigned int ResultADC, FLAG;
unsigned char temp, idle; //High Byte result store, 8bits long
//***********************ADC and SPI Settings****************************//
Initialize_control(); //Initialize Control Configuration Pins
InitializeADC(); //Initialize ADC in Continuous Mode
USART_initialize(); //Initialize USART module
InitializeMasterSPI(); //Initialize SPI module
//***********************ADC Capture and Output to SPI******************//
while(1){ //While ADC buffer has something
//Enable transmission
TXREG = 0xff; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
TXREG = 0x0; //Debugger
while(!TXSTAbits.TRMT);//wait while TSR is full
}
return 0;
}
//////////////////INTERRUPT SERVICE ROUTINE/////////////////
static void interrupt isr(void){
// The PIC hardware has already disabled global interrupts
// by the time it starts executing the ISR,
// so there's no need to do "PIE1bits.RCIE = 0;".
int count;
//Read USART data
//PIR1bits.RCIF;//Data has been passed to RCREG
RX_Data[count] = RCREG; //Read RX register
count++;
//Reading RCREG automatically clears the RX flag.
// so there's no need to do "PIR1bits.RCIF = 0;".
// Q: How to read more than 1 byte?
// A: FIGURE 20-5 of the datasheet
// Implies that there's only a 1 byte buffer.
// Therefore, to read more than 1 byte, we must:
// pull the current byte out of the hardware buffer,
// store it in a software buffer RX_Data[] in RAM,
// then return to normal background main loop
// until the next byte in the message
// triggers another interrupt.
// Would it be better to do the following in the main loop?
if (count==3){
//Use data for control
Control_Arduino(RX_Data);
count = 0;
}
/*
The datasheet p. 229 is a little confusing about
whether "CREN" should be set (step 5) or cleared (step 9).
p. 219 which clearly seems to say CREN should be set.
But maybe it needs to be cleared to flush out any errors,
and then be set?
Are the following 2 lines really necessary?
*/
RCSTAbits.CREN = 0; //clear error (if any)
RCSTAbits.CREN = 1; //Enables Receiver
// the PIC hardware enables global interrupts
// automatically during the return-from-interrupt,
// so there's no need to do a "PIE1bits.RCIE = 1;"
// See the datasheet section 10.0: "Interrupts" for details.
}
//**********************Functions****************************//
void USART_initialize(void){
//Configuration TX and RX pins
// *normally* we use a "0" to indicate "output",
// but the TX output pin is different, see p. 217 of datasheet
TRISCbits.RC6 = 1; //TX output
TRISCbits.RC7 = 1; //RX input
//TXSTA: Transmit Status and Control Register
TXSTAbits.SYNC = 0; //Asynchronous mode
TXSTAbits.TX9 = 0; //8bit transmission
TXSTAbits.BRGH = 1; //Set HIGH Baud rate
TXSTAbits.TXEN = 1; //Enable transmitter
TXSTAbits.SENDB = 0; //Disable break
//RCSTA: Receive Status and Control Register
RCSTAbits.SPEN = 1; //Serial Port enabled
RCSTAbits.RX9 = 0; //8bit reception
RCSTAbits.CREN = 1; //Enables Receiver
//Test bits
// RCSTAbits.FERR = 0; //No framing error, cleared by reading
// RCSTAbits.OERR = 0; //No Overrun error, cleared by clearing CREN
//Disable receiver CREN 0
//BAUDCON Control register
BAUDCONbits.BRG16 = 1; //16bit baud rate generator
SPBRG = 0xCF; // Set to 19200 baud rate, 12Mhz, High Speed, BRG16
//Test bits
// BAUDCONbits.RCIDL = 0; //Receive in progress
// USART interrupts configuration
RCONbits.IPEN = 1; // ENABLE interrupt priority
// (p. 4 of http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf )
ei(); // same as INTCONbits.GIE = 1; // ENABLE interrupts
INTCONbits.PEIE = 1; // ENable peripheral interrupts.
PIE1bits.RCIE = 1; // ENABLE USART receive interrupt
PIE1bits.TXIE = 0; // disable USART TX interrupt
// make sure the RX flag is clear
PIR1bits.RCIF = 0;
}
Other code online:
"AN944: Using the EUSART on the PIC16F688"
http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf
https://forum.sparkfun.com/viewtopic.php?t=7542
http://panteltje.com/panteltje/pic/scope_pic/
http://www.microchip.com/forums/m411875.aspx
http://www.enmcu.com/guides/autobaudratebasedoneusartmodule
Tell us if you ever figure out the real problem, OK?
RECEIVING
The normal approach for implementing a software asynchronous receiver is to have a timer tick that runs continuously at 3x or 5x the baud rate (note: odd numbers are better than even numbers). Watch the input to be low on two consecutive ticks. Once that is observed, start sampling the input on every third tick, until you have sampled it nine more times. If the input is high on the ninth time, you've received a properly-framed character. If it's low on the ninth time, you have a framing error.
* * * S - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - S
-----______000000111111222222333333444444555555666666777777----
--______000000111111222222333333444444555555666666777777-------
The above timing diagram shows how things should work. The top line shows what happens on each timer tick (each non-blank is a timer tick; the * is a tick waiting for the start bit, a S is checking to ensure that the line is still low after having received what looked like a start bit. The numbers 0-7 represent the sampling of bits 0-7, and S is the stop bit. The bottom two lines show the incoming data in the cases where one just barely catches the beginning of a start bit (on the third asterisk), or where one just barely misses catching it on one interrupt (so the line's been low for a third of a bit time by the time the start bit is noticed). Note that even with that level of uncertainty, the source is guaranteed to be sending bit 0 when it's sampled, and likewise for the rest of the bits.
One software approach is to sample the line at the indicated interrupts and ignore it on the ones marked with dashes. An alternative is to blindly sample the line on every interrupt into a 32-bit shift register, using something like:
rrf headtail,w
bcf _tail,3
btfsc _INPUTPORT,_INPUTBIT
bsf _STATUS,_tail,3
rrf buff2,w
movff buff1,buff2
movff buff0,buff1
movwf buff0
rrf headtail,f
The last four bits received from the port will be in headtail bits 3..0. The 24 bits before those will be in buff0..buff2, with each one holding every third bit. The bits before that will be in headtail bits 7..4. If one does that, one can check whether headtail holds the bit pattern 00xxxx1x. If it does, copy buff1 to wherever you want the incoming data, copy buff1 to the spot you want the data, OR headtail with 11000011, and full buff0..buff2 with FF. Otherwise do nothing. This approach may be a tiny bit slower than selectively loading or ignoring the data input, but may be better able to recover from framing errors.
TRANSMISSION
Transmission is easier than reception. Arrange for a piece of code to run once per bit time (if your tick is at 3x the baud rate, run the code every third tick). The simplest way to set up the code is to use a couple of bytes to hold the data that should be sent out the port, including start and stop bits. There are a variety of approaches one may use. A rather versatile one would be:
; At start of interrupt
btfss TransmitBuffL,0
bcf OUTPUT
btfsc TransmitBuffL,0
bsf OUTPUT
; Later, after having handled reception:
btfss TransmitBitsLeft,7 ; Assume this counts down to -1 (i.e. 255)
decfsz TransmitTicks,f
goto noTransmit ; Transmit if no bits left, or no ticks
movlw 3
movwf TransmitTicks ; Handle bit transmission every third interrupt
decf TransmitBitsLeft,f
rrf TransmitBuffH,f
rrf TransmitBuffL,f
NoTransmit:
One may prepare a byte for transmission when TransmitTicks bit 7 is set. When that is the case, place the bit sequence to be set into TransmitBuffH and TransmitBuffL, set TransmitTicks to the length of the first bit (typically 3), and TransmitBitsLeft to the total length of the word including start and stop bits. Something like:
TxByte: ; Sends byte in W. Assumes TransmitBitsLeft has high bit set
movwf TransmitBuffL,f
movlw 3
movwf TransmitTicks
movwf TransmitBuffH,f ; LSB (stop bit) is set. Upper bits don't matter.
movlw 9 ; Total frame length (incl. start and stop) minus one
movwf TransmitBitsLeft
bcf _STATUS,_CARRY ; Start bit should be low
rlf TransmitBuffL,f ; Stick start bit in front of what we're sending
rlf TransmitBuffH,f
This approach can send out normal data frames using the style indicated. If one needs more stop bits, one may make sure TransmitBuffH has enough bits set, and increase TransmitBitsLeft appropriately. If one wants to send out a BREAK, one may set TransmitBuffL to 2 and TransmitBitsLeft to 1, set TransmitTicks to the desired length of the break signal (in ticks). To idle the line for a certain length of time, set TransmitBuffL to 1, TransmitBitsLeft to 0, and set TransmitTicks to the desired idle time (in ticks).
Best Answer
It's a little confusing that the code in the question differs to the code in pastebin - but assuming that the pastebin code is correct, I'd say that the problem is that you're sending uninitialised data from the array instead of the characters that you put in it.
should be
It's important to copy/paste the code directly (using pastebin is great!) because you've actually corrected this yourself in the question - making it hard for people to spot the problem :)
This may have been easier to spot yourself if you initialised the buffer to a known value on startup (eg 0x5A).
You also mention that you reset the
TxCurrentPos
&TxEndPos
variables to zero at some point, but I can't see that in your code. It's best to do this whenever you increment those values. EgAside: I like that you've removed the redundant TxBufferSize variable in the question - this follows the DRY Principle and eliminates the source for an error. Having data duplicated in two spots is asking for trouble.