아트메가/활용

CLCD ATMEGA128로 제어하기 2편

원원 2022. 8. 21. 22:21

안녕하세요. ATMEGA로 CLCD를 제어하는 2편 해보겠습니다.
여기서는 1편에서 올렸던 코드를 사용하기쉽게 수정하고 CGRAM에 대해서 알아보겠습니다

CGRAM이란
사용자가 문자를 만들어서 저장할수있는 장소입니다. 사용자가 문자 8개를 만들어서 저장 가능합니다.

CGRAM Address를 보면 b5~b3가 3비트이므로 문자 8개 저장 가능합니다.
첫번째 CGRAM 주소의 000000부터 시작해서 000111까지 데이터를 한줄씩 저장 가능합니다.
CGRAM의 주소는 DDRAM의 데이터와 대응이 됩니다. 그래서 데이터를 저장하고 사용할때는 0x00부터 0x07까지 사용하면 됩니다.(총8개)
그리고 CGRAM에서 주의할점은 CGRAM Address은 b5~b3가 주소 기준이므로 첫번째 주소는 0x00이고 두번째는 0x01이고 세번째는 0x10입니다. 그래서 shift연산을 하면 쉽게 주소를 정할 수 있습니다

CGRAM 데이터 저장순서
1) 사용할 CGRAM address 주소진입

2) 문자 넣기 (1바이트 8개)

3) 커서 초기화하기

3번과정은 안넣으면 원하는대로 작동을 안해서 넣었습니다
2번과정의 문자넣기는 아래의 사이트를 이용하면 편합니다
https://maxpromer.github.io/LCD-Character-Creator/


소스코드 (4bit제어만 구현했습니다)

#define __DELAY_BACKWARD_COMPATIBLE__
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stdio.h>
 
#define HIGH 1
#define LOW 0
#define LEFT 0
#define RIGHT 1
unsigned char myChar1[] = {0x08,0x14,0x09,0x1D,0x0B,0x01,0x08,0x0F};
unsigned char myChar2[] = {0x01,0x09,0x15,0x15,0x15,0x15,0x09,0x01};
unsigned char myChar3[] = {0x01,0x09,0x15,0x15,0x09,0x01,0x1F,0x01};
unsigned char myChar4[] = {0x00,0x1D,0x11,0x1D,0x11,0x1D,0x01,0x00};
unsigned char myChar5[] = {0x00,0x04,0x04,0x0A,0x11,0x00,0x1F,0x00};
unsigned char myChar6[] = {0x1F,0x10,0x1F,0x10,0x1F,0x04,0x1F,0x00};
unsigned char myChar7[] = {0x01,0x1D,0x05,0x1D,0x11,0x1D,0x01,0x01};
    
/* HIGH : Data, LOW: Instruction*/
void lcd_setRS(unsigned char high_low)
{// PC5
    if(high_low)
    PORTC |= 0x20;
    else
    PORTC &= ~0x20;
    _delay_ms(1);
}
 
/* HIGH : Read, LOW: Write*/
void lcd_setRW(unsigned char high_low)
{ // PC6
    if(high_low)
    PORTC |= 0x40;
    else
    PORTC &= ~0x40;
    _delay_ms(1);
}
 
/* HIGH : Enable LOW : Disable*/
void lcd_setEnable(unsigned char high_low)
{ //PC7
    if(high_low)
    PORTC |= 0x80;
    else
    PORTC &= ~0x80;
    _delay_ms(1);
}
 
void lcd_set_8bit_data(unsigned char data)
{
    lcd_setRS(HIGH);
    _delay_ms(1);
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = data;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
    _delay_ms(1);
}
 
 
void lcd_set_4bit_data(unsigned char data)
{
    lcd_setRS(HIGH);
    _delay_ms(1);
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = data;
    PORTA &= 0xf0;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
 
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = (data<<4);
    PORTA &= 0xf0;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
    _delay_ms(1);
}
 
