BASIC4MCU | 질문게시판 | 답변 : Atmega128 온도센서 활용 재질문입니다
페이지 정보
작성자 master 작성일2022-11-26 13:51 조회579회 댓글0건본문
#define F_CPU 16000000UL // CPU 클록 값=16 MHz
#define F_SCK 40000UL // SCK 클록 값=40 KHz
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//
#define LM75A_ADDR 0x98 // 0b10011000,7비트를 1비트 left shift
#define LM75A_CONFIG_REG 1
#define LM75A_TEMP_REG 0
#define STOP 0 // 체온계 모드
#define GO 1 // 온도계 모드
//
unsigned char digit[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x67};
volatile int temperature=0; // 전역변수(Global Variable)
volatile int stop_temp=0; // 정지 시 온도
volatile int state=GO;
int sw=0;
//
void init_twi_port(){
DDRC=0xff; DDRG=0xff; // FND 출력 세팅
TWSR=TWSR&0xfc; // Prescaler 값=00(1배)
TWBR=(F_CPU/F_SCK-16)/2; // 공식 참조,bit rate 설정
}
//
int read_twi_2byte_nopreset(char reg){
char high_byte,low_byte;
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x08); // START 전송
// START 상태 검사,이후 ACK 및 상태 검사
TWDR=LM75A_ADDR|0; // SLA+W 준비,W=0
TWCR=(1<<TWINT)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x18); // SLA+W 전송
TWDR=reg; // LM75A Reg 값 준비
TWCR=(1<<TWINT)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x28); // LM75A Reg 값 전송
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x10); // RESTART 전송
//RESTART 상태 검사,이후 ACK,NO_ACK 상태 검사
TWDR=LM75A_ADDR|1; // SLA+R 준비,R=1
TWCR=(1<<TWINT)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x40); // SLA+R 전송
TWCR=(1<<TWINT)|(1<<TWEN|1<<TWEA); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x50); // 1st DATA 준비
high_byte=TWDR; // 1st DATA 수신
TWCR=(1<<TWINT)|(1<<TWEN); while(((TWCR &(1<<TWINT))==0x00)||(TWSR&0xf8)!=0x58); // 2nd DATA 준비
low_byte=TWDR; // 2nd DATA 수신
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN); while((TWCR &(1<<TWSTO))); // STOP 확인 // STOP 전송
return((high_byte<<8)| low_byte); // 수신 DATA 리턴
}
//
void display_FND(int value){
char digit[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x67,0x00,0x40 }; //‘0’~‘9’,‘ ’,‘-’
char fnd_sel[4]={0x01,0x02,0x04,0x08};
int value_int,value_deci,num[4],i;
if((value&0x8000)!=0x8000)num[3]=10; // Sign 비트 체크 // 양수인 경우는 디스플레이 없음
else{
num[3]=11; // 음수인 경우는 ‘-’ 디스플레이
value=(~value)+1; // 2’s Complement 값을 취함
}
value_int=(char)((value&0x7f00)>>8); // High Byte bit6~0 값(정수 값)
value_deci=(char)(value&0x0080); // Low Byte bit7 값(소수 첫째자리값)
num[2]=(value_int/10)%10;
num[1]=value_int%10;
num[0]=(value_deci==0x80)?5:0; // 소수 첫째자리가 1이면 0.5에 해당하므로
// 5를 디스플레이
for(i=0;i<4;i++){
PORTC=digit[num[i]]; PORTG=fnd_sel[i];
if(i==1)PORTC|=0x80; // 왼쪽에서 3번째 FND에는 소수점(.)을 찍음
if(i%2)_delay_ms(2); // 2번은 2ms 지연
else _delay_ms(3); // 2번은 3ms 지연,총 10ms 지연
}
}
//
ISR(INT4_vect){
_delay_ms(100); // 스위치 바운스 시간 동안 기다림
EIFR|=1<<4; // 바운스에 의해 생긴 인터럽트는 무효화 - 디바운싱
if((PINE&0x10)!=0x00)return; // SW1이 눌려진 것이 아니면
if(state==STOP)state=GO; // STOP 상태라면 GO 상태로 변경
else{
state=STOP; // GO 상태라면 STOP 상태로 변경
stop_temp=read_twi_2byte_nopreset(LM75A_TEMP_REG); // 그리고,‘현재 온도’를 읽어서 저장
}
}
//
int main(void){
int i;
DDRC=0xff; // C 포트는 FND 데이터 출력 신호
DDRG=0x0f; // G 포트는 FND 선택 출력 신호
DDRE=0xef; // 0b11101111,PE4(SW1)는 입력
EICRB=0x02; // INT4 트리거 모드는 하강 에지(falling edge)
EIMSK=0x10; // INT4 인터럽트 인애이블
SREG|=0x80; // SREG의 I(Interrupt Enalbe)비트(bit7)‘1’로 세트
init_twi_port(); // TWI 및 포트 초기화
while(1){ // 온도값 읽어 FND 디스플레이
for(i=0;i<60;i++){ // 0.6초 동안 처리
if(state==GO){ // 온도계 모드인 경우
if((i==0)||(i==30))temperature=read_twi_2byte_nopreset(LM75A_TEMP_REG); // 억세스시간(300ms)동안 기다리기 // 위하여 30번에 1번 꼴로 실제 억세스
display_FND(temperature); // 한 번 디스플레이에 약 10ms 소요
}
else{ // 체온계 모드인 경우
if(i<30){ temperature=stop_temp; display_FND(temperature); } // 0.3초는 디스플레이
else { PORTG=0x00; _delay_ms(10); } // 0.3초는 디스플레이 끔
}
}
}
}
남에게 보여주지 않더라도 소스코드 정리를 잘 해야지 가독성이 좋아져서수정이나 디버깅이 좀 더 수월해집니다.//프로그램에서 "포인터 지정 2바이트 read"로 구현한 부분을
"포인터지정"과 "포인터 미지정 2바이트 read"의 2단계 로 나누어서 구현하려고 하는데
코드를 어떤식으로 고쳐야 할지 여쭤봅니다!!
무슨 뜻일까요?int read_twi_2byte_nopreset(char reg){이 함수를 말하는 것일까요?레지스터를 지정해서 읽는 부분은 알겠습니다.레지스터 지정하지 않고 읽겠다는 것은 무슨 뜻인가요?전체를 읽고 싶다는 건가요?아니면 안 읽고 싶다는 건가요?미지정 2바이트 리드가 왜 필요한거죠?
댓글 0
조회수 579등록된 댓글이 없습니다.