STM32

STM32 I2C

오버헤드프레스 2023. 7. 6. 13:06

04 project를 05로 변환
GPIO Setting
Parameter Setting

i2c_lcd.h

 

/*
 * i2c_lcd.h
 *
 *  Created on: 2019. 9. 4.
 *      Author: k
 */

#ifndef INC_I2C_LCD_H_
#define INC_I2C_LCD_H_

#define I2C_LCD_ADDRESS (0x27<<1)
#define BACKLIGHT_ON 0x08

/* LCD command   */
#define DISPLAY_ON 0x0C
#define DISPLAY_OFF 0x08
#define CLEAR_DISPLAY 0x01  //Delay 2msec
#define RETURN_HOME 0x02

void lcd_command(uint8_t command);
void lcd_data(uint8_t data);
void i2c_lcd_init(void);
void lcd_string(uint8_t *str);
void move_cursor(uint8_t row, uint8_t column);

#endif /* INC_I2C_LCD_H_ */

 

i2c_lcd.c

 

/*
 * i2c_lcd.c
 *
 *  Created on: 2019. 9. 4.
 *      Author: k
 */
#include "main.h"
#include "i2c_lcd.h"  // < >

#include "stm32f4xx_hal.h"
#include <string.h>
#include <stdio.h>

extern I2C_HandleTypeDef hi2c1;
extern UART_HandleTypeDef huart3;

void i2c_lcd_main(void);

void i2c_lcd_main(void)
{

	uint8_t value=0;

 	i2c_lcd_init();


	while(1)
	{
		move_cursor(0,0); //0번째 COLLUM에 Hello World
		lcd_string("Hello World!!!");
		move_cursor(1,0); //1번째 collum에 500ms마다 0 1 2 3...
		lcd_data(value + '0');
		value++;
		if(value>9)value=0;
		HAL_Delay(500);
	}
}

void lcd_command(uint8_t command)
{

	uint8_t high_nibble, low_nibble;
	uint8_t i2c_buffer[4];
	high_nibble = command & 0xf0;
	low_nibble = (command<<4) & 0xf0;
	i2c_buffer[0] = high_nibble | 0x04 | 0x08; //en=1, rs=0, rw=0, backlight=1
	i2c_buffer[1] = high_nibble | 0x00 | 0x08; //en=0, rs=0, rw=0, backlight=1
	i2c_buffer[2] = low_nibble  | 0x04 | 0x08; //en=1, rs=0, rw=0, backlight=1
	i2c_buffer[3] = low_nibble  | 0x00 | 0x08; //en=0, rs=0, rw=0, backlight=1
	while(HAL_I2C_Master_Transmit(&hi2c1, I2C_LCD_ADDRESS,
			i2c_buffer, 4, 100)!=HAL_OK){
		//HAL_Delay(1);
	}
	return;
}

// 1 byte write
void lcd_data(uint8_t data)
{

	uint8_t high_nibble, low_nibble;
	uint8_t i2c_buffer[4];
	high_nibble = data & 0xf0;
	low_nibble = (data<<4) & 0xf0;
	i2c_buffer[0] = high_nibble | 0x05 | 0x08; //en=1, rs=1, rw=0, backlight=1
	i2c_buffer[1] = high_nibble | 0x01 | 0x08; //en=0, rs=1, rw=0, backlight=1
	i2c_buffer[2] = low_nibble  | 0x05 | 0x08; //en=1, rs=1, rw=0, backlight=1
	i2c_buffer[3] = low_nibble  | 0x01 | 0x08; //en=0, rs=1, rw=0, backlight=1
	while(HAL_I2C_Master_Transmit(&hi2c1, I2C_LCD_ADDRESS,
			i2c_buffer, 4, 100)!=HAL_OK){
		//HAL_Delay(1);
	}
	return;
}
// lcd 초기화
void i2c_lcd_init(void)
{

	lcd_command(0x33);
	lcd_command(0x32);
	lcd_command(0x28);	//Function Set 4-bit mode
	lcd_command(DISPLAY_ON);
	lcd_command(0x06);	//Entry mode set
	lcd_command(CLEAR_DISPLAY);
	HAL_Delay(2);
}

// null을 만날때 까지 string을 LCD에 출력
void lcd_string(uint8_t *str)
{
	while(*str)
	{
		lcd_data(*str++);
	}
}

// 해당 줄,col으로 이동 하는 함수
void move_cursor(uint8_t row, uint8_t column)
{
	lcd_command(0x80 | row<<6 | column);
	return;
}

 

