FND 모듈
7-Segment
FND란 Flexible Numeric Display(가변 숫자 표시기)의 약자로, 흔히 7-Segment라고 부릅니다.
7-Segment 표시 장치는 위와같이 7개의 선분으로 숫자 및 문자를 표현합니다. 또한 소수를 나타내기 위해서 숫자의 오른쪽 아래에 소수점(DP)이 붙는 경우도 있습니다.
7-Segment는 8비트를 사용하여 A~G, DP 위치의 LED를 제어합니다. 위와 같이 각 자리에 매핑되는 비트를 0으로 설정하면 해당 LED가 켜지는 방식입니다.
4-Bits
4Bits FND 모듈은 7-Segment 4개를 사용하여 4자리수를 표현하는 모듈입니다. 각 자리수는 하위 4비트를 사용하여 표현합니다.
GPIO를 이용한 모듈 제어
FND 모듈을 제어하기 위해서는 SCLK, RCLK, DIO 3개의 핀이 사용됩니다.
SCLK와 RCLK을 HIGH로 초기화하고, DIO를 통해 어떤 세그먼트의 LED를 표시할지 송신합니다. 데이터 전송이 완료된 후 SCLK 클럭을 LOW-HIGH로 변환하여 데이터 프레임 전송이 완료되었음을 알립니다.
다음으로 어떤 자리수의 세그먼트를 제어할지 DIO로 전송하고, RCLK를 LOW-HIGH로 변환하여 데이터 프레임 전송이 완료되었음을 알립니다.
SCLK를 사용하여 클럭 동기화하는 부분은 SPI 방식으로 통신이 가능합니다. 하지만 이번에는 SPI가 내부적으로 어떻게 동작하는지 알아보기 위해 GPIO를 사용하여 FND 모듈을 제어합니다. SPI 통신에 대한 자세한 내용은 다음 강의에서 다룹니다.
개발환경
개발도구
구분 | 내용 |
통합 개발 환경 | STM32CubeIDE |
BOM
상품명(링크) | 수량 |
STM32F103 Development Board | 1 |
74HC595D FND 모듈 | 1 |
ST-Link STM32 디버거 (with JTAG 20-pin cable) | 1 |
USB 2.0 A to mini-B 커넥터 | 1 |
소켓 점퍼 케이블 40P (칼라) (M/M) 20cm | 5 |
H/W
H/W 구성도
강의에서는 브레드 보드를 사용하지만, 저는 여러번 테스트를 하다보니 간단하게 직접 연결해서 사용했습니다. 디버깅을 위한 ST-Link는 생략했습니다.
HSI(Human System Interface)
제가 사용한 Nexperia 74HC595D는 강의에서 사용한 Shenzhen Titan Micro Elec의 TM74HC595과 Clock Polarity가 반대입니다. 해당 부분은 다음 글에서 자세히 알아보겠습니다.
S/W
소스 코드
여기서는 핵심 코드만 정리하겠습니다. 전체 코드는 강의를 참고하시기 바랍니다.
void send(uint8_t x)
{
for (int i = 8; i > 0; i--)
{
if (x & 0x80)
{
HAL_GPIO_WritePin(FND_DIO_GPIO_Port, FND_DIO_Pin, HIGH);
}
else
{
HAL_GPIO_WritePin(FND_DIO_GPIO_Port, FND_DIO_Pin, LOW);
}
x <<= 1;
HAL_GPIO_WritePin(FND_SCLK_GPIO_Port, FND_SCLK_Pin, LOW);
HAL_GPIO_WritePin(FND_SCLK_GPIO_Port, FND_SCLK_Pin, HIGH);
}
}
먼저 가장 핵심이 되는 SCLK 신호에 맞춰서 DIO를 통해 데이터를 전송하는 코드입니다.
& 연산을 통해 최상위 비트가 1인 경우 HIGH를, 0인 경우 LOW를 전송하고, 왼쪽으로 비트를 시프트합니다. 즉, 8비트의 숫자를 받으면 왼쪽부터(MSB, Most Significant Bit) 한 비트씩 전송하는 것입니다. 비트를 전송할때마다 SCLK_Pin을 LOW-HIGH로 변환하여 SCLK을 구현합니다.
void send_port(uint8_t x, uint8_t port)
{
send(x);
send(port);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, LOW);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, HIGH);
}
다음으로는 send() 함수를 사용하여 데이터와 포트를 전송하는 코드입니다. 이 때 RCLK을 LOW-HIGH로 변환하여 데이터 프레임 전송이 완료되었음을 알립니다.
void init_fnd()
{
_LED_0F[0] = 0xC0; //0
_LED_0F[1] = 0xF9; //1
_LED_0F[2] = 0xA4; //2
_LED_0F[3] = 0xB0; //3
_LED_0F[4] = 0x99; //4
_LED_0F[5] = 0x92; //5
_LED_0F[6] = 0x82; //6
_LED_0F[7] = 0xF8; //7
_LED_0F[8] = 0x80; //8
_LED_0F[9] = 0x90; //9
_LED_0F[10] = 0x88; //A
// ...
}
void digit4_show(int n, int replay, uint8_t show_zero)
{
int n1, n2, n3, n4;
n1 = (int) n % 10;
n2 = (int) ((n % 100)) / 10;
n3 = (int) ((n % 1000)) / 100;
n4 = (int) ((n % 10000)) / 1000;
for (int i = 0; i <= replay; i++)
{
send_port(_LED_0F[n1], 0b0001);
if (show_zero | n > 9)
{
send_port(_LED_0F[n2], 0b0010);
}
if (show_zero | n > 99)
{
send_port(_LED_0F[n3], 0b0100);
}
if (show_zero | n > 999)
{
send_port(_LED_0F[n4], 0b1000);
}
}
}
실질적으로 사용하게되는 digit4_show() 함수입니다. 최대 4자리수의 숫자를 인자로 받아서 각 자리수를 출력합니다. replay를 사용해서 출력 속도를 조절하고, show_zero를 통해 0을 기본으로 출력할지 선택합니다. 각 자리 숫자 및 문자는 _LED_0F[] 배열에 미리 초기화를 해서 0~9에 대응되는 비트값을 바로 사용할 수 있습니다. 마지막으로 하위 4비트 값(0b0000)을 사용해서 자리수를 지정합니다.
void digit4_temp(int n, int replay)
{
int n1, n2, n3, n4;
n1 = (int) n % 10;
n2 = (int) ((n % 100)) / 10;
n3 = (int) ((n % 1000)) / 100;
n4 = (int) ((n % 10000)) / 1000;
for (int i = 0; i <= replay; i++)
{
send_port(_LED_0F[n1], 0b0001);
send_port(_LED_0F[n2] & 0x7F, 0b0010);
if (n > 99)
{
send_port(_LED_0F[n3], 0b0100);
}
if (n > 999)
{
send_port(_LED_0F[n4], 0b1000);
}
}
}
digit4_show()를 변형한 온도를 표시하는 digit4_temp() 함수입니다. 가장 우측 자리는 소수점을 표현하기 때문에 항상 값을 출력해야합니다. 2번째 자리 또한 항상 값을 출력해야하고, 소수점을 표현하기 위해 DP(0b01111111)를 출력해야합니다.
참고자료
'Embedded' 카테고리의 다른 글
[임베디드] SSD1306 OLED 모듈 제어 - I2C (1) | 2024.09.02 |
---|---|
[임베디드] 74HC595D FND 모듈 제어 - SPI (0) | 2024.08.10 |
[임베디드] FT232RL USB 모듈 제어 - UART (0) | 2024.07.29 |