I'm trying to send data to an SD card from a PIC18f4580, but the PIC is not sending what it should be.
related global variables:
unsigned c开发者_如何学Pythonhar TXBuffer[128]; //tx buffer
unsigned char TXCurrentPos = 0x00; //tracks the next byte to be sent
unsigned char TXEndPos = 0x00; //tracks where new data should be put into the array
I am adding data to a buffer using the following function:
void addToBuffer(char data){
TXBuffer[TXEndPos] = data;
TXEndPos++;
}
And putting the data from the TXBuffer into TXREG with the following interrupt:
else if (PIR1bits.TXIF == 1){
if((TXEndPos - TXCurrentPos) > 0){ // if there is data in the buffer
TXREG = TXBuffer[TXCurrentPos]; // send next byte
TXCurrentPos++; // update to the new position
}
Using an oscilloscope I am able to see that the PIC is sending 0x98, regardless of what I put into the buffer. In fact I never put 0x98 into the buffer.
However, if I replace
TXREG = TXBuffer[TXCurrentPos];
with
TXREG = 0x55;
or
TXREG = TXCurrentPos;
then I get the expected results, that is the PIC will send 0x55 repeatedly, or count up from 0 respectively.
So why does the PIC have trouble sending data from the array, but any other time it is fine? I'll emphasize that transferring is handled in an interrupt, because I feel like that's the root of my issue.
EDIT: It is a circular buffer in the sense that TXEndPos and TXCurrentPos return to 0 when they reach 127. I also disable the transmit interrupt when TXEndPos - TXCurrentPos == 0, and re-enable it when adding data to the buffer. Really, my code works completely as expected in that if I add 13 characters to TXBuffer in main, my PIC will transmit 13 characters and then stop. The problem is that they are always the same (wrong) character - 0x98.
EDIT2: more complete functions are here: http://pastebin.com/MyYz1Qzq
Perhaps TXBuffer doesn't really contain the data you think it does? Maybe you're not calling addToBuffer or calling it at the wrong time or with the wrong parameter?
You can try something like this in your interrupt handler:
TXBuffer[TXCurrentPos] = TXCurrentPos;
TXREG = TXBuffer[TXCurrentPos];
TXCurrentPos++;
Just to prove to yourself you can read and write to TXBuffer and send that to the USART.
Also try:
TXREG = TXEndPos;
To see if this matches your expectation (= the length of your message).
I am assuming there's some other code we're not seeing here that takes care of starting the transmission. Also assuming this is done per message with the position being reset between messages - i.e. this is not supposed to be a circular buffer.
EDIT: Based on looking at the more recently posted code: Don't you need to kickstart the transmitter by writign the first byte of your buffer to TXREG? What I would normally do is enable the interrupt and write the first byte into the transmit register and a quick look at the datasheet seems to indicate that's what you need to do. Another thing is I still don't see how you ensure a wraparound from 127 to 0?
Also your main() seems to just end abruptly, where does the execution continue once main ends?
There are a lot of things you are not taking care of. TXBuffer needs to be a circular buffer. Once you increment TXEndPos past 127 then you need to wrap it back to 0. Same for TXCurrrentPos. That also affects the test to see if there's something in the buffer, the > 0 test isn't good enough. Generic advice is available here.
Your code is incomplete, but it looks wrong as-is: what happens if there is nothing to send? You don't seem to load TXREG
then, so why would anything be transmitted, be it 0x98
or anything else?
The way it is usually done when this kind of code architecture is used is to turn off TXIE
if there is nothing to send (in a else
part of the IRQ routine), and turn it on unconditionally at the end of the addToBuffer
function (since you then know for sure that there is at least one character to send).
Also, you should test TXEndPos
and TXCurrentPos
for equality directly, since that would let you use a circular buffer very easily by adding two modulo operations.
精彩评论