1. 오늘의 목표
: 버튼을 누를 때마다 FND 세그먼트의 숫자가 계속 증가하도록 출력하기
1-1. 세그먼트의 Pin 보는 방법
- VCC : VCC와 GND가 연결되어야 FND LED가 켜질 것
- SCLK : 이 클럭을 기준으로 DO로 데이터가 들어와서 FND모듈이 이 데이터를 2진수로 변환하여 읽어서 숫자를 FND에 출력하게 됨
- DO(Data Output) : FND가 어떤 정보를 보냄
*DI(Data Input) : FND 모듈이 정보를 받음
=> 이때 FND 세그먼트의 특징은 내가 원하는 숫자나 데이터를 보여주는 모듈이기에 데이터를 보낼 일은 없음
1-2. FND
- 7세그먼트의 다른 이름
- 메인칩 + 메인칩을 사용하는데 필요한 최소한의 회로 = 모듈 (=쪽보드)
- 뒷면에 칩 2개가 존재
=> 메인칩(TM74HC595) + 7세그먼트 합친 모듈 = FND
1-3. 7 세그먼트의 구성
- 이 모든 부분부분이 LED이므로 총 소수점 표시(.)까지 8개의 LED 존재
=> 이때 소수점은 제외해서 총 7개이므로 7 세그먼트라고 부름 - 만약 이 LED 키기 위해 3.3V가 필요하다면 원하는 부분에 3.3V 공급하면 그 부분에만 불이 들어오게됨
- 메인칩 없이 LED를 제어하고 싶다면 GPIO를 이용해서 제어방법도 존재
- 원래는 메인 칩(STM32)와 FND의 LED 부분부분을 직접 연결해야함
- 이때, 너무 많아지기에 중간에 LCD 드라이버를 이용해서 LCD드라이버와 FND 모듈에 LED 8개 연결
- 최종적으로 STM32와 LCD 드라이버가 통신하여 FND 제어
* LCD 드라이버 : TM74HC595
1-4. TM74HC595의 특징
- QA~QH까지 8개 존재
- STM32 - TM74HC595 - FND에서 TM-FND 사이의 다리들이 QA~QH임
- 연결 구성을 보는 방법은 모듈 데이터 시트 OR 테스터기로 쇼트테스트 OR 남이 정리해놓은 것 OR 샘플 코드 구해서 일단 동작시키고 그다음에 추리
2. FND 본격적인 제어
2-1. SPI통신
- SPI에는 CLK(클럭), DI(데이터), CS가 존재하는데 이때 CS 없는 경우 존재
=> 내가 데이터를 보내고 싶다면 CLK 주기에 맞춰서 데이터 전송
2-2. 회로도 구성하기
- 수컷-암컷 빨강/검정 점퍼선 이용해 각각 빵판의 +,-와 FND의 VCC와 GND에 연결
- 암컷-암컷 점퍼선 이용해서 SCLK-PB15/ RCLK-PB13/ DIO-PB14 연결
2-3. PB15/14/13 설정
- STM32 칩 자체에서 SPI 통신 지원
=> DMA 이용 가능 (메모리에서 데이터 바로 읽어오는 기능) - 우리는 GPIO 3개를 통해 우리가 직접 클럭을 만들고, 데이터 읽어오는 것 / 쓰는 것 모두 직접 작성하기
- PB13/14/15 : GPIO Output으로 설정
2-4. 샘플 코드 수행해보기
- fnd_controller.c와 fnd_controller.h 헤더파일 생성해서 샘플코드 작성
- 핀과 그룹들이 main.h에 정의되어있기에 헤더파일에 #include "main.h" 해줄 것
(1) 첫번째 send 함수
- 데이터가 오면 X & 0x80 연산 수행
<=> X & 1000 0000 == 1이면 HIGH 쓰고 아니면 LOW로 씀
<=> 우리가 원하는 데이터 X를 8bit로 넣어서 0x80과 & 연산 후 if~else문 수행 후 해당 X를 왼쪽으로 1칸 shift연산 - 결국, 내가 보내는 8bit 데이터 1bit마다 &연산해서 HIGH 와 LOW결정
ex) 1010 0011 보내면 & 연산과 << 1 연산으로 인해 결론적으로 H L H L L L H H 로 결정 - 맨 아래 두 줄 코드는 클럭 생성
=> LOW -> HIGH로 내리고 올리면서 하나의 클럭을 생성해주기에 if~else문으로 DIO를 HIGH/LOW 중 하나 쓴 상태에서 클럭이 생성되므로 해당 DIO의 HIGH 또는 LOW값을 써주게 됨 - 이때, for문이 모두 끝나고 나면 HIGH에서 끝나기에 기본적으로 데이터를 안보낼 때는 HIGH 상태임을 알 수 있음
(2) 2번째 send 함수
- 평상시엔 LOW로 있다가 HIGH로 감
- 상승 엣지에서 데이터를 내보내고 하강 엣지에선 데이터 hold
(3) 나머지 함수들
↓
(4) 선언부
(5) true, false 정의
(6) 최종 코드
#include "fnd_controller.h"
#define HIGH 1
#define LOW 0
#define false 0
#define true 1
uint8_t _LED_0F[29];
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
_LED_0F[11] = 0x83; //b
_LED_0F[12] = 0xC6; //C
_LED_0F[13] = 0xA1; //d
_LED_0F[14] = 0x86; //E
_LED_0F[15] = 0x8E; //F
_LED_0F[16] = 0xC2; //G
_LED_0F[17] = 0x89; //H
_LED_0F[18] = 0xF9; //I
_LED_0F[19] = 0xF1; //J
_LED_0F[20] = 0xC3; //L
_LED_0F[21] = 0xA9; //n
_LED_0F[22] = 0xC0; //O
_LED_0F[23] = 0x8C; //P
_LED_0F[24] = 0x98; //q
_LED_0F[25] = 0x92; //S
_LED_0F[26] = 0xC1; //U
_LED_0F[27] = 0x91; //Y
_LED_0F[28] = 0xFE; //hight -
}
void send(uint8_t X){
for (int i = 8; i >= 1; 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);
}
}
void send_port(uint8_t X, uint8_t port)
{
send(X);
send(port);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, HIGH);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, LOW);
}
void digit4_show(int n, int replay, uint8_t showZero)
{
int n1, n2, n3, n4;
n1 = (int) n % 10;
n2 = (int) ((n % 100)-n1)/10;
n3 = (int) ((n % 1000) - n2 - n1) / 100;
n4 = (int) ((n % 10000) - n3 - n2 - n1) / 1000;
for(int i = 0; i<=replay; i++){
send_port(_LED_0F[n1], 0b0001);
if(showZero | n>9)send_port(_LED_0F[n2], 0b0010);
if(showZero | n>99)send_port(_LED_0F[n3], 0b0100);
if(showZero | n>999)send_port(_LED_0F[n4], 0b1000);
}
}
void digit4_replay(int n, int replay)
{
digit4_show(n,replay,false);
}
void digit4(int n)
{
digit4_show(n,0,false);
}
void digit4showZero_replay(int n, int replay)
{
digit4_show(n, replay, true);
}
void digit4showZero(int n)
{
digit4_show(n, 0, true);
}
void digit2(int n, int port, int replay)
{
int n1, n2;
n1 = (int) n % 10;
n2 = (int) ((n % 100)-n1)/10;
for(int i = 0; i<=replay; i++){
send_port(_LED_0F[n1], port);
send_port(_LED_0F[n2], port<<1);
}
}
void digit2_port(int n, int port)
{
digit2(n, port, 0);
}
(7) find_controller.c 의 모든 소스코드를 find_controller.h에 추가하여 함수의 헤더부분만 정의
(8) 최종 소스코드와 헤더파일
: 위의 사진들 중에서 오류가 있기에 아래 코드만 참조
#include "fnd_controller.h"
uint8_t _LED_0F[29];
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
_LED_0F[11] = 0x83; //b
_LED_0F[12] = 0xC6; //C
_LED_0F[13] = 0xA1; //d
_LED_0F[14] = 0x86; //E
_LED_0F[15] = 0x8E; //F
_LED_0F[16] = 0xC2; //G
_LED_0F[17] = 0x89; //H
_LED_0F[18] = 0xF9; //I
_LED_0F[19] = 0xF1; //J
_LED_0F[20] = 0xC3; //L
_LED_0F[21] = 0xA9; //n
_LED_0F[22] = 0xC0; //O
_LED_0F[23] = 0x8C; //P
_LED_0F[24] = 0x98; //q
_LED_0F[25] = 0x92; //S
_LED_0F[26] = 0xC1; //U
_LED_0F[27] = 0x91; //Y
_LED_0F[28] = 0xFE; //hight -
}
void send(uint8_t X){
for (int i = 8; i >= 1; 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);
}
}
void send_port(uint8_t X, uint8_t port)
{
send(X);
send(port);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, HIGH);
HAL_GPIO_WritePin(FND_RCLK_GPIO_Port, FND_RCLK_Pin, LOW);
}
void digit4_show(int n, int replay, uint8_t showZero)
{
int n1, n2, n3, n4;
n1 = (int) n % 10;
n2 = (int) ((n % 100)-n1)/10;
n3 = (int) ((n % 1000) - n2 - n1) / 100;
n4 = (int) ((n % 10000) - n3 - n2 - n1) / 1000;
for(int i = 0; i<=replay; i++){
send_port(_LED_0F[n1], 0b0001);
if(showZero | n>9)send_port(_LED_0F[n2], 0b0010);
if(showZero | n>99)send_port(_LED_0F[n3], 0b0100);
if(showZero | n>999)send_port(_LED_0F[n4], 0b1000);
}
}
void digit4_replay(int n, int replay)
{
digit4_show(n,replay,false);
}
void digit4(int n)
{
digit4_show(n,0,false);
}
void digit4showZero_replay(int n, int replay)
{
digit4_show(n, replay, true);
}
void digit4showZero(int n)
{
digit4_show(n, 0, true);
}
void digit2(int n, int port, int replay)
{
int n1, n2;
n1 = (int) n % 10;
n2 = (int) ((n % 100)-n1)/10;
for(int i = 0; i<=replay; i++){
send_port(_LED_0F[n1], port);
send_port(_LED_0F[n2], port<<1);
}
}
void digit2_port(int n, int port)
{
digit2(n, port, 0);
}
/*
* fnd_controller.h
*
* Created on: Jan 24, 2025
* Author: mj492
*/
#ifndef SRC_FND_CONTROLLER_H_
#define SRC_FND_CONTROLLER_H_
#include "main.h"
#define HIGH 1
#define LOW 0
#define false 0
#define true 1
void init_fnd();
void send(uint8_t X);
void send_port(uint8_t X, uint8_t port);
void digit4_show(int n, int replay, uint8_t showZero);
void digit4_replay(int n, int replay);
void digit4(int n);
void digit4showZero_replay(int n, int replay);
void digit4showZero(int n);
void digit2(int n, int port, int replay);
void digit2_port(int n, int port);
#endif /* SRC_FND_CONTROLLER_H_ */
(9) main 함수에서 실제 실행해보기
- main.c에 #include "fnd_controller.h"
- main 함수에 init_fnd(); 함수 실행
- while문 내에 99까지 숫자 증가하는 코드 작성
+ 다른 작업도 수행해보기
EX1. 9999까지 출력
EX2. A 출력해보기
'임베디드' 카테고리의 다른 글
[오제이 튜브의 임베디드 강의] 21강. FND 제어 소스 분석! (0) | 2025.01.25 |
---|---|
[오제이 튜브의 임베디드 강의] 20강. SPI통신 제대로 배워보자! (0) | 2025.01.25 |
[오제이 튜브의 임베디드 강의] 18강. 내 힘으로 스위치 회로 만들기 (0) | 2025.01.24 |
[오제이 튜브의 임베디드 강의] 17강. 내 힘으로 LED회로 만들어서 제어하기! (0) | 2025.01.24 |
[오제이 튜브의 임베디드 강의] 16강. printf()도 쉽지 않다구!! (1) | 2025.01.23 |