I use ultrasonic sensor in many projects. I always use the pinmode to set the IN/OUT pin definition.
Strangely, I just noticed that in one projects I forgot to call the init routine, so the pins were never assigned.
Yet the sensor was working well.
This is strange since the default should be input, so I would expect the sensor results to be wrong. Yet they were good.
Any idea how it was still working?
Perhaps the IO pins kept previous programming although I uploaded many times after the last time I used the pinmode command?
When a pin is in INPUT mode, digitalWrite() will be turning the internal pullup resistor ON/OFF when you write a HIGH/LOW, respectively. This may be good enough to use as an output signal depending on the specific sensor being used.
This is also going to be highly dependent on the library being used, and the specific sensor. Generally I would expect the library itself to handle setting the pinMode.
You would need to look at the library code, there may be an assumption for default pins if none are specified, and occasionally the begin() function can be a dummy that doesn't actually do anything.
I can (maybe) understand that digitalwrite HIGH will change the pullup (??) and drive the pin high, but how can a digitalwrite LOW drive the pin low, since there is no pull down resistor internally? Also, shouldn't I use the PULLUP command in order to use the pullup resistor?
You should use INPUT_PULLUP if that is what your hardware demands. But the Arduino core is a layer applied to the underlying hardware which has it's own behaviours. Best place to understand them, is reading the MCU data sheet.
AVR is a type of MCU manufactured by the Microchip company. It's in all the original Arduinos, UNO, Mega, etc..
Key aspect for you should be... this behaviour is accidental and you should always initialize ports explicitly, because if you don't, it won't be portable to other platforms like newer Arduinos and ESP32, etc.
I totally agree - the code should be set correctly. I already fixed it, as I am going to port it to Wemos32 soon. Yet I am still puzzled, because I remember from the past that when I forgot to define the IO, it didn't work.
I will invest some time to solve the mystery.