1. 지난 시간에 했던 Init 소스 다시 분석해보기
- 온도센서 제어 : 처음 초기화 하는 부분인 Ds18b20_Init(); 함수 + 실질적인 온도 가져오는 부분인 Ds18b20_ManualConvert(); 함수로 구성
- Ds18b20_Init(); 함수 : 1-Wire 통신 자체에 대한 부분 + 온도 센서와 통신하는 부분
1-1. Ds18b20_Init(); 함수의 1-Wire 통신 자체에 대한 부분
bool Ds18b20_Init(void) : 온도 센서 초기화
OneWire_Init(&OneWire,_DS18B20_GPIO ,_DS18B20_PIN); // 타이머 시작, GPIO 세팅
OneWire_First(&OneWire); // 0xF0 명령어를 통해 장치 하나 찾기
OneWire_GetFullROM(&OneWire, ds18b20[TempSensorCount-1].Address); // 찾은 장치의 주소 저장
OneWire_Next(&OneWire); // 다음 장치 찾음
DS18B20_SetResolution(&OneWire, ds18b20[i].Address, DS18B20_Resolution_12bits); // 온도센서의 해상도(Resolution) 설정
DS18B20_DisableAlarmTemperature(&OneWire, ds18b20[i].Address); // 온도센서 알람 해지
1-2. Ds18b20_Init(); 함수의 온도 센서와 통신하는 부분( DS18B20_SetResolution(); 와 DS18B20_DisableAlarmTemperature)
2. Ds18b20_ManualConvert(); 함수 분석
- 전처리문 먼저 수행하는데 이때 _DS18B20_USE_FREERTOS가 1이 아니므로 else문이 수행됨
- Ds18b20Timeout=_DS18B20_CONVERT_TIMEOUT_MS/10; 통해 타임아웃 시간 정함
cf. _DS18B20_CONVERT_TIMEOUT_MS는 5000으로 정의되어있음 - DS18B20_StartAll(&OneWire); 수행
- OneWire_Reset(OneWire) 수행 후 OneWire_WriteByte(OneWire, ONEWIRE_CMD_SKIPROM); 통해ONEWIRE_CMD_SKIPROM(= 0xCC)를 씀
* 0xCC는 'Skip ROM: 0xCC'(ROM 명령어) 라는 명령어로 모든 slave 장치에게 동시에 cmd 보낼 때 사용 - 0xCC를 보냈기에 모든 장치에게 명령어를 보냄
- OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP); 통해 DS18B20_CMD_CONVERTTEMP(=0x44)를 씀
* 0x44는 'Convert T: 0x44'(Function 명령어)로 온도 변환 시작함
cf. 'Convert T: 0x44' 명령어
- '온도 정보 구해와' 라는 명령어
- 이때, 신호선으로 전원 공급받는 경우 / 외부 전원일 경우로 나뉨
- 전자 : 이 명령어를 보내고 신호선을 high로 올려서 온도 변환하는 동안 전원 공급해야함
- 후자(우리 case) : 전원이 항상 올라가있으므로 데이터 line을 통해 진행(0) / 완료(1) 응답을 보내줌
- 온도 변환 시간 = 93.75 μs(9비트) ~ 750 μs(12비트) (우리는 12비트 사용)
cf. 명령어 = ROM 명령어 + Function 명령어
=> ROM 명령어 : 1-Wire 통신 지원하는 모든 장치들이 공통적으로 모두 갖고 있는 명령어
=> Function 명령어 : 각각의 장치마다 특수한 기능이 있기에 칩 제조사마다 다른 명령어 갖고 있음
- DS18B20_StartAll(&OneWire); 수행되면서 온도 변환 시작
- !DS18B20_AllDone(&OneWire); 통해 while문 시작
- 아까 OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP); 통해 진행 중인지 아닌지 응답을 받아서 하나의 장치라도 진행 중이면 Low로 떨어지게 됨
cf. 1-wire는 pull up상태이므로 한 장치라도 수행중이라면 당기기에 low가 되고 모든 장치가 맞물려있으므로 전체 버스는 low가 됨 - 이때, 앞에 !가 있으므로 하나의 장치라도 수행 중이라면 Low가 되고 !에 의해 1이 되어 while문이 수행됨
- 최종적으로 500번 루프를 돌고나면 5000ms가 흐르게 되고 while문이 종료
- 이때, Ds18b20Timeout이 안걸렸다면 if문으로 아니라면 else문 수행 (실패)
- while문은 센서가 변환을 완료할 때까지 기다리는 구조인데, 만약 성공적으로 완료했다면 Timeout이 0이 되기전 break문을 빠져나와 0보다 큰 값이라 if-for문이 수행되어 DS18B20_Read 함수 수행 / Timeout이 0이하라면 0일 때 변환이 완료된 것인지, Timeout이 발생한 건지 구분을 할 수 없기에 else문을 통해 false를 저장
- DS18B20_Read();는 주소값을 읽어오고 그 주소값이 올바른 주소인지 chk하여 장치 찾은 칩이 0x28이면 next step으로 / 아니라면 false 반환
* DS18B20의 family code : 0x28이므로 8bit가 0x28포함 - 0x28이라면 if(!OneWire_ReadBit(OneWire))통해 한 번 더 0(진행 중)/1(완료) 확인하여 진행 중이라면 실패 반환
- 아까 if문 통해 한 번 더 chk후 완료됐음을 확인하면 위의 함수들 차례로 수행
- OneWire_SelectWithPointer(OneWire, ROM); 통해 특정 주소 선택
- OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); 통해 '온도 정보 읽겠다'라는 명령어 write
cf. scratchpad : 메모리 같은 공간으로 온도 정보 read - for문을 통해 데이터 9개 읽고 crc 검사 (오류 검사)
- 읽어온 9 byte의 데이터 중 0번지와 1번지의 연산을 통해 온도 정보를 temperature에 저장
- OneWire_Reset(OneWire); 통해 리셋
- temperature & 0x8000 연산 통해 negative 검사
- resolution = ((data[4] & 0x60) >> 5) + 9; 통해 보수 get
- digit = temperature >> 4; 과 digit |= ((temperature >> 8) & 0x7) << 4; 과 switch문 통해 소수점/정수 구간 get(하위 4bit는 소수점구간, 상위 12bit는 정수 구간)
- 구한 소수점과 정수를 더해서 float decimal에 저장
- 만약 minus라면 0 - decimal을 통해 음수로 표현
- 다 구해진 값은 *destination(처음 호출된 인자)에 저장
- 온도가 다 구해지면 true를 반환하며 아래 사진에서의 DS18B20_Read 함수 완료
'임베디드' 카테고리의 다른 글
[오제이 튜브의 임베디드 강의] 29강. 난방실 만들기(온도에 따른 드라이기 제어) (0) | 2025.02.11 |
---|---|
[오제이 튜브의 임베디드 강의] 28강. 드라이기를 내 마음대로 껐다, 켰다 해보자 (0) | 2025.02.05 |
[오제이 튜브의 임베디드 강의] 26강. 다른 사람 소스 분석하는 방법! (0) | 2025.02.05 |
[오제이 튜브의 임베디드 강의] 25강. 어디서도 안 알려주는 프로토콜의 원리! (1) | 2025.01.28 |
[오제이 튜브의 임베디드 강의] 24강. 1-Wire통신! 나름 유명했다. (온도센서) (0) | 2025.01.28 |