Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

UART issue using PIC 18F4520 and Mikroc

Status
Not open for further replies.

djc

Advanced Member level 1
Joined
Jan 27, 2013
Messages
402
Helped
3
Reputation
6
Reaction score
2
Trophy points
1,298
Location
India
Activity points
4,554
Hello all,
I have to interface a thermal printer, a 16x2 LCD, a RTC and have to do a UART communication with another PIC18F4520. i have done RTC, LCD interfacing and can run a thermal printer too. However i am trying to do a serial communication. When i do it either LCD goes blank or LCD hangs and no data is displayed on the LCD. I am using ethernet to serial converter module for the communication between two devices. Then I tried to send and receive the data manually to a single microcontroller by connecting it to my laptop using serial to USB converter. However still i am not able to receive the data. I am using timer interrupt for RTC read and display LCD. Serial interrupt for receiving the serial data. May i ask for the little guidance.
Printer code is removed because of space .

Code:
 #define Prog_Key   RA3_bit
#define Shift_Key  RA4_bit
#define Qry  RA2_bit



//*****************************LCD   Connections **************************//////
sbit LCD_RS at RB1_bit;
sbit LCD_EN at RB6_bit;
sbit LCD_D4 at RB5_bit;
sbit LCD_D5 at RB4_bit;
sbit LCD_D6 at RB3_bit;
sbit LCD_D7 at RB2_bit;

sbit LCD_RS_Direction at TRISB1_bit;
sbit LCD_EN_Direction at TRISB6_bit;
sbit LCD_D4_Direction at TRISB5_bit;
sbit LCD_D5_Direction at TRISB4_bit;
sbit LCD_D6_Direction at TRISB3_bit;
sbit LCD_D7_Direction at TRISB2_bit;
//*****************************LCD   Connections **************************//////

// *********************Software I2C connections  **************************//////
sbit Soft_I2C_Scl           at RC3_bit;
sbit Soft_I2C_Sda           at RC4_bit;
sbit Soft_I2C_Scl_Direction at TRISC3_bit;
sbit Soft_I2C_Sda_Direction at TRISC4_bit;
// *********************Software I2C connections  **************************//////



char txt1[] = "Cables & Wireless";             //serial data
char txt2[] = "Date:";
char txt3[] = "Time:";
char txt4[] = "Current Count";
char txt5[] = "Target";
char txt6[] = "Totalizer";

char seconds=00,minutes=10,hours=11,week=01,date=01,month=10,year=20,set=0,cur_pos=0;
char Data[10],uart_rd[10],i=0,flag=0,count=0,data_fnd=0;
char *res,j=0;
char output[10];
char one_s=0, one_sec=0;

void interrupt(void){


     if(RCIF_bit == 1){
     i=0;
     j = RCREG;
     while(j != ' ; '){
     output[i++] = j;//RCREG;
       j = UART1_Read();//RCREG;
     if(j == ';'){flag=1;break;}
     }
     RCIF_bit = 0;
     i=0;
     }
    
   
     if(TMR0IF_bit == 1){
     one_s++;
     TMR0H = 0xE1;
     TMR0L = 0x78;
     TMR0IF_bit = 0;
     }   

}

void RTC_Write_Time()
{        seconds = Dec2Bcd (seconds);
         hours   = Dec2Bcd (hours);
         minutes = Dec2Bcd (minutes);
         week    = Dec2Bcd (week);
         date    = Dec2Bcd (date);
         month   = Dec2Bcd (month);
         year    = Dec2Bcd (year);

         Soft_I2C_Start();
         //Soft_I2C_Write(0xD1);    /////////////////////////////
         //Soft_I2C_Write(0x00);    //////////////////////////// /
         //Soft_I2C_Stop();         ////////////////////////////

         Soft_I2C_Start();
         Soft_I2C_Write(0xD0);
         Soft_I2C_Write(0x00);

         //Soft_I2C_Write(0x00);    // Sec
         Soft_I2C_Write(seconds);    // Sec
         Soft_I2C_Write(minutes);  // min
         Soft_I2C_Write(hours);   //Hour
         Soft_I2C_Write(week);   //day
         Soft_I2C_Write(date);  //date
         Soft_I2C_Write(month); //month
         Soft_I2C_Write(year);  //year

         Soft_I2C_Write(0x90);
         Soft_I2C_Stop();
         Delay_ms(5);
}


