Estoy tratando de usar una pantalla LCD de 16x2 para ser programada por el microcontrolador ATmega328P usando Atmel Studio v7. Estoy usando una biblioteca para este propósito que encontré en internet. Escribí este programa para medir las RPM de un motor utilizando sus sensores de efecto Hall:
#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);
}
Este programa funciona como se esperaba. Sin embargo, muestra casillas negras en la primera línea cuando intento escribir este código:
#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);
}
Como puede ver, la inicialización del LCD en ambos programas es la misma, pero el segundo programa no escribe nada en el LCD, mientras que el primero sí lo hace.
Estoy usando el modo de 4 bits para escribir en la pantalla LCD. Las conexiones de los pines son las siguientes:
Vss - > GND
Vdd - > 5V
V0 - > Entrada de bote de 10k
RS - > Puerto D0
EN - > Puerto d1
D0-D3 - > no conectado
D4 - > Puerto C1
D5 - > Puerto c2
D6 - > Puerto C3
D7 - > Puerto C4
El archivo lcd.h que estoy usando se muestra a continuación:
//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]!='#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);
}
';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]!='#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);
}
';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
No puedo entender por qué la pantalla LCD funciona con el primer programa y no con el segundo. Por favor ayuda.