Electrical – Problems with LCD when using it with ATmega328P

atmegaatmega328patmel-studiocharacter-lcd

I'm trying to use a 16×2 LCD screen to be programmed by the ATmega328P microcontroller using Atmel Studio v7. I am using a library for this purpose that I found on the internet. I wrote this program for measurement of RPM of a motor using its hall effect sensors:

#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#define D4 eS_PORTC1
#define D5 eS_PORTC2
#define D6 eS_PORTC3
#define D7 eS_PORTC4
#define RS eS_PORTD0
#define EN eS_PORTD1

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include "lcd.h" 

volatile uint16_t count = 0;

volatile float rpm = 0;

volatile float rps = 0;
int speed = 0;

volatile int flag = 0, prevflag = 0;
int num = 0;
char sec[4];

void Timer_init()
{
    TCCR1A |= (1<<COM1A1);
    TCCR1B  |= (1<<WGM12)|(1<<CS12)|(1<<CS10);

    OCR1A = 15624;

    TIMSK1 |= (1<<OCIE1A);
}

void ADC_init()
{
    ADMUX |= (1<<REFS0);
    ADMUX &= ~((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));
    ADCSRA |= (1<<ADEN)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

int main(void)
{
    DDRD |= (1<<DDD0)|(1<<DDD1);
    DDRD &= ~(1<<DDD2);
    DDRC |= (1<<DDC1)|(1<<DDC2)|(1<<DDC3)|(1<<DDC4);

    ADC_init();
    Timer_init();
    sei();
    Lcd4_Init();
    Lcd4_Clear();

    ADCSRA |= (1<<ADSC);
    while(1)
    {

    }
}

ISR (ADC_vect)
{
    int num = ADC;
    if (num >= 950)
        flag = 1;
    else
        flag  = 0;

    if (flag != prevflag)
        count++;
    prevflag = flag;

    ADCSRA |= (1<<ADSC);
}

ISR (TIMER1_COMPA_vect)
{
    rps = (float)count/(21.0 * 1.81);
    rpm = rps * 60.0;
    count = 0;
    Lcd4_Clear();
    Lcd4_Set_Cursor(1,1);
    Lcd4_Write_String("RPM = ");
    Lcd4_Set_Cursor(1,8);
    itoa(rpm, sec, 10);
    Lcd4_Write_String(sec);
}

This program works as expected. However, it shows black boxes on the first line when I try to write this code:

#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#define D4 eS_PORTC1
#define D5 eS_PORTC2
#define D6 eS_PORTC3
#define D7 eS_PORTC4
#define RS eS_PORTD0
#define EN eS_PORTD1

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include "lcd.h"


int sp,input;
char string[10];

void adc_init_current();
uint16_t adc_read();
int pid();
void pwm_init();
void tim1_init();
void adc_init_setpoint();

int main(void)
{
    DDRD |= (1<<DDD0)|(1<<DDD1);
    DDRC |= (1<<DDC1)|(1<<DDC2)|(1<<DDC3)|(1<<DDC4);

    sei();
    pwm_init();
    adc_init_setpoint();

    Lcd4_Init();
    Lcd4_Clear();
    Lcd4_Set_Cursor(1,1);
    Lcd4_Write_String("Hello");
    _delay_ms(2000);

    sp = adc_read()*255/1023;
    itoa(sp,string,10);
    Lcd4_Set_Cursor(1,1);
    Lcd4_Write_String("SP=");
    Lcd4_Set_Cursor(1,4);
    Lcd4_Write_String(string);
    while (1) 
    {
        //sp = adc_read();
        //OCR0A = (float)sp*255/1023;
    }
}
int pid()
{
    double error, k_p=1,k_i=0,k_d=0,integral=0,derivative=0,lastError=0,sampleTime=0.01,output;
    error = sp-input;
    integral += error*sampleTime;
    derivative = (error - lastError)/sampleTime;
    output = k_p*error + k_i*integral + k_d*derivative;
    lastError = error;
    return output;
}
void adc_init_current()
{
    ADMUX |= (1<<REFS0);
    ADCSRA |= (7<<ADPS0)|(1<<ADEN);
    ADMUX &= ~(15<<MUX0);   
}
void adc_init_setpoint()
{
    ADMUX |= (1<<REFS0)|(1<<MUX0)|(1<<MUX2);
    ADMUX &= ~(1<<MUX3)|(1<<MUX1);
    ADCSRA |= (7<<ADPS0)|(1<<ADEN);
}
uint16_t adc_read()
{
    ADCSRA |= (1<<ADSC);
    while (ADCSRA & (1<<ADSC));
    return ADC;
}
void pwm_init()
{
    TCCR0A |= (1<<WGM00)|(1<<WGM01)|(1<<COM0A1);
    TCCR0B |= (1<<CS01);
    DDRD|= (1<<DDD6);
}
void tim1_init()
{
    TCCR1A |= (1<<COM1A1);
    TCCR1B |= (1<<WGM12)|(1<<CS12);
    TIMSK1 |= (1<<OCIE1A);
    OCR1A = 625;
}
ISR (TIMER1_COMPA_vect)
{
    input = (adc_read()-512)*255/1023;
    Lcd4_Set_Cursor(1,8);
    Lcd4_Write_String("Cur=");
    itoa(input,string,10);
    Lcd4_Set_Cursor(1,12);
    Lcd4_Write_String(string);
    double output = pid();
    if (output >= 255)
    {
        output = 255;
    }
    OCR0A = output;
    Lcd4_Set_Cursor(2,1);
    itoa(output,string,10);
    Lcd4_Write_String("Output = ");
    Lcd4_Set_Cursor(2,10);
    Lcd4_Write_String(string);
}

As you can see, the LCD initialization in both programs is the same, yet the second program does not write anything on the LCD, while the first one does.

I am using 4-bit mode to write to the LCD. The pin connections are as follows:
Vss -> GND
Vdd -> 5V
V0 -> Input from 10k pot
RS -> Port D0
EN -> Port D1
D0-D3 -> not connected
D4 -> Port C1
D5 -> Port C2
D6 -> Port C3
D7 -> Port C4
The lcd.h file I am using is given below:

//LCD Functions Developed by electroSome
#define eS_PORTA0 0
#define eS_PORTA1 1
#define eS_PORTA2 2
#define eS_PORTA3 3
#define eS_PORTA4 4
#define eS_PORTA5 5
#define eS_PORTA6 6
#define eS_PORTA7 7
#define eS_PORTB0 10
#define eS_PORTB1 11
#define eS_PORTB2 12
#define eS_PORTB3 13
#define eS_PORTB4 14
#define eS_PORTB5 15
#define eS_PORTB6 16
#define eS_PORTB7 17
#define eS_PORTC0 20
#define eS_PORTC1 21
#define eS_PORTC2 22
#define eS_PORTC3 23
#define eS_PORTC4 24
#define eS_PORTC5 25
#define eS_PORTC6 26
#define eS_PORTC7 27
#define eS_PORTD0 30
#define eS_PORTD1 31
#define eS_PORTD2 32
#define eS_PORTD3 33
#define eS_PORTD4 34
#define eS_PORTD5 35
#define eS_PORTD6 36
#define eS_PORTD7 37

#ifndef D0
#define D0 eS_PORTA0
#define D1 eS_PORTA1
#define D2 eS_PORTA2
#define D3 eS_PORTA3
#endif

#include<util/delay.h>

void pinChange(int a, int b)
{
    if(b == 0)
    {
        if(a == eS_PORTB0)
        PORTB &= ~(1<<PORTB0);
        else if(a == eS_PORTB1)
        PORTB &= ~(1<<PORTB1);
        else if(a == eS_PORTB2)
        PORTB &= ~(1<<PORTB2);
        else if(a == eS_PORTB3)
        PORTB &= ~(1<<PORTB3);
        else if(a == eS_PORTB4)
        PORTB &= ~(1<<PORTB4);
        else if(a == eS_PORTB5)
        PORTB &= ~(1<<PORTB5);
        else if(a == eS_PORTB6)
        PORTB &= ~(1<<PORTB6);
        else if(a == eS_PORTB7)
        PORTB &= ~(1<<PORTB7);
        else if(a == eS_PORTC0)
        PORTC &= ~(1<<PORTC0);
        else if(a == eS_PORTC1)
        PORTC &= ~(1<<PORTC1);
        else if(a == eS_PORTC2)
        PORTC &= ~(1<<PORTC2);
        else if(a == eS_PORTC3)
        PORTC &= ~(1<<PORTC3);
        else if(a == eS_PORTC4)
        PORTC &= ~(1<<PORTC4);
        else if(a == eS_PORTC5)
        PORTC &= ~(1<<PORTC5);
        else if(a == eS_PORTC6)
        PORTC &= ~(1<<PORTC6);
        else if(a == eS_PORTD0)
        PORTD &= ~(1<<PORTD0);
        else if(a == eS_PORTD1)
        PORTD &= ~(1<<PORTD1);
        else if(a == eS_PORTD2)
        PORTD &= ~(1<<PORTD2);
        else if(a == eS_PORTD3)
        PORTD &= ~(1<<PORTD3);
        else if(a == eS_PORTD4)
        PORTD &= ~(1<<PORTD4);
        else if(a == eS_PORTD5)
        PORTD &= ~(1<<PORTD5);
        else if(a == eS_PORTD6)
        PORTD &= ~(1<<PORTD6);
        else if(a == eS_PORTD7)
        PORTD &= ~(1<<PORTD7);
    }
    else
    {
        if(a == eS_PORTB0)
        PORTB |= (1<<PORTB0);
        else if(a == eS_PORTB1)
        PORTB |= (1<<PORTB1);
        else if(a == eS_PORTB2)
        PORTB |= (1<<PORTB2);
        else if(a == eS_PORTB3)
        PORTB |= (1<<PORTB3);
        else if(a == eS_PORTB4)
        PORTB |= (1<<PORTB4);
        else if(a == eS_PORTB5)
        PORTB |= (1<<PORTB5);
        else if(a == eS_PORTB6)
        PORTB |= (1<<PORTB6);
        else if(a == eS_PORTB7)
        PORTB |= (1<<PORTB7);
        else if(a == eS_PORTC0)
        PORTC |= (1<<PORTC0);
        else if(a == eS_PORTC1)
        PORTC |= (1<<PORTC1);
        else if(a == eS_PORTC2)
        PORTC |= (1<<PORTC2);
        else if(a == eS_PORTC3)
        PORTC |= (1<<PORTC3);
        else if(a == eS_PORTC4)
        PORTC |= (1<<PORTC4);
        else if(a == eS_PORTC5)
        PORTC |= (1<<PORTC5);
        else if(a == eS_PORTC6)
        PORTC |= (1<<PORTC6);
        else if(a == eS_PORTD0)
        PORTD |= (1<<PORTD0);
        else if(a == eS_PORTD1)
        PORTD |= (1<<PORTD1);
        else if(a == eS_PORTD2)
        PORTD |= (1<<PORTD2);
        else if(a == eS_PORTD3)
        PORTD |= (1<<PORTD3);
        else if(a == eS_PORTD4)
        PORTD |= (1<<PORTD4);
        else if(a == eS_PORTD5)
        PORTD |= (1<<PORTD5);
        else if(a == eS_PORTD6)
        PORTD |= (1<<PORTD6);
        else if(a == eS_PORTD7)
        PORTD |= (1<<PORTD7);
    }
}



//LCD 8 Bit Interfacing Functions
void Lcd8_Port(char a)
{
    if(a & 1)
    pinChange(D0,1);
    else
    pinChange(D0,0);

    if(a & 2)
    pinChange(D1,1);
    else
    pinChange(D1,0);

    if(a & 4)
    pinChange(D2,1);
    else
    pinChange(D2,0);

    if(a & 8)
    pinChange(D3,1);
    else
    pinChange(D3,0);

    if(a & 16)
    pinChange(D4,1);
    else
    pinChange(D4,0);

    if(a & 32)
    pinChange(D5,1);
    else
    pinChange(D5,0);

    if(a & 64)
    pinChange(D6,1);
    else
    pinChange(D6,0);

    if(a & 128)
    pinChange(D7,1);
    else
    pinChange(D7,0);
}
void Lcd8_Cmd(char a)
{
    pinChange(RS,0);             // => RS = 0
    Lcd8_Port(a);             //Data transfer
    pinChange(EN,1);             // => E = 1
    _delay_ms(1);
    pinChange(EN,0);             // => E = 0
    _delay_ms(1);
}

void Lcd8_Clear()
{
    Lcd8_Cmd(1);
}

void Lcd8_Set_Cursor(char a, char b)
{
    if(a == 1)
    Lcd8_Cmd(0x80 + b);
    else if(a == 2)
    Lcd8_Cmd(0xC0 + b);
}

void Lcd8_Init()
{
    pinChange(RS,0);
    pinChange(EN,0);
    _delay_ms(20);
    ///////////// Reset process from datasheet /////////
    Lcd8_Cmd(0x30);
    _delay_ms(5);
    Lcd8_Cmd(0x30);
    _delay_ms(1);
    Lcd8_Cmd(0x30);
    _delay_ms(10);
    /////////////////////////////////////////////////////
    Lcd8_Cmd(0x38);    //function set
    Lcd8_Cmd(0x0C);    //display on,cursor off,blink off
    Lcd8_Cmd(0x01);    //clear display
    Lcd8_Cmd(0x06);    //entry mode, set increment
}

void Lcd8_Write_Char(char a)
{
    pinChange(RS,1);             // => RS = 1
    Lcd8_Port(a);             //Data transfer
    pinChange(EN,1);             // => E = 1
    _delay_ms(1);
    pinChange(EN,0);             // => E = 04
    _delay_ms(1);
}

void Lcd8_Write_String(char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
    Lcd8_Write_Char(a[i]);
}

void Lcd8_Shift_Right()
{
    Lcd8_Cmd(0x1C);
}

void Lcd8_Shift_Left()
{
    Lcd8_Cmd(0x18);
}
//End LCD 8 Bit Interfacing Functions

//LCD 4 Bit Interfacing Functions

void Lcd4_Port(char a)
{
    if(a & 1)
    pinChange(D4,1);
    else
    pinChange(D4,0);

    if(a & 2)
    pinChange(D5,1);
    else
    pinChange(D5,0);

    if(a & 4)
    pinChange(D6,1);
    else
    pinChange(D6,0);

    if(a & 8)
    pinChange(D7,1);
    else
    pinChange(D7,0);
}
void Lcd4_Cmd(char a)
{
    pinChange(RS,0);             // => RS = 0
    Lcd4_Port(a);
    pinChange(EN,1);            // => E = 1
    _delay_ms(1);
    pinChange(EN,0);             // => E = 0
    _delay_ms(1);
}

void Lcd4_Clear()
{
    Lcd4_Cmd(0);
    Lcd4_Cmd(1);
}

void Lcd4_Set_Cursor(char a, char b)
{
    char temp,z,y;
    if(a == 1)
    {
        temp = 0x80 + b;
        z = temp>>4;
        y = (0x80+b) & 0x0F;
        Lcd4_Cmd(z);
        Lcd4_Cmd(y);
    }
    else if(a == 2)
    {
        temp = 0xC0 + b;
        z = temp>>4;
        y = (0xC0+b) & 0x0F;
        Lcd4_Cmd(z);
        Lcd4_Cmd(y);
    }
}

void Lcd4_Init()
{
    Lcd4_Port(0x00);
    _delay_ms(20);
    ///////////// Reset process from datasheet /////////
    Lcd4_Cmd(0x03);
    _delay_ms(5);
    Lcd4_Cmd(0x03);
    _delay_ms(11);
    Lcd4_Cmd(0x03);
    /////////////////////////////////////////////////////
    Lcd4_Cmd(0x02);
    Lcd4_Cmd(0x02);
    Lcd4_Cmd(0x08);
    Lcd4_Cmd(0x00);
    Lcd4_Cmd(0x0C);
    Lcd4_Cmd(0x00);
    Lcd4_Cmd(0x06);
}

void Lcd4_Write_Char(char a)
{
    char temp,y;
    temp = a&0x0F;
    y = a&0xF0;
    pinChange(RS,1);             // => RS = 1
    Lcd4_Port(y>>4);             //Data transfer
    pinChange(EN,1);
    _delay_ms(1);
    pinChange(EN,0);
    _delay_ms(1);
    Lcd4_Port(temp);
    pinChange(EN,1);
    _delay_ms(1);
    pinChange(EN,0);
    _delay_ms(1);
}

void Lcd4_Write_String(char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
    Lcd4_Write_Char(a[i]);
}

void Lcd4_Shift_Right()
{
    Lcd4_Cmd(0x01);
    Lcd4_Cmd(0x0C);
}

void Lcd4_Shift_Left()
{
    Lcd4_Cmd(0x01);
    Lcd4_Cmd(0x08);
}
//End LCD 4 Bit Interfacing Functions

I can't figure out why the LCD works with the first program and not with the second one. Please help.

Best Answer

You have code which "works", and code which "doesn't work". That is a good situation for debugging.

Even without the facilities of a full debugger, as is common on many ARM-Cortex devices, you can apply several different debugging approaches. One of them is described on the Stack Overflow MCVE page - create a minimum failing code example. Often, while doing that, people discover the underlying bug.

At the moment, there is lots of code which is not related to the LCD in both examples. So work to remove unnecessary code, using one of the two techniques mentioned on that MCVE page: Either "restart from scratch" (starting from nothing to add only the necessary code) or "divide and conquer" (removing unnecessary code until the problem disappears, then add back only that last part) to end up with only the minimum code needed to reproduce your problem.

Then it is easier for you to compare the minimum working code, to the minimum non-working code, and focus on the differences.

Also, I expect you will discover some unexpected parts of your non-working code, which seem to affect the LCD display, during that "minimisation" process - and you can debug from there. If not, and you end up with just a few lines of code in each example, one of which works and one which does not, then it is much easier for other people to help. Good luck!

Related Topic