void RTC_Read(){
        Soft_I2C_Start();
        Soft_I2C_Write(0xD0);
        Soft_I2C_Write(0);
        Soft_I2C_Start();
        Soft_I2C_Write(0xD1);
        seconds=Soft_I2C_Read(1);
        seconds = Bcd2Dec(seconds);
        minutes=Soft_I2C_Read(1);
        minutes = Bcd2Dec(minutes);
        hours=Soft_I2C_Read(1);
        hours = Bcd2Dec(hours);

        week=Soft_I2C_Read(1);
        week = Bcd2Dec(week);
        date=Soft_I2C_Read(1);
        date = Bcd2Dec(date);
        month=Soft_I2C_Read(1);
        month = Bcd2Dec(month);
        year=Soft_I2C_Read(1);
        year = Bcd2Dec(year);

        //Soft_I2C_Read(0);
        Soft_I2C_Stop();         //' Issue stop signal}
        Delay_ms(20);
}

void Display_Time(){
   LCD_Out(1,1,"Date:  /  /");
   Lcd_Chr(1, 6, (date / 10)   + 48);
   Lcd_Chr(1, 7, (date  % 10)   + 48);

   Lcd_Chr(1, 9, (month / 10) + 48);
   Lcd_Chr(1,10, (month % 10) + 48);

   Lcd_Chr(1,12, (year / 10) + 48);
   Lcd_Chr(1,13, (year % 10) + 48);

   LCD_Out(2,1,"Time:  :  :");
   Lcd_Chr(2, 6,(hours / 10)   + 48);
   Lcd_Chr(2, 7,(hours % 10)   + 48);

   Lcd_Chr(2, 9,(minutes / 10) + 48);
   Lcd_Chr(2,10,(minutes % 10) + 48);

   Lcd_Chr(2,12,(seconds / 10) + 48);
   Lcd_Chr(2,13,(seconds % 10) + 48);
   Lcd_Cmd(_LCD_CURSOR_OFF);
}

void Reg_Init(){
  ADCON0 = 0x00;
  ADCON1 = 0x0F;
  //ADCON2 = 0;
  ADON_bit = 0;

  SSPCON1 = 0x00;
  CCP1CON = 0x00;
  CCP2CON = 0x00;

// CMCON = 0x00;
// CVRCON = 0x00;
//  CM0_bit = 0;
//  CM1_bit = 0;
//  CM2_bit = 0;

  TRISA = 0xFF;      //Port A as input
  TRISB = 0x00;
  TRISC = 0x01000000;
  //PORTA = 0xff;      //Initial Value
}

void UART_Init(){
  UART1_Init(9600);               // Initialize UART module at 9600 bps
  Delay_ms(100);

  //TXSTA = 0x20;                    //SYNC bit cleared
  //RCSTA = 0x90;                    //SPEn bit enabled
  //SPBRG = 12;

  //RCIF_bit = 1;
  //TXIF_bit = 1;

  //RCIE_bit = 1;           //UART receice interrupe enable
  //TXIE_bit = 1;           //UART transmit interrupe enable

  //RCIP_bit = 1;           //Receiver high prio
  //TXIP_bit = 0;            //Transmitter low priority

  //GIE_bit = 1;
  //PEIE_bit = 1;

}
void LCD_I2C_Init(){
  Soft_I2C_Init();
  Delay_ms(10);

  Lcd_Init();                        // Initialize LCD
  Delay_ms(10);
  Lcd_Cmd(_LCD_CLEAR);               // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off
  Lcd_Out(1,1,txt1);                 // Write text in first row
  Delay_ms(2000);
  Lcd_Cmd(_LCD_CLEAR);
  Delay_ms(10);

  RTC_Write_Time();
  Delay_ms(10);
  RTC_Read();
  Delay_ms(10);
  Display_Time();
}

void Timer_Init(){
T0CON = 0b00000111;  //TMR0ON=1,16 bit timer,Internal clock,Low to high transition of T0CK1 pin
GIE_bit = 1;
PEIE_bit = 1;

TMR0IE_bit = 1;
INT0IE_bit = 0;

TMR0H = 0xE1;
TMR0L = 0x78;
TMR0ON_bit = 1;

}

