반응형

https://youtube.com/live/64BtomW26XQ

[STM32#12] I2C버전의 1602LCD를 STM32f103rb nucleo에 연결해서 디스플레이에 다양한 센서값 출력하는 방법 알아보기!(녹칸다 내맘대로 STM32)

심심한녹칸다의 내맘대로 STM32시리즈이다!

STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g399b448d9bb_1_162#slide=id.g399b448d9bb_1_162

이번편은 1602LCD입니다~!

 

(i2c 설정)

 

(연결도)

 

(LCD사용을 위한 기본 추가 코드)

#define delay_ms HAL_Delay
#define SYS_CLOCK    64
#define SYSTICK_LOAD 63999
uint32_t millis_cnt = 0;
uint32_t millis() {
 return millis_cnt;
}
uint32_t micros() {
 return (millis_cnt & 0x3FFFFF) * 1000 + (SYSTICK_LOAD - SysTick->VAL) / SYS_CLOCK;
}
void delay_us(uint32_t us) {  // 64MHz 보정
 if (us > 1) {
   uint32_t count = us * 7 - 6;
   while (count--);
 } else {
   uint32_t count = 2;
   while (count--);
 }
}
#define ADDRESS   0x27<<1
#define RS1_EN1   0x05
#define RS1_EN0   0x01
#define RS0_EN1   0x04
#define RS0_EN0   0x00
#define BackLight 0x08
// RS-Q0 / RW-Q1 / EN-Q2 / BackLight-Q3 / D4-Q4 / D5-Q5 / D6-Q6 / D7-Q7
void LCD_DATA(uint8_t data) {
 uint8_t temp=(data & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(data & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((data << 4) & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp = ((data << 4) & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD(uint8_t cmd) {
 uint8_t temp=(cmd & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(cmd & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD_4bit(uint8_t cmd) {
 uint8_t temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_INIT(void) {
 delay_ms(100);
 LCD_CMD_4bit(0x03); delay_ms(5);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x02); delay_us(100);
 LCD_CMD(0x28);  // 4 bits, 2 line, 5x8 font
 LCD_CMD(0x08);  // display off, cursor off, blink off
 LCD_CMD(0x01);  // clear display
 delay_ms(3);
 LCD_CMD(0x06);  // cursor movint direction
 LCD_CMD(0x0C);  // display on, cursor off, blink off
}
void LCD_XY(char x, char y) {
 if      (y == 0) LCD_CMD(0x80 + x);
 else if (y == 1) LCD_CMD(0xC0 + x);
 else if (y == 2) LCD_CMD(0x94 + x);
 else if (y == 3) LCD_CMD(0xD4 + x);
}
void LCD_CLEAR(void) {
 LCD_CMD(0x01);
 delay_ms(2);
}
void LCD_PUTS(char *str) {
 while (*str) LCD_DATA(*str++);
}

 

(LCD관련 함수)

LCD_INIT(); //I2C 1602LCD를 초기화한다!

LCD_XY(char x, char y); //LCD에서 입력커서의 위치를 결정한다!

LCD_XY(0, 0); //LCD의 좌측상단 모서리부터 문자를 순서대로 출력하겠다!

LCD_XY(0, 1); //LCD의 좌측하단 모서리부터 문자를 순서대로 출력하겠다!

LCD_CLEAR(); //LCD에 입력되어있는 모든 문자열을 지워버린다!

LCD_PUTS(char *str); //입력된 문자열을 커서의 시작위치부터 해서 순서대로 출력한다!(실제로 화면에 글자가 보인다)


1.STM32프로젝트를 생성하고 IOC에서 I2C통신을 활성화한다음 첫번째줄에는 “NOCKANDA”라고 출력하고 두번째 줄에는 “STM32 TEST!”라고 출력하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 //예제1번에 지정된 문자열을 커서위치를 잡으면서 출력한다!
 LCD_XY(0, 0); LCD_PUTS("NOCKANDA        ");
 LCD_XY(0, 1); LCD_PUTS("STM32 TEST!     ");
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //메인루프는 아무것도 할게 없음!
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


2.STM32에서 1초간격으로 1씩 증가하는 변수가 있다! 이 값을 첫번째 줄에 “CNT = ????”형식으로 출력하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 int cnt = 0;//카운터
 char buff[20]; //가변적인 문자열을 저장할 버퍼
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //cnt변수값을 %d자리에 넣어서 문자열을 생성한다음 buff에 입력한다!
	  sprintf(buff,"CNT = %05d",cnt);
	  //LCD에 buff에 들어있는값을 출력한다!
	  LCD_XY(0, 0); LCD_PUTS(buff);
	  cnt++;
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


3.PB1에 연결된버튼을 누르면 LCD의 첫번째줄에 BTN1 PRESSED!라고 출력되고, PA8에 연결된 버튼을 누르면 BTN2 PRESSED!라고 출력되도록 하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0){
		  LCD_XY(0, 0); LCD_PUTS("BTN1 PRESSED!   ");
		  HAL_Delay(300);
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0){
		  LCD_XY(0, 0); LCD_PUTS("BTN2 PRESSED!   ");
		  HAL_Delay(300);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


4.버튼8개를 모두 이용해서, LCD화면에 아래와 같은 형식으로 출력하시오!(버튼8개의 상태를 2진수로 출력해라!)
    00000000 : 모든 버튼이 안눌려지고있다!
    11110000 : 1~4까지는 눌려지고있고, 5~8까지는 안눌려지고있음!
    10101010 : 홀수번째 버튼만 눌려지고 있는 상태임!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 char buff[20];
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //100밀리초간격으로 버튼1~8까지의 상태를 변수에 저장해서 한번에 출력한다!
	  uint8_t btn1 = !HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
	  uint8_t btn2 = !HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8);
	  uint8_t btn3 = !HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
	  uint8_t btn4 = !HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6);
	  uint8_t btn5 = !HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5);
	  uint8_t btn6 = !HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7);
	  uint8_t btn7 = !HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11);
	  uint8_t btn8 = !HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12);
	  sprintf(buff,"%d%d%d%d%d%d%d%d",btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8);
	  LCD_XY(0, 0); LCD_PUTS(buff);
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


5.쉴드에 붙어있는 로터리엔코더를 시계방향으로 돌리면 값이 1씩 증가하고, 반시계방향으로 돌리면 값이 1씩 감소하도록 해서 두번째 라인에 출력하고 첫번째줄에는 그냥 할게없으니 “NOCKANDA EX5”라고 출력하시오! 그리고 PC7에 연결된 스위치를 누르면 카운터값이 0으로 초기화되도록 하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 char buff[20];
 int cnt = 0;
 uint8_t old_rot_A = 0;
 LCD_XY(0, 0); LCD_PUTS("NOCKANDA! EX5!!!");
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //PA11에 A가 연결되었고 PA12에 B가 연결되었다!
	  //A의 상승엣지가 발생했을때 B의 상태가 HIGH면 CCW, LOW면 CW이다!
	  uint8_t now_rot_A = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11);
	  if(now_rot_A == 1 && old_rot_A == 0){
		  uint8_t now_rot_B = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12);
		  if(now_rot_B){
			  //CCW
			  cnt--;
		  }else{
			  //CW
			  cnt++;
		  }
		  sprintf(buff,"CNT = %05d",cnt);
		  LCD_XY(0, 1); LCD_PUTS(buff);
	  }
	  old_rot_A = now_rot_A;
	  HAL_Delay(10);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0){
		  cnt = 0;
		  sprintf(buff,"CNT = %05d",cnt);
		  LCD_XY(0, 1); LCD_PUTS(buff);
		  HAL_Delay(300);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


6.예제5와 동일하게 작동이 되는데, 증감되는 변수가 실수형이고 값을 0.5씩 증감되도록 하시오! 

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 char buff[20];
 float cnt = 0;
 uint8_t old_rot_A = 0;
 LCD_XY(0, 0); LCD_PUTS("NOCKANDA! EX6!!!");
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //PA11에 A가 연결되었고 PA12에 B가 연결되었다!
	  //A의 상승엣지가 발생했을때 B의 상태가 HIGH면 CCW, LOW면 CW이다!
	  uint8_t now_rot_A = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11);
	  if(now_rot_A == 1 && old_rot_A == 0){
		  uint8_t now_rot_B = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12);
		  if(now_rot_B){
			  //CCW
			  cnt -= 0.5;
		  }else{
			  //CW
			  cnt += 0.5;
		  }
		  //정수부3자리, 실수부1자리
		  //sprintf(buff,"CNT = %3.1f",cnt);
		  sprintf(buff,"CNT = %3d.%1d",(int)cnt,abs(((int)(cnt*10))%10));
		  LCD_XY(0, 1); LCD_PUTS(buff);
	  }
	  old_rot_A = now_rot_A;
	  HAL_Delay(1);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0){
		  cnt = 0;
		  sprintf(buff,"CNT = %3d.%1d",(int)cnt,abs(((int)(cnt*10))%10));
		  LCD_XY(0, 1); LCD_PUTS(buff);
		  HAL_Delay(300);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


7.PA0에 연결된 가변저항값을 측정해서 0~4095 범위로 두번쨰 줄에 값을 출력하고 첫번째 줄에는 적당한 문구를 출력하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 HAL_ADC_Start(&hadc1); //딱 한번만 호출
 uint16_t adc_value0 = 0;
 char buff[20];
 LCD_XY(0, 0); LCD_PUTS("NOCKANDA! EX7!!!");
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //100밀리초 간격으로 가변저항값을 측정해서 출력한다!
	  if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
	  {
		  // 값 처리
		  adc_value0 = HAL_ADC_GetValue(&hadc1); //0~4095
		  sprintf(buff,"ROTARY = %4d",adc_value0);
		  LCD_XY(0, 1); LCD_PUTS(buff);
	  }
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


8.PA0에 연결된 가변저항과 PA1에 연결된 CDS값을 동시에 측정해서 1602LCD의 두번째줄에 전압으로 나란하게 출력하시오!

/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 float a0 = 0;
 float a1 = 0;
 char buff[20];
 LCD_XY(0, 0); LCD_PUTS("NOCKANDA! EX7!!!");
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //PA0 ADC1 RANK1
	  HAL_ADC_Start(&hadc1);
	  HAL_ADC_PollForConversion(&hadc1, 100);
	  a0 = 3.3*HAL_ADC_GetValue(&hadc1)/4095; //0.0~3.3
	  //PA1 ADC1 RANK2
	  HAL_ADC_Start(&hadc1);
	  HAL_ADC_PollForConversion(&hadc1, 100);
     a1 = 3.3*HAL_ADC_GetValue(&hadc1)/4095; //0.0~3.3
	  sprintf(buff,"PA0=%.1f,PA1=%.1f",a0,a1);
	  LCD_XY(0, 1); LCD_PUTS(buff);
	  HAL_Delay(100);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
반응형
Posted by 덕력킹
,