Language/AVR

ATmega 128 : 4-Digit FND 동작 구현

짱도르딘 2024. 5. 30. 14:35
728x90

이번에는 7 segment가 4개로 구성된 4-Digit FND 동작을 구현해보았다.

 

부품은 3461AS-1을 사용하였고, 부품에 대한 내용은 아래와 같다.

 

3461AS Pin Configuration

 

위 그림을 보아 알 수 있듯이 4-Digit FND는 Common Cathode 방식으로 동작되며 12, 9, 8, 6pin을 Ground에 묶어서 동작을 구현한다. 이전과는 달리, 이번에는 PORT G를 사용하였다. PORT G에는 12, 9, 8, 6번 핀이 연결되어 있으며, 방향설정을 주 목적으로 다룬다.

 

void FND_Display(uint16_t data) // 4자리니까 16비트
{
	static uint8_t position = 0; // Digit position 변수 설정
	uint8_t fndData[]=
	{
		0x3F,
		0x06,
		0x5B,
		0x4F,
		0x66,
		0x6D,
		0x7D,
		0x27,
		0x7F,
		0x67
	};
	
	switch (position)
	{
		case 0:
		// 첫번째 자리 FND 출력하기 위해서 0번핀을 LOW로 놓고 1,2,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<0); // Digit 1을 (1000의 자리를) Low
		FND_SELECT_PORT |= (1<<1) | (1<<2) | (1<<3); // Digit 2, 3, 4 High
		FND_DATA_PORT = fndData[data/1000%10]; // 입력된 데이터의 1000의자리를 구해서 FND에 출력한다.
		break;
		
		case 1:
		// 두번째 자리 FND 출력하기 위해서 1번핀을 LOW로 놓고 0,2,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<1); // Digit 2을 (100의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<2) | (1<<3); // Digit 1, 3, 4 High
		FND_DATA_PORT = fndData[data/100%10]; // 입력된 데이터의 100의자리를 구해서 FND에 출력한다.
		break;
		
		case 2:
		// 세번째 자리 FND 출력하기 위해서 2번핀을 LOW로 놓고 0,1,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<2); // Digit 3을 (10의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<1) | (1<<3); // Digit 1, 2, 4 High
		FND_DATA_PORT = fndData[data/10%10]; // 입력된 데이터의 10의자리를 구해서 FND에 출력한다.	
		break;
		
		case 3:
		// 네번째 자리 FND 출력하기 위해서 3번핀을 LOW로 놓고 0,1,2을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<3); // Digit 4을 (10의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<1) | (1<<2); // Digit 1, 2, 3 High
		FND_DATA_PORT = fndData[data%10]; // 입력된 데이터의 1의자리를 구해서 FND에 출력한다.
		break;			
		
	}
	position++; // 다음 자리로 이동하기 위해 포지션 증가
	position = position % 4; // 4자리 출력 후 다시 첫번째로 돌아가기 위해 4로 나눈 나머지
}


FND_Display 함수는 main 함수 내 while문에서 무한 루프로 동작하며, 입력된 숫자를 4자리 7 segment에 표시를 하는 동작을 수행한다. 코드에서 position이 0이면 case 0의 코드 블록이 실행되어 천의 자리를 표시하고, position이 1이면 case 1의 코드 블록이 실행되어 백의 자리를 표시하는 방식으로 진행된다. 코드를 보면 case 3부터 시작해서 case 0으로 돌아오는 것도 확인할 수 있다.

이는 position 변수의 초기 값이 0으로 설정되어 있고, switch 문에서 case 0부터 case 3까지 비교하는 방식 때문이다.

 

하지만 position++ 연산 후에 position = position % 4;라는 코드가 있는 것을 확인할 수 있다. 이 코드는 position 변수의 값이 4보다 커지면 4로 나눈 나머지를 다시 position에 할당하는 코드이다.
즉, position이 3이 되면 다음에는 position++를 통해 4가 되고, position = position % 4;를 통해 0으로 다시 초기화된다.

따라서 실제 FND 출력에서는 case 3 -> case 0 -> case 1 -> case 2 순으로 진행되고, 다시 case 3으로 돌아오는 순환적인 방식으로 동작하게 된다.
결론적으로, 이 코드는 case 문의 순서와 position 변수의 초기 값, 그리고 position을 초기화하는 연산을 통해 4자리 FND에 숫자를 순차적으로 표시하는 효과를 만들어 낸다.

 

int main()
{
	FND_DATA_DDR = 0xff;
	FND_SELECT_DDR = 0xff;
	FND_SELECT_PORT = 0x00; //초기값 설정
	
	uint16_t count = 0;
	uint32_t timeTick = 0;
	uint32_t prevTime = 0;
	
	while(1)
	{
		FND_Display(count);
		if (timeTick - prevTime > 100)
		{
			prevTime = timeTick;
			count++;
		}
		_delay_ms(1);
		timeTick++;
	}
}

 

