336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Leave messages below

의뢰는 http://instructables.tistory.com/64로 남겨주세요


https://electrosome.com/hc-sr04-ultrasonic-sensor-pic/


HC-SR04는 4핀짜리 Ultra Sonic Sensor이다.

여기서는 MikroC로 짠 코드와 MPLAB으로 짠 코드를 비교할 것이다.


MPLAB-XC8.zip

▼Proteus ISIS 추가용 라이브러리 (HC-SR04) (☞출처)

Ultrasonic Sensor Library for Proteus.rar

▼Proteus ISIS용 HC-SR04 ---PIC칩용 (☞출처)

ultrasound.rar


▼Proteus, Hyperterminal & Virtual Port

https://www.youtube.com/watch?v=gwkju6f2Twk

▼Google에서 Virtual Port Emulator라고 검색

http://www.eterlogic.com/Products.VSPE.html

SetupVSPE.zip





▼MikroC

// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;

sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections

void main()
{
  int a;
  char txt[7];
  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);          // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);     // Cursor off

  TRISB = 0b00010000;           //RB4 as Input PIN (ECHO)

  Lcd_Out(1,1,"Developed By");
  Lcd_Out(2,1,"electroSome");

  Delay_ms(3000);
  Lcd_Cmd(_LCD_CLEAR);

  T1CON = 0x10;                 //Initialize Timer Module

  while(1)
  {
    TMR1H = 0;                  //Sets the Initial Value of Timer
    TMR1L = 0;                  //Sets the Initial Value of Timer

    PORTB.F0 = 1;               //TRIGGER HIGH
    Delay_us(10);               //10uS Delay
    PORTB.F0 = 0;               //TRIGGER LOW

    while(!PORTB.F4);           //Waiting for Echo
    T1CON.F0 = 1;               //Timer Starts
    while(PORTB.F4);            //Waiting for Echo goes LOW
    T1CON.F0 = 0;               //Timer Stops

    a = (TMR1L | (TMR1H<<8));   //Reads Timer Value
    a = a/58.82;                //Converts Time to Distance
    a = a + 1;                  //Distance Calibration\
    if(a>=2 && a<=400)          //Check whether the result is valid or not
    {
      IntToStr(a,txt);
      Ltrim(txt);
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
    }
    else
    {
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Out of Range");
    }
    Delay_ms(400);
  }
}



▼MPLAB XC8

#define _XTAL_FREQ 8000000

#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include <xc.h>
#include "lcd.h";
#include <pic16f877a.h>

// BEGIN CONFIG
#pragma config FOSC = HS   
#pragma config WDTE = OFF  
#pragma config PWRTE = OFF 
#pragma config BOREN = ON 
#pragma config LVP = OFF   
#pragma config CPD = OFF   
#pragma config WRT = OFF  
#pragma config CP = OFF    
//END CONFIG
void main()
{ 
  int a;

  TRISB = 0b00010000;         //RB4 as Input PIN (ECHO)
  TRISD = 0x00;               // LCD Pins as Output

  Lcd_Init();

  Lcd_Set_Cursor(1,1);
  Lcd_Write_String("Developed By");
  Lcd_Set_Cursor(2,1);
  Lcd_Write_String("electroSome");

  __delay_ms(3000);
  Lcd_Clear();

  T1CON = 0x10;               //Initialize Timer Module

  while(1)
  { 
    TMR1H = 0;                //Sets the Initial Value of Timer
    TMR1L = 0;                //Sets the Initial Value of Timer

    RB0 = 1;                  //TRIGGER HIGH
    __delay_us(10);           //10uS Delay 
    RB0 = 0;                  //TRIGGER LOW

    while(!RB4);              //Waiting for Echo
    TMR1ON = 1;               //Timer Starts
    while(RB4);               //Waiting for Echo goes LOW
    TMR1ON = 0;               //Timer Stops

    a = (TMR1L | (TMR1H<<8)); //Reads Timer Value
    a = a/58.82;              //Converts Time to Distance
    a = a + 1;                //Distance Calibration
    if(a>=2 && a<=400)        //Check whether the result is valid or not
    { 
      Lcd_Clear();
      Lcd_Set_Cursor(1,1);
      Lcd_Write_String("Distance = ");

      Lcd_Set_Cursor(1,14);
      Lcd_Write_Char(a%10 + 48);

      a = a/10;
      Lcd_Set_Cursor(1,13);
      Lcd_Write_Char(a%10 + 48);

      a = a/10;
      Lcd_Set_Cursor(1,12);
      Lcd_Write_Char(a%10 + 48);

      Lcd_Set_Cursor(1,15);
      Lcd_Write_String("cm");
    }  
    else
    {
      Lcd_Clear();
      Lcd_Set_Cursor(1,1);
      Lcd_Write_String("Out of Range");
    }
    __delay_ms(400);
  }
}

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

