본문 바로가기
임베디드

[오제이 튜브의 임베디드 강의] 27강. 온도센서 검증하기!

by 덤더리덤떰 2025. 2. 5.

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 함수 완료