이제 메인 함수 부분을 들여다보자.

 

메인함수 부분은 FND에 숫자를 표시하고 100ms마다 카운트를 증가시키는 역할을 한다. 

if(timeTick - prevTime > 100): 코드는 timeTick과 prevTime의 차이가 100보다 큰지 확인하는 것이다. 여기서 timeTick이란, 시스템 클럭의 틱을 나타내는 변수를 의미한다. 시스템 클럭은 일정한 주기로 움직이며, 틱은 그 주기의 한 번의 움직임을 의미한다. prevTime은 이전 틱을 저장하는 변수이다.
즉, timeTick - prevTime은 지난 시간 동안 얼마나 많은 틱이 발생했는지를 나타낸다고 생각하면 된다.

count 변수의 역할은 주로 디스플레이되는 숫자를 제어하는 것이다. FND_Display 함수는 count 변수를 매개변수로 받아 해당 숫자를 7세그먼트 디스플레이에 표시하게 된다. 또한 main 함수의 무한 루프에서는 count 값을 주기적으로 증가시킴으로써 디스플레이되는 숫자가 시간이 지남에 따라 변경되도록 한다.

 

전체 코드는 아래와 같다.

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

#define FND_DATA_DDR	DDRC // 데이터 포트 방향 설정
#define FND_SELECT_DDR	DDRG // Common Cathode 방향 설정
#define FND_DATA_PORT	PORTC
#define FND_SELECT_PORT PORTG // 방향설정

void FND_Display(uint16_t data) // 4자리니까 16비트
{
	static uint8_t position = 0; // Digit position 변수 설정
	uint8_t fndData[]=
	{
		0x3F,
		0x06,
		0x5B,
		0x4F,
		0x66,
		0x6D,
		0x7D,
		0x27,
		0x7F,
		0x67
	};
	
	switch (position)
	{
		case 0:
		// 첫번째 자리 FND 출력하기 위해서 0번핀을 LOW로 놓고 1,2,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<0); // Digit 1을 (1000의 자리를) Low
		FND_SELECT_PORT |= (1<<1) | (1<<2) | (1<<3); // Digit 2, 3, 4 High
		FND_DATA_PORT = fndData[data/1000%10]; // 입력된 데이터의 1000의자리를 구해서 FND에 출력한다.
		break;
		
		case 1:
		// 두번째 자리 FND 출력하기 위해서 1번핀을 LOW로 놓고 0,2,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<1); // Digit 2을 (100의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<2) | (1<<3); // Digit 1, 3, 4 High
		FND_DATA_PORT = fndData[data/100%10]; // 입력된 데이터의 100의자리를 구해서 FND에 출력한다.
		break;
		
		case 2:
		// 세번째 자리 FND 출력하기 위해서 2번핀을 LOW로 놓고 0,1,3을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<2); // Digit 3을 (10의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<1) | (1<<3); // Digit 1, 2, 4 High
		FND_DATA_PORT = fndData[data/10%10]; // 입력된 데이터의 10의자리를 구해서 FND에 출력한다.	
		break;
		
		case 3:
		// 네번째 자리 FND 출력하기 위해서 3번핀을 LOW로 놓고 0,1,2을 HIGH로 한다
		FND_SELECT_PORT &= ~(1<<3); // Digit 4을 (10의 자리를) Low
		FND_SELECT_PORT |= (1<<0) | (1<<1) | (1<<2); // Digit 1, 2, 3 High
		FND_DATA_PORT = fndData[data%10]; // 입력된 데이터의 1의자리를 구해서 FND에 출력한다.
		break;			
		
	}
	position++; // 다음 자리로 이동하기 위해 포지션 증가
	position = position % 4; // 4자리 출력 후 다시 첫번째로 돌아가기 위해 4로 나눈 나머지
}

int main()
{
	FND_DATA_DDR = 0xff;
	FND_SELECT_DDR = 0xff;
	FND_SELECT_PORT = 0x00; //초기값 설정
	
	uint16_t count = 0;
	uint32_t timeTick = 0;
	uint32_t prevTime = 0;
	
	while(1)
	{
		FND_Display(count);
		if (timeTick - prevTime > 100)
		{
			prevTime = timeTick;
			count++;
		}
		_delay_ms(1);
		timeTick++;
	}
}

 

 

 

728x90

'Language > AVR' 카테고리의 다른 글

STM32 : LED  (0) 2024.09.12
ATmega 128 : CLCD, I2C  (0) 2024.09.10
ATmega 128 : FND 동작 구현  (0) 2024.05.29
ATmega 128 : Led Bar 버튼 인터럽트 동작 구현  (0) 2024.05.29
ATmega 128 : Led Bar 버튼 3개 동작 구현  (0) 2024.05.29