I hope that you can understand the working of the above program through comments. 

If you have any doubts, just comment below.

Distance Calibration

For accurate distance measuring you may calibrate the obtained result. Here for making the displayed distance more accurate, I added 1 to the the measured distance. This constant of calibration can be find using a series of practical experiments with a ruler scale.

In the above program there is a small problem as it infinitely waiting for ECHO and to ECHO goes LOW. If HIGH echo pulse is not received due to any reason, the program may get stuck there. So it is not a good practice to infinitely wait for ECHO and to ECHO goes LOW.  The best solution is to use PORTB On-Change Interrupt feature of PIC Microcontroller.

PORTB On-Change Interrupt

Four pins of PORTB (RB4 – RB7) have interrupt on-change feature.

포트B(RB4~RB7) 는 인터럽트 on-change 특성을 갖고있다.

Only those pins configured as INPUT PIN can cause this Interrupt while this interrupt is enabled.

이런 입력핀들만이 인터럽트를 유발할 수 있다. while 이 인터럽트가 enabled된 동안에

If the Logic State of any of these four pin changes (only Input Pins), interrupt will be generated.

만약 이 4개핀(PB4~PB7)이 바뀌었으면, 인터럽트가 발생할 것이다.


PORTB On-Change Interrupt can be enabled by :

  • Set Global Interrupt Enable bit : INTCON.GIE = 1
  • Set PORTB On-Change Interrupt Enable Bit : INTCON.RBIE = 1


다음 조건하에 PortB의 On-Change 인터럽트는 인에이블될수 있다.

● INTCON안의 GIE비트가 1로 Set됬을때

● INTCON안의 RBIE비트가 1로 Set됬을때


Note : PORTB On-Change Interrupt flag (INTCON.RBIF) will be set whenever this interrupt is generated and it should be cleared in software


이제 인터럽트가 추가된 코드를 보자



▼MikroC (Interrupt Used)

// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;

sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections

int a;

//Interrupt function will be automatically executed on Interrupt
void interrupt() 
{
  if(INTCON.RBIF == 1)                 //Makes sure that it is PORTB On-Change Interrupt
  {
    INTCON.RBIE = 0;                   //Disable On-Change Interrupt
    if(PORTB.F4 == 1)                  //If ECHO is HIGH
      T1CON.F0 = 1;                    //Start Timer
    if(PORTB.F4 == 0)                  //If ECHO is LOW
    {
      T1CON.F0 = 0;                    //Stop Timer
      a = (TMR1L | (TMR1H<<8))/58.82;  //Calculate Distance
    }
  }
  INTCON.RBIF = 0;                     //Clear PORTB On-Change Interrupt flag
  INTCON.RBIE = 1;                     //Enable PORTB On-Change Interrupt
}
 
void main()
{
  char txt[7];
  Lcd_Init();
  Lcd_Cmd(_LCD_CLEAR);                 // Clear display
  Lcd_Cmd(_LCD_CURSOR_OFF);            // Cursor off

  TRISB = 0b00010000;
  INTCON.GIE = 1;                      //Global Interrupt Enable
  INTCON.RBIF = 0;                     //Clear PORTB On-Change Interrupt Flag
  INTCON.RBIE = 1;                     //Enable PORTB On-Change Interrupt

  Lcd_Out(1,1,"Developed By");
  Lcd_Out(2,1,"electroSome");

  Delay_ms(3000);
  Lcd_Cmd(_LCD_CLEAR);

  T1CON = 0x10;                        //Initializing Timer Module

  while(1)
  { 
    TMR1H = 0;                         //Setting Initial Value of Timer
    TMR1L = 0;                         //Setting Initial Value of Timer

    a = 0;

    PORTB.F0 = 1;                      //TRIGGER HIGH
    Delay_us(10);                      //10uS Delay
    PORTB.F0 = 0;                      //TRIGGER LOW

    Delay_ms(100);                     //Waiting for ECHO
    a = a + 1;                         //Error Correction Constant
    if(a>2 && a<400)                   //Check whether the result is valid or not
    {
      IntToStr(a,txt);
      Ltrim(txt);
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Distance = ");
      Lcd_Out(1,12,txt);
      Lcd_Out(1,15,"cm");
    }
    else
    {
      Lcd_Cmd(_LCD_CLEAR);
      Lcd_Out(1,1,"Out of Range");
    }
    Delay_ms(400);
  }
}



