| ??? 07/20/10 16:25 Read: times |
#177396 - Which register bank are you using? Responding to: ???'s previous message |
I use the same part (DS89C450) and have both UARTS working using interrupts, but in order to do it, I used the "using" keyword. This keyword switches the register banks used when the interrupt is services so that interrupts don't trample over each other or have to use the stack.
Here is my initialization code: void sbufs_init(void) {
// General Serial Mode Setup
PCON &= 0xBF; // No Frame Error Mode for SBUF0 and SBUF1
// Serial 0 Mode Setup
SM0 = 0; // SBUF0 Mode 0
SM1 = 1; // SBUF0 Mode 0
SM2 = 0; // No multiprocessor communication mode
REN = 1; // Recieve enable
RI = 0; // RI must be clear to recieve
PCON &= 0x7F; // Single Speed for sbuf0
RXD0 = 1; // Latch port high for serial functions to work correctly
// Serial 1 Mode Setup
SM01 = 0; // SBUF1 Mode 0
SM11 = 1; // SBUF1 Mode 0
SM21 = 0; // No multiprocessor communication mode
REN1 = 0; // Recieve only enabled when expecting an incomming message
WDCON = WDCON & 0x7F; //01111111B Single Speed for sbuf1
RXD1 = 1; // Latch port high for serial functions to work correctly
TEN = 0; // Disable transmit for RS485 until needed
// Interrupt Settings
ET1 = 0; // Disable T1 interrupts since using T1 for baud generation
ET2 = 0; // Disable T2 interrupts since using T2 for baud generation
// SBUF1 Baud clock
TMOD = TMOD & 0x0F; // reset timer1 mode bits
TMOD = TMOD | 0x20; // t1 8bit auto reload timer using system clk
TCON = TCON & 0x33; // reset t1 control bits and INT1 control bits
TH1 = 0xFD; // 9600 for serial port 1
TR1 = 1; // Start the Baud clock
// SBUF0 Baud clock
T2MOD &= 0xFC; // Not driving external pin with T2 and T2 counts up
T2CON = 0x30; // timer 2 is baud for sbuf0 TX and RX
RCAP2H = 0xFF; // Setup 9600 baud
RCAP2L = 0xDC; // Communication for S0
TR2 = 1; // Start the Baud clock
// Initialize ptrs
RX_IN_PTR_0 = 0;
RX_OUT_PTR_0 = 0;
RX_EMPTY_0 = 1;
RX_IN_PTR_1 = 0;
RX_OUT_PTR_1 = 0;
RX_EMPTY_1 = 1;
TX_IN_PTR_0 = 0;
TX_OUT_PTR_0 = 0;
TX_EMPTY_0 = 1;
TX_IN_PTR_1 = 0;
TX_OUT_PTR_1 = 0;
TX_EMPTY_1 = 1;
}
And the ISR code:
void serial0_ISR(void) interrupt 4 using 2{
if(RI) {
RI = 0; // Always acknowledge the interrupt
if(RX_EMPTY_0 || (((RX_IN_PTR_0 + 1) % RX_BUF_SIZE_0) != RX_OUT_PTR_0)) { // buffer full if in+1 == out
RX_BUF_0[RX_IN_PTR_0]=SBUF0;
RX_IN_PTR_0 = (RX_IN_PTR_0 + 1) % RX_BUF_SIZE_0;
RX_EMPTY_0 = 0; // not empty any more
}
}
else {
TI = 0; // always acknowledge interrupt
// put_char routine must not fill the buffer such that in ptr catches out ptr
if(TX_OUT_PTR_0 != TX_IN_PTR_0) {
SBUF0 = TX_BUF_0[TX_OUT_PTR_0];
TX_OUT_PTR_0 = (TX_OUT_PTR_0 + 1) % TX_BUF_SIZE_0;
}
else TX_EMPTY_0 = 1; // we are done when out ptr catches in ptr
}
}
void serial1_ISR(void) interrupt 7 using 2{
if(RI1) {
RI1 = 0; // Always acknowledge the interrupt
if(RX_EMPTY_1 || (((RX_IN_PTR_1 + 1) % RX_BUF_SIZE_1) != RX_OUT_PTR_1)) { // buffer full if in+1 == out
RX_BUF_1[RX_IN_PTR_1]=SBUF1;
RX_IN_PTR_1 = (RX_IN_PTR_1 + 1) % RX_BUF_SIZE_1;
RX_EMPTY_1 = 0; // not empty any more
}
}
else {
TI1 = 0;
// put_char routine must not fill the buffer such that in ptr catches out ptr
if(TX_OUT_PTR_1 != TX_IN_PTR_1) {
REN1 = 0; // can't send and recieve at the same time
TEN = 1;
SBUF1 = TX_BUF_1[TX_OUT_PTR_1];
TX_OUT_PTR_1 = ++TX_OUT_PTR_1 % TX_BUF_SIZE_1;
}
else {
TX_EMPTY_1 = 1; // we are done when out ptr catches in ptr
TEN = 0;
REN1 = 1; // finished talking, now we listen
}
}
}
Note that UART1 is setup for half duplex communication. Please don't copy the style of this code as it is old and I would have chosen to do things differently these days, but it does work. Take a look at Mark A. Odell's code in the code section here at 8052.com for a better structured library. http://www.8052.com/codelib/files/efdUartDriver.zip --David |



