blueroomelectronics
Well-Known Member
I'm just learning C so bear with me.
It's not beautiful and I could use some advice on cleaning up and making the code more efficient. I'm porting it over from a Swordfish BASIC program I wrote recently and I've only just started learning C (two weeks so far). It's written for the 18F46K22 as a tertiary serial port on PORTB0 & 1 using Timers 2 & 4 plus INT0
I'll run it on actual hardware in the next couple of days. I'd appreciate any comments or concerns.
Untested on XC8, the Swordfish version works.
It's not beautiful and I could use some advice on cleaning up and making the code more efficient. I'm porting it over from a Swordfish BASIC program I wrote recently and I've only just started learning C (two weeks so far). It's written for the 18F46K22 as a tertiary serial port on PORTB0 & 1 using Timers 2 & 4 plus INT0
I'll run it on actual hardware in the next couple of days. I'd appreciate any comments or concerns.
Untested on XC8, the Swordfish version works.
Code:
/*
* Author: Blue Bill
*
* Created on June 13, 2013, 11:10 AM
* 9600baud interrupt driven low CPU overhead full duplex software serial port
* Uses Two timers and INT0 (falling edge IRQ on RX)
* RB.0 = RX, RB.1 = TX in this example
* this example uses Timers 2 & 4 (other timers can be used if desired)
* a 1MHz instuction clock was used for simplicity
*/
#define QBAUD 103 // 4000000 / 4 / 9600 - 1
union both { // QTXSend.byte = char, QTXSend.Shiftbit.B0
char byte;
struct {
unsigned LSB : 1, none : 6, MSB : 1;
} Shiftbit;
} QTXSend;
unsigned char QTXControl = 0; // make = 11 to transmit byte in TXQSend
unsigned char QRXCount = 0; // shift in counter
char QRXin = '\0'; // QRX recieve byte
void InitializeQART(void);
void interrupt ISR(void);
main(void) {
InitializeQART();
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
QTXSend.byte = 'a'; // test
QTXControl = 11; // test
while (1) {
}
}
void InitializeQART(void) {
TRISBbits.RB0 = 1; // QRX in (INT0\ & RB0)
TRISBbits.RB1 = 0; // QTX out
LATBbits.LB1 = 1; // Space
PR2 = QBAUD; // TMR2 104µS QTX clock
T2CON = 0b00000100; // Timer2 1:1 postscaler, T2 on, 1:1 prescaler
PR4 = QBAUD; // TMR4 104µS QRX clock
T4CON = 0b00000000; // Timer4 1:1 postscaler, T4 off, 1:1 prescaler
INTCON2bits.INTEDG0 = 0; // falling edge detect enabled on RB.0
INTCONbits.INT0IE = 1; // enable INT on falling edge RB.0
PIE1bits.TMR2IE = 1; // enable TMR2 (TX) interrupts
PIE5bits.TMR4IE = 0; // disable TMR4 (RX) interrupts
}
void interrupt ISR(void) {
// QTX 104µS (9600baud,N,8,1)
// check QTXControl for 0 before putting a byte into QTXSend
// then QTXControl = 11; to send the byte in QTXSend
if (PIR1bits.TMR2IF == 1) { // QTX baud clock every 104µS period
if (QTXControl != 0) { // copy 11 into QTXControl to send char in QTXSend
QTXControl--;
if (QTXControl == 10) { //
LATBbits.LATB1 = 0; // Start bit
} else {
if (QTXSend.Shiftbit.LSB == 0) {
LATBbits.LB1 = 0;
} else {
LATBbits.LB1 = 1;
}
QTXSend.byte >>= 1;
QTXSend.Shiftbit.MSB = 1; // fill with 1's
}
}
PIR1bits.TMR2IF = 0; // QTX done
}
// QRX Start bit detect (INT0 falling edge)
if (INTCONbits.INT0IF) { // QRX pin went low
if (INTCONbits.INT0IE == 1) { // only process if IE enabled (Start bit)
TMR4 = QBAUD >> 1; // add 0.5 bit to sample clock
T4CONbits.TMR4ON = 1; // start timer 4
INTCONbits.INT0IE = 0; // disable INT on falling edge RB.0
PIE5bits.TMR4IE = 1; // enable TMR4 (RX) interrupts
}
INTCONbits.INT0IF = 0; // always clear IRQ request
}
// QRX shift bits from PORTB.0 into QRXin
if (PIR5bits.TMR4IF == 1) {
if (PIE5bits.TMR4IE == 1) {
if (PORTBbits.RB0 == 0) { // shift bit into QRXin
QRXin |= 0x80;
} else {
QRXin &= 0x7F;
}
if (QRXCount > 7) { // full byte shifted in
T4CONbits.TMR4ON = 0; // Stop timer 4
PIE5bits.TMR4IE = 0; // ignore timer 4 IE
QRXCount = 0; // clear the bit shift counter
INTCONbits.INT0IE = 1; // enable INT on falling edge RB.0 and wait for next Start bit
} else {
QRXin >>= 1; // shift bits in
QRXCount++; // increment bit shift counter and wait
}
}
PIE5bits.TMR4IE = 0; // always clear IRQ request
}
}