You don't need microseconds delay, but a timer counter with microseconds accuracy.
Looking at the datasheet linked by @JRE, this is an asynchronous protocol. The host transmits a long low pulse (at least 18 milliseconds), and that's the only time when the MCU should delay anything. But you already have a milliseconds delay function (and anyway it'd be better done in the milliseconds interrupt that's probably already running).
Then the device answers with a start cycle and 40 data cycles, where the length of the high phase encodes the bit value. You have to measure the elapsed time between the rising and the falling edge.
If the milliseconds interrupt is running, then there is already something counting the cycles. Usually it's the SysTick
timer. Wait for the rising edge on the pin, get a timestamp from SysTick->VAL
, wait for the falling edge, read the counter again, and subtract the previous timestamp. Watch out for overflow, add SysTick->LOAD+1
to the result if it's negative. Divide the result by the clock frequency (in MHz) to get a microsecond value.
However, you might prefer to have the MCU do something useful, or let it sleep to conserve power while the data comes in.
A timer and DMA can do most of the work on their own
Read the TIM2/TIM3 functional description / Input capture mode section in the Reference Manual.
As the low phase of the signal should be always 50 us long, you can as well measure the time between two consecutive falling edges. The example in the manual is for rising edges, but it can of course be modified to capture falling edges by changing the CC1P
and CC1NP
bits in Step 3.
- Pick a timer channel and the corresponding DMA channel. Use the table titled Summary of the DMA requests for each channel.
- Set up the DMA channel to transfer 41 (for 1 start pulse + 40 data pulses) halfwords (16 bits) from the
CCR
register of the timer channel to a suitably sized array in memory.
- You can enable the DMA transfer complete interrupt in order to run a handler when, well, the data transfer is complete.
- Set up the timer with a prescaler that is your system clock frequency in MHz (write one less in
PSC
, and don't forget to set UG
in EGR
) to conveniently get a timestamp in milliseconds.
- Proceed with the procedure described in the Input capture mode section. There is even a simple code example in the appendix. Adapt it for capturing falling edges, and in the last step, enable DMA instead of the channel interrupt in
DIER
.
- As a safety net, you can enable the timer update interrupt. It will fire after 65535 microseconds, letting the program know that the transfer has timed out. A lower timeout value can be set in
ARR
.