이번 프로젝트에서는 LCD에 간단한 문장을 띄워보도록 하겠습니다. 사용하려는 LCD는 아래와 같은 특징을 가지고 있습니다.
1602 LCD 디스플레이의 특징
- 디스플레이 크기: 16 문자와 2 줄의 텍스트를 표시할 수 있습니다.
- 간단한 문자 출력: 문자열, 숫자 및 간단한 그래픽을 쉽게 표시할 수 있습니다.
- 백라이트 제어: 대부분의 1602 LCD에는 백라이트가 있어 어두운 환경에서도 데이터를 쉽게 읽을 수 있습니다.
I2C 인터페이스 사용의 장점
- 핀 수 절감: I2C 인터페이스를 사용하면 데이터 전송을 위해 단 두 개의 핀만 사용됩니다(SDA와 SCL). 이는 특히 핀 수가 제한된 소형 MCU에서 매우 유용합니다.
- 네트워크 확장성: 여러 I2C 장치를 동일한 버스에 연결하여 각 장치를 고유한 주소로 제어할 수 있습니다. 이는 다양한 센서나 출력 장치를 추가할 때 유연성을 제공합니다.
STM32와의 통합
- HAL 라이브러리 지원: STM32 HAL(Hardware Abstraction Layer) 라이브러리를 사용하여 I2C 통신을 간편하게 구현할 수 있습니다. 이를 통해 LCD 초기화, 문자 출력, 명령 전송 등을 쉽게 처리할 수 있습니다.
- 포괄적인 개발 환경: STM32CubeMX 같은 툴을 사용하여 프로젝트 초기 설정을 쉽게 구성하고, 코드 생성을 자동화하여 개발 시간을 단축할 수 있습니다.
- 저전력 운영: STM32의 저전력 모드와 결합할 때, LCD의 전력 소모를 최소화하면서 효율적으로 정보를 표시할 수 있습니다.
프로그래밍 및 사용 용이성
- 커스텀 문자 생성: 사용자 정의 문자를 만들어 특별한 기호나 아이콘을 디스플레이할 수 있습니다.
- 다양한 라이브러리 지원: 다양한 오픈 소스 라이브러리와 예제 코드가 인터넷에 많이 있어, 빠르게 시작할 수 있습니다.
STM32의 표준 모드를 사용하여 최대 100 kHz의 클럭 속도로 구성되어 있습니다. I2C 주소 길이는 7-bit이며, 이중 주소 모드는 사용하지 않습니다. 클럭 신호의 스트레칭은 비활성화되어 있지 않아, 슬레이브가 필요시 클럭을 지연시킬 수 있습니다. GPIO 핀 PB8은 I2C의 시리얼 클럭 라인(SCL)으로, PB9는 시리얼 데이터 라인(SDA)으로 설정되어 있어 데이터 통신을 위해 사용됩니다.
/*
* myLib.h
*
* Created on: Jul 19, 2024
* Author: user
*/
#ifndef INC_MYLIB_H_
#define INC_MYLIB_H_
#define MAX_BUF 480
#define LCD1602_ADDR (0x27<<1) //0x4E
typedef struct
{
char *key; //key[6];
int op_no;
} myCMDSET;
typedef union
{
char v0[MAX_BUF];
short v1[MAX_BUF/2];
int v2[MAX_BUF/4];
long v3[MAX_BUF/4];
} myBuffer;
#endif /* INC_MYLIB_H_ */
다양한 데이터 타입을 저장할 수 있는 유니온 myBuffer와 명령어 세트를 위한 구조체 myCMDSET를 정의하고 있습니다. myBuffer 유니온은 최대 480 바이트를 다룰 수 있으며, 다양한 크기의 데이터 배열(char, short, int, long)을 저장할 수 있습니다. LCD1602_ADDR는 I2C 주소를 0x4E로 정의하여 LCD 디스플레이와의 통신에 사용합니다. myCMDSET 구조체는 명령어 키와 연산자 번호를 포함하고 있습니다.
/*
* lcd.c
*
* Created on: Jul 31, 2024
* Author: user
*/
#include "main.h"
#include "myLib.h"
extern I2C_HandleTypeDef hi2c1;
int i2c_scan() // 현재 연결되어 있는 I2C device의 주소를 표시하고 반환
{
int addr,ret;
for(addr=0;addr<128;addr++)
{
if(HAL_I2C_IsDeviceReady(&hi2c1, addr<<1, 1, 10) == HAL_OK)
{
printf(" 0x%02x", addr); ret = addr;
}
else printf(" . ");
if((addr % 8) == 0) printf("\r\n");
HAL_Delay(10);
}
printf("\r\n");
return ret;
}
void lcd_command(char cmd) // cmd : abcd efgh
{
char d1,d2,data[4];
d1 = cmd & 0xf0; // d1 : abcd 0000
d2 = (cmd & 0x0f)<<4; // d2 : 0000 efgh ==> efgh 0000
data[0] = d1 | 0x0c; // 0c : 0000 1100 => write|enable|NC|RS(1/0)
data[1] = d1 | 0x08; // 08 : 0000 1000 => write|disable|NC|RS
data[2] = d2 | 0x0c;
data[3] = d2 | 0x08;
HAL_I2C_Master_Transmit(&hi2c1, LCD1602_ADDR, data, 4, 10);
}
void lcd_data(char ch) // ch : abcd efgh, 단일 문자 전송
{
char d1,d2,data[4];
d1 = ch & 0xf0; // d1 : abcd 0000
d2 = (ch & 0x0f)<<4; // d2 : 0000 efgh ==> efgh 0000
data[0] = d1 | 0x0d;
data[1] = d1 | 0x09;
data[2] = d2 | 0x0d;
data[3] = d2 | 0x09;
HAL_I2C_Master_Transmit(&hi2c1, LCD1602_ADDR, data, 4, 10);
}
void lcd_print(char *s)
{
while(*s) lcd_data(*s++);
}
void lcd_printEx(char *s, int ln)
{
if(ln == 1) lcd_command(0x80);
else if(ln == 2) lcd_command(0xc0);
while(*s) lcd_data(*s++);
}
void lcd_init() // 1602 LCD 초기화 : Disp ON, Cursor Position, etc...
{
lcd_command(0x01); // screen clear
lcd_command(0x02); // cursor 초기 위치
lcd_command(0x06); // 문자 입력 모드 : 좌 -> 우
lcd_command(0x0f); // display mode : Disp On, Curs On, Flash On
}
I2C 통신을 사용하여 STM32에서 1602 LCD 디스플레이를 제어하기 위한 코드를 포함하고 있습니다. i2c_scan 함수는 I2C 버스상에서 연결된 디바이스의 주소를 검색하고 표시합니다. lcd_command와 lcd_data 함수는 LCD 디스플레이에 명령과 데이터를 보내는 데 사용되며, 명령은 데이터를 4바이트 배열로 분할하여 전송합니다. lcd_print 함수는 문자열을 LCD에 출력하고, lcd_printEx는 지정된 줄에 문자열을 출력합니다. 마지막으로, lcd_init 함수는 디스플레이 초기화 과정을 담당하여 화면을 클리어하고 커서를 초기 위치로 설정합니다.
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
ProgramStart("1602 LCD - I2C interface");
i2c_scan();
lcd_init();
lcd_print(" Hello world");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
int ln = 1;
while (1)
{
lcd_command(0x01); HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
lcd_printEx(" Hello world", ln); HAL_Delay(500);
if(++ln > 2) ln = 1;
}
/* USER CODE END 3 */
}
시스템 클록을 설정하고, GPIO, UART, 및 I2C 통신을 초기화 한 후 LCD 스크린을 시작합니다. i2c_scan 함수를 호출하여 I2C 디바이스를 검색하고, lcd_init 함수로 LCD를 초기화합니다. 초기화 후 "Hello world" 메시지를 LCD에 출력하고, 무한 루프 내에서 이 메시지를 번갈아 두 줄에 걸쳐 출력하면서 화면을 깜빡이게 합니다.
'하만 세미콘 아카데미 > Embedded (STM32)' 카테고리의 다른 글
[Embedded] STM32CubeIDE - RTOS (0) | 2024.05.31 |
---|---|
[Embedded] STM32 - Servo Motor (0) | 2024.05.31 |
[Embedded] STM32 - UART DMA (0) | 2024.05.31 |
[Embedded] STM32 - UART Bluetooth (0) | 2024.05.31 |
[Embedded] STM32 - UART (0) | 2024.05.31 |