Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

mikroC problem

Status
Not open for further replies.

colin mac

New Member
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);
}
 
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(){
 
  // ...
 
}
 
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?
 
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:
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 ..
 
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().
 
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:
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 ..
 

Attachments

  • untitled.jpg
    untitled.jpg
    41.1 KB · Views: 585
Last edited:
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:
@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)
 
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:
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 :)
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top