0. 문제점과 해결
- 7 세그먼트에 4개의 숫자를 표현할 수 있는 led가 있는데, 동시에 같은 숫자는 표현이 가능하지만 다른 숫자는 x
ex) 8888(ㅇ), 123(x) - 이 문제점을 해결하기 위해 각각의 다른 숫자를 빠르게 껐다키면서 1-2-3-4번째 led가 on-off되는 것을 switching시키면서 우리 눈에는 동시에 다른 숫자들을 볼 수 있도록 구현
- 그럼, 이 숫자를 표현하기 위해 main함수 내의 while(1) 문을 수행해야하는데 숫자만 표현하고 있으면 다른 일은 할 수 없는 상태가 됨
- 따라서, while문에서 작업하지 않도록 타이머를 이용하여 100마이크로세컨드마다 1-2-3-4번째 led의 switching을 하여 숫자 표현을 하도록 한 상태
- 이때, 숫자 표현을 할 때를 제외한 다른 시간에서는 메인 함수의 while문이 돌아가는데 printf("hello world") 수행하도록 함
- 현재는 동시에 7세그먼트에 숫자 표현을 하면서, "hello world"가 출력되도록 코드를 짠 상태
1. 또다른 문제점
- 7세그먼트 표현 영역 + 온도를 가져오는 영역이 있는데 각각 서로 GPIO를 통해 신호를 생성
- main 내 수행하는 온도를 가져오는 영역에서 GPIO신호를 만들다가 갑자기 타이머로 jump해서 7세그먼트 표현 영역에서 신호를 만들어서 보내고 응답을 받고 난 다음 다시 온도를 가져오는 영역으로 넘어가면, 이 영역에서 신호를 만들던 게 중간에 끊기거나 만약 신호를 만들었던 상태라면 바로 응답을 받아야 하는데 delay가 생기는 문제 등 발생
*타이머가 일어나면 언제든지 jump가 가능 - 온도를 가져오는 시퀀스에서는 7세그먼트 표현으로 jump하는 일이 발생하지 않아야한다
- 만약, 건너뛰더라도 온도를 가져오는 영역에서 통신하고 있는 상태라면 7세그먼트 표현 영역에서 GPIO신호를 생성하는 일을 할 수 없도록, 즉 온도를 가져오는 영역에서의 일이 다 끝나고 타이머가 호출되면 7세그먼트 표현 영역에서의 작업 시작하도록 해야한다.
=> 그럼 타이머를 이용해 쓰레드 방식처럼 구현하지 않고 하드웨어적으로 해결이 가능할까? NO
1-1. HW적 해결이 불가능한 이유
: 현재 우리가 가지고 있는 7세그먼트 모듈 = 7세그먼트 자체 부품 + 쉬프트 레지스터
(1) 7 세그먼트
- 사진1처럼 A-G는 숫자 나타내는 한 가닥, DP는 점을 표현
- 이때, 사진에서처럼 맞물려있기 때문에 A에 GPIO 신호 3.3V를 공급하게 되면 4개의 모든 LED의 A가 켜지는 구조
ex) 1111 - 추가로, DIG1/2/3/4 신호가 있는데 만약 1,3번의 LED의 A부분만 키고 싶다면 A(11)에 GPIO 신호 3.3V + DIG1(12) + DIG3(8)에 신호를 공급하면 됨
ex) 1 1 - BUT, 이 7세그먼트 자체는 동시에 한 번만 신호를 보내서 각 LED 1,2,3,4번째에 다른 숫자들을 표현하는 게 불가능
ex) 1342 (x)

(2) 쉬프트 레지스터
: 프로그래밍이 가능한 칩이 아님
: 직렬신호를 병렬 신호로 바꾸는 역할을 해주는 회로도일 뿐.
: 아래 사진과 같이 직렬신호를 병렬신호로 바꿈

- 현재 fnd에 숫자 표현하는 방식이 만약 보낼 데이터가 1000 0000이라면 먼저 1을 보내기에 0x80과 &연산을 하면 1이므로 if문이 수행되어 위 사진에서의 DATA INPUT A에 HIGH(=1)
- 따라서, 사진2처럼 HIGH로 올라간 상태에서 쉬프트클럭을 LOW -> HIGH로 변경되고 이렇게 클럭을 아래로 내렸다가 올리면 DATA INPUT A에 1이 가서 SRA에 저장이됨
- 그 이후의 비트들도 이러한 방식으로 SRA에 있던 1은 아래로 내려가서 SRB로, 그다음 bit 0은 SRA로 순차적으로 저장이 됨
- 그럼 SRA/B/C/D/E/F/G/H에는 0/0/0/0/0/0/0/1이 저장이 되고, 이 상태에서 LATCH CLK을 한 번 내렸다 올리면 이 비트들이 오른쪽으로 그대로 LRA/B/C/D/E/F/G/H에 이동이 되면서 출력이 됨
- 이 8개의 비트들이 모여서 7세그먼트에서의 하나의 숫자를 표현하는 구조


