Let me skip the theory, you can it read elsewhere. Just upload the code and enjoy.
Well, of course you need an ultrasonic transmitter (left side of the picture, the NANO connected to the turquoise cable) and the receiver (the NANO connected to the red cable). You can get the modules separately or dismantle one of that cheap HC-SR04 modules which are meant for distance measuring by echo. Ultrasonic modules have a very sharp beam, so both of them have to look at each other. To achieve this, just cut a card board and give it a shape like rails.
The output will be plotted in the Serial Plotter and might give you pictures like this:
So, what can you see in the diagram?
Well, the transmitter continuously sends sound at a frequency of 40435 Hertz. When I started to move it towards the receiver the frequency registered by the receiver slowly went up to 40441 Hertz. When I stopped moving the transmitter, it went back to normal. I do not know the exact speed of moving but it was definitely below one inch per second. On reversing the movement I get a valley instead of a hill. The software is very easy. First the transmitter:
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
// PB1 = pin9 and PB2 = pin-10 as outputs
DDRB = B00000110;
TCCR1A = B10110010;
TCCR1B = B00011001;
byte ocr1a = 198; // 40,4 kHz
ICR1 = 2 * ocr1a;
OCR1A = ocr1a; // duty cycle
OCR1B = ocr1a; // same duty cycle
Serial.print("ICR1 = ");
Serial.println(ICR1);
Serial.print("freq = ");
Serial.println(F_CPU / ICR1);
}
void loop() {}
The outputs are pin-9 and pin-10 (push/pull), no GND connection. Pins 9 and 10 both are controlled by Timer-1, so these pins cannot be changed.
That was a short one. Now the receiver:
/*
inputPin ist A0
wegen Zugriffen auf PORT
und TIMER1 NICHT fuer R4
*/
const byte inputPin = A0;
const byte flankenZuZaehlen = 255;
// 255 * 1/40000 = 6,3 Millisekunden
// gleitender Mittelwert:
const byte N = 450;
float buffer[N];
float summe = 0;
byte zeiger = 0;
long drucke = 0;
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
Serial.flush();
initTimer();
}
void loop() {
long t = getTime();
float freq = 0.5 * F_CPU * flankenZuZaehlen / t;
float avg = mean(freq);
if (drucke++ > N) Serial.println(avg);
}
word getTime() {
byte countDown = flankenZuZaehlen;
byte a;
byte b = PINC;
// warte auf die naechste Flanke
do {
a = b;
b = PINC;
} while (a == b);
noInterrupts();
TCNT1 = 0;
// --- beginne die Messung --- :
while (countDown) {
b = PINC;
// zaehle BEIDE Flanken:
if (a != b) countDown--;
a = b;
}
interrupts();
return TCNT1;
}
void initTimer() {
// mache TCNT1 zum 16-bit-Register:
TCCR1A = 0;
// setze Prescaler auf 1:
// TCNT1 zaehlt die Takte
TCCR1B = 0b00000001;
// nur A0 input, alle anderen sind 0
DDRC = B11111110;
}
float mean(float w) {
summe = summe - buffer[zeiger];
buffer[zeiger] = w;
summe = summe + buffer[zeiger];
if (++zeiger >= N)zeiger = 0;
return summe / N;
}
The receiver has to be connected to GND and A0, but any other pin can be defined in the program.
That's all!
Comments