void Para_Setting(){
//Display_Time();
Lcd_Out(1,1,txt2);
LCD_Cmd(_LCD_BLINK_CURSOR_ON);
//LCD_Chr(1,6,32);


while(set == 0){
          if(Button(&PORTA, 3, 50, 0)) {
            if(Button(&PORTA, 3, 50, 0)){
               if(cur_pos == 0){
               date++;
                   if(date == 32){date = 01;}
                   Lcd_Chr(1, 6, (date / 10)   + 48);
                   Lcd_Chr(1, 7, (date  % 10)   + 48);
                   Lcd_Out(1,1,txt2);
               }
               if(cur_pos == 1){
               month++;
                   if(month == 13){month = 01;}
                   Lcd_Chr(1, 9, (month / 10)   + 48);
                   Lcd_Chr(1, 10, (month  % 10)   + 48);
                   LCD_Out(1,8,"/");
               }
               if(cur_pos == 2){
               year++;
                   if(year == 100){year = 00;}
                   Lcd_Chr(1,12, (year / 10) + 48);
                   Lcd_Chr(1,13, (year % 10) + 48);
                   LCD_Out(1,11,"/");
               }
               if(cur_pos == 3){
               hours++;
                   if(hours==25){hours=0;}
                   Lcd_Chr(2, 6,(hours / 10)   + 48);
                   Lcd_Chr(2, 7,(hours % 10)   + 48);
                   LCD_Out(2,1,"Time:");
               }
               if(cur_pos == 4){
               minutes++;
                   if(minutes==61){minutes=0;}
                   Lcd_Chr(2, 9,(minutes / 10) + 48);
                   Lcd_Chr(2,10,(minutes % 10) + 48);
                   LCD_Out(2,8,":");
               }
             
               if(cur_pos == 5){
               seconds++;
                   if(seconds == 61){seconds=0;}
                   Lcd_Chr(2,12,(seconds / 10) + 48);
                   Lcd_Chr(2,13,(seconds % 10) + 48);
                   LCD_Out(2,11,":");
               }
            }
          }
         
         
          if(Button(&PORTA, 4, 20, 0)) {
            if(Button(&PORTA, 4, 20, 0)){
               cur_pos = cur_pos+1;
               if(cur_pos == 1){
               LCD_Out(1,8,"/");
               }
             
               if(cur_pos == 2){
               LCD_Out(1,11,"/");
               }
             
               if(cur_pos == 3){
               LCD_Out(2,1,"Time:");
               }
             
               if(cur_pos == 4){
               LCD_Out(2,8,":");
               LCD_Cmd(_LCD_BLINK_CURSOR_ON);
               }
             
               if(cur_pos == 5){
               LCD_Out(2,11,":");
               }
             
               if(cur_pos == 6){set = 1;cur_pos=0;RTC_Write_Time();}
            }
          }
      }
}

void main() {
  Reg_Init();
  LCD_I2C_Init();
  UART_Init();
  Timer_Init();


     while(1){
     //UART1_Write_Text(output);
     if(set==0){                                //Para Setting
     //Delay_ms(100);
     if(Button(&PORTA, 3, 20, 0)){
                  if(Button(&PORTA, 3, 20, 0)){

                  while ((Button(&PORTA, 3, 20, 0))){
                  //Delay_ms(10);
                  }
                  Para_Setting();
                  }
     }
     set=1;
     }
     if(one_s >= 1){
     RTC_Read();Display_Time();
     one_s = 0;
     }       

      if((Button(&PORTA, 2, 10, 0))){
                                      while (Qry==0)  {}
                                     UART1_Write_Text("R;");

      }
               
                    if(flag==1){                                         
                    LCD_Out(2,1,output);
                    UART1_Write_Text(output);                  
                    //}
                     flag=0;
                    }


     }
}
 

Little edit is there. Using this i am able to receive the data which i sent manually from serial terminal. However when tried to communicate with another PIC, LCD hangs up.

Code:
void interrupt(void){


     if(RCIF_bit == 1){
     UART1_Read_Text(output, ";", 9);
     flag=1;     
     RCIF_bit = 0;
     }
    
     if(TMR0IF_bit == 1){
     one_s++;
     TMR0H = 0xE1;
     TMR0L = 0x78;
     TMR0IF_bit = 0;
     }
}

void main(){
        if(flag==1){
                
        LCD_Out(2,1,output);
        flag=0;
        i=0;
        }
}

Rest of the code is same.
Thanks in advance.
 

EEK! that is horrible code!
The reason it stops is you are holding up the interrupt waiting for another character to arrive but the interrupts are disabled at that time. When you enter the ISR it suspends further interrupts until you exit.

Change the code so you detect the incoming character inside the ISR and save it but then do the checking and string construction in the main() section of your code. Golden rule of interrupts is 'get out as fast as you can'. Use the ISR to detect an event but run the code to deal with it outside the ISR.

Another point - don't use the break instruction in an ISR, it implies you have a loop which is bad in itself but consider also where it 'breaks' to.

Brian.
 
  • Like
Reactions: djc

Thanks for your valuable time and suggestions sir. Can you please comment on the second code.
The reason it stops is you are holding up the interrupt waiting for another character to arrive but the interrupts are disabled at that time
Does it mean that i should not use 'While' inside the ISR.
 

