저번 포스팅에서는 FND를 작동시키는데 초점을 뒀다면 이번 포스팅에선 FND가 어떤 방식으로 작동하는지를 볼것이다.
(FND_controller.c위주로 볼 것이다.)
void send(uint8_t X){
for (int i = 8; i >= 1; i--) //DIO를 8bit로 나눈다음 펄스 전송
{
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); //CLK만들기
HAL_GPIO_WritePin(FND_SCLK_GPIO_Port, FND_SCLK_Pin, HIGH);
}
}
while(1)
{
send(0xF8);
}
0xF8를 비트로 나타내면 "1111 1000"이고, 그 펄스를 오실로스코프로 확인해봤다.
- 노란색은 SCLK(클럭)이고 파랑색은 DIO(데이터)이다.
- SCLK는 평상시에 HIGH를 유지하다가 LOW에서 HIGH로 올라갈 때 데이터가 전송되는걸 볼 수 있다.
**SPI 통신은 클럭이 서로 일치하지 않아도 어느정도 신호가 간다. 클럭이 서로 일치하지 않은 이유는 클럭을 소프트웨어적으로 보냈기 때문이다. 하드웨어로 보낸다면 일치한다.
while(1)
{
send(0xF8);
send(0b0001);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, LOW);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, HIGH);
HAL_Delay(1000);
}
- 노란색은 SCLK(클럭)이고, 파란색은 DIO(데이터)이다.
- 여기서 중요한건 while문에서 send를 두 번 작성했기 때문에 SCLK이 " 8bit X 2 = 16bit" 된다는 점이다. 첫 번째 8bit는 DIO가 전송될 때 사용되고, 두 번째 8bit는 FND 자릿수를 결정하는데 사용된다.
- DIO는 8bit씩 쪼개서 보내는데, 첫 번째 DIO에서는 0b11111000를 보내고 두 번째 DIO는 0b00000001를 보내는걸 확인할 수 있다.
(그림에서는 FND 세 번째 자리를 출력하고 있다. 다시 오실로스코프를 찍어 수정하자)
RCLK이 LOW에 있다가 HIGH로 올라가는데 무슨 의미를 갖는지는 모르겠다. 아무튼 SCLK, RCLK, DIO의 펄스가 있어서 MCU에서 FND로 데이터가 전송되는 것이다.
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);
}
while(1)
{
send_port(0b11111110, 0b0001);
HAL_Delay(1000);
send_port(0b11111101, 0b0001);
HAL_Delay(1000);
send_port(0b11111011, 0b0001);
HAL_Delay(1000);
send_port(0b11110111, 0b0001);
HAL_Delay(1000);
send_port(0b11101111, 0b0001);
HAL_Delay(1000);
send_port(0b11011111, 0b0001);
HAL_Delay(1000);
send_port(0b10111111, 0b0001);
HAL_Delay(1000);
send_port(0b01111111, 0b0001); // .을 나타내는 방법
HAL_Delay(1000);
}
FND가 풀업 저항으로 연결되있기 때문에 ON이 될려면 0이 되야한다.
ex) 0xF8은 왜 7일까? ---> 0b11111000이고, A/B/C가 켜지게 될 것이다.
void digit4_show(int n, int replay, uint8_t showZero)
{
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); //n이 9보다 작으면 첫번째 자리 on
if(showZero | n>9)send_port(_LED_0F[n2], 0b0010); //n이 9보다 크면 두번째 자리 on
if(showZero | n>99)send_port(_LED_0F[n3], 0b0100); //n이 99보다 크면 세번째 자리 on
if(showZero | n>999)send_port(_LED_0F[n4], 0b1000); //n이 999보다 크면 네번째 자리 on
}
}
//만약 789가 켜진다면 알아서 자릿수에 맞춰 들어갈 것이다. 어디에 출력시킬건지 자릿수만 맞춰주면 됨
void digit4_replay(int n, int replay)
{
digit4_show(n,replay,false); //showzero = false
}
void digit4(int n)
{
digit4_show(n,0,false); //showzero = false
}
void digit4showZero_replay(int n, int replay)
{
digit4_show(n, replay, true); //showzero = true
}
void digit4showZero(int n)
{
digit4_show(n, 0, true); //showzero = true
}
while(1)
{
for(int i = 0; i<=9999; i++)
{
digit4_replay(i, 50); //애초에 digit4_replay는 digit4_show를 포함하고
있고, digit4_show는 false로 정의하고 있다.
}
}
1) int n = int i이므로 i가 789라면 n도 789이다.
n1 = 789 % 10 = 9
n2 = (789 % 100) / 10 = 8
n3 = (789 % 1000) / 100 = 7
n4 = (789 % 10000) / 1000 = 0
2) showzero가 0 or 1일 경우
showzero가 true(1)이라면 0이여도 FND에 불빛이 들어올 것이고,
showzero가 false(0)이라면 FND에 불빛이 들어오지 않을 것이다.
void digit4_temper(int n, int replay, uint8_t showZero)
{
int n1, n2, n3;
n1 = (int) n % 10;
n2 = (int) ((n % 100)-n1)/10;
n3 = (int) ((n % 1000) - n2 - n1) / 100;
for(int i = 0; i<=replay; i++)
{
send_port(_LED_0F[n1], 0b0001);
if(n>9)send_port(_LED_0F[n2] & 0x7F, 0b0010);
if(n>99)send_port(_LED_0F[n3], 0b0100);
}
}
void digit_temper(int n, int replay)
{
digit4_temper(n, replay, true);
}
while(1)
{
for(int i=0; i<=999; i++)
{
digit4_temper(i, 50);
}
}