/*
* Lab5_Task3_LCD.c
*
* Created: 2024-05-06 18:15:10
* Author : ralli
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define DATA0 PD0
#define DATA1 PD1
#define DATA2 PD2
#define DATA3 PD3
#define DATA4 PD4
#define DATA5 PD5
#define DATA6 PD6
#define DATA7 PD7
#define RS PB0
#define E PB1
const uint8_t CURSOR_POSITIONS[2][16] = {
{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F},
{0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F}
};
int main(void)
{
INIT_DATAPINS();
INIT_LCD();
LCD_DISPLAY_STRING("Voltage:", 8);
LCD_SET_CURSOR_POSITION(0,15);
LCD_DISPLAY_STRING("V", 1);
LCD_SET_CURSOR_POSITION(1,0);
LCD_DISPLAY_STRING("Light:", 6);
LCD_SET_CURSOR_POSITION(1,15);
LCD_DISPLAY_STRING("%", 1);
while (1);
}
void INIT_LCD(void){
PORTB &= (0 << RS);
LCD_DISPLAY_ON_OFF_CONTROL();
LCD_FUNCTION_SET();
LCD_ENTRY_MODE_SET();
PORTB |= (1 << RS);
}
void LCD_DISPLAY_STRING(char* str, uint8_t length){
for(int i = 0; i < length; i++){
char character = str[i];
LCD_DISPLAY_CHAR(character);
}
}
void LCD_DISPLAY_CHAR(unsigned int ascii_value){
PORTD = ascii_value;
LCD_ENABLE();
}
/*TELLS LCD TO USE 8 DATA-PINS FOR INFORMATION. ENABLES DISPLAY TO USE 2 LINES OF TEXT.
FUNCTION SET
RS: 0
RW: 0
MODE: 4-bit DATA4 LOW
-> 8-bit DATA4 HIGH
LINENUMBER: 1-line DATA3 LOW
-> 2-line DATA3 HIGH
DOTS: -> 5x8 DOTS LETTERS DATA2 LOW
5x11 DOTS LETTERS DATA2 HIGH
*/
void LCD_FUNCTION_SET(void){
// 0011 1000 8-bit mode, 2 line, 5x8 format
PORTD = 0;
PORTD |= (0 << DATA7) | (0 << DATA6) | (1 << DATA5) | (1 << DATA4) | (1 << DATA3) | (0 << DATA2) | (0 << DATA1) | (0 << DATA0);
}
void INIT_DATAPINS(void){
DDRD = 0b11111111;
DDRB = (1 << E) | (1 << RS);
}
/* CLEARS ENTIRE DISPLAY, AND SENDS CURSOR TO STARTING POSITION
CLEAR DISPLAY
RS: 0
RW: 0
*/
void LCD_CLEAR_DISPLAY(void){
// 0000 0001 CLEAR DISPLAY
PORTD = 0;
PORTD |= (0 << DATA7) | (0 << DATA6) | (0 << DATA5) | (0 << DATA4) | (0 << DATA3) | (0 << DATA2) | (0 << DATA1) | (1 << DATA0);
LCD_ENABLE();
}
/* SENDS CURSOR TO STARTING POSITION
CLEAR DISPLAY
RS: 0
RW: 0
*/
void LCD_RETURN_HOME(void){
// 0000 0010 RETURN HOME
PORTD = 0;
PORTD |= (0 << DATA7) | (0 << DATA6) | (0 << DATA5) | (0 << DATA4) | (0 << DATA3) | (0 << DATA2) | (1 << DATA1) | (0 << DATA0);
LCD_ENABLE();
}
/* TELLS THE LCD TO READ DATAPINS, RW & RS PINS, AND DO OPERATION. THE ENABLE-PIN IS HIGH FOR A SHORT WHILE, THEN GOES LOW AGAIN.
AFTER SETTING UP THE DATAPINS, THE ENABLE NEEDS TO BE TOGGLED FOR THE CHARACTER TO DISPLAY.
E: 1
*/
void LCD_ENABLE(void){
_delay_us(1);
PORTB ^= (1 << E);
_delay_us(1);
PORTB ^= (1 << E);
}
void LCD_SET_CURSOR_POSITION(int row, int column){
LCD_SET_DDRAM_ADDRESS(CURSOR_POSITIONS[row][column]);
//Serial.println(CURSOR_POSITIONS[row][column]);
}
void LCD_SET_DDRAM_ADDRESS(unsigned char address){
PORTB &= (0 << RS);
PORTD = 128;
PORTD |= address;
LCD_ENABLE();
PORTB |= (1 << RS);
}
/*SETTINGS FOR DISPLAY ON/OFF, CURSOR ON/OFF, BLINKING CURSOR ON/OFF
FUNCTION SET
RS: 0
RW: 0
DISPLAY ON/OFF: DISPLAY OFF DATA2 LOW
->DISPLAY ON DATA2 HIGH
CURSOR ON/OFF: CURSOR OFF DATA1 LOW
-> CURSOR ON DATA1 HIGH
BLINKING ON/OFF: -> BLINKING CURSOR OFF DATA0 LOW
BLINKING CURSOR ON DATA0 HIGH
*/
void LCD_DISPLAY_ON_OFF_CONTROL(void){
// 0000 1111 DISPLAY ON, CURSOR ON, BLINK ON
PORTD = 0;
PORTD |= (0 << DATA7) | (0 << DATA6) | (0 << DATA5) | (0 << DATA4) | (1 << DATA3) | (1 << DATA2) | (1 << DATA1) | (1 << DATA0);
LCD_ENABLE();
}
/*SETTINGS FOR WHICH WAY THE CURSOR MOVES, CONTROLS TO SHIFT ENTIRE DISPLAY LEFT/RIGHT
FUNCTION SET
RS: 0
RW: 0
INCREMENT/DECREMENT: CURSOR TO LEFT DATA1 LOW
->CURSOR TO RIGHT DATA1 HIGH
IF INCREMENT IS HIGH = SHIFT LEFT, INCREMENT IS LOW = SHIFT RIGHT
SHIFT LEFT/RIGHT: SHIFT DATA0 HIGH
BLINKING ON/OFF: -> BLINKING CURSOR OFF DATA0 LOW
BLINKING CURSOR ON DATA0 HIGH
*/
void LCD_ENTRY_MODE_SET(void){
// 0000 0000 Left->Right
PORTD = 0;
PORTD |= (0 << DATA7) | (0 << DATA6) | (0 << DATA5) | (0 << DATA4) | (0 << DATA3) | (1 << DATA2) | (1 << DATA1) | (0 << DATA0);
}