Correct.
An ISR is triggered by an external event, in your case a character arriving in the USART. Characters could arrive at any time so your ISR has to be ready to receive the next one. The same applies to other sources of interrupts and until the ISR ends, no further interrupts can be processed. While you were waiting for the next character, everything stopped but because the interrupts were suspended, no further characters could be received.

The better way to do it is like this:
Code:
void interrupt(void){
     if(RCIF_bit){
     ReceivedCharacter = RCREG;
     flag=1;   
     }
   
     if(TMR0IF_bit){
     TMR0H = 0xE1;
     TMR0L = 0x78;
     one_s++;
     TMR0IF_bit = 0;
     }
}

then in your main loop, read 'flag' and if it is set, use the value in 'ReceivedCharacter' then reset 'flag' again for next time. So all you do in the ISR is save the character and use 'flag' to tell the main loop that one is present. It takes all the processing delays out of the ISR so it is ready to respond to the next interrupt as quickly as possible. Note that reading RCREG automatically clears the RCIF bit so you don't have to do it in our code.

Brian.
 
  • Like
Reactions: djc

Hi
Can you please comment on the second code.
This usually we expect from you. But your code is rather undocumented.
So we need to go through line after line ang gues what it is meant to do. This takes a lot of time - we don´t have.

*******
Some recommendations:
* If possible speed up your interfaces. 9600 baud is slow.
* use software buffers and do the data transfer via interrupt. No blocking within interrupt.
* draw a timing table. How often do you want which function to be processed. (example: 2 display updates per second is sufficient for measurement values. or once per second if you just show the clock, or once per minute if the clock shows no seconds, just minutes and hours.)

Klaus
 

Hi
This usually we expect from you. But your code is rather undocumented.
So we need to go through line after line ang gues what it is meant to do. This takes a lot of time - we don´t have.

*******
Some recommendations:
* If possible speed up your interfaces. 9600 baud is slow.
* use software buffers and do the data transfer via interrupt. No blocking within interrupt.
* draw a timing table. How often do you want which function to be processed. (example: 2 display updates per second is sufficient for measurement values. or once per second if you just show the clock, or once per minute if the clock shows no seconds, just minutes and hours.)

Klaus
Thanks klausST for your suggestions. However baud rate can not be changed now as other hardware has the same one and it is fixed. However will try to change display routine. Will display time change per minute instead of per second now.
--- Updated ---

Hello all,
The data controller going to receive consists of 7 bytes of data including spaces and a terminating character which is semicolon. However i think some how i am not able to receive that semicolon. When i try to receive that data on serial terminal, it works fine. Data received is like " 45;", spaces and an integer. Modified code is as follows
Code:
void interrupt(void){

     if(RCIF_bit == 1){           
        j = RCREG;       
        flag=1;
      }
    
     if(TMR0IF_bit == 1){
     one_s++;
     TMR0H = 0x85;                //E1     for 8 Mhz
     TMR0L = 0xED;                //78
     TMR0IF_bit = 0;
     }
}

void main(){                   
                   if((Button(&PORTA, 2, 10, 0))){          //Button press to make a query
                                     while (Qry==0)  {}
                                     UART1_Write_Text("R;");
                                     i=0;
                    }
                  
                   if(flag==1){
                   uart_rd[i] = j;
                   if(uart_rd[i] == ';'){
                   count=1;
                   }
                   else{ i++; }       
                   flag=0;
                   }
                  
                   if(count == 1){
                   Lcd_Cmd(_LCD_CLEAR);
                   for(k=0;k<i;k++){
                   InttoStr(uart_rd[k],Data);
                   LCD_Out(2,k,Data);
                   }
                   i=0;
                   count = 0;
                   }
}

At the max what i could gat is " 32". Means spaces and ascii character for 32 again. I apologize for posting such questions.
 
Last edited:

Hi,

I´m not able to write C code...

make the byte array uart_rd[32] global, volatile // uart receive buffer
make an integer uart_rc global, volatile // Uart receive counter
make an integer flag global, volatile // message received flag

within the ISR (pseudo code):
Code:
if(RCIF_bit == 1){         
   array uart_rd[uart_rc] = RCREG;       // store received byte into the array
   if (uart_rd[uart_rc++]==";"){                // check whether it´s the delimiter
      flag=1;                                                        //if delimiter received, set flag
      }
   }
in the main code you should just read the last xx bytes before the delimiter, then set uart_rc = 0 and clear the flag.

to be more failure proof, either use a circuilar buffer, or limit the value of the receive counter.
it´s useful to clear the buffer (set uart_rc = 0) after a receive timeout. (in case uart_rc doesn't change for xx milliseconds)

Klaus
 
Last edited:

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top