main.c

 

i2c_lcd_main 호출

 

i2c_lcd_main test

 

 

 

 

LCD에 시각, 날짜 표시하기

 

internal_rtc.c

 

#include "main.h"   //GPIO & HAL 관련 정보
#include "i2c_lcd.h"

extern void get_rtc_time(void);
void set_rtc(char *date_time);
extern RTC_HandleTypeDef hrtc;

RTC_TimeTypeDef sTime = {0}; //시각정보
RTC_DateTypeDef sDate = {0}; //날짜정보

//ex) 23년 bin로 저장된 format
//7654 3210
//---- ----
//0010 0011
//---- ----
//   2    3
// ==> 23
unsigned char bin2dec(unsigned char byte)
{
	unsigned char high, low;

	low = byte & 0x0f;  //상위 4bit는 무시하고 하위 4bit만 취한다.
	high = (byte >> 4) * 10;

	return high + low;
}
//10진수 --> BCD   ex) 23 : 0001 0111
unsigned char dec2bin(unsigned char byte)
{
	unsigned char high, low;

	high = (byte / 10) << 4;  //상위 4bit에 위치 00000010 --> 00100000
	low = byte % 10; //00000011

	return high + low; //0010 0011
}

//RTC에서 날짜와 시각정보를 가져오는 함수
void get_rtc_time(void)
{
	static RTC_TimeTypeDef oTime; //static 함수가 빠져나가도 이전 값을 유지하게함, 이전 시각정보
	char lcd_buff[40];

	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BCD);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
	if(oTime.Seconds != sTime.Seconds)
	{
		//YYYY-MM-DD HH.mm:ss
		printf("%04d-%02d-%02d %02d:%02d:%02d\n",
				bin2dec(sDate.Year)+2000, bin2dec(sDate.Month), bin2dec(sDate.Date),
				bin2dec(sTime.Hours), bin2dec(sTime.Minutes), bin2dec(sTime.Seconds));//4자리 찍기
		sprintf(lcd_buff,"DATE: %04d-%02d-%02d\n",
				bin2dec(sDate.Year)+2000, bin2dec(sDate.Month), bin2dec(sDate.Date));
		move_cursor(0,0); //0번째 COLLUM에 Hello World
		lcd_string(lcd_buff);

		sprintf(lcd_buff,"TIME: %02d:%02d:%02d\n",
		bin2dec(sTime.Hours), bin2dec(sTime.Minutes), bin2dec(sTime.Seconds));//4자리 찍기
		move_cursor(1,0); //1번째 collum에 500ms마다 0 1 2 3...
		lcd_string(lcd_buff);
	}
	oTime.Seconds = sTime.Seconds;
}
//시각과 날짜를 보정하는 함수
//ex) 230705160400 의 주소가 data_time이라는 변수에 넘어온다.
void set_rtc(char *date_time) //pointer는 메모리 주소를 저장하는 공간, 이유: 서로다른 함수를 access한다.
                              //왜 쓰는가 :정역변수를 쓰면 정역변수, 지역변수를 안써도 메모리를 잡아먹고 있어서
{
	char yy[4], mm[4], dd[4];  //날짜, 2의 배수로 사용
	char hh[4], min[4], ss[4]; //시각 정보

	strncpy(yy, date_time, 2);
	strncpy(mm, &date_time[2], 2); //m[0]:'0', m[1]:'0', m[2]: '\0'
	//strncpy(yy, date_time+2, 2); 위랑 같은 것
	strncpy(dd,date_time+4, 2);

	strncpy(hh, date_time+6, 2);
	strncpy(min, date_time+8, 2);
	strncpy(ss, date_time+10, 2);

	//1. ascii --> int -->bcd
	sDate.Year = dec2bin(atoi(yy));
	sDate.Month = dec2bin(atoi(mm));
	sDate.Date = dec2bin(atoi(dd));

	sTime.Hours = dec2bin(atoi(hh));
	sTime.Minutes = dec2bin(atoi(min));
	sTime.Seconds = dec2bin(atoi(ss));

	HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD);
	HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD);

}

 

main.c

i2c_lcd_init으로 lcd 초기화
i2c_lcd_init 호출

 

 

 

 

\n 제거시 마지막 =모양 사라짐

아스키 코드 0x20 이후로는 화면에 찍히지만

0x20전은 화면에 출력 x

\n은 0x10 LF이기 때문에 화면에 출력되지 않는다.