BASIC4MCU | 질문게시판 | atmega128과 초음파 센서 SRF02
페이지 정보
작성자 마프하나 작성일2022-11-22 14:48 조회1,175회 댓글3건본문
SRF02의 사용법을 실습해보려고 하는데요. LCD화면에 거리 값이 000cm 로 출력되고 거리 인식이 안되어서 여러 방면으로 찾아 보았지만 잘 모르겠어서 질문 드립니다.
다른 사람들의 코드를 비교해봐도 크게 다른 점은 없다고 생각됩니다. 현재 의심 중인 것은 VCC를 atmega에 연결하여 센서를 사용하기에 출력이 모자란 것이 아닌가 하는 의심입니다.
그 외에는 선 연결이 잘못 된 것은 아닌가 싶지만 SDA는 PD1,SCL은 PD0, Mode은 비워두고, VCC와 GND은 atmega의 해당 칸에 연결하여서 그 문제는 일단 아니라고 생각합니다.
TWI.h
#define F_CPU 14745600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define ExtDev_ERR_MAX_CNT 2000
//TWI Master Teansmitter/Receiver Mode에서의 상태 코드
#define TWI_START 0x08
#define TWI_RESTART 0x10
#define MT_SLA_ACK 0x18
#define MT_DATA_ACK 0x28
#define MR_SLA_ACK 0x40
#define MR_DATA_ACK 0x50
#define MR_DATA_NACK 0x58
// TWI Slave Receiver Mode에서의 상태 코드
#define SR_SLA_ACK 0x60
#define SR_STOP 0xA0
#define SR_DATA_ACK 0x80
#define SR_DATA_NACK 0x58
//TWI Init
void Init_TWI()
{
TWBR = 0x32; //SCL = 100KHz
TWCR = (1<<TWEN); // TWI Enable
TWSR = 0x00; //100Hz
}
void Init_TWI_400K()
{
//FSCK = 14.7456MHZ
//SCL = FSCK / (16 + (2 * 10)) = 409600
TWBR = 0x0A; //SCL = 400KHz
TWCR = (1<<TWEN); // TWI Enable
TWSR = 0x00; //100Hz
}
/***************************************************/
/* 마스터 송신기 모드에서의 송신 관련 함수 */
/***************************************************/
// 신호 전송 완료 검사 및 Status 확인 + Timeout Check
// error code 0 : no error, 1 : timeout error 2 : TWI Status error
unsigned char TWI_TransCheck_ACK(unsigned char Stat)
{
unsigned int ExtDev_ErrCnt = 0;
while (!(TWCR & (1<<TWINT))) // 패킷 전송 완료될 때 까지 wait
{
if(ExtDev_ErrCnt++ > ExtDev_ERR_MAX_CNT){ return 1; }
}
if ((TWSR & 0xf8) != Stat)return 2; // 전송 검사(ACK) : error시 2 반환
else return 0;
}
// START 전송
unsigned char TWI_Start()
{
TWCR = ((1<<TWINT) | (1<<TWSTA) | (1<<TWEN)); // START 신호 보내기
// while (TWCR & (1<<TWINT)) == 0x00); // START 신호 전송 완료될 때 까지 wait
return TWI_TransCheck_ACK(TWI_START);
}
// SLA+W 패킷 전송
unsigned char TWI_Write_SLAW(unsigned char Addr)
{
TWDR = Addr; // SLA + W 패킷(슬레이브 주소+Write bit(Low))
TWCR = (1<<TWINT) | (1<<TWEN); // SLA + W 패킷 보내기
return TWI_TransCheck_ACK(MT_SLA_ACK);
}
// 데이터 패킷 전송
unsigned char TWI_Write_Data(unsigned char Data)
{
TWDR = Data; // 데이터
TWCR = (1<<TWINT) | (1<< TWEN); // 데이터 패킷 송신
return TWI_TransCheck_ACK(MT_DATA_ACK);
}
// STOP 전송
void TWI_Stop()
{
TWCR = ((1<<TWINT) | (1<<TWSTO) | (1<<TWEN)); // STOP 신호 보내기
}
// RESTART 전송
unsigned char TWI_Restart()
{
// unsigned char ret_err=0;
TWCR = ((1<<TWINT) | (1<<TWSTA) | (1<<TWEN)); // Restart 신호 보내기
return TWI_TransCheck_ACK(TWI_RESTART);
}
// Write Packet function for Master
unsigned char TWI_Master_Transmit(unsigned char Data, unsigned char Addr)
{
unsigned char ret_err=0;
ret_err = TWI_Start(); // START 신호 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Write_SLAW(Addr); // 슬레이브 주소 송신
if(ret_err != 0) return ret_err;
ret_err = TWI_Write_Data(Data); // 데이터 송신
if(ret_err != 0) return ret_err;
TWI_Stop(); // STOP 신호 송신
return ret_err; // error 코드 반환
}
/***************************************************/
/* 마스터 수신기 모드에서의 송신 관련 함수 */
/**************************************************/
// SLA+R 패킷 전송
unsigned char TWI_Write_SLAR(unsigned char Addr)
{
// unsigned char ret_err=0;
TWDR = Addr|0x01; // SLA + R 패킷(슬레이브 주소+Read bit(High))
TWCR = (1<<TWINT) | (1<<TWEN); // SLA + R 패킷 보내기
return TWI_TransCheck_ACK(MR_SLA_ACK);
}
// 데이터 패킷 수신
unsigned char TWI_Read_Data(unsigned char* Data)
{
unsigned char ret_err=0;
TWCR = (1<<TWINT)|(1<< TWEN);
ret_err = TWI_TransCheck_ACK(MR_DATA_ACK);
if(ret_err != 0)
return ret_err; // if error, return error code
*Data = TWDR; // no error, return 수신 데이터(포인터로)
return 0; // 정상 종료
}
unsigned char TWI_Read_Data_NACK(unsigned char* Data)
{
unsigned char ret_err=0;
TWCR = (1<<TWINT)|(1<< TWEN); // SLA + W 패킷 보내기
ret_err = TWI_TransCheck_ACK(MR_DATA_NACK);
*Data = TWDR; // no error, return 수신 데이터(포인터로)
return 0; // 정상 종료
}
// Read Packet function for Master
unsigned char TWI_Master_Receive(unsigned char Addr, unsigned char* Data)
{
unsigned char rec_data;
unsigned char ret_err=0;
ret_err = TWI_Start(); // START 신호 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Write_SLAR(Addr); // 슬레이브 주소 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Read_Data(&rec_data); // 데이터수신
if(ret_err != 0) return ret_err; // error시 종료
TWI_Stop(); // STOP 신호 송신
*Data = rec_data;
return 0; // 전상 종
}
/*****************************************************/
/* 슬레이브 수신기 모드에서의 수신 관련 함수 */
/*****************************************************/
// Slave 주소 설정 함수
void Init_TWI_Slaveaddr(unsigned char Slave_Addr)
{
TWAR = Slave_Addr;
}
// SLA 패킷에 대한 ACK 생성 함수
unsigned char TWI_Slave_Match_ACK()
{
// unsigned char ret_err=0;
TWCR = ((1<<TWINT)|(1<<TWEA) |(1<<TWEN));
// ACK 생성 모드 활성화
return TWI_TransCheck_ACK(SR_SLA_ACK);
// 패킷 수신 완료 대기 및 SLA + W 패킷에 대한 ACK 확인
}
// STOP 조건 수신 및 ACK 생성 함수
unsigned char TWI_Slave_Stop_ACK()
{
// unsigned char ret_err=0;
TWCR = ((1<<TWINT)|(1<<TWEA) |(1<<TWEN));
// ACK 생성 모드 활성화
return TWI_TransCheck_ACK(SR_STOP);
// STOP 신호 수신 대기
}
// 데이터 수신 함수
unsigned char TWI_Slave_Read_Data(unsigned char* Data)
// unsigned char* Data : 주소 값 입력
{
unsigned char ret_err=0;
TWCR = ((1<<TWINT)|(1<<TWEA) |(1<<TWEN));
// ACK 생성 모드 활성화
ret_err = TWI_TransCheck_ACK(SR_DATA_ACK);
if(ret_err != 0)
return ret_err; // if error, return error code
*Data = TWDR; // no error, return 수신 데이터
return 0; // 정상 종료
}
// Read Packet function for Slave
unsigned char TWI_Slave_Receive(unsigned char* Data)
{
unsigned char ret_err=0;
unsigned char rec_data;
ret_err = TWI_Slave_Match_ACK();
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Slave_Read_Data(&rec_data);
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Slave_Stop_ACK();
if(ret_err != 0) return ret_err; // error시 종료
*Data = rec_data; // 수신 데이터 반환
return 0; // 정상 종료
}
/*****************************************************************/
/* Master TX/RX Mixed function like EEPROM, Sonar etc */
/*****************************************************************/
unsigned char TWI_Master_Receive_ExDevice(unsigned char devAddr,unsigned char regAddr, unsigned char* Data)
{
unsigned char rec_data;
unsigned char ret_err=0;
ret_err = TWI_Start(); // START 신호 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Write_SLAW(devAddr); // 슬레이브 주소 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Write_Data(regAddr); // 레지스터주소 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Restart(); // Restart 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Write_SLAR(devAddr); // 슬레이브 레지스터 주소 송신
if(ret_err != 0) return ret_err; // error시 종료
ret_err = TWI_Read_Data_NACK(&rec_data); // 레지스터 데이터 수신(주소 전달)
if(ret_err != 0) return ret_err; // error시 종료
TWI_Stop(); // STOP 신호 송신
*Data = rec_data;
return 0;
}
main.c
#define F_CPU 14745600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "TWI.h"
#include "lcd.h"
#define COM_REG 0
#define SRF02_1st_Seq_change 160
#define SRF02_2nd_Seq_change 170
#define SRF02_3rd_Seq_change 165
#define SRF02_Return_inch 80
#define SRF02_Return_Cm 81
#define SRF02_Return_microSecond 82
unsigned char ti_Cnt_1ms;
unsigned char LCD_DelCnt_1ms;
ISR(TIMER0_COMP_vect)
{
ti_Cnt_1ms ++;
LCD_DelCnt_1ms ++;
}
void Timer0_Init() //타이머 기본 설정
{
TCCR0 = (1<<WGM01)|(1<<CS00)|(1<<CS01)|(1<<CS02);
TCNT0 = 0x00;
OCR2 = 14;
TIMSK = (1<<OCIE0);
}
unsigned char SRF02_I2C_Write(char address, char reg, char data)
{
unsigned char ret_err = 0;
ret_err = TWI_Start();
ret_err = TWI_Write_SLAW(address);
if(ret_err !=0) return ret_err;
ret_err = TWI_Write_Data(reg);
if(ret_err != 0) return ret_err;
ret_err = TWI_Write_Data(data);
if(ret_err != 0) return ret_err;
TWI_Stop();
return 0;
}
unsigned char SRF02_I2C_Read(char address, char reg, unsigned char* Data)
{
char read_data = 0;
unsigned char ret_err = 0;
ret_err = TWI_Start();
ret_err = TWI_Write_SLAW(address);
if(ret_err !=0) return ret_err;
ret_err = TWI_Write_Data(reg);
if(ret_err !=0) return ret_err;
ret_err = TWI_Restart();
PORTB|= 0x08;
if(ret_err !=0) return ret_err;
ret_err = TWI_Write_SLAR(address);
PORTB |= 0x10;
if(ret_err !=0) return ret_err;
ret_err = TWI_Read_Data_NACK(&read_data);
PORTB |= 0x20;
if(ret_err !=0) return ret_err;
TWI_Stop();
*Data = read_data;
return 0;
}
unsigned char startRanging(char addr)
{
return SRF02_I2C_Write(addr, COM_REG, SRF02_Return_Cm);
}
unsigned int getRange(char addr, unsigned int*pDistance)
{
unsigned char temp;
unsigned char res = 0;
res = SRF02_I2C_Read(addr,2,&temp);
if(res) return res;
*pDistance = temp << 8;
res = SRF02_I2C_Read(addr,3,&temp);
if(res) return res;
*pDistance |= temp;
return res;
}
unsigned char change_Sonar_Addr(unsigned char ori, unsigned char des)
{
unsigned char res = 0;
switch(des)
{ //초음파센서는 FE까지 주소가 가능
case 0xE0:
case 0xE2:
case 0xE4:
case 0xE6:
case 0xE8:
case 0xEA:
case 0xEC:
case 0xEE:
case 0xF0:
case 0xF2:
case 0xF4:
case 0xF6:
case 0xF8:
case 0xFA:
case 0xFC:
case 0xFE:
res = SRF02_I2C_Write(ori, COM_REG, SRF02_1st_Seq_change);
if(res) return res;
res = SRF02_I2C_Write(ori, COM_REG, SRF02_2nd_Seq_change);
if(res) return res;
res = SRF02_I2C_Write(ori, COM_REG, SRF02_3rd_Seq_change);
if(res) return res;
res = SRF02_I2C_Write(ori,COM_REG,des);
if(res) return res;
break;
default:
return -1;
}
return 0;
}
void main(void)
{
char Sonar_Addr = 0xE0;
unsigned int Sonar_range;
char Message[40];
int readCnt = 0;
unsigned char res = 0;
DDRD |= 0x03;
LCD_Init();
Timer0_Init();
Init_TWI();
_delay_ms(1000);
sei();
startRanging(Sonar_Addr);
ti_Cnt_1ms = 0;
LCD_DelCnt_1ms = 0;
while (1)
{
if(ti_Cnt_1ms > 66){ //66ms이상일 때 동작 // 충분한 시간이 있어야함
res = getRange(Sonar_Addr, &Sonar_range);
/*if(res)
{
LCD_Pos(0,0);
LCD_Str("Measured Dist.= ");
LCD_Pos(1,5);
LCD_Str("ERR ");
}
else if(LCD_DelCnt_1ms > 66)
{
LCD_Pos(0,0);
LCD_Str("Measured Dist.= ");
sprintf(Message, "%01d %03d cm",readCnt,Sonar_range);
LCD_Pos(1,5); //거리는 센티미터 단위로 출력
LCD_Str(Message);
LCD_DelCnt_1ms = 0;
}*/
if(LCD_DelCnt_1ms > 66)
{
LCD_Pos(0,0);
LCD_Str("Measured Dist.= ");
sprintf(Message, "%01d %03d cm",readCnt,Sonar_range);
LCD_Pos(1,0); //거리는 센티미터 단위로 출력
LCD_Str(Message);
LCD_DelCnt_1ms = 0;
}
startRanging(Sonar_Addr);
ti_Cnt_1ms = 0;
readCnt = (readCnt + 1)%10;
}
}
}
댓글 3
조회수 1,175master님의 댓글
master 작성일
https://eduino.kr/product/detail.html?product_no=39&gclid=EAIaIQobChMIkYCFlZHD-wIV15lmAh2B_wKTEAQYASABEgKiQfD_BwE
1100원짜리 4선식 초음파센서를 사용하는 것이 낫지 않나요?
질문의 센서를 사용해야 하는 특별한 이유가 없다면 말이죠
https://cafe.naver.com/circuitsmanual/6156
예제도 쉽게 찾을 수 있습니다.
마프하나님의 댓글
마프하나
일단은 현재 가지고 있는 센서가 SRF02뿐이고, I2C 통신에 대하여 연습을 해보고 싶어서 SRF02 초음파 센서를 사용해보고 싶습니다. 어디 문제있는 부분이 있는지 확인 해 주실 수 있으시다면 감사하겠습니다.
master님의 댓글
master 작성일
통신을 할 때는 오실로스코프 및 로직아날라이저 등의 계측기가 디버깅 할 때 좋습니다.
https://cafe.naver.com/circuitsmanual/12425
강좌글도 참고하세요