Hi there !
i am trying to send Serial information to an LCD display (hd44780)
there is two main part in my code : the USART part and the LCD part. both are working well, separately.
but when i want to send USART ascii data to my LCD it is not working.
if i send a string, there is nothing
and if i send a char, it displays a 'ä' character (which is weird, i didn't know this was in ASCII table lol.
here's my code :
//--------------------------------------------------------
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//--------------------------------------------------------
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define BAUD 9600
#define MYUBRR(F_CPU,BAUD)((F_CPU/16/BAUD)-1)
//--------------------------------------------------------
#define E (1<<PD3)
#define RS (1<<PD2)
//--------------------------------------------------------
void USART_Init(uint32_t ubrr)
{
/*Set BaudRate*/
UBRR0L = MYUBRR(F_CPU,ubrr);
UBRR0H = (MYUBRR(F_CPU,ubrr) >> 8);
/*Enable Receiver and Transmitter*/
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
/*Set Frame format: 8data, 2stop bit*/
UCSR0C = (1<<USBS0) | (3<<UCSZ00);
}
uint32_t USART_Receive(void)
{
while(!(UCSR0A & (1<<RXC0)));
return UDR0;
}
void USART_Transmit(unsigned char _data)
{
//Wait for empty transmit buffer
while(!(UCSR0A & (1<<UDRE0)));
//Put data into buffer, sends the data
UDR0 = _data;
}
//--------------------------------------------------------
//latch E pin command
void latch(void)
{
PORTD |= E; //send high
_delay_us(500); //wait
PORTD &= ~E; //send low
_delay_us(500); //wait
}
//to send commands in the right order
void lcd_cmd(uint8_t cmd)
{
PORTD = (PORTD & 0x0F) | (cmd & 0xF0); //send high nibble
PORTD &= ~RS; //send 0 to select command register
latch(); //latch the data
PORTD = (PORTD & 0x0F) | (cmd << 4); //send low nibble
latch(); //latch the data
}
//init sequence
void lcd_init()
{
//Init ports for LCD
DDRD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7);
//send pulse to latch the data
latch();
_delay_ms(2); //delay for stable power
//command to set up the LCD
lcd_cmd(0x33);
_delay_us(100);
lcd_cmd(0x32);
_delay_us(100);
lcd_cmd(0x28); //2 lines 5x7 matrix dot
_delay_us(100);
//lcd_cmd(0x0E); // display ON, cursor ON
lcd_cmd(0x0C); //display ON, cursor ON
_delay_us(100);
lcd_cmd(0x01); //clear LCD
_delay_ms(20); //wait
lcd_cmd(0x06); //shift cursor to right
_delay_ms(1);
}
void lcd_setcursor(uint8_t x, uint8_t y)
{
uint8_t firstcharadr[] = {0x80,0xC0,0x94,0xD4};
lcd_cmd(firstcharadr[y-1]+ x-1);
_delay_us(1000);
}
uint16_t lcd_char(uint8_t data)
{
PORTD = (PORTD & 0x0F) | (data & 0xF0); //send high nibble
PORTD |= RS; //send one to select command register
latch();
PORTD = (PORTD & 0x0F) | (data<<4); //send high nibble
latch();
return data;
}
uint32_t lcd_print(char *str)
{
uint8_t k = 0;
while(str[k] != 0)
{
lcd_char(str[k]);
k++;
}
return str;
}
int main()
{
USART_Init(BAUD);
lcd_init();
lcd_setcursor(1,1);
USART_Transmit('R');
lcd_print("USART Test :");
lcd_setcursor(1,2);
//UCSR0B |= (1<<RXCIE0);
//sei();
while(1){
while(!(UCSR0A & (1<<UDRE0)));
lcd_char(USART_Receive());
}
return 0;
}
i've read somewhere that i cannot do this that way because an LCD display is not a serial monitor. which make sens. it works like old terminals, i guess. a terminal receive serial data and have internal logics that displays the text one character at a time.
if this is the solution, how can i create sort of a buffer and put it to the display ? like so :
this is a practice for low-level programming on Atmega328p.
i am not using arduino high-level code here.