▼MPLAB XC8 (Interrupt Used)

#define _XTAL_FREQ 8000000

#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include <xc.h>
#include "lcd.h";
#include <pic16f877a.h>

// BEGIN CONFIG
#pragma config FOSC = HS 
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = ON 
#pragma config LVP = OFF 
#pragma config CPD = OFF 
#pragma config WRT = OFF 
#pragma config CP = OFF
//END CONFIG

int a;

void interrupt echo()
{
  if(RBIF == 1)                       //Makes sure that it is PORTB On-Change Interrupt
  {
    RBIE = 0;                         //Disable On-Change Interrupt
    if(RB4 == 1)                      //If ECHO is HIGH
    TMR1ON = 1;                       //Start Timer
    if(RB4 == 0)                      //If ECHO is LOW
    {
      TMR1ON = 0;                     //Stop Timer
      a = (TMR1L | (TMR1H<<8))/58.82; //Calculate Distance
    }
  }
  RBIF = 0;                           //Clear PORTB On-Change Interrupt flag
  RBIE = 1;                           //Enable PORTB On-Change Interrupt
}
void main()
{
  TRISB = 0b00010000;                 //RB4 as Input PIN (ECHO)
  TRISD = 0x00;                       // LCD Pins as Output
  GIE = 1;                            //Global Interrupt Enable
  RBIF = 0;                           //Clear PORTB On-Change Interrupt Flag
  RBIE = 1;                           //Enable PORTB On-Change Interrupt

  Lcd_Init();

  Lcd_Set_Cursor(1,1);
  Lcd_Write_String("Developed By");
  Lcd_Set_Cursor(2,1);
  Lcd_Write_String("electroSome");

  __delay_ms(3000);
  Lcd_Clear();

  T1CON = 0x10;                       //Initialize Timer Module

  while(1)
  {
    TMR1H = 0;                        //Sets the Initial Value of Timer
    TMR1L = 0;                        //Sets the Initial Value of Timer

    RB0 = 1;                          //TRIGGER HIGH
    __delay_us(10);                   //10uS Delay
    RB0 = 0;                          //TRIGGER LOW 

    __delay_ms(100);                  //Waiting for ECHO
    a = a + 1;                        //Error Correction Constant

    if(a>=2 && a<=400)                //Check whether the result is valid or not
    {
      Lcd_Clear();
      Lcd_Set_Cursor(1,1);
      Lcd_Write_String("Distance = ");

      Lcd_Set_Cursor(1,14);
      Lcd_Write_Char(a%10 + 48);

      a = a/10;
      Lcd_Set_Cursor(1,13);
      Lcd_Write_Char(a%10 + 48);

      a = a/10;
      Lcd_Set_Cursor(1,12);
      Lcd_Write_Char(a%10 + 48);

      Lcd_Set_Cursor(1,15);
      Lcd_Write_String("cm");
    }
    else
    {
      Lcd_Clear();
      Lcd_Set_Cursor(1,1);
      Lcd_Write_String("Out of Range");
    }
    __delay_ms(400);
  }
}

--------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------

http://waihung.net/hc-sr04-ultrasonic-sensor-on-pic/

▲ PIC16F877A, HC-SR04, LCD16x2, MPLAB X(MPLAB IDE를 사용해도 무방하다)

▲Hi-Tech C compiler (하이텍 C 컴파일러)


HI-TECH_PICC_PRO_9.71a (Activate하는법).zip


▼좀더 많은 칩을 지원해준다. (9.71a 압축을 풀어보고 사용하려는 칩을 지원해주지 않느다면 아래것을 받도록 하자.)

