I am writing my own library to control a little robot.
This library should make it possible letting students at our primary school to program the robot in a more kids friendly way. So all the complexity of controlling stepper motors, servo's and sensors is 'hidden' in the library.
After successfully creating a library to contol the stepper motors using port register i ran into an issue controlling the HC-SR04. The Trigger and Echo pin to the sensor are connected to the same port. After triggering the sensor, the port mode is changed to input mode and the pulse duration is measured. When using the Arduino library, the code works fine. Currently i have replaced the code using the Arduino libraries triggering the HC-SR04 using port registers and that works fine.
#include "LandjePingSensor.h"
LandjePingSensor::Init(int pingSensorPort)
{
_pingSensorPort = pingSensorPort;
_distanceInCM = 0;
_pingPinBitmask = digitalPinToBitMask(_pingSensorPort); // translate pin number to port register bitmask for selected pin.
_pingOutputRegister = portOutputRegister(digitalPinToPort(_pingSensorPort)); // Get the output port register for selected pin.
_echoInputRegister = portInputRegister(digitalPinToPort(_pingSensorPort)); // Get the input port register for the echo pin.
_pingModeRegister = (uint8_t *) portModeRegister(digitalPinToPort(_pingSensorPort)) ; // get DDR register for pin
};
LandjePingSensor::Ping()
{
*_pingModeRegister |= _pingPinBitmask; // Set pin to output in DDR register
*_pingOutputRegister &= ~_pingPinBitmask; // LOW
delayMicroseconds(2);
*_pingOutputRegister |= _pingPinBitmask; // HIGH
delayMicroseconds(10);
*_pingOutputRegister &= ~_pingPinBitmask; // LOW
*_pingModeRegister &= ~_pingPinBitmask; // Set pin to input in DDR register
int duration = pulseIn(_pingSensorPort, HIGH);
_distanceInCM = duration/58.2;
}
int LandjePingSensor::GetDistanceInCM()
{
return (_distanceInCM);
}
When initializing calling the functions, it does return the correct distance;
[code]LandjePingSensor p;
p.Init(pingSensor) ;
p.Ping() ;
Serial.println(p.GetDistanceInCM()) ;
To replace the pulseIn statement (int duration = pulseIn(_pingSensorPort, HIGH); _distanceInCM = duration/58.2;) i wrote the following code
Serial.println("wait for previous");
// if pin on inputregister is HIGH echo is still receiving, probably halfway other ping
if (!(*_echoInputRegister & _pingPinBitmask))
{
Serial.println("done waiting for previous");
long _startPing = 0;
Serial.println(_startPing);
long _duration = 0;
Serial.println("done waiting echo");
// wait for the pulse to become HIGH
// micros + max echo time (25cm * 58.2)
long maxwaitdur = micros() + (25*58.2) ;
boolean waittimeout = false;
// Wait till pin becomes high
while ((!(*_echoInputRegister & _pingPinBitmask)) & !waittimeout)
{ //
Serial.println(*_echoInputRegister) ;
Serial.println(_pingPinBitmask) ;
Serial.println("While 1");
Serial.println(micros());
Serial.println(maxwaitdur);
if (micros() > maxwaitdur)
{
waittimeout = true;
Serial.println("Timeout 1");
}
}
Serial.println("Pin raised");
// if no timeout occured, wait for ping to become liw
if (!waittimeout)
{
_startPing = micros();
maxwaitdur = micros() + 1000;
// wait till pin becomes low (echo received)
while ((*_echoInputRegister & _pingPinBitmask) & !waittimeout)
{
if ((micros() > maxwaitdur))
{
waittimeout = true;
Serial.println("Timeout 2");
}
}
Serial.println("Pin lowered");
}
if (!waittimeout)
{
_duration = micros() - _startPing;
Serial.println(_duration);
}
// wait for the echo
Serial.println("done waiting for echo");
The code is still messy a bit messy, sorry for that. But the functionally is should do;
- Skip the time duration measurement if Input at pin is high. Probably another echo is still being processed
- Wait till the signal at the ping goes high
- After the signal goes high, wait till it goes low
- Measure the pulse duration
When running the code the output is;
wait for previous
done waiting for previous
0
done waiting echo
0
32
While 1
80376724
80381256
0
32
While 1
80382840
80381256
Timeout 1
Pin raised
done waiting for echo
0
For some not known reason to me is that the raised signal at the input in is not detected.
The value of the inout register is also 0 and therefore not matching the bitmask (32) of the port.
Any ideas ?
If you want to explore the whole class in detail, it can be found here ;
https://github.com/reddipped/LandjeRobot