F. Software - Acknowledgements

F.1 Main Code
/* Scott Clandinin
* Tech Thesis Project V2
* Weather data from Open Weather Map:
* http://api.openweathermap.org/data/2.5/find?q=Saskatoon&units=metric&appid=1324024f8cb94b1444352b7f894fb724
* Word of the day from Wordnik
* http://api.wordnik.com/v4/words.json/wordOfTheDay?api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5
*
* CSN-A2 thermal receipt printer
* ESP8266-12 Wi-Fi module
*
*/
#include
#include "defines.h"
#include "prototypes.h"
#include "delays.h"
#include
#include
//global variables
unsigned char data[255];
unsigned char word[15] = " ";
unsigned char partOfSpeech[10] = " ";
char buff;
//variables to send to LCD
char weather1[14] = "Scott's Wi-Fi";
char weather2[16] = "Weather Station";
char printing[13] = "Now Printing";
char press[15] = "Press to Print";
char fail1[11] = "Connection";
char fail2[7] = "Failed";
char try[10] = "Try Again";
char connected[18] = "Wi-Fi Connected ";
char paperOut[13] = "Out of Paper";
char paperIn[15] = "Paper Replaced";
char connect[14] = "Connecting...";
void main ()
{
int status;
//initializations
port_init();
lcd_init();
serial_init();
// fprintf(_H_USART, "AT+UART=19200,8,1,0,0\r\n"); //change default baud rate
// fprintf(_H_USART, "AT+CWMODE=1\r\n"); //AP + station mode
fprintf(_H_USER, "%c%c%c%c%c", 0x1B, 0x37, 0x07, 0x64, 0x02); //1ms heat time, 20us heat interval
delay ();
sleep_all();
paperCheck(); //check paper status
send_command(0x01); //clear display
send_string(press, 14);
while (1)
{
paperCheck(); //check paper status
delay ();
if (!button) //push button
{
status = wifi_connect(); //attempt to connect
if (status == 1) //if connected, get the weather and word
{
send_command(0x01); //clear display
send_string(connected, 17);
get_weather(); //get and print weather
get_wordoftheday(); //get and print word of the day
delaywifi2();
}
else //if connection failed, notify user and sleep
{
send_command(0x01); //clear display
send_string(fail1, 10);
send_command(0xC0); //second line
send_string(fail2, 6);
delaywifi2();
send_command(0x01); //clear display
send_string(try, 9);
delaywifi2();
}
sleep_all();
send_command(0x01); //clear display
send_string(press, 14);
}
}
}
// *************************************** get_weather
void get_weather()
{
char temp[5] = " ";
char wind[5] = " ";
weather_start(); //connect to server
RCSTA1bits.CREN = 1; //enable receive
wifi_skip_data(); //skip headers
weather_read(); //store data
RCSTA1bits.CREN = 0; //disable receive
fprintf(_H_USER, "%c", 0xFF); //wake
fprintf(_H_USER, "%c%c", 0x1B, 0x40); //clear print buffer
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x01); //justify center
fprintf(_H_USER, "-------------------------------\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x30); //double size and width
fprintf(_H_USER, "Current Weather\r\n");
fprintf(_H_USER, "in Saskatoon\r\n\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00); //normal size
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x01); //justify center
fprintf(_H_USER, "Temperature:\r\n");
get_temp(&temp); //get the temperature
send_string(temp, 2);
fprintf(_H_USER, "%s", temp);
fprintf(_H_USER, " %cC\r\n\r\n", 0xF8);
send_data(0xDF);
send_data('C');
fprintf(_H_USER, "Wind Speed:\r\n");
get_wind(&wind); //get the wind speed
fprintf(_H_USER, "%s", wind);
fprintf(_H_USER, " m/s\r\n\r\n");
fprintf(_H_USER, "via openweathermap.org\r\n");
fprintf(_H_USER, "--------------------------------\r\n");
fprintf(_H_USER, "%c%c", 0x1B, 0x40); //clear print buffer
}
// *************************************** get_wordoftheday
void get_wordoftheday()
{
unsigned char definition[120] = " ";
word_start(); //connect to server
RCSTA1bits.CREN = 1; //enable receive
wifi_skip_data(); //skip headers
word_read(&word); //find word of the day
definition_read(&definition); //get the definition
partOfSpeech_read(&partOfSpeech); //get the part of speech of the word
RCSTA1bits.CREN = 0; //disable receive
fprintf(_H_USER, "%c", 0xFF); //wake
fprintf(_H_USER, "%c%c", 0x1B, 0x40); //clear print buffer
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x30); //double size and width
fprintf(_H_USER, "Word of the Day\r\n\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00); //normal size
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x00); //justify left
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x08); //bold
fprintf(_H_USER, "%s - %s\r\n\r\n", word, partOfSpeech);
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00); //not bold
fprintf(_H_USER, "%s\r\n\r\n", definition);
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x01); //justify center
fprintf(_H_USER, "via wordnik.com\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x00); //justify left
fprintf(_H_USER, "-------------------------------\r\n");
fprintf(_H_USER, "By Scott Clandinin\r\n\r\n\r\n\r\n\r\n");
}
// *************************************** sleep_all
void sleep_all()
{
send_command(0x01); //clear display
send_string(weather1, 13);
send_command(0xC0); //second line
send_string(weather2, 15);
delay();
INTCONbits.INT0IF = 0; //ext interrupt flag low
fprintf(_H_USART, "AT+GSLP=5000\r\n"); //send ESP to sleep
delay();
reset = 0; //bring line low to reset
Sleep(); //send micro to sleep
Nop();
//wake
delay();
reset = 1; //wake ESP
}
//misc
#include "port_init.c"
#include "delays.c"
//LCD
#include "lcd.c"
//USART
#include "wifi_serial.c"
#include "_user_putc.c"
//Printer
#include "printer_serial.c"
//Parsing
#include "parsing.c"
F.2 Port Initialization
// *************************************** port_init
void port_init()
{
OSCCON = 0x70; //16MHz
ANSELA = 0;
ANSELB = 0;
ANSELC = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0b00100000;
TRISA = 0;
TRISB = 0b10000001;
TRISC = 0b10000000;
INTCONbits.INT0IE = 1; //enable external interrupts
}
F.3 Defines
#define button PORTBbits.RB0
#define reset PORTCbits.RC5
#define LED PORTBbits.RB1
#define DC PORTCbits.RC2
#define RW PORTCbits.RC1
#define EN PORTCbits.RC0
//************************************************************************************************
//Configuration Bits Set in code
//You find the definitions in MPlab only
//Help -> PIC18 Config Settings -> PIC18F25K22
#pragma config FOSC = INTIO67 //Internal oscillator block, CLKOUT function on RA6, port function on RA7
#pragma config PLLCFG = OFF //Oscillator multiplied by 4
#pragma config PRICLKEN = ON //Primary clock is always enabled
#pragma config IESO = OFF //Oscillator Switchover mode disabled
#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
#pragma config PWRTEN = OFF //Power up timer disabled
#pragma config BOREN = OFF //Brown-out Reset disabled in hardware only
#pragma config BORV = 190 //VBOR set to 1.90 V nominal
#pragma config WDTEN = OFF //Watch dog timer is always disabled. SWDTEN has no effect.
#pragma config CCP2MX = PORTB3 //CCP2 input/output is multiplexed with RB3
#pragma config PBADEN = OFF //PORTB<5:0> pins are configured as digital I/O on Reset
#pragma config HFOFST = OFF //HFINTOSC output and ready status are delayed by the oscillator stable status
#pragma config MCLRE = EXTMCLR //MCLR pin enabled, RE3 input pin disabled
#pragma config STVREN = OFF //Stack full/underflow will cause Reset
#pragma config LVP = OFF //NO Low Voltage Program, Single-Supply ICSP disabled
#pragma config XINST = OFF //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = ON //Background debugging on RB7 & RB6
//
#pragma config CP0 = OFF //BLOCK 0 NOT CODE PROTECTED
#pragma config CP1 = OFF //BLOCK 1 NOT CODE PROTECTED
#pragma config CP2 = OFF //BLOCK 2 NOT CODE PROTECTED
#pragma config CP3 = OFF //BLOCK 3 NOT CODE PROTECTED
#pragma config CPB = OFF //BOOT BLOCK NOT CODE PROTECTED
#pragma config CPD = OFF //DATA EEPROM NOT CODE PROTECTED
#pragma config WRT0 = OFF //BLOCK 0 NOT WRITE PROTECTED
#pragma config WRT1 = OFF //BLOCK 1 NOT WRITE PROTECTED
#pragma config WRT2 = OFF //BLOCK 2 NOT WRITE PROTECTED
#pragma config WRT3 = OFF //BLOCK 3 NOT WRITE PROTECTED
#pragma config WRTB = OFF //BOOT BLOCK NOT WRITE PROTECTED
#pragma config WRTC = OFF //CONFIGURATION REGISTER NOT WRITE PROTECTED
#pragma config WRTD = OFF //DATA EEPROM NOT WRITE PROTECTED
#pragma config EBTR0 = OFF //BLOCK 0 NOT PROTECTED FROM TABLE READS FROM OTHER BLOCKS
#pragma config EBTR1 = OFF //BLOCK 1 NOT PROTECTED FROM TABLE READS FROM OTHER BLOCKS
#pragma config EBTR2 = OFF //BLOCK 2 NOT PROTECTED FROM TABLE READS FROM OTHER BLOCKS
#pragma config EBTR3 = OFF //BLOCK 3 NOT PROTECTED FROM TABLE READS FROM OTHER BLOCKS
#pragma config EBTRB = OFF //BOOT BLOCK NOT PROTECTED FROM TABLE READS FROM OTHER BLOCKS
F.4 Function Prototypes
void port_init();
void sleep_all();
void get_weather();
void get_wordoftheday();
//lcd functions
void lcd_init();
void send_command(char command);
void send_data(char data);
void send_string(char string[],int length);
char reverse_bits(char value);
//wifi functions
void serial_init();
int wifi_connect();
void wifi_acknowledge();
void wifi_skip_data();
void weather_start();
void weather_read();
void word_start();
void word_read(char word[]);
void definition_read(char definition[]);
void partOfSpeech_read(char partOfSpeech[]);
//parsing code
int find_temp();
void get_temp(char temp[]);
int find_wind();
void get_wind(char wind[]);
//printer functions
int _user_putc (char c);
void printerTest();
void paperCheck();
char printerRead();
//delay functions
void delay();
void delaylcd();
void delaywifi();
void delaywifi2();
F.5 Wi-Fi
// *************************************** serial_init
void serial_init()
{
//USART 1 - wifi module
TXSTA1bits.SYNC = 0;
TXSTA1bits.BRGH = 1;
TXSTA1bits.TX9 = 0;
TXSTA1bits.TXEN = 1;
RCSTA1bits.SPEN = 1;
RCSTA1bits.RX9 = 0;
//default baud rate
// SPBRG1 = 0x08; //115200 baud rate
// SPBRGH1 = 0x00; //115200 baud rate
//deisred baud rate
SPBRG1 = 0x33; //19200 baud rate
SPBRGH1 = 0x00; //19200 baud rate
//ESP boot mode baud rate
// SPBRG1 = 0x0C; //74880 baud rate
// SPBRGH1 = 0x00; //74880 baud rate
//USART 2 - Printer
TXSTA2bits.SYNC = 0;
TXSTA2bits.BRGH = 1;
TXSTA2bits.TX9 = 0;
TXSTA2bits.TXEN = 1;
RCSTA2bits.SPEN = 1;
RCSTA2bits.RX9 = 0;
SPBRG2 = 0x33; //19200 baud rate
SPBRGH2 = 0x00; //19200 baud rate
}
// *************************************** wifi_acknowledge
//check that a command to the ESP was successful
void wifi_acknowledge()
{
char buffer = 'a';
RCSTA1bits.CREN = 1;
while (buffer != 'K') //wait for connection acknowledgment
{
while (!PIR1bits.RC1IF);
buffer = RCREG1;
}
RCSTA1bits.CREN = 0;
}
// *************************************** wifi_connect
//connect to wireless AP
int wifi_connect()
{
char buffer = 'a';
char buffer2 = 'a';
send_command(0x01); //clear display
send_string(connect, 13);
delay();
fprintf(_H_USART, "AT+CWJAP=\"SASKPOLYTECHPublic\",\"\"\r\n");
RCSTA1bits.CREN = 1;
while (buffer != 'K') //wait for connection acknowledgment
{
while (!PIR1bits.RC1IF);
buffer = RCREG1;
}
while (buffer2 != 'K' && buffer2 != ':') //wait for connection acknowledgment
{
while (!PIR1bits.RC1IF);
buffer2 = RCREG1;
}
RCSTA1bits.CREN = 0;
if (buffer2 == 'K')
{
return 1;
}
else
{
return 0;
}
}
// *************************************** weather_start
//begin the connection for weather retrieval
void weather_start()
{
fprintf(_H_USART, "AT+CIPSTART=\"TCP\",\"api.openweathermap.org\",80\r\n");
wifi_acknowledge(); //wait for connection acknowledgment
fprintf(_H_USART, "AT+CIPSEND=127\r\n");
wifi_acknowledge(); //wait for connection acknowledgment
fprintf(_H_USART, "GET /data/2.5/find?q=Saskatoon&units=metric&appid=1324024f8cb94b1444352b7f894fb724 HTTP/1.0\r\nHost: api.openweathermap.org\r\n\r\n\r\n");
}
// *************************************** word_start
//begin the connection for word retrieval
void word_start()
{
fprintf(_H_USART, "AT+CIPSTART=\"TCP\",\"api.wordnik.com\",80\r\n");
wifi_acknowledge(); //wait for connection acknowledgment
fprintf(_H_USART, "AT+CIPSEND=127\r\n");
wifi_acknowledge(); //wait for connection acknowledgment
fprintf(_H_USART, "GET /v4/words.json/wordOfTheDay?api_key=a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5 HTTP/1.0\r\nHost: api.wordnik.com\r\n\r\n\r\n");
}
// *************************************** wifi_skip_data
//skips beginning data sent by server about unwanted server request details
//until a curly bracket appears, denoting the start of the JSON data
void wifi_skip_data()
{
char buffer1;
buffer1 = 'a';
while (buffer1 != '{') //skip to the start of the JSON data
{
while (!PIR1bits.RC1IF);
buffer1 = RCREG1;
}
}
// *************************************** weather_read
//store the weather until carriage return appears,
//meaning end of data string
void weather_read()
{
int i;
for (i = 0; i < 255; i++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
data[i] = RCREG1;
if (data[i] == 0x0D)
{
return;
}
}
}
// *************************************** word_read
void word_read(char word[])
{
int i,j;
char buffer1, buffer2;
//wait for 'w' to appear
while (buffer1 != 'w')
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
//skip next 6 characters
for (i = 0; i < 6; i++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
//record word until " appears
for (j = 0; j < 10; j++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer2 = RCREG1;
if (buffer2 == '"')
{
return;
}
word[j] = buffer2;
}
return;
}
// *************************************** definition_read
void definition_read(char definition[])
{
int i,j;
char buffer1, buffer2;
//wait for ']' to appear
while (buffer1 != ']')
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
//skip next 25 characters
for (i = 0; i < 25; i++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
//record word until " appears
for (j = 0; j < 255; j++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer2 = RCREG1;
if (buffer2 == '"')
{
return;
}
definition[j] = buffer2;
}
return;
}
// *************************************** partOfSpeech_read
void partOfSpeech_read(char partOfSpeech[])
{
int i,j;
char buffer1, buffer2, buffer3;
//wait for ',' to appear twice
while (buffer1 != ',')
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
while (buffer2 != ',')
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer2 = RCREG1;
}
//skip next 16 characters
for (i = 0; i < 22; i++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer1 = RCREG1;
}
//record word until " appears
for (j = 0; j < 30; j++)
{
while (!PIR1bits.RC1IF)
{
Nop();
}
buffer3 = RCREG1;
if (buffer3 == '"')
{
return;
}
partOfSpeech[j] = buffer3;
}
return;
}
F.6 LCD
// *************************************** lcd_init
void lcd_init()
{
delaylcd();
send_command(0x38); //function set, 8 bit, 2 line
send_command(0x0C); //turn display on, cursor off
send_command(0x06); //entry mode, cursor increment and no display shift
send_command(0x01); //clear display
}
// *************************************** send_command
void send_command(char command)
{
char value;
DC = 0; //D/C set to command
RW = 1; //R/W starts high
delaylcd();
RW = 0; //set R/W for write
delaylcd();
EN = 1; //enable the chip select
delaylcd();
value = reverse_bits(command);
PORTA = value;
delaylcd();
EN = 0; //enable the chip select
delaylcd();
RW = 1; //R/W starts high
delaylcd();
}
// *************************************** send_data
void send_data(char data)
{
char value;
DC = 1; //D/C set to data
RW = 1; //R/W starts high
delaylcd();
RW = 0; //set R/W for write
delaylcd();
EN = 1; //enable the chip select
delaylcd();
value = reverse_bits(data);
PORTA = value;
delaylcd();
EN = 0; //enable the chip select
delaylcd();
RW = 1; //R/W starts high
delaylcd();
}
// *************************************** send_string
//sends a string to the LCD
void send_string(char string[],int length)
{
int i;
for (i = 0; i < length; i++)
{
send_data(string[i]);
}
}
// *************************************** reverse_bits
//reverses data and command bytes before sending them to
//the LCD. The micro data pins were laid out on the PCB in the
//opposite orientation
char reverse_bits(char value)
{
char reversed = 0;
int i;
for(i=0; i<=7; i++)
{
reversed<<=1;
reversed|=(value&1);
value>>=1;
}
return reversed;
}
F.7 Thermal Printer
// *************************************** printerTest
//testing the different fonts and functions of the printer
void printerTest()
{
fprintf(_H_USER, "%c%c%c%c%c", 0x1B, 0x37, 0x07, 0x64, 0x02); //1ms heat time, 20us heat interval
fprintf(_H_USER, "Lorem ipsum dolor sit amet, \r\n\r\n");
//justification
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x02);
fprintf(_H_USER, "Right justified\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x01);
fprintf(_H_USER, "Center justified\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x61, 0x00);
fprintf(_H_USER, "Left justified\r\n");
//font test
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00);
fprintf(_H_USER, "Font A test\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x01);
fprintf(_H_USER, "Font B test\r\n");
//bold test
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x08); //bold
fprintf(_H_USER, "Bolded text\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00); //not bold
fprintf(_H_USER, "Not bolded\r\n");
//double height and width
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x30); //double size and width
fprintf(_H_USER, "double height and width\r\n");
fprintf(_H_USER, "%c%c%c", 0x1B, 0x21, 0x00); //normal size
fprintf(_H_USER, "Normal size\r\n");
}
// *************************************** paperCheck
//check the status of the printer and loop while the paper is out
void paperCheck()
{
char status;
status = printerRead();
if (status != 0x24)
{
return;
}
else
{
send_command(0x01); //clear display
send_string(paperOut, 12);
}
while (status == 0x24)
{
LED = 0;
delay ();
delay ();
delay ();
LED = 1;
delay ();
delay ();
delay ();
status = printerRead();
}
LED = 0; //turn off LED
send_command(0x01); //clear display
send_string(paperIn, 14);
delaywifi2();
delaywifi2();
send_command(0x01); //clear display
send_string(press, 14);
}
// *************************************** printerRead
//request the status from the printer
char printerRead()
{
char status;
RCSTA2bits.CREN = 1; //receive enable
fprintf(_H_USER, "%c%c%c", 0x1B, 0x76, 0x04); //request paper status
while (!PIR3bits.RC2IF)
{
Nop();
}
status = RCREG2;
RCSTA2bits.CREN = 0; //receive disable
return status;
}
F.8 Weather Parsing
// *************************************** find_temp
int find_temp()
{
char letter1, letter2, letter3, letter4;
int i;
for (i = 0; i < 255; i++)
{
letter1 = data[i];
letter2 = data[i+1];
letter3 = data[i+2];
letter4 = data[i+3];
if (letter1 == 't' && letter2 == 'e' && letter3 == 'm' && letter4 == 'p')
{
return i;
}
}
return 0;
}
// *************************************** get_temp
void get_temp(char temp[])
{
int location;
int i = 0;
location = find_temp();
location = location + 6;
while (data[location] != ',')
{
temp[i] = data[location];
i++;
location++;
}
}
// *************************************** find_wind
int find_wind()
{
char letter1, letter2, letter3, letter4, letter5;
int i;
for (i = 0; i < 255; i++)
{
letter1 = data[i];
letter2 = data[i+1];
letter3 = data[i+2];
letter4 = data[i+3];
letter5 = data[i+4];
if (letter1 == 's' && letter2 == 'p' && letter3 == 'e' && letter4 == 'e' && letter5 == 'd')
{
return i;
}
}
return 0;
}
// *************************************** get_wind
void get_wind(char wind[])
{
int location;
int i = 0;
location = find_wind();
location = location + 7;
while (data[location] != ',')
{
wind[i] = data[location];
i++;
location++;
}
}
F.9 Delay Functions
// *************************************** delay
void delay ()
{
int i;
for (i = 0; i < 10000; i++)
{
Delay1TCY();
Delay1TCY();
Delay1TCY();
Delay1TCY();
}
}
// *************************************** delaywifi
//short wifi delay
void delaywifi ()
{
int i;
for (i = 0; i < 10; i++)
{
delay();
}
}
// *************************************** delaywifi2
//longer wifi delay
void delaywifi2 ()
{
int i;
for (i = 0; i < 20; i++)
{
delay();
}
}
// *************************************** delaylcd
//time between LCD commands
void delaylcd ()
{
int i;
for (i = 0; i < 999; i++)
{
Delay1TCY();
}
}
F.10 USART 2 Enable
// *************************************** _user_putc.c
/* this default version should not do anything. it is entirely a
placeholder symbol. To keep code size at a minimum, it is declared
without a return value or parameters. The caller will still clean up
the stack frame correctly.
When using the _H_USER stream, the function will be implemented in
application code with the prototype:
int _user_putc (char c);
*/
// *************************************** _user_putc
//function to allow fprintf to work on Tx2
int _user_putc (char c)
{
while(!PIR3bits.TX2IF);
TXREG2 = c;
return c;
}
|