picc-9_82-win.vol1.egg


picc-9_82-win.vol2.egg


PIC16F877A_Ultrasonic_LCD.rar

Main코드는 아래와 같다. (나머지는 파일을 받으면 된다.)

#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include <htc.h>
#define _XTAL_FREQ 16e6
__CONFIG(WDTE_OFF & CP_OFF & FOSC_HS & PWRTE_ON & LVP_OFF);


#define RS RB2
#define EN RB3
#define D4 RB4
#define D5 RB5
#define D6 RB6
#define D7 RB7

#include "lcd.h"

#define _XTAL_FREQ 16e6

// Lcd4_Init(); Lcd4_Clear() Lcd4_Set_Cursor() : Lcd4_Write_Char() Lcd4_Write_String()

unsigned int distance = 0;
char lcd_distance[10];

void sendPulse(void);
unsigned int readUltrasonic(void);

int main(int argc, char** argv) {
    TRISB = 0;
    RB0 = 0;
    TRISD = 0xFF;
    OPTION_REG &= 0b11000110;
    Lcd4_Init();

    Lcd4_Set_Cursor(1,0);
    Lcd4_Write_String("Ultrasonic");

    while(1) {
        distance = readUltrasonic()/1.7;

        sprintf(lcd_distance,"%d",distance);
        Lcd4_Set_Cursor(2,0);
        Lcd4_Write_String(lcd_distance);

        //Lcd4_Set_Cursor(2,6);
        Lcd4_Write_String(" cm     ");

        __delay_ms(300);

    }

    return (EXIT_SUCCESS);
}

void sendPulse(void) {
    RB0 = 1;
    __delay_us(10);
    RB0 = 0;
}

unsigned int readUltrasonic(void){
    unsigned int time = 0;
    

    while(1) { if(RD0==0) { break; } }

    sendPulse();
    while(1) {
        if(RD0==1)
        {
            TMR0 = 0;
            while(1)
            {
                if(RD0==0){
                    time = TMR0;
                    return time;
                }
            }
        }
    }

}


---------------------------------------------------------------------------------------

https://electrosome.com/blinking-led-pic-microcontroller-hi-tech-c/

추가로 Hi-Tech 기본코드는 아래와 같다.




#include <htc.h>
#define _XTAL_FREQ 8000000
void main()
{
  TRISB=0X00;
  PORTB=0X00;
  while(1)
  { 
    PORTB=0XFF;
    __delay_ms(1000);
    PORTB=0X00;
    __delay_ms(1000);
  }
}


Posted by ElectricShock
:
BLOG main image
잡동사니들(지극히 개인취향인...) (다른글에도 댓글 부탁해요♥) You May Leave English Messages on GuestBook. by ElectricShock

공지사항

카테고리

분류 전체보기 (782)
Programming(=프로그래밍) (3)
MiDi (2)
Animation (4)
Blender (3D Graphic Program.. (10)
Blendtuts.com (Series) (1)
Blender 기초 팁들 (2)
Processing (디지털미디어과) (2)
Music (1)
Books in the world (0)
Communication(CAN, UART, et.. (12)
MCU Examples (PIC 기반) (7)
Transistor (1)
Mikro C Pro (11)
Mikro Pascal (1)
Proton IDE (0)
Robot (0)
Swift 3D (1)
Dummies Series (1)
All about Hacking (0)
제2 외국어 (1)
PIC 해외서적들 (3)
AVR (25)
PIC (MikroC) (MPLAB) (4)
Assembly (2)
ARM (3)
Arduino (26)
PSpice (1)
Proteus ISIS (14)
CodeVision (2)
FPGA (15)
MPLAB (24)
PCB (the Procedure) (15)
3D Printer (5)
PICKIT3 (6)
Matlab (11)
RaspBerry PI (15)
BeagleBone (1)
Android Studio (17)
졸업작품 (172)
Korea History (0)
Issue(사회) (73)
Multimeter 리뷰 (1)
Oscilloscope (1)
A (34)
B (19)
J (6)
C (32)
P (12)
T (37)
H (12)
I (12)
M (44)
R (5)
E (5)
F (2)
D (9)
O (2)
L (7)
S (9)
W (2)
V (6)
G (14)
Visual C++ or Visual Studio (2)
Android App Development (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백