1 | /*
|
2 | *********************************************************
|
3 | Filename: SRF05.h
|
4 | Version: 1.0
|
5 | Date: 01.11.2012
|
6 | Author: Jascha Breithaupt
|
7 | Website: www.jaybe-stuff.de
|
8 | *********************************************************
|
9 | Description:
|
10 | ------------
|
11 | This library is to use one Devantech SRF04/05 (or similar) by simply
|
12 | including this header to your program.
|
13 | See data sheet (ger/eng):
|
14 | http://www.robotikhardware.de/download/srf05doku.pdf
|
15 | *********************************************************
|
16 | Features:
|
17 | ---------
|
18 | Mode 1: - is fully compatible with SRF04/US-020/HC-SR04
|
19 | - uses 2 pins (echo/trigger)
|
20 | Mode 2: - uses 1 pin (e.g. PD2/INT0)
|
21 | Output: - measured time (µs)
|
22 | - distance in cm
|
23 | - distance in inch
|
24 | *********************************************************
|
25 | How to use:
|
26 | -----------
|
27 | 1. Include "SRF05.h" in your code
|
28 | 2. Check settings:
|
29 | choose mode [1/2]
|
30 | configure pins (e.g. PORTD/DDRD/PD2)
|
31 | define ISRs (e.g. INT0_vect/TIMER0_COMP_vect)
|
32 | define CPU-clock (e.g. 16000000UL -> UL: UnsignedLong)
|
33 | 3. Initialize the sensor in your code:
|
34 | SRF05_INIT();
|
35 | 4. Now you can get the data from your SRF05:
|
36 | value/time in µs: SRF05_VALUE();
|
37 | distance in cm: SRF05_CM();
|
38 | distance in inch: SRF05_INCH();
|
39 |
|
40 | *********************************************************
|
41 | Code Example:
|
42 | -------------
|
43 | #define F_CPU 16000000UL
|
44 |
|
45 | #include <avr/io.h>
|
46 | #include <avr/interrupt.h>
|
47 | #include <util/delay.h>
|
48 | #include "SRF05.h"
|
49 |
|
50 | int main(void)
|
51 | {
|
52 | SRF05_INIT();
|
53 | uint16_t distance = 0;
|
54 |
|
55 | while(1)
|
56 | {
|
57 | distance = SRF05_VALUE();
|
58 | distance = SRF05_CM();
|
59 | distance = SRF05_INCH();
|
60 | }
|
61 | }
|
62 | *********************************************************
|
63 | Notes:
|
64 | ------
|
65 | - Tested with Atmel ATMEGA32 @ 16MHz and Atmel Studio 6 SP1
|
66 | - To use another INT or TIMER you have to fit registers!
|
67 | *********************************************************
|
68 | */
|
69 |
|
70 | /* ***************************************************** */
|
71 | /* S E T T I N G S */
|
72 | /* ***************************************************** */
|
73 | // CHOOSE MODE
|
74 | const uint8_t SRF05_MODE = 2;
|
75 | /* ***************************************************** */
|
76 | // CONFIGURE THESE FOR MODE 1
|
77 | #define SRF05_TPORT PORTD //
|
78 | #define SRF05_TREGISTER DDRD // TRIGGER
|
79 | #define SRF05_TPIN PD6 //
|
80 |
|
81 | #define SRF05_EPORT PORTD //
|
82 | #define SRF05_EREGISTER DDRD // ECHO
|
83 | #define SRF05_EPIN PD2 //
|
84 | /* ***************************************************** */
|
85 | // CONFIGURE THESE FOR MODE 2
|
86 | #define SRF05_TEPORT PORTD //
|
87 | #define SRF05_TEREGISTER DDRD // TRIGGER/ECHO
|
88 | #define SRF05_TE PD2 //
|
89 | /* ***************************************************** */
|
90 | // DEFINE INTERRUPT/TIMER ISR
|
91 | #define SRF05_INT INT0_vect
|
92 | #define SRF05_TIMER TIMER0_COMP_vect
|
93 | /* ***************************************************** */
|
94 | // DEFINE CPU
|
95 | #ifndef F_CPU
|
96 | #define F_CPU 16000000UL
|
97 | #endif
|
98 | #ifndef XTAL
|
99 | #define XTAL 16000000UL
|
100 | #endif
|
101 | /* ***************************************************** */
|
102 | /* E N D S E T T I N G S */
|
103 | /* ***************************************************** */
|
104 | #pragma once // MS-compiler
|
105 | #include <util/delay.h>
|
106 | #pragma once
|
107 | #include <avr/interrupt.h>
|
108 |
|
109 | volatile uint16_t usec = 0; // save pulse length in µs
|
110 | volatile uint8_t intocc = 0; // indicate if interrupt has occurred
|
111 | volatile uint8_t meascomp = 0; // indicate that measurement is complete
|
112 | /* ***************************************************** */
|
113 | /* ***************************************************** */
|
114 |
|
115 |
|
116 | // INITIALIZE SRF05
|
117 | void SRF05_INIT()
|
118 | {
|
119 | // SETUP TIMER
|
120 | TCCR0 = (1 << WGM01); // mode 2: CTC of Timer0
|
121 | OCR0 = ((F_CPU/8)/100000)-1; // ((16000000 / 8 ) / 100000) -1 = 19 -> 155 steps = interrupt every 10µs
|
122 | TIMSK |= (1 << OCIE0); // Enable Compare Match interrupt
|
123 | TCNT0 = 0; // set timer to 0
|
124 |
|
125 | // SETUP INTERRUPT
|
126 | GICR |= (1 << INT0); // external interrupt mask register INT0
|
127 | MCUCR = (1 << ISC01) | (1 << ISC00); // trigger on rising edge
|
128 |
|
129 | // SETUP PINS
|
130 | if(SRF05_MODE == 1)
|
131 | {
|
132 | SRF05_TREGISTER |= (1 << SRF05_TPIN); // set trigger pin to output
|
133 | SRF05_EREGISTER &= ~(1 << SRF05_EPIN); // set echo pin/INT0 as input
|
134 | }
|
135 | if(SRF05_MODE == 2) // might be deleted
|
136 | {
|
137 | SRF05_TEREGISTER |= (1 << SRF05_TE); // set pin to output
|
138 | }
|
139 | }
|
140 |
|
141 | // GET DISTANCE VALUE (µs)
|
142 | uint16_t SRF05_VALUE()
|
143 | {
|
144 | usec = 0; // reset microseconds counter variable
|
145 | TCNT0 = 0; // set timer to 0
|
146 |
|
147 | // TRIGGER MEASUREMENT
|
148 | if(SRF05_MODE == 1)
|
149 | {
|
150 | SRF05_TPORT |= (1 << SRF05_TPIN); // set trigger pin to 1
|
151 | _delay_us(10); // minimum 10µs trigger signal
|
152 | SRF05_TPORT &= ~(1 << SRF05_TPIN); // set trigger pin to 0
|
153 | }
|
154 | if(SRF05_MODE == 2)
|
155 | {
|
156 | _delay_ms(50); // ensure the ultrasonic "beep" has faded away
|
157 | SRF05_TEREGISTER |= (1 << SRF05_TE); // set pin to output
|
158 | SRF05_TEPORT |= (1 << SRF05_TE); // set pin to 1
|
159 | _delay_us(10);
|
160 | SRF05_TEPORT &= ~(1 << SRF05_TE); // set pin to 0
|
161 | SRF05_TEREGISTER &= ~(1 << SRF05_TE); // set pin to input
|
162 | _delay_us(800); // wait for SRF to change from trigger to echo
|
163 | }
|
164 |
|
165 | // TRIGGER INT0 ON RISING EDGE
|
166 | MCUCR = (1 << ISC01) | (1 << ISC00);
|
167 |
|
168 | // ENABLE INTERRUPTS
|
169 | sei();
|
170 |
|
171 | // WAIT UNTIL MEASUREMENT IS COMPLETE
|
172 | while(meascomp != 1){}
|
173 |
|
174 | // DISABLE INTERRUPTS
|
175 | cli();
|
176 |
|
177 | meascomp = 0; // reset
|
178 |
|
179 | return usec; // value;
|
180 | }
|
181 |
|
182 | // GET DISTANCE IN CM
|
183 | uint16_t SRF05_CM()
|
184 | {
|
185 | if(SRF05_MODE == 1){return SRF05_VALUE() / 58;}
|
186 | if(SRF05_MODE == 2){return SRF05_VALUE() / 58;} // 29? -> data sheet
|
187 | }
|
188 |
|
189 | // GET DISTANCE IN INCH
|
190 | uint16_t SRF05_INCH()
|
191 | {
|
192 | if(SRF05_MODE == 1){return SRF05_VALUE() / 148;}
|
193 | if(SRF05_MODE == 2){return SRF05_VALUE() / 148;} // 74? -> data sheet
|
194 | }
|
195 |
|
196 | // EXTERNAL INTERRUPT
|
197 | ISR(SRF05_INT)
|
198 | {
|
199 |
|
200 | if(intocc == 0)
|
201 | { // INTERRUPT ON RISING EDGE
|
202 | TCCR0 |= (1 << CS01); // start Timer0 with prescaler 8
|
203 |
|
204 | // TRIGGER INT0 ON FALLING EDGE
|
205 | MCUCR = (1 << ISC01) | (0 << ISC00); // EICRA = External Interrupt Control Register A
|
206 |
|
207 | intocc = 1; // to indicate, that an interrupt has already occurred
|
208 | }
|
209 | else
|
210 | { // INTERRUPT ON FALLING EDGE
|
211 | TCCR0 &= ~(1<<CS01); // stop Timer0
|
212 |
|
213 | intocc = 0; // reset variable
|
214 | meascomp = 1; // variable to indicate end of measurement
|
215 | }
|
216 | }
|
217 |
|
218 | //INTERRUPT EVERY 10µS
|
219 | ISR(SRF05_TIMER)
|
220 | {
|
221 | usec += 10;
|
222 | }
|