Transmitting a single character over EUSART from pic16f887 to PC terminal

Thread Starter

GrafZeppelin

Joined May 3, 2013
11
I am trying to transmit a character "a" from pic16f887 and see the result on the terminal, but all I get is a question mark(using USART terminal), or nothing at all(Putty, Hyperterminal). I am not so great with C, as I'm only a beginer, but I really need to get this working for my school project.. I have tried many codes I've found over the internet, and I did manage to receive a character from the terminal and, lets say, turn on a LED, but I just can't manage to make it send anything. And I have a strong feeling its somewhere in the code.. Im using MPLAB and Hi-Tech C compiler to build the project. Here it is:

Rich (BB code):
#include <pic.h> 
 #include <stdlib.h> 
 #include <stdio.h> 
 #include <pic16f887.h> 
 
 unsigned char cUART_char; 
 unsigned char cUART_data_flg; 
 void init_uart(void); 
 void UART_putc(unsigned char c); 
 void InterruptHandlerLow ();
 void main(){
TRISA = 0;
 PORTA = 0;
TRISB = 0;
 PORTB = 0;
 TRISD = 0;
 PORTD = 0;
 ANSELH = 0;

    init_uart(); // init UART module
  
 while (1) // infinite loop which handles ncoming data as they arrive   
 {       
 if (cUART_data_flg==1)// if new data available, send it back through USART tx line (echo it)       
        {           
            UART_putc(cUART_char);            
            cUART_data_flg=0; // clear new data flag so one charactor will echoed once    
     }
 }
 }
 #pragma code
 #pragma interrupt InterruptHandlerLow
  
 void InterruptHandlerLow ()
 {
       if (RCIF==1)
          {
           if(RCSTA&0x06)
                  {     
                      CREN=0;    //Overrun error (can be cleared by clearing bit CREN)     
                      cUART_char=RCREG;    //clear Framing error      
                      CREN=1;   
                  }
                else   
                {            
                    cUART_char = RCREG; // read new data into variable       
                    cUART_data_flg = 1; // new data received. so enable flg   
                 }
          }
 }
 void init_uart(void)
 {
 TRISC7=1; //Make UART RX pin input   
 TRISC6=0; //Make UART TX pin output   
 SYNC = 0;   // enables for asynchronous EUART
 SPEN = 1;   // enables EUSART and sets TX (RC6) as output; ANSEL must be cleared if shared with analog I/O
 CREN = 1;
 TX9 = 0;    // 8bit mode       RX9 = 0;
 TXEN = 1;    // enables Transmitter
 BRGH = 1;      // baud rate select     BRG16 = 0;
 SPBRG = 25;    //baud rate select  9600@4Mhz   SPBRGH = 0;
 RCIE=1;                // receive interrupt enable
 GIE=1;         // global interrupt enable
 PEIE=1 ;       // Peripheral Interrupt Enable bit
 }
  
 void UART_putc(unsigned char c)
 { 
 TXEN=0;// disable transmission 
 TXREG=0x61;            // load txreg with data 
 TXEN=1;    // enable transmission 
 while(TRMT==0) // wait here till transmit complete 
 {    
 }
 }
Please if someone sees a problem (or more) in this code, help me to crack this ;) Oh and I am transmitting when pressing a button connected to a TX pin (RC6)..
 

tshuck

Joined Oct 18, 2012
3,534
I don't think the Hi-Tech compiler allows you to define interrupts with a #pragma, though I could be wrong on this. I know the C18 compiler does, since you used an ISR name that suggests priority interrupts, I assume this is what you learned on.

I have always used:
Rich (BB code):
void interrupt ISR();
 

JohnInTX

Joined Jun 26, 2012
4,787
Oh and I am transmitting when pressing a button connected to a TX pin (RC6)..
How does that work? TX should go to your MAX232 only. Having a button pressed on it will foul the works.

Rich (BB code):
void UART_putc(unsigned char c)  
{   TXEN=0; // disable transmission   
 TXREG=0x61;            // load txreg with data   
 TXEN=1;    // enable transmission   
 while(TRMT==0) // wait here till transmit complete   
 {      
  }  
}
You don't have to disable TXEN each time you write a character and in fact, that will terminate any transmission in progress (maybe the previous char you thought you'd sent??). Just enable it once, poll TXIF (not TRMT) at the beginning of the routine to see if the UART can accept another character (its double buffered so you can load a char while the previous one is transmitting). When TXIF==1, write TXREG and then go away. Make sure you don't have TXIE == 1 since you are not handling it in an interrupt.

Your setup looks OK as far as baud rate. Make sure BRGH16==0. In the future, its better to set these bit mapped registers with a single write of a binary constant i.e. 0bxxxxxxx, its easier to read.

Rich (BB code):
if(RCSTA&0x06)
This actually looks at framing errors as well as overrun errors. Its OK they way you have it but you don't have to cycle CREN on a framing error. Framing errors are almost always the result of a baudrate error. Overruns mean you didn't read a received char before another arrived and the UART will stop generating RX interrupts. You are correct to check for overruns on each char received and are handling them correctly. But, the reason for separating them is for diagnostic purposes. FERR implies configuration issues, OERR implies your code is not spiffy enough to handle the datarate e.g. not using a receive buffer. Its nice to know the difference.

As far as the interrupt pragmas, I don't use HTC on midrange so check you manuals to be sure its happening as it should.

Have fun.
 

THE_RB

Joined Feb 11, 2008
5,438
'a' in TTL USART with a start bit is; 010000110
'?' in TTL USART with a start bit is; 011111100

They are only similar if inverted, do you have an issue with data inversion?
 
Top