02_센서구동함수_SRF02
프로젝트/스마트독서실 시스템

02_센서구동함수_SRF02

728x90

이전에 구성도를 이런식으로 구현할꺼라 글을 쓴적이 있는데, 실제로 구현을하기 위해서는 우선 각 센서들의 구동함수를 알아야합니다. 제일 핵심센서이고 가장 기능을 구현하기 까다로운 SRF02센서에 대해 적어보겠습니다.

 

 

1. 센서개요

이하 내용은 모두 SRF02 데이터시트를 참조하였습니다. I2C Mode만 다뤘습니다.

 

SRF02는 작은 설치 면적 PCB의 단일 변환기 초음파 거리 측정기입니다. I2C 및 직렬 인터페이스를 모두 제공합니다. 직렬 인터페이스는 9600 보드, 1 시작, 2 정지 및 패리티 비트가 없는 표준 TTL 레벨 UART 형식이며 모든 마이크로컨트롤러의 직렬 포트에 직접 연결할 수 있습니다. 최대 16개의 SRF02를 단일 버스(I2C 또는 직렬)에 함께 연결할 수 있습니다. SRF02의 새로운 명령에는 수신 주기 없이 자체적으로 초음파 버스트를 보내는 기능과 선행 버스트 없이 수신 주기를 수행하는 기능이 포함됩니다. 이것은 우리 소나에서 요청된 기능이며 SRF02는 그 구현을 처음으로 확인했습니다. SRF02는 전송과 수신 모두에 단일 변환기를 사용하기 때문에 최소 범위는 다른 이중 변환기 레인저보다 높습니다. 최소 측정 범위는 약 15cm(6인치)입니다. 모든 거리 측정기와 마찬가지로 SRF02는 미국, cm 또는 인치 단위로 측정할 수 있습니다.

 

 

SRF02는 I2C모드 말고도 사용할 수 있지만, I2C모드로 사용할 것이기때문에 그에 관해서만 작성하겠습니다.  

I2C 모드에서 SRF02를 사용하려면 모드 핀에 아무것도 연결되어 있지 않은지 확인하고 연결되지 않은 상태로 두어야 합니다. I2C 버스는 OOPic, Stamp BS2p, PicAxe 등과 같은 널리 사용되는 컨트롤러와 다양한 마이크로 컨트롤러에서 사용할 수 있습니다. 프로그래머에게 SRF02I2C 주소가 다르다는 점을 제외하고 유비쿼터스 24xx 시리즈 EEPROM과 동일한 방식으로 동작합니다. SRF02의 기본 배송 주소는 0xE0입니다. 사용자는 16개의 주소 E0, E2, E4, E6, E8, EA, EC, EE, F0, F2, F4, F6, F8, FA, FC 또는 FE 중 하나로 변경할 수 있으므로 최대 16개의 소나를 사용할 수 있습니다.

 

 

2. Registers

 

SRF02에는 총 6개의 레지스터가 있습니다.

위치 0명령 레지스터이며, 범위 세션을 시작 하는데 사용됩니다. 읽을 수는 없으며 범위는 최대 65ms까지 지속되고 범위가 지정되는 동안은 I2C버스의 명령이 응답하지 않습니다.. 위 이유가 센서를 한번 감지하고 최소 65ms이후에 그다음 센서를 탐지해야 하는 이유입니다. 위치 23최신 최신 범위의 16비트 결과이고, 값이 0이 나온다면 개체가 없음을 나타냅니다. 데이터시트를 보면, 65ms보다 빠르게 범위 지정을 하지말라고 다시한번 경고하고 있습니다. 위치 4516비트 부호없는 수로, 센서가 탐지할 수 있는 대략적인 가장 가까운 범위입니다.

 

3. 명령어

 

인치, 센티미터 또는 마이크로초 단위로 결과를 반환하기 위한 (80~82) 명령

동일 동작을 하지만 버스트를 전송하지 않는 (86~88) 명령

레인징을 수행하지 않고 전송하는 명령(92)

I2C 주소를 변경하는 명령 (160~170) 으로 구성되어 있습니다.

 

4. SRF02 주소확인

 

위에서 SRF02주소를 적어줘야하고, 바꿀 수 있다고 했는데 확인법은 아래와 같습니다.

SRF02 주소확인

전원이 공급되었을 때 빛의 점등으로 구별할 수 있습니다.

 

5. 동작 프로그램 예시

 

아래는 SRF02센서 3개를 동시에 구동하여 거리를 받아오는 함수이며, I2C를 이용합니다.

