닫기

[참고 자료] NTC Thermistor를 이용한 디지털 온도계 제작

  • 등록 2015.01.05 14:01:27
URL복사

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

AVR Studio V4.19
// WinAVR 20050214

#include "main.h"
#include "localmath.h"

#ifdef ADC_BubbleSort_Enable
 #define SWAP(a, b)  { dword t;  t=a;  a=b;  b=t; }

 word BubbleSort(word *p, byte num){
  byte i, j;
  long k=0;
 
  for(i=0; i<_AVERGE_NUMBER_-1; i++) {
   for(j=1; j<_AVERGE_NUMBER_-i; j++) {
    if(p[j-1] > p[j])  SWAP(p[j-1],p[j]);
   }
  }
  for(i=_AVERGE_NUMBER_/3; i < (_AVERGE_NUMBER_/3)*2; i++) k += p[i];
 
  return k/(_AVERGE_NUMBER_/3);
 }
#endif

void Is_Rx(void){
while(g_RxTopCount != g_RxButtomCount){
if(g_RxEnd == 0){
   if(g_RxRingBuffer[g_RxButtomCount] == _STX_)      str  = g_WorkBuf;
   else  if(g_RxRingBuffer[g_RxButtomCount] == _ETX_)   g_RxEnd++;

   *str++   = g_RxRingBuffer[g_RxButtomCount++];
    *str     = 0;
    g_RxButtomCount  %= _BufferLength_;
   }
   else{
    if(g_RxEnd < 3){
     g_RxEnd++;
     *str++         =  g_RxRingBuffer[g_RxButtomCount++];
     *str          =  0;
     g_RxButtomCount %=   _BufferLength_;
    }
   }
  }
 }
}

void Delay_xMs(word i){
 CLEARBIT(TIMSK, TOIE0);       // 타이머0 인터럽트 금지
 g_DelayValue  = i;
  SETBIT(TIMSK, TOIE0);        // 타이머0 인터럽트 허용
  
  if((SREG & 0x80) == 0) sei();    // 인터럽터 활성화가 되어 있지 않다면 강제로 전체 인터럽터 활성화
 
 while(g_DelayValue)
  wdt_reset();
}

