+ Reply to Thread
Results 1 to 13 of 13

Thread: mikroC problem

  1. #1
    colin mac Good colin mac Good colin mac Good colin mac Good
    Join Date
    Jun 2007
    Location
    Ireland
    Posts
    342

    Default mikroC problem

    I wrote a C program that sends a character to the lcd then jumps the cursor to the 2nd line. I changed my program to send a string and I'm finding these two functions are not doing the job. I'm using bitwise operators to assign the MSB of a char to D7, the next MSB to D6, etc. Can anyone see what's wrong?

    Code:
    void sendString(char *str)
    {
      int index = 0;
      while (str[index] != 0)
      {
         sendChar(str[index]);
         index++;
      }
    }
    
    void sendChar(char c)
    {
      RS = 1;
      D7 = (c >> 7) & 1;
      D6 = (c >> 6) & 1;
      D5 = (c >> 5) & 1;
      D4 = (c >> 4) & 1;
      enable();
      D7 = (c >> 3) & 1;
      D6 = (c >> 2) & 1;
      D5 = (c >> 1) & 1;
      D4 = (c >> 0) & 1;
      enable();
      delay_ms(200);
    }
    


  2. #2
    eng1 Excellent eng1 Excellent eng1 Excellent eng1 Excellent eng1 Excellent
    Join Date
    Apr 2006
    Location
    Italy
    Posts
    938

    Default

    Quote Originally Posted by colin mac View Post
    I wrote a C program that sends a character to the lcd then jumps the cursor to the 2nd line. I changed my program to send a string and I'm finding these two functions are not doing the job. I'm using bitwise operators to assign the MSB of a char to D7, the next MSB to D6, etc. Can anyone see what's wrong?

    Code:
    void sendString(char *str)
    {
      int index = 0;
      while (str[index] != 0)
      {
         sendChar(str[index]);
         index++;
      }
    }
     
    void sendChar(char c)
    {
      RS = 1;
      D7 = (c >> 7) & 1;
      D6 = (c >> 6) & 1;
      D5 = (c >> 5) & 1;
      D4 = (c >> 4) & 1;
      enable();
      D7 = (c >> 3) & 1;
      D6 = (c >> 2) & 1;
      D5 = (c >> 1) & 1;
      D4 = (c >> 0) & 1;
      enable();
      delay_ms(200);
    }
    
    The while loop in the function sendString might never end. It depends on how you initialize the strings of course. One usually uses the special character '\0' to terminate strings as in the following code:
    Code:
    void sendString(char *str){
      unsigned char index = 0;
      while (str[index] != '\0'){
         sendChar(str[index]);
         index++;
         }
    }
     
    unsigned char mystr = "Hello\0";
     
    void main(){
     
      // ...
     
    }
    

  3. #3
    3v0
    3v0 is online now
    3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent 3v0 Excellent
    Join Date
    Jul 2006
    Location
    USA
    Posts
    6,464
    Blog Entries
    11

    Default

    Did you initialize the display ?
    Were you able to send and display a single char?
    Please post questions to the forums. PM's are for personal communication.

    BCHS/3v0's Tutorials
    Junebug USB PIC programmer kit., USB Bit Whacker,
    The 15 Minute Printed Circuit Board! (+drill time)

  4. #4
    arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent
    Join Date
    Apr 2008
    Location
    Belgrade, .rs
    Posts
    832

    Default

    Quote Originally Posted by colin mac View Post
    I wrote a C program that sends a character to the lcd then jumps the cursor to the 2nd line. I changed my program to send a string and I'm finding these two functions are not doing the job. I'm using bitwise operators to assign the MSB of a char to D7, the next MSB to D6, etc. Can anyone see what's wrong?
    apart from what is already noted (string initialisation - your while will never end if string is not properly initialised and lcd init function - lcd will not display data if not properly initialised) why don't you use built in lcd functions in mikroC .. there are 4bit and 8bit lcd driving functions that are fast and work fine .. check out the Lcd_Config(), Lcd_Custom_Config() and Lcd8_Config() in the mikroC help?

  5. #5
    colin mac Good colin mac Good colin mac Good colin mac Good
    Join Date
    Jun 2007
    Location
    Ireland
    Posts
    342

    Default

    Yes i can comment out those functions and send a char by hard coding the ascii value in their place.
    I've used the debugger and the port value looks fine and the while loop ends when I expect. I've tried unsigned char, char, using '/0' instead of 0, initialising the string different ways. The cursor moves to the 2nd line alright but nothing displays.

    Code:
    #define D7 PORTB.F7
    #define D6 PORTB.F6
    #define D5 PORTB.F5
    #define D4 PORTB.F4
    #define E PORTB.F3
    #define RS PORTB.F2
    
    void functionSet(void);
    void entryMode(void);
    void displayOn(void);
    void sendString(char *str);
    void moveTo2nd(void);
    void sendChar(char c);
    void enable (void);
    
    void main(void)
    {
      TRISB = 0;
      delay_ms(200);
      functionSet();
      entryMode();
      displayOn();
      sendString("Hello");
      moveTo2nd();
      sendString("world");
      while(1);
    }
    
    // 0010 - 4 bit mode
    // 0010 1010 - 2 lines, 5 X 8.
    void functionSet(void)
    {
      RS = 0;
      D7 = 0;
      D6 = 0;
      D5 = 1;
      D4 = 0;
      enable();
      delay_ms(200);
      enable();
      D7 = 1;
      enable();
      delay_ms(200);
    }
    
    void enable(void)
    {
      E = 1;
      E = 0;
    }
    
    void entryMode(void) //0000 0110, increment with no shift
    {
      RS = 0;
      D7 = 0;
      D6 = 0;
      D5 = 0;
      D4 = 0;
      enable();
      D6 = 1;
      D5 = 1;
      enable();
      delay_ms(200);
    }
    
    void displayOn(void) //0000 1111. cursor on. blinking on.
    {
      RS = 0;
      D7 = 0;
      D6 = 0;
      D5 = 0;
      D4 = 0;
      enable();
      D7 = 1;
      D6 = 1;
      D5 = 1;
      D4 = 1;
      enable();
      delay_ms(200);
    }
    
    
    void sendString(char *str)
    {
      int index = 0;
      while (str[index] != 0)
      {
         sendChar(str[index]);
         index++;
      }
    }
    
    void sendChar(char c)
    {
      RS = 1;
      D7 = (c >> 7) & 1;
      D6 = (c >> 6) & 1;
      D5 = (c >> 5) & 1;
      D4 = (c >> 4) & 1;
      enable();
      D7 = (c >> 3) & 1;
      D6 = (c >> 2) & 1;
      D5 = (c >> 1) & 1;
      D4 = (c >> 0) & 1;
      enable();
      delay_ms(200);
    }
    
    void moveTo2nd(void)   //1100 0000 - move cursor to 2nd line
    {
      RS =  0;
      D7 = 1;
      D6 = 1;
      D5 = 0;
      D4 = 0;
      enable();
      D7 = 0;
      D6 = 0;
      enable();
      delay_ms(200);
    }
    
    Last edited by colin mac; 21st July 2008 at 04:24 PM.

  6. #6
    arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent
    Join Date
    Apr 2008
    Location
    Belgrade, .rs
    Posts
    832

    Default

    first, change the enable() function
    Code:
    void enable(void)
    {
      E = 1;
      Delay_us(2); // this delay is necessary according to datasheet
      E = 0;
    }
    
    this "should" do the trick. The other thing you might change is to remove delay_ms(200) and actually check for "busy" from the lcd, anyway, the 20ms should be enough if you want to just "wait" instead of read the busy state ..

  7. #7
    colin mac Good colin mac Good colin mac Good colin mac Good
    Join Date
    Jun 2007
    Location
    Ireland
    Posts
    342

    Default

    I don't think it's the delays, since I can send out a char by just sending an ascii value to the port and I tried just passing one char to sendChar() and it didn't work leaving me to believe it's a problem with sendChar().

  8. #8
    eng1 Excellent eng1 Excellent eng1 Excellent eng1 Excellent eng1 Excellent
    Join Date
    Apr 2006
    Location
    Italy
    Posts
    938

    Default

    Quote Originally Posted by colin mac View Post
    Yes i can comment out those functions and send a char by hard coding the ascii value in their place.
    I've used the debugger and the port value looks fine and the while loop ends when I expect. I've tried unsigned char, char, using '/0' instead of 0, initialising the string different ways. The cursor moves to the 2nd line alright but nothing displays.
    Please note that '/0' is not a single character. You should use '\0' instead, as I wrote in my previous post. That character must be placed at the end of each string and in the while loop of sendString.
    Code:
    void main(void)
    {
    TRISB = 0;
    delay_ms(200);
    functionSet();
    entryMode();
    displayOn();
    sendString("Hello\0");
    moveTo2nd();
    sendString("world\0");
    while(1);
    }
    
    I agree with arhi as far as the delay is concerned. The Enable bit must be set for a minimum time. Also, check if the the pins of PORTB are multiplexed with analog converters or comparators.
    Last edited by eng1; 21st July 2008 at 06:24 PM. Reason: typo corrected

  9. #9
    arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent
    Join Date
    Apr 2008
    Location
    Belgrade, .rs
    Posts
    832

    Default

    Quote Originally Posted by colin mac View Post
    I don't think it's the delays, since I can send out a char by just sending an ascii value to the port and I tried just passing one char to sendChar() and it didn't work leaving me to believe it's a problem with sendChar().
    I still believe it might be it .. you can check the I2C lcd controller using PIC16F690 post where there is source (in csc but easily converted to mikroc) that works ok ... (compiled in mikroC, tested in ISIS)

    in particular this code works:
    Code:
    #define D7 PORTD.F7
    #define D6 PORTD.F6
    #define D5 PORTD.F5
    #define D4 PORTD.F4
    #define E PORTD.F3
    #define RS PORTD.F2
    
    
    
    void lcd_send_nibble( unsigned char n ) {
      D7 = (n >> 3) & 1;
      D6 = (n >> 2) & 1;
      D5 = (n >> 1) & 1;
      D4 = n & 1;
      _asm nop
      E=1;
      delay_us(2);
      E=0;
    }
    
    
    
    void lcd_send_byte( unsigned char address, unsigned char n ) {
      RS = address;
      _asm nop
       E = 0;
       lcd_send_nibble(n >> 4);
       lcd_send_nibble(n & 0xf);
       Delay_ms(200);
    }
    
    #define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
    unsigned char const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
    
    void xlcd_init() {
        unsigned char i;
        RS = 0;
        E = 0;
        Delay_ms(15);
        for(i=1;i<=3;++i) {
           lcd_send_nibble(3);
           Delay_ms(5);
        }
        lcd_send_nibble(2);
        for(i=0;i<=3;++i)
           lcd_send_byte(0,LCD_INIT_STRING[i]);
    }
    
    void main(){
      ADCON1 = 0xff;
      TRISD = 0;
      PORTD = 0;
    
      TRISC = 0;
      PORTC = 0;
    
      xlcd_init();
      lcd_send_byte(0,1); //clear screen
      lcd_send_byte(1,'h');
      lcd_send_byte(1,'e');
      lcd_send_byte(1,'l');
      lcd_send_byte(1,'l');
      lcd_send_byte(1,'o');
    }
    
    attached pic is this code simulated in ISIS

    as for the "end of string" .. when you make string as you did "blah blah" mikroC automatically add '\0' to the end of it so you do not need to take care of that, also sprintf and other functions do the correct cstring termination ..
    Attached Images

  10. #10
    colin mac Good colin mac Good colin mac Good colin mac Good
    Join Date
    Jun 2007
    Location
    Ireland
    Posts
    342

    Default

    That was an accident. '\0' and 0 are identical.
    If a string is passed or declared like "this" the null character is automatically added.

    edit - ok arhi. thanks
    Last edited by colin mac; 21st July 2008 at 06:23 PM.

  11. #11
    arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent
    Join Date
    Apr 2008
    Location
    Belgrade, .rs
    Posts
    832

    Default

    @colin
    I use the "send_nibble" because of the init part .. but you can do it the way you are doing it .. the thing is in the timing ...

    note the _asm nop in 2 places .. for some reason - it is necessary - bit's me why but it helps, same thing work on 20 and on 8mhz .. so .. just one instruction delay is necessary . for whatever reason ...

    also, when I remove the 2us delay for enable bit, the simulation does not run .. hence - it is necessary .. (also noted in the datasheet)

  12. #12
    colin mac Good colin mac Good colin mac Good colin mac Good
    Join Date
    Jun 2007
    Location
    Ireland
    Posts
    342

    Default

    well I couldn't figure out why it wouldn't work even with the delay, or why you code does.
    I was just guessing with delays.
    Turns out the code works in microchip's compiler though using their delay library.

    Code:
    #include <p18F2520.h> 
    #include <delays.h>
    
    #pragma config OSC = RC
    #pragma config LVP = OFF, PWRT = ON, WDT = OFF
    #pragma config PBADEN = OFF
    #pragma config DEBUG = OFF
    
    #define D7 LATBbits.LATB7
    #define D6 LATBbits.LATB6
    #define D5 LATBbits.LATB5
    #define D4 LATBbits.LATB4
    #define E LATBbits.LATB3
    #define RS LATBbits.LATB2
    
    void functionSet(void);
    void entryMode(void);
    void displayOn(void);
    void sendChar(char c);
    void enable (void);
    void sendString(far rom char *str);
    void moveTo2nd(void);
    
    void main(void)
    {
      TRISB = 0;
      Delay10TCYx(80);
      functionSet();
      entryMode();
      displayOn();
      sendString("Hello");
      moveTo2nd();
      sendString("World");
      while(1);
    }
    
    // 0010 - 4 bit mode
    // 0010 1010 - 2 lines, 5 X 8.
    void functionSet(void)
    {
      RS= 0;
      D7 = 0;
      D6 = 0;
      D5 = 1;
      D4 = 0;
      enable();
      Delay10TCYx(80);
      enable();
      D7 = 1;
      enable();
      Delay10TCYx(80);
    }
    
    void enable(void)
    {
      E = 1;
      Delay10TCYx(1);
      E = 0;
    }
    
    void entryMode(void) //0000 0110, increment with no shift
    {
      RS = 0;
      D7 = 0;
      D6 = 0;
      D5 = 0;
      D4 = 0;
      enable();
      D6 = 1;
      D5 = 1;
      enable();
      Delay10TCYx(80);
    }
    
    void displayOn(void) //0000 1111. cursor on. blinking on.
    {
      RS = 0;
      D7 = 0;
      D6 = 0;
      D5 = 0;
      D4 = 0;
      enable();
      D7 = 1;
      D6 = 1;
      D5 = 1;
      D4 = 1;
      enable();
      Delay10TCYx(80);
    }
    
    
    void sendString(far rom char *str)
    {
      int index = 0;
      while (str[index] != '\0')
      {
         sendChar(str[index]);
         index++;
      }
    }
    
    void sendChar(char c)
    {
      RS = 1;
      D7 = (c >> 7) & 1;
      D6 = (c >> 6) & 1;
      D5 = (c >> 5) & 1;
      D4 = (c >> 4) & 1;
      enable();
      D7 = (c >> 3) & 1;
      D6 = (c >> 2) & 1;
      D5 = (c >> 1) & 1;
      D4 = (c & 1);
      enable();
      Delay10TCYx(80);
    }
    
    void moveTo2nd(void)   //1100 0000 - move cursor to 2nd line
    {
      RS =  0;
      D7 = 1;
      D6 = 1;
      D5 = 0;
      D4 = 0;
      enable();
      D7 = 0;
      D6 = 0;
      enable();
       Delay10TCYx(80);
    }
    
    Last edited by colin mac; 21st July 2008 at 09:26 PM.

  13. #13
    arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent arhi Excellent
    Join Date
    Apr 2008
    Location
    Belgrade, .rs
    Posts
    832

    Default

    Quote Originally Posted by colin mac View Post
    well I couldn't figure out why it wouldn't work even with the delay, or why you code does.
    I was just guessing with delays.
    Turns out the code works in microchip's compiler though using their delay library.
    not sure where is the problem, difference between your code and what I wrote is only in two nop's and 2us delay when triggering enable ... The 200ms delay is actually replacing the "check if lcd is busy" part, it saves one pin but slow down the communication as most lcd's I tried are not busy after ~15 ms .. (simulator was showing busy for ~180ms) anyhow, I prefer to use one more pin on the uC but to get 2way communication with the lcd. To be honest, after I made this I'm using it everywhere, as having lcd along with other i2c devices on the bus takes only 2 pin's from mine main uC and I'm free to use the other ones for "more important" and "time critical" things

+ Reply to Thread

Similar Threads

  1. mikroC lib troubble
    By Kryten in forum Micro Controllers
    Replies: 18
    Latest: 18th January 2010, 04:08 AM
  2. mikroC demo version limits
    By ssylee in forum Micro Controllers
    Replies: 8
    Latest: 19th October 2007, 08:21 PM
  3. Servo motor~~~~ problem~.....shaking problem!!!!!
    By Gundam82 in forum Robotics Chat
    Replies: 10
    Latest: 4th October 2004, 07:12 PM

Tags for this Thread