- send_port에서 보면 X는 8비트, port는 4비트임
- 그 뒤에 RCLK은 LATCH CLK으로 한 번 아래로 내려갔다 올라가게 함
- 8비트는 FND 세그먼트 시트에서 봤던 A~G이고, 4비트는 DIG1~4임
- 이때, 7세그먼트에서 4개의 숫자 중 하나의 숫자를 표현하기 위해 8bit로 구성된 하나의 모듈과 몇번째 LED를 킬지 결정하는 4bit로 구성된 하나의 모듈이 합쳐져서 최종적으로 우리가 원하는 위치에 있는 LED의 숫자를 키는 것임
- 참고로, 사진1처럼 LED들이 연결되어 있기에 비트들이 밀려나면 그 밀려난 비트는 옆의 7세그먼트로 이동


2. 소스 코드 짜기
2-1. 목표
- 온도 정보 가져오는 통신 구간 (우선순위 1)
- 온도정보를 가져올땐, 7세그먼트 제어하지 않는다
- 너무 오랫동안 온도정보를 가져오는 시간을 가지면 7세그먼트가 안켜지는 시간이 너무 길다
=> 그래서 온도정보를 가져오는 부분을 분해하고 간추린다 - 분해를 해서, 중간중간에 7세그먼트를 키는 부분이 동작하도록 한다.
2-2. 코드정리
- stm32f1xx_it.c의 TIM3_IRQHandler 함수에서 digit4_temper((int) (getCurrentTemper() * 10)); 주석처리
- 사진1처럼 main함수 주석처리
- 실행하면 사진2처럼 현재 온도 정보 출력되는 거 확인


2-3. 코드 분해
(1) Ds18b20_Init 함수

- 사진1처럼 Init이 아직되지 않았으면 아무것도 간섭하지 않도록 하기 위해 초기에 Init이 됐는지 안됐는지 보기 위해 코드 작성
- Ds18b20_Init 함수에서처럼 OneWire_Init 호출하고, OneWire_First 함수는 주소를 찾는 동작이고 우리는 온도센서를 하나만 사용하기 때문에 아예 주소값을 fix시켜서 OneWire_First 함수 생략하기
- 이때, 찾은 주소는 OneWire.ROM_NO에 저장되므로 사진2처럼 0~7번지까지 일단 다 0x00으로 지정
- OneWire_GetFullROM(&OneWire, ds18b20[TempSensorCount-1].Address) 함수의 역할 : ROM_NO에 저장한 주소값들을 2번째 인자 ds18b20[TempSensorCount-1].Address에 저장
- 이때, ds18b20은 Ds18b20Sensor_t ds18b20[_DS18B20_MAX_SENSORS];로 정의되어있는데 _DS18B20_MAX_SENSORS은 1로 정의되어있음 (즉, 배열의 요소가 최대 1개)
=> 따라서, 사진3처럼 소스코드 작성 후 사진4처럼 인자 수정




- 그다음 OneWireDevices = OneWire_Next(&OneWire); 함수는 장치가 하나밖에 없기 때문에 다음 장치 주소 찾는 동작하는 함수이므로 생략 가능
- 사진1처럼 함수 추가하고, 해당 함수들의 인자 수정
- 사진2처럼 m_init 리턴해주는 함수 추가
- 헤더파일에 함수원형 선언해주기


- 사진1처럼 main함수 내 Ds18b20_ManualConvert();에 breakpoint 걸고 ds18b20의 초기값들 관찰하여 사진2처럼 그대로 값 입력해주기


(2) Ds18b20_ManualConvert함수

- 사진1,2처럼 소스코드 추가
=> 평상시엔 안바쁘지만 어떤 작업을 할 땐 바쁘다는 것을 알리기 위한 소스코드 - StartConverting 함수를 Ds18b20_ManualConvert 함수 위에 옮기기


- 사진1에서의 빨간네모 부분을 단순화하기위해 사진2/3처럼 함수 추가
- 이때, StartConverting() 함수에 DS18B20_StartAll(&OneWire); 다음 라인에 m_isConverting = 1; 추가



- 사진1처럼 원본 소스코드에서 if(Ds18b20Timeout>0)에서의 동작을 분해하여 작성
- 헤더파일에 함수원형 추가해주기
- 사진3처럼 main에 소스코드 작성 후 실행해보기






+ TIM3_IRQHandler 아래 사진과 같이 수정(main함수도)


'임베디드' 카테고리의 다른 글
[오제이 튜브의 임베디드 강의] 34강. I2C로 OLED를 제어해보자. (0) | 2025.02.14 |
---|---|
[오제이 튜브의 임베디드 강의] 33강. 이제는 쉬워진 I2C 통신 (0) | 2025.02.14 |
[오제이 튜브의 임베디드 강의] 30강. 쓰레드 흉내내기! (0) | 2025.02.12 |
[오제이 튜브의 임베디드 강의] 29강. 난방실 만들기(온도에 따른 드라이기 제어) (0) | 2025.02.11 |
[오제이 튜브의 임베디드 강의] 28강. 드라이기를 내 마음대로 껐다, 켰다 해보자 (0) | 2025.02.05 |