Transmitting a single character over EUSART from pic16f887 to PC terminal

Discussion in 'Programmer's Corner' started by GrafZeppelin, May 3, 2013.

  1. GrafZeppelin

    Thread Starter New Member

    May 3, 2013
    11
    0
    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:

    Code ( (Unknown Language)):
    1. #include <pic.h>
    2.  #include <stdlib.h>
    3.  #include <stdio.h>
    4.  #include <pic16f887.h>
    5.  
    6.  unsigned char cUART_char;
    7.  unsigned char cUART_data_flg;
    8.  void init_uart(void);
    9.  void UART_putc(unsigned char c);
    10.  void InterruptHandlerLow ();
    11.  void main(){
    12. TRISA = 0;
    13.  PORTA = 0;
    14. TRISB = 0;
    15.  PORTB = 0;
    16.  TRISD = 0;
    17.  PORTD = 0;
    18.  ANSELH = 0;
    19.  
    20.     init_uart(); // init UART module
    21.  
    22.  while (1) // infinite loop which handles ncoming data as they arrive  
    23.  {      
    24.  if (cUART_data_flg==1)// if new data available, send it back through USART tx line (echo it)      
    25.         {          
    26.             UART_putc(cUART_char);            
    27.             cUART_data_flg=0; // clear new data flag so one charactor will echoed once    
    28.      }
    29.  }
    30.  }
    31.  #pragma code
    32.  #pragma interrupt InterruptHandlerLow
    33.  
    34.  void InterruptHandlerLow ()
    35.  {
    36.        if (RCIF==1)
    37.           {
    38.            if(RCSTA&0x06)
    39.                   {    
    40.                       CREN=0;    //Overrun error (can be cleared by clearing bit CREN)    
    41.                       cUART_char=RCREG;    //clear Framing error      
    42.                       CREN=1;  
    43.                   }
    44.                 else  
    45.                 {            
    46.                     cUART_char = RCREG; // read new data into variable      
    47.                     cUART_data_flg = 1; // new data received. so enable flg  
    48.                  }
    49.           }
    50.  }
    51.  void init_uart(void)
    52.  {
    53.  TRISC7=1; //Make UART RX pin input  
    54.  TRISC6=0; //Make UART TX pin output  
    55.  SYNC = 0;   // enables for asynchronous EUART
    56.  SPEN = 1;   // enables EUSART and sets TX (RC6) as output; ANSEL must be cleared if shared with analog I/O
    57.  CREN = 1;
    58.  TX9 = 0;    // 8bit mode       RX9 = 0;
    59.  TXEN = 1;    // enables Transmitter
    60.  BRGH = 1;      // baud rate select     BRG16 = 0;
    61.  SPBRG = 25;    //baud rate select  9600@4Mhz   SPBRGH = 0;
    62.  RCIE=1;                // receive interrupt enable
    63.  GIE=1;         // global interrupt enable
    64.  PEIE=1 ;       // Peripheral Interrupt Enable bit
    65.  }
    66.  
    67.  void UART_putc(unsigned char c)
    68.  {
    69.  TXEN=0;// disable transmission
    70.  TXREG=0x61;            // load txreg with data
    71.  TXEN=1;    // enable transmission
    72.  while(TRMT==0) // wait here till transmit complete
    73.  {    
    74.  }
    75.  }
    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)..
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    sounds like a baud rate error. Double and triple check your configuration on both the PIC and the terminal.
     
  3. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    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:
    Code ( (Unknown Language)):
    1. void interrupt ISR();
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,345
    1,028
    How does that work? TX should go to your MAX232 only. Having a button pressed on it will foul the works.

    Code ( (Unknown Language)):
    1. void UART_putc(unsigned char c)  
    2. {   TXEN=0; // disable transmission  
    3.  TXREG=0x61;            // load txreg with data  
    4.  TXEN=1;    // enable transmission  
    5.  while(TRMT==0) // wait here till transmit complete  
    6.  {      
    7.   }  
    8. }
    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.

    Code ( (Unknown Language)):
    1. 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.
     
  5. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    '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?
     
Loading...