void SPI_WriteByte(unsigned char CMD){
 SPDR = CMD;
 while(!(SPSR & (1<}

void Init_SPI_Clock_Devide(byte Devide){
 if(      Devide == 2)  SPSR |= (1< else if(Devide == 4)   SPSR |= (0< else if(Devide == 8)   SPSR |= (1< else if(Devide == 16)  SPSR |= (1< else if(Devide == 32)  SPSR |= (1< else if(Devide == 64)  SPSR |= (1< else if(Devide == 128)  SPSR |= (1< else         SPSR |= (1<}

void Init_SPI(void){
 Init_SPI_Clock_Devide(2);
                                                             
 SPDR  = 0;            // 초기화 
                                                            
 SETBIT(SPCR, MSTR);         // SPI 마스타로 동작
 SETBIT(SPCR, SPE);          // SPI 활성화
 CLEARBIT(SPCR, CPOL);        // SPI 모드 0으로 동작, 클럭 발생 상승 부터
 CLEARBIT(SPCR, CPHA);        // SPI ?
 CLEARBIT(SPCR, DORD);        // MSB를 먼저 출력
                                                             
 #ifdef _Is_Is_SPI_Interrupt__Proc_                          
  SETBIT(SPCR, SPIE);        // SPI 인터럽터 활성화
 #endif
}

 

byte Write_SPI_One_byte(byte i){ 
 while(g_Flag_SPI_TxStatus) wdt_disable();

 SPDR  = i; 
 return SPDR;
}

void Write_SPI_Several_byte(byte length, byte* pSend){
 while(length--)  Write_SPI_One_byte(*pSend++);
}

void Init_ADC(void){
// ADCSRA = 0;        // 2분주
// ADCSRA = 1;        // 2분주
// ADCSRA = 2;        // 4분주
// ADCSRA = 3;        // 8분주
// ADCSRA = 4;        // 16분주
// ADCSRA = 5;        // 32분주
// ADCSRA = 6;        // 64분주
 ADCSRA = 7;        // 128분주
  SETBIT(ADCSRA, ADEN);                  // AD 활성화          

 ADMUX   = 0x02;                    // 입력 AIN2

 #ifdef ADC_ISR_Load
   CLEARBIT(ADMUX, REFS1);   SETBIT(ADMUX, REFS0);    // 기준 전압은 AVcc로 사용
 // SETBIT(ADMUX, REFS1);    SETBIT(ADMUX, REFS0);    // 기준 전압은 내부 2.5V로 사용
 // SETBIT(ADMUX, REFS1);    SETBIT(ADMUX, REFS0);

   SETBIT(ADCSRA, ADIE);                 // AD 변환 인터럽터 작동
   SETBIT(ADCSRA, ADSC);                 // AD 변환 시작       

 #else
   SETBIT(ADCSR, ADFR);                 // AD 자유 변환 시작       
 #endif
 
 SETBIT(MCUCR, SM0);                   // AD Noise Reducation
}

word Read_ADC(void){
 ADCSRA   |= (1 << ADSC);
 while(!(ADCSRA  & (1 << ADIF)));
 return ADC;
}

void Init_USART(unsigned long BaudRate){         
  UBRR0H  = 0;
  UBRR0L  = (byte)((_FCPU_/(16 * BaudRate))-1);

// Enable receiver and transmitter, receiver Interrupt Enable
 UCSR0B  = (1<

// Set frame format: 8data, 1stop bit 
 UCSR0C  = (3<}

void Init_Ext_Int(void){
 SETBIT(EICRB, ISC41);  CLEARBIT(EICRB, ISC40);
 SETBIT(EICRB, ISC51);  CLEARBIT(EICRB, ISC50);
 SETBIT(EICRB, ISC61);  CLEARBIT(EICRB, ISC60);

 SETBIT(EIMSK, INT4);
 SETBIT(EIMSK, INT5);
 SETBIT(EIMSK, INT6);
}

void Init_timer0(void){
 #ifdef _FCPU_16MHz_
  TCNT0    = _Timer0_16M_64Dived_1mSec_;   // 16MHz 클럭 8분주 일때 1mSec 발생
 #else
  TCNT0    = _Timer0_8M_64Dived_1mSec_;   // 8MHz 클럭 8분주 1mSec 발생
 #endif

 SETBIT(TCCR0, CS02);             // 64분주
  SETBIT(TIMSK, TOIE0);              // 타이머0 인터럽트 허용
}                                              
                                               
void Init_timer1(void){              // 카운터로 사용한다
 TCCR1A   = 0;              // 자유증가 카운터 모드
 SETBIT(TCCR1B, CS11);            // 8 분주
 TCNT1    = _TDELAY_;
  SETBIT(TIMSK, TOIE1);              // 타이머1 인터럽트 허용
}

void Init_timer2(void){
 SETBIT(TCCR2, CS20);
 TCNT2  = 0;
  SETBIT(TIMSK, TOIE2);              // 타이머2 인터럽트 허용
}                                              
                                               
void Init_timer3(void){                        
 TCCR3A = 0;                // 자유증가 카운터 모드
 SETBIT(TCCR3B, CS31);            // 8 분주
 TCNT3  = 0xff-50;                         
  SETBIT(ETIMSK, TOIE3);             // 타이머3 인터럽트 허용
}

byte Sum_Char_Return(byte i){
 if(i > 9)  return (i-10) + 'A';
 else    return  i     + '0';
}

byte BCC_Hi_Byte(byte i){
 I  >>= 4;
 
 return Sum_Char_Return(i);
}

byte BCC_Low_Byte(byte i){
 I  &= 0x0f;
 
 return Sum_Char_Return(i);
}

byte SUM_Check(void){
 byte i = 0;
 
 str  = g_WorkBuf;
 while(*str != _ETX_)   i += *str++;
 i   += *str++;

 if(BCC_Hi_Byte(i)  != *str++)  return 1;
 if(BCC_Low_Byte(i) != *str++)  return 2;
  
 return 0;

 

 

 


SIGNAL(SIG_ADC){
 CLEARBIT(ADCSRA, ADIF);            // 인터럽터 플레그 클리어

 #ifdef ADC_Convert_Enable
 
  #ifdef ADC_BubbleSort_Enable
   _g_AdcTempBuffer[_g_AdcTempBufCount++]   =  ADC;
   _g_AdcTempBufCount            %= _AVERGE_NUMBER_;
  #endif

 #endif
 
  SETBIT(ADCSR, ADSC);             // AD 변환 시작 
}

SIGNAL(SIG_OVERFLOW0){
 #ifdef _FCPU_16MHz_
  TCNT0    = _Timer0_16M_64Dived_1mSec_;    // 16MHz 클럭 64분주 일때 1mSec 발생
 #else
  TCNT0    = _Timer0_8M_64Dived_1mSec_;    // 8MHz 클럭 64분주 1mSec 발생
 #endif

 if(g_DelayValue > 0)    g_DelayValue--;
 
 if(g_DelayRun > 0)  g_DelayRun--;
 else{
  g_DelayRun = 500;
  g_Run_Flag = ~g_Run_Flag;
  
  if(g_Run_Flag)  SETBIT(PORTD,  _RUN_);
  else      CLEARBIT(PORTD, _RUN_);
 }
 
#ifdef _Is_KeyPressDisp_test_Proc 
 if(TESTBIT(g_KeyStatus, 0)){
  if(TESTBIT(PINE, 6))  CLEARBIT(g_KeyStatus, 0);
 }
 if(TESTBIT(g_KeyStatus, 1)){
  if(TESTBIT(PINE, 5))  CLEARBIT(g_KeyStatus, 1);
 }
 if(TESTBIT(g_KeyStatus, 2)){
  if(TESTBIT(PINE, 4))  CLEARBIT(g_KeyStatus, 2);
 }
#endif
}

SIGNAL(SIG_OVERFLOW1){
  CLEARBIT(TIMSK, TOIE1);                // 타이머1 인터럽트 금지
 _g_CommanSelect++;
 _g_CommanSelect   %= _FndCommMaxLength_;

 #ifdef _Is_KeyPressDisp_test_Proc 
  PORTA   = _ga_DispBUF[  _g_CommanSelect];
  PORTC   = _ga_FndComConst[_g_CommanSelect];    // FND Com 제어, 1개의 자리만 점등
 #endif
 
 TCNT1    = _TDELAY_;
  SETBIT(TIMSK, TOIE1);                  // 타이머1 인터럽트 허용
}

SIGNAL(SIG_OVERFLOW3){
 TCNT3   = 0xff-100;                // 8MHz / 8 /100 = 20KHz
}

SIGNAL(SIG_USART0_RECV){
 byte  i = UDR0;
 
 g_RxRingBuffer[g_RxTopCount++] = i;            // 수신 링 버퍼
 g_RxTopCount           %= _BufferLength_;
}

SIGNAL(SIG_INTERRUPT4){
 SETBIT(g_KeyStatus, 2);
}

SIGNAL(SIG_INTERRUPT5){
 SETBIT(g_KeyStatus, 1);
}

SIGNAL(SIG_INTERRUPT6){
 SETBIT(g_KeyStatus, 0);
}

void Init_Port(void){
// 1 일때 출력, 0 일때 입력으로 설정 된다 
 DDRA  = 0xff;            // 모두 출력, FND 데이터 출력
 PORTA  = 0xff;            // 소등 데이터 출력

 DDRB    = (1<<_SS_)+(1<<_SCK_)+(1<<_MOSI_)+(1<<_PWM_A_)+(1<<_PWM_B_);
 PORTB  = (1<<_SS_)+(1<<_SCK_)+(1<<_MOSI_)+(1<<_PWM_A_)+(1<<_PWM_B_);

 DDRC    = 0xff;            // 전체출력
 PORTC  = 0xff;            // 세그먼트 공통 단자 끄기

 DDRD = (1<<_Tx1_)+(1<<_START_)+(1<<_CHOICE_)+(1<<_RUN_)+(1<<_BUZZER_)+(1<<_BUZZER_)+(1<<_PowerEnable_);
 PORTD = (1<<_Rx1_)+(1<<_Tx1_)+(1<<_START_)+ (1<<_RUN_)+(1<<_BUZZER_)+(1<<_BUZZER_)+(1<<_PowerEnable_);

 DDRE     =  (1<<_Tx0_)+(1<<_Set_)+(1<<_Up_)+(1<<_Down_)+(1<<_RTS_);
 PORTE  = (1<<_Rx0_)+(1<<_Tx0_)+(1<<_Set_)+(1<<_Up_)+(1<<_Down_)+(1<<_RTS_);

 DDRF    = 0x00;            // 전체입력
 PORTF  = 0x00;
}
void SystemInit(void){
 Init_Port();   
            
 SETBIT(SFIOR, TSM);          // 타이머 클럭 동기화 동작
                                      
  Init_timer0();              // mSec Delay 함수사용
  Init_timer1();              // FND 표시용

 Init_ADC();  

 Init_SPI();
 Init_USART(19200);
 
 Init_Ext_Int();

 CLEARBIT(MCUCSR, WDRF);
 wdt_enable(WDTR_1S);
 
  sei();
}

// 써미스터 부품 번호 : NTCALUGE2C90169
void Temp_Cal(void){
 word   Vo;      // 써미스터와 직렬로 연결 된 분압저항 중간에서 읽은 전압
 double R29 = 9729    // 써미스터와 직렬로 연결 되는 분압저항 값
 double Rt;
 double T, C;

 double Ro = 10000;    // 25도에서 NTC 저항 값
 double To = 298.15;   // 섭씨 25도 = 절대온도 298.15eh = 273.15 + C
 double B  = 3813;    // 물질 상수, 오차율 +- 0.5% 이하

#ifdef ADC_ISR_Load
 Vo = BubbleSort(_g_AdcTempBuffer, _AVERGE_NUMBER_);   // 온도센서 저항 값
#else
 Vo = Read_ADC();
#endif

 Rt      = R29 * ((1023.0/(double)Vo)-1.0);      // 온도센서 저항 측정, 1023 이 5V
 T       = 1.0/((1.0/To)+(1/B)*log((Rt/Ro)));      // B parameter를 이용한 온도 계산 방정식
 C       = T - 273.15; 
 g_temp_float  = C;

 g_temp_float  = g_temp_float;
}

void Float_Str2FND(byte *ps){
 byte i=0, *pd;
 
 pd  = _ga_DispBUF;
 
 while(i < 6){
  if(*ps >= '0' && *ps <= '9')  *pd = _ga_FndFontConst[*ps - '0'];
  else{
   if(*ps == '.'){
    if(i){
     *pd--;
     *pd &= _DIGITE_Dot_;        // 소수점 생성
     i--;
    }
   }
   else{ 
    if(*ps == '-') *pd = _DIGITE_Minus_;   // - 생성
    else    *pd = 0;
   }
  }
  i++;
  *pd++;
  *ps++;
 }
 *pd++ = 0;
}

void Temp_Display(void){
 dtostrf(g_temp_float, 3 ,5, string);
 Float_Str2FND(string);
}

void Task_Temp(void){
 Temp_Cal();
 Temp_Display();
}

void main(void){
 SystemInit();

 Task_Temp();

 while(1){
  Task_Temp();
  Delay_xMs(250);
  wdt_reset();
 }
}

 


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define _FCPU_8MHz_          8000000UL
//#define _FCPU_16MHz_        16000000UL
 #ifdef _FCPU_16MHz_
  #define _FCPU_          _FCPU_16MHz_
 #else   
  #define _FCPU_          _FCPU_8MHz_
 #endif 

#define WDTR_15MS  0
#define WDTR_30MS  1
#define WDTR_60MS  2
#define WDTR_120MS 3
#define WDTR_250MS 4
#define WDTR_500MS 5
#define WDTR_1S   6
#define WDTR_2S   7

#define _Timer0_16M_64Dived_1mSec_  0xff-((_FCPU_/64)/1000)       // 255-((16000000/64)/1000) = 5
#define _Timer0_8M_64Dived_1mSec_    0xff-((_FCPU_/64)/1000)       // 255-((8000000 /64)/1000) = 130

#define ADC_BubbleSort_Enable
#define ADC_Convert_Enable
#define ADC_ISR_Load
                                 
#define byte          unsigned char  
#define word            unsigned int
#define dword int         unsigned long

#define SETBIT(  ADDRESS, BIT) (ADDRESS |=  (1<#define CLEARBIT(ADDRESS, BIT)  (ADDRESS &= ~(1<#define TESTBIT( ADDRESS, BIT)  (ADDRESS &   (1<

typedef union{
  byte      b_Value[2];
  unsigned long W_Value;
}W2b;

W2b ConvWB;

typedef union{
  byte      b_Value[4];
  unsigned long L_Value;
}L4b;
L4b ConvLB;
L4b integ;

typedef union{
  byte      b_Value[8];
  unsigned long L_Value[2];
  double     d_Value;
}D8b;

D8b Double_64bit;

#define _Is_KeyPressDisp_test_Proc

#define _SegA_        0x01
#define _SegB_        0x02
#define _SegC_        0x04
#define _SegD_        0x08
#define _SegE_        0x10
#define _SegF_        0x20
#define _SegG_        0x40
#define _SegDp_        0x80
#define _DIGITE_0_      ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegE_ + _SegF_)
#define _DIGITE_1_      ~(_SegB_ + _SegC_)
#define _DIGITE_2_      ~(_SegA_ + _SegB_ + _SegD_ + _SegE_ + _SegG_)
#define _DIGITE_3_      ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegG_)
#define _DIGITE_4_      ~(_SegB_ + _SegC_ + _SegF_ + _SegG_)
#define _DIGITE_5_      ~(_SegA_ + _SegC_ + _SegD_ + _SegF_ + _SegG_)
#define _DIGITE_6_      ~(_SegA_ + _SegC_ + _SegD_ + _SegE_ + _SegF_ + _SegG_)
#define _DIGITE_7_      ~(_SegA_ + _SegB_ + _SegC_ + _SegF_)
#define _DIGITE_8_      ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegE_ + _SegF_ + _SegG_)
#define _DIGITE_9_      ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegF_ + _SegG_)
#define _SPACE_        ~0

#define _b_          ~(_SegC_ + _SegD_ + _SegE_ + _SegF_ + _SegG_)
#define _a_          ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegE_ + _SegG_)
#define _A_          ~(_SegA_ + _SegB_ + _SegC_ + _SegE_ + _SegF_ + _SegG_)
#define _t_          ~(_SegD_ + _SegE_ + _SegF_ + _SegG_)
#define _E_          ~(_SegA_ + _SegD_ + _SegE_ + _SegF_ + _SegG_)
#define _R_          ~(_SegA_ + _SegB_ + _SegC_ + _SegE_ + _SegF_ + _SegG_)
#define _r_          ~(_SegE_ + _SegG_)
#define _S_          ~(_SegA_ + _SegC_ + _SegD_ + _SegF_ + _SegG_)
#define _y_          ~(_SegB_ + _SegC_ + _SegF_ + _SegG_)

#define _C_          ~(_SegA_ + _SegD_ + _SegE_ + _SegF_)
#define _h_          ~(_SegC_ + _SegE_ + _SegF_ + _SegG_)
#define _g_          ~(_SegA_ + _SegB_ + _SegC_ + _SegD_ + _SegF_ + _SegG_)

#define _DIGITE_Dot_     ~_SegDp_
#define _DIGITE_Minus_    ~_SegG_

#define _TDELAY_        65535-4000

#define _FndCommMaxLength_   6
static  byte _g_CommanSelect   = 0;
   byte _ga_DispBUF[_FndCommMaxLength_ + 1]= {0, };
const  byte _ga_FndFontConst[] = {_DIGITE_0_, _DIGITE_1_, _DIGITE_2_, _DIGITE_3_, _DIGITE_4_,
                                    _DIGITE_5_, _DIGITE_6_, _DIGITE_7_, _DIGITE_8_, _DIGITE_9_, 0 };
const  byte _ga_FndComConst[]  = {~0x08, ~0x10, ~0x20, ~0x01, ~0x02, ~0x04, 0xff, 0};

// PORTA
 #define _Sag_A_       0
 #define _Sag_B_       1
 #define _Sag_C_       2
 #define _Sag_D_       3
 #define _Sag_E_       4
 #define _Sag_F_       5
 #define _Sag_G_       6
 #define _Sag_P_       7
 
// PORTB
 #define _SS_         0
 #define _SCK_         1
 #define _MOSI_       2
 #define _MISO_       3
 #define _PWM_A_       4
 #define _PWM_B_       5
 #define _DSR_         6
 #define _DCD_         7
 
// PORTC
 #define _COM0_       0
 #define _COM1_       1
 #define _COM2_       2
 #define _COM3_       3
 #define _COM4_       4
 #define _COM5_       5
 #define _COM6_       6
 #define _COM7_       7
 
// PORTD
 #define _START_         0
 #define _CHOICE_        1
 #define _Rx1_          2
 #define _Tx1_          3
 #define _RUN_          4
 #define _BUZZER_        5
 #define _PowerEnable_         6
 #define _CTS_          7
 
// PORTE
 #define _Rx0_         0
 #define _Tx0_         1
 #define _Ain0_         2
 #define _Ain1_         3
 #define _Set_         4
 #define _Up_         5
 #define _Down_       6
 #define _RTS_         7
 
// PORTF
 #define _Adc0_       0
 #define _Adc1_       1
 #define _Adc2_       2
 #define _Adc3_       3
 #define _TCK_         4
 #define _TMS_         5
 #define _TDO_        6
 #define _TDI_         7

#define _AVERGE_NUMBER_   6
#ifdef ADC_BubbleSort_Enable
 word  _g_AdcTempBuffer[_AVERGE_NUMBER_+1]   = {0, };
 byte _g_AdcTempBufCount = 0;
#endif

byte g_Run_Flag     = 0;
word g_DelayRun     = 0;
word g_DelayValue        = 0;
word gw_Delay_10uSec     = 0;
                                 
//=========== 232 통신 관련 ===========================================================
#define _NUL_             0x00
#define _BufferLength_   100
#define _STX_              0x02
#define _ETX_      0x03
#define _ACK_      0x06
#define _NAK_      0x15

//=========== SPI 통신 관련 ===========================================================
byte g_Flag_SPI_TxStatus = 0;

byte g_RxRingBuffer[_BufferLength_+1] = {0, };
byte g_WorkBuf[20]   = {0, };
byte g_TxBuf[20]    = {0, };
byte g_RxEnd     = 0;
byte g_RxTopCount   = 0;
byte g_RxButtomCount  = 0;

//=========== 공용  ===========================================================
#define _Err_OpenTempSenser_    1

byte *str;
byte g_KeyStatus    = 0;
byte string[20]    = {0, };
double g_temp_float  = 0;






주요파트너/추천기업