ATmega128 I2C 1602 텍스트 LCD 코드

2019. 7. 11. 22:29임베디드/ATmega128

이론적인 설명은 https://noel-embedded.tistory.com/621 링크를 참조하기를 바란다

 

결국 우리는 i2c를 이용할 것이고, i2c 연결상 4bit 인터페이스를 사용할 수밖에 없기 때문에 4bit 인터페이스 대로 움직여야 한다. LCD 드라이버인 HD44780 데이터시트를 보면 어떻게 4bit 인터페이스로 진입하는지 자세히 설명이 되어있다

 

 

기다려야 하는 시간과, 명령어를 어떻게 보내야되는지 설명이 되어있다. 간략히 요약하자면 3에 대한 값을 각각 3번씩, 이후에 2에 대한 값을 한 번 보내야 한다. 그리고 설정부분인데 

1. Function Set을 설정

2. display control 설정

3. 화면 clear

4. entry mode 설정

 

그리고 DDRAM 주소를 정하고 데이터를 순차적으로 보내면 된다

 

/*
* clcd.c
*
* Created: 2019-07-06 오후 3:07:03
* Author: user
*/
#include "clcd.h"
#include "uart.h"
#define F_SCL 100000UL // SCL frequency
#define RS1_EN1 0x05
#define RS1_EN0 0x01
#define RS0_EN1 0x04
#define RS0_EN0 0x00
#define BackLight 0x08
uint8_t I2C_addr_PCF8574 = (0x20 << 1);
/*
RS 0
RW 1
E 2
BT 3
*/
void twi_transmit(uint8_t data)
{
while(i2c_transmit(I2C_addr_PCF8574, &data, 1));
}
void i2c_lcd_init(void)
{
i2c_init();
_delay_ms(2000);
i2c_lcd_command_8(0x30); _delay_ms(10);
i2c_lcd_command_8(0x30); _delay_ms(5);
i2c_lcd_command_8(0x30); _delay_us(100);
i2c_lcd_command_8(0x20); _delay_us(100);
printf("Before Initialize... \r\n");
i2c_lcd_command(0x28); _delay_us(50); // function set(4-bit, 2 line, 5x7 dot) i2c_lcd_command(0x0C); _delay_us(50); // display control(display ON, cursor OFF)
i2c_lcd_command(0x08); _delay_us(50); // display control(display ON, cursor OFF)
i2c_lcd_command(0x01); _delay_ms(3); // clear display
i2c_lcd_command(0x06); _delay_us(50); // entry mode set(increment, not shift)
i2c_lcd_command(0x0C); _delay_us(50); // entry mode set(increment, not shift)
printf("Connect Ok\r\n");
}
void i2c_lcd_command_8(uint8_t command)
{
uint8_t c_buf[2];
c_buf[0] = (command&0xF0) | RS0_EN1 | BackLight;
c_buf[1] = (command&0xF0) | RS0_EN0 | BackLight;
twi_transmit(c_buf[0]); _delay_ms(1);
twi_transmit(c_buf[1]); _delay_ms(1);
}
void i2c_lcd_command(uint8_t command)
{
uint8_t c_buf[4];
c_buf[0] = (command &0xF0) | RS0_EN1 | BackLight;
c_buf[1] = (command &0xF0) | RS0_EN0 | BackLight;
c_buf[2] = ((command <<4)&0xF0) | RS0_EN1 | BackLight;
c_buf[3] = ((command <<4)&0xF0) | RS0_EN0 | BackLight;
twi_transmit(c_buf[0]); _delay_ms(1);
twi_transmit(c_buf[1]); _delay_ms(1);
twi_transmit(c_buf[2]); _delay_ms(1);
twi_transmit(c_buf[3]); _delay_ms(1);
}
void i2c_lcd_data(uint8_t data)
{
uint8_t d_buf[4];
d_buf[0] = (data &0xF0) | RS0_EN1 | BackLight;
d_buf[1] = (data &0xF0) | RS0_EN0 | BackLight;
d_buf[2] = ((data <<4)&0xF0) | RS0_EN1 | BackLight;
d_buf[3] = ((data <<4)&0xF0) | RS0_EN0 | BackLight;
twi_transmit(d_buf[0]); _delay_ms(1);
twi_transmit(d_buf[1]); _delay_ms(1);
twi_transmit(d_buf[2]); _delay_ms(1);
twi_transmit(d_buf[3]); _delay_ms(1);
}
void i2c_lcd_goto_XY(uint8_t row, uint8_t col)
{
uint8_t address = (0x40 * row) + col;
uint8_t command = 0x80 | address;
i2c_lcd_command(command);
}
void i2c_lcd_string(uint8_t row, uint8_t col, char *string)
{
i2c_lcd_goto_XY(row, col);
while(*string) {
i2c_lcd_data(*string++);
}
}
view raw noworklcd.c hosted with ❤ by GitHub