void lcd_set_8bit_instruction(unsigned char data)
{
    lcd_setRS(LOW);
    _delay_ms(1);
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = data;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
    _delay_ms(1);
}
 
 
void lcd_set_4bit_instruction(unsigned char data)
{
    lcd_setRS(LOW);
    _delay_ms(1);
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = data;
    PORTA &= 0xf0;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
 
    lcd_setEnable(HIGH);
    _delay_us(0.6);
    PORTA = (data<<4);
    PORTA &= 0xf0;
    _delay_ms(1);
    lcd_setEnable(LOW);
    _delay_ms(1);
    PORTA = 0x00;
    _delay_ms(1);
}
 
void lcd_init_4bit(void)
{
    DDRC = 0xff;
    DDRA = 0xff;
    lcd_setRS(LOW);
    lcd_setRW(LOW);
    lcd_setEnable(LOW);
    _delay_ms(1);
    /* 4bit setting */
    lcd_set_8bit_instruction(0x20); // 4bit
    lcd_set_4bit_instruction(0x28); // 2line
    lcd_set_4bit_instruction(0x01); // clear
    lcd_set_4bit_instruction(0x02); // cursor default
    lcd_set_4bit_instruction(0x0c); // display on
}
 
void lcd_data_4bit(char *s)
{
    while(*s)
    {
        if(*s == '\n')
        {
            *s++;
            lcd_set_4bit_instruction(0xC0);
        }
        else
            lcd_set_4bit_data(*s++);
    }
}
 
void lcd_move(int direction, int count, int delay)
{
    int i;
    for(i=1; i<=count ; i++)
    {
        if(direction == RIGHT)
            lcd_set_4bit_instruction(0x1C);
        else if(direction == LEFT)
            lcd_set_4bit_instruction(0x18);
        _delay_ms(delay);
    }
}
 
void lcd_4bit_CGRAM(int add, unsigned char s[])
{
    int i;
    lcd_set_4bit_instruction(0x40 | add<<3);
    for(i=0;i<8;i++)
    {
        lcd_set_4bit_data(s[i]);
    }
    lcd_set_4bit_instruction(0x02);
}
 
void lcd_init_myCGRAM()
{
    lcd_4bit_CGRAM(0,myChar1);
    lcd_4bit_CGRAM(1,myChar2);
    lcd_4bit_CGRAM(2,myChar3);
    lcd_4bit_CGRAM(3,myChar4);
    lcd_4bit_CGRAM(4,myChar5);
    lcd_4bit_CGRAM(5,myChar6);
    lcd_4bit_CGRAM(6,myChar7);
}
int main(void)
{
    int i;
 
    _delay_ms(500);
    lcd_init_4bit();
    lcd_init_myCGRAM();
 
    lcd_set_4bit_data(0);
    lcd_set_4bit_data(0);
    lcd_set_4bit_data(1);
    lcd_set_4bit_data(2);
    lcd_set_4bit_data(' ');
    lcd_set_4bit_data(3);
    lcd_set_4bit_data(4);
    lcd_set_4bit_data(5);
    lcd_set_4bit_data(6);
    
    while(1)
    {
        lcd_move(RIGHT,6,500);
        lcd_move(LEFT,6,500);
    }
}

 

다음에는 LCD를 I2C로 제어하는 모듈이 있어서 ATMEGA128로 LCD를 I2C로 제어하는걸 해보겠습니다
CLCD MCU없이 제어하기 (ADM1602) 1편 => CLCD 기초설명
CLCD MCU없이 제어하기 (ADM1602) 2편 => 여러기능 테스트
CLCD MCU없이 제어하기 (ADM1602) 3편 => DDRAM,CGROM,CGRAM,AC설명
CLCD ATMEGA128로 제어하기 1편
CLCD ATMEGA128로 제어하기 2편
CLCD ATMEGA128로 제어하기 3편(I2C)