본문 바로가기
임베디드 개발/STM32 (ARM Cortex-M)

STM32 , IC 74138 디코더 소스코드로 구현하기 ( Nucleo-144용 I/O 호환보드 사용 )

by eteo 2022. 5. 20.

 

결과물

 

 

 

다음과 같이 74138을 3x8디코더로 사용했을 때의 기능을 STM32보드 사용해 소스코드로 구현하기.

 

 

 

 

주의할 것은 디코더의 출력이 Active low라 default가 high고 해당되는 핀만 low신호가 나간다.

 

사용의 편리를 위해 Nucleo-144용 I/O 호환보드를 사용하였다.

 

 

출처 : https://cafe.naver.com/cortexworld/948

 

Nucleo-144용 I/O 보드

대한민국 모임의 시작, 네이버 카페

cafe.naver.com

 

 

 

LED1~LED8 은 PD0~PD7 포트를 사용하고

SW1~SW4 는 PG0~PG3 포트를 사용하고 있다.

 

 

주의할 것은 이미 호환보드에서 사용하려고 reserved 된 포트가 있어서 내가 추가로 빼려면 겹치지 않게 잘 골라야한다. 아쉽게도 호환보드의 data sheet는 구할 수 없었다.

 

 

 

소스코드

  while (1)
  {
	  unsigned char input1;
	  unsigned char input2;
	  unsigned char input3;

	  input1 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8);
	  input2 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9);
	  input3 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_12);

	  if(input1 & !input2 & !input3){
		  ttl74138();
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

 

while문 내에서 enable 신호를 구현한 것인데

G1=PC8

G2A=PC9

G2B=PC12

G1이 HIGH이고 G2A, G2B가 LOW일 때 ttl74138 함수가 실행된다.

 

 

 

위의 코드를 레지스터 제어 버전으로 짧게 만든 것.

  GPIO_PinState G1G2 = (GPIOC->IDR >>8 & 1) & !(GPIOC->IDR >> 9 & 1) & !(GPIOC->IDR >> 12 & 1);
  if(G1G2){
      ttl74138();
  }

내가 켜있는지 꺼있는지 확인하고 싶은 비트를 >> 1의자리로 옮기고 1이랑 & 연산을 하면 확인 가능하다.

 

 

 

ttl74138 함수의 내부

void ttl74138(){
	  unsigned char input[3]={0,};
	  unsigned char num;

	  for(int i=0; i<3; i++){
		  input[i] = (!HAL_GPIO_ReadPin(GPIOG, 0x0008 >> i)) * (0x0001)<<i;
	  }

	  num = input[0]+input[1]+input[2];

	  if(num==0){
		  GPIOD->ODR = 0x7f;
	  }else if(num==1){
		  GPIOD->ODR = 0xbf;
	  }else if(num==2){
		  GPIOD->ODR = 0xdf;
	  }else if(num==3){
		  GPIOD->ODR = 0xef;
	  }else if(num==4){
		  GPIOD->ODR = 0xf7;
	  }else if(num==5){
		  GPIOD->ODR = 0xfb;
	  }else if(num==6){
		  GPIOD->ODR = 0xfd;
	  }else if(num==7){
		  GPIOD->ODR = 0xfe;
	  }

}

 

 

 

 

3x8 디코더라 스위치 PG1-3만 사용하였으며,

 

for문에서는 스위치 PG1-3 상태를 읽어서 1, 2, 4 씩 곱하면서 input 배열에 저장한다.

 

스위치는 풀업이기 때문에 앞에 !을 붙였다

 

 

 

 

GPIO_PIN_번호는 gpio 헤더파일 내에 다음과 같이 16진수로 define 되어있기 때문에

 

0x0008 부터 << i 하면 차례로  PG3, PG2, PG1 이 된다.

 

 

 

 

마지막으로 1을 i만큼 shift해서 1, 2, 4 를 곱해준다.

 

 

그 다음에는 num변수에 다 더해서 저장하고 if else문으로 숫자에 따라 LED를 켠다. 

 

LED를 8개를 한꺼번에 조작하기에 HAL 함수보다 레지스터에 접근하는 방법이 훨씬 쉽다고 느꼈다. 한문장으로 제어가 가능하다.

 

 

예를 들어 내가 PD6번의 LED만 끄고 싶으면

 

GPIOD->ODR = 0xbf

 

으로 제어하면 된다.

 

 

 

 

 

혹은 0~7 값을 가지는 num변수를 그대로 그대로 활용하려면 위와 같은 if else문을 대신해 코드를 짧게 짤 수 있다.

GPIOD->ODR |= ~(1 << (7-num)) & 0x00ff;
GPIOD->ODR &= ~(1 << (7-num));
// 8~15 포트는 안건드리고 원하는 비트만 켜고 끄기