본문 바로가기
하만 세미콘 아카데미/Embedded (STM32)

[Embedded] STM32 - 1602LCD-I2C

by smileww 2024. 5. 31.

이번 프로젝트에서는 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