============================================================================

[+추가 19.07.11] 다른 방법도 있었다

 

그래서 아두이노 i2cLCD 라이브러리 소스파일을 받아서 ATmega128로 옮기는 작업을 하려고 한다

https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library 아두이노 i2cLCD 라이브러리 소스파일의 주소다

 

그리고 통신에 필요한 twi와 wire 소스파일도 받아야한다

https://github.com/ninjablocks/arduino/tree/master/Wire 

 

먼저 새 프로젝트를 만든 후 다음과 같이 빈 소스파일들을 생성해서 ATmega128 소스에 맞춰서 동작시킬 것이다

 

먼저 소스를 작성하기 위해서 Wire 라이브러리가 무슨 역할을 하는지 알아야 한다

 

https://www.arduino.cc/en/reference/wire

 

Wire 라이브러리는 I2C/TWI를 위한 라이브러리라고 소개되어있다

Cpp 파일이라서, 고치는 데 약간의 지식들이 필요하다

여기서는 위 방법은 사용하지 않고, 직접 코드를 구현해서 동작시켰다

============================================================================

 

깃허브주소

https://github.com/surinoel/avr/tree/master/1602clcd/i2c1602clcd

 

/*
* clcd.c
*
* Created: 2019-07-06 오후 3:07:03
* Author: user
*/
#include "clcd.h"
#include "uart.h"
#define F_SCL 100000UL // SCL frequency
#define RS1_EN1 0x05
#define RS1_EN0 0x01
#define RS0_EN1 0x04
#define RS0_EN0 0x00
#define BackLight 0x08
uint8_t I2C_addr_PCF8574 = (0x27 << 1);
void i2c_lcd_init(void)
{
i2c_init();
_delay_ms(500);
printf("Before Initialize... \r\n");
i2c_lcd_command_8(0x30); _delay_ms(5);
i2c_lcd_command_8(0x30); _delay_us(100);
i2c_lcd_command_8(0x30); _delay_us(100);
i2c_lcd_command_8(0x20); _delay_us(100);
i2c_lcd_command(0x28); _delay_us(50);
i2c_lcd_command(0x08); _delay_us(50);
i2c_lcd_command(0x01); _delay_ms(3);
i2c_lcd_command(0x06); _delay_us(50);
i2c_lcd_command(0x0C); _delay_us(50);
printf("Connect Ok\r\n");
}
void i2c_lcd_command_8(uint8_t command)
{
uint8_t c_buf[2];
c_buf[0] = (command&0xF0) | RS0_EN1 | BackLight;
c_buf[1] = (command&0xF0) | RS0_EN0 | BackLight;
while(i2c_transmit(I2C_addr_PCF8574, c_buf, 2));
}
void i2c_lcd_command(uint8_t command)
{
uint8_t c_buf[4];
c_buf[0] = (command &0xF0) | RS0_EN1 | BackLight;
c_buf[1] = (command &0xF0) | RS0_EN0 | BackLight;
c_buf[2] = ((command <<4)&0xF0) | RS0_EN1 | BackLight;
c_buf[3] = ((command <<4)&0xF0) | RS0_EN0 | BackLight;
while(i2c_transmit(I2C_addr_PCF8574, c_buf, 4));
}
void i2c_lcd_data(uint8_t data)
{
uint8_t d_buf[4];
d_buf[0] = (data &0xF0) | RS1_EN1 | BackLight;
d_buf[1] = (data &0xF0) | RS1_EN0 | BackLight;
d_buf[2] = ((data <<4)&0xF0) | RS1_EN1 | BackLight;
d_buf[3] = ((data <<4)&0xF0) | RS1_EN0 | BackLight;
while(i2c_transmit(I2C_addr_PCF8574, d_buf, 4));
}
void i2c_lcd_goto_XY(uint8_t row, uint8_t col)
{
uint8_t address = (0x40 * row) + col;
uint8_t command = 0x80 | address;
i2c_lcd_command(command);
}
void i2c_lcd_string(uint8_t row, uint8_t col, char *string)
{
i2c_lcd_goto_XY(row, col);
while(*string) {
i2c_lcd_data(*string++);
}
}
view raw i2c1602clcd.c hosted with ❤ by GitHub