#include <mega128.h>
#include <delay.h>
#include <stdio.h>
#include "lcd.h"
#include "twi.h"
#include "srf02.h"

unsigned char ti_Cnt_1ms;
unsigned char LCD_DelCnt_1ms;

void Timer0_Init()  // 타이머 설정
{
    TCCR0 = (1<<WGM01)|(1<<CS00)|(1<<CS01)|(1<<CS02);
    TCNT0 = 0x00;
    OCR0 = 100;
    TIMSK = (1<<OCIE0);
}


interrupt[TIM0_COMP] void timer0_comp(void)  
{
    ti_Cnt_1ms++;
    LCD_DelCnt_1ms++;
}

int SRF_Run(char Sonar_Addr){ //주소를 보내면, 측정값을 반환하는 함수
    unsigned char res;    
    unsigned int Sonar_range;  
    
    res = getRange(Sonar_Addr, &Sonar_range);
        if(res)
        {         
            return 0;
        }
        else if(LCD_DelCnt_1ms > 100)
        {            
            LCD_DelCnt_1ms = 0;            
            return Sonar_range;
        } 
}

void main(void)
{
    unsigned char res;
    char Sonar_Addr = 0xE0;
    unsigned int Sonar_range_1,Sonar_range_2,Sonar_range_3; //측정값 저장 공간 선언
    char Message[40];
    int readCnt = 0; 
    DDRD |= 0x03;
    
    LCD_Init();
    Timer0_Init();
    Init_TWI();
    delay_ms(1000);
    SREG |= 0x80;
    
    startRanging(Sonar_Addr);
    ti_Cnt_1ms = 0;
    Sonar_range_1 = 0; 
    Sonar_range_2 = 0;  
    Sonar_range_3 = 0;    
    LCD_DelCnt_1ms = 0;     
    while(1)
    {      
        if(ti_Cnt_1ms > 100) 
        { // 1>2>3>1>2>3>1>... 이런식으로 주소를 바꿔주게 설정                   
            if (Sonar_Addr == 0xE0){  
                Sonar_Addr = 0xEC;
                startRanging(Sonar_Addr);
                Sonar_range_1 = SRF_Run(Sonar_Addr);
            } 
            else if (Sonar_Addr == 0xEC) {
                Sonar_Addr = 0xE2;
                startRanging(Sonar_Addr);
                Sonar_range_2 = SRF_Run(Sonar_Addr);
            }
            else{
                Sonar_Addr = 0xE0;
                startRanging(Sonar_Addr);
                Sonar_range_3 = SRF_Run(Sonar_Addr);
            }            
            LCD_Clear();  //LCD 공간에 측정값을 퍼뜨려서 출력
            sprintf(Message, "%03dcm", Sonar_range_1);
            LCD_Pos(0,0);
            LCD_Str(Message);
                
            sprintf(Message, "%03dcm", Sonar_range_2);
            LCD_Pos(1,0);
            LCD_Str(Message); 
            
            sprintf(Message, "%03dcm", Sonar_range_3);
            LCD_Pos(1,5);
            LCD_Str(Message); 
                
            LCD_DelCnt_1ms = 0;             
            ti_Cnt_1ms = 0;
        } 
    }
}

 

위에 헤더파일들이 정의되어있는데, twi,lcd헤더같은경우 글의 C언어 - 마이크로프로세서 에서 소개한 글에서 내용을 확인할 수 있습니다. 아래는 srf02센서 구현을 위해 구현한 헤더입니다.

 

#define SRF02_Return_inch           80
#define SRF02_Return_Cm             81
#define SRF02_Return_microSecond    82

#define COM_REG                     0
                   
#define SRF02_1st_Seg_change        160
#define SRF02_2nd_Seg_change        170
#define SRF02_3rd_Seg_change        165


unsigned char SRF02_I2C_Write(char address, char reg, char data)
{   //SRF02를 I2C를 통하여 전송
    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)
    {
        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_Seg_change);
        if(res) return res;
        res = SRF02_I2C_Write(ori, COM_REG, SRF02_2nd_Seg_change);
        if(res) return res;
        res = SRF02_I2C_Write(ori, COM_REG, SRF02_3rd_Seg_change);
        if(res) return res;
        
        res = SRF02_I2C_Write(ori, COM_REG, des);
        if(res) return res;
        break; 
        
    default:
        return -1;
    }
    return 0;
}

twi 방식을 이용하여 센서를 구현함을 알 수 있습니다!

 

첫번째 센서 끝!

 

 

728x90