HC-SR04 Ultrasonic Sensor Works only at 1MHz on ATtiny85

Go To Last Post
9 posts / 0 new
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0



I was playing around with Arduino Nano and the  ultrasononic sensor hc-sr04. Using arduino nano the code bellow works perfectly, but when I try to run the same code on ATtiny85, if I don't set the clock to 1MHz before flashing, the code do not works and I got no sense measures. The same behavior on ATtiny13 occurs running at 1.2MHz. Therefore, my question is: is there a reason for the sensor works only at 1MHz? Why the sensor not works on ATtiny85 @ 8MHz, but works on Nano @ 16MHz?


int ECHO_PIN = PB4;
int LED_PIN = PB1;  

void setup() {
  pinMode(LED_PIN, OUTPUT);

void loop() {

  digitalWrite(TRIGGER_PIN, LOW);

  digitalWrite(TRIGGER_PIN, HIGH);

  digitalWrite(TRIGGER_PIN, LOW);

  pinMode(ECHO_PIN, INPUT);
  long duration = pulseIn(ECHO_PIN, HIGH);
  cm = (duration/2) / 29.1;

  if(cm < 5.0){
    digitalWrite(LED_PIN, HIGH);
    } else {
    digitalWrite(LED_PIN, LOW);



Thanks in advance,

Eduardo Lopes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The timing depends on knowing what speed the CPU is executing at (and/or what speed timers are running at).


If you change that speed, you will need to adjust the code accordingly.


Have you done that?

eduardocl wrote:

cm = (duration/2) / 29.1;

Where does the Magic Number 29.1 come from? Is it still valid at the new frequency?




Here's a tutorial on using HC-SR04:




and there are many, many previous discussions ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Apr 21, 2021 - 07:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello awneil,


the magic number I got from a tutorial available online. Most of the examples works perfectly on Arduino Mega, Nano or Uno. Some tutorials use the libs NewPing or Ultrasonic libs on attiny85, but for me, not worked. I was suspecting that there were something wrong in the delay functions, but I'm still newbie in micro-controllers to have a clue of what is taking place. Anyway, thanks for the link, I don't know why I couldn't find it since I search here... Thanks!



  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

So, I was bored...  And I haven't tinkered in a while.

And I happen to have some T13's in the drawer.

And a couple of the HC-SR04 ultrasound modules.


So I thought I'd give it a try using the T13 at 1.2 MHz.


The goal is to use the T13, at 1.2 MHz, with the SR04 to turn on an LED if the target is <= 5 cm from the SR04 module.

(As per the OP's first post.)


First the lessons learned:

1) Why in the world would one run a time sensitive project at 1.2 MHz when the micro will run at 20 MHz?

The PING travels at about 343.2 meters/second, 20'C, dry air.

That is about 2.913 uS / mm of travel distance.

That means that in the time it takes the PING to travel 1 mm the micro will execute 3.497 clock cycles.

(2.913 uSec/mm  /  0.833 uSec/clock cycle) = 3.497 clock cycles / mm of Ping travel distance.


That just doesn't give one much processing power in which to time the pulse to the mm distance, (ignoring, for the moment, the inherent inaccuracies of the SR04 itself).


However, all is not lost.

One can measure the PING travel distance in cm's, instead of in mm's, by noting that one has 35 uSec / cm to work with, which gives one 42 clock cycles of processing time per each cm of PING travel distance.

That is lots better than 3.5 clock cycles!


If one ran the micro at 20 MHz, one would have 58 clock cycles / mm of PING travel distance, so measuring to the mm would be doable.

At 20 MHz one would also have 700 clock cycles per cm of PING travel, so that would be like using a super computer for the task!


Running the micro at 1.2 MHz is clearly tying one hand behind your back.

You can still perform the task, but it is a bit more challenging and less precise.


2) The T13 has a single Timer/Counter, and it doesn't have the input capture mode to allow it to easily measure a pulse width using the T/C hardware.

So, one is left with measuring the pulse width in software, which is certainly doable.

Typically, especially when referring to my coding, the hardware approach would be significantly more accurate with fewer code and loop and If/Then induced timing errors.


3) With the small amount of memory in the T13 one can't just throw a GLCD on the micro to read the PING travel distance, or in fact to display any debugging information.

Hence, as per the OP's original post, the output to detect an object is <= 5 cm from the sensor is merely an LED.


That said, I hooked up an LED and an SR04 to the T13, and then I added two more LEDs because a project can never have too many LEDs!


One LED flashes as a heartbeat to show that the micro is running, and that a new measurement is about to be taken.

One LED is the Target is <= 5 cm away indicator.

The third LED is turned on and off inside the timing loop, so that it can be tweaked for 35 uSec / Tic, which means each Tic count equals 1 cm of PING travel distance.

The O'scope image shows the 35 uSec Tic loop, from Rising Edge to Rising Edge of the pulse train.


The TIC timing loop is about 35 uSec.  It uses a software uSec delay counter, (not a Timer/Counter generated Tic), and was tuned to +/- 1 uSec in the delay.

The slow micro clock makes it harder to fine tune the loop timing, although I moved on before I started inserting NOP's to try to tweak it a bit further.


The (in)accuracy of the internal RC clock, and the loop timing jitter watching for the Echo Pulse to transition high, also add small errors.

But those are overwhelmed by the fact that the program is measuring the Ping Travel Distance in units of cm,  not mm.


4) The T13's have sat in the drawer for years.  I'm glad I finally had a reason to pull one out and do something with it.








'File: Tiny13 SR04 Ultrasound V1.bas
'Carter   April 21, 2021

'This uses an ATTiny13 micro to drive an HC-SR04
'Ultrasound Module.
'If the distance to the target is < 5 it turns on an LED.
'SLOW micro clock, so measure distance in cm units, not mm units.
'No interrupts used.

'There is NO GLCD to show the range.
'This runs at 1.2 MHz as that is the Forum Question spec.
'The micro could run at 20 MHz for better time resolution
'and for more processing power...

'This is simplistic.
'The T13 has a single 8-Bit Timer/Counter which does
'not have built-in pulse width measuring capability,
'so that is done in SW.

'With this SLOW clock frequency, the Ping travels 1 mm
'every 3.497 clock cycles.
'So, this clock is too slow to measure the Ping travel
'distance in mm.
'Can, however, use 35 clock cycles / cm to measure it in cm.

'Program simply counts 35 uSec Tics from the start of
'the Echo Pulse until it goes low.
'Each Tic = 1 cm in Ping travel distance.
'Note, therefore, that Range to target  = Ping travel distance/2
'as the Ping travels both out and back.

'Ping Speed = 343.2 meters/second, 20'C, Dry air
'That gives 2.913 uSec / mm Ping travel time.

'This is a simplistic implementation.
'It measures Range to Target in cm, not mm.
'Loop timing was adjusted with O'scope.
'Loop overhead for entry/exit was ignored.
'If one desired more accuracy, then pick a micro
'with a T/C that can directly measure pulse widths
'and run the micro at a faster clock frequency!

'ATTiny13  5V  1.2 MHz (Int RC Osc)
'Set FUSES for Int 4.8 MHz Clock Source.
'PB0  LED 1
'PB1  Echo Signal, (Input)
'PB2  Trigger      (Output)
'PB3  NC
'PB4  LED 2

   $regfile = "attiny13.dat"      'Micro used
   $crystal = 1200000             '1.2 MHz,  Internal RC Osc

   $hwstack = 20                 'Hardware Stack    (24)
   $swstack = 10                 'Software Stack    (10)
   $framesize = 24               'Frame Space       (30)

   'Now Configure the Port's Pins for Input or Output mode.
   Config PortB.0 = Output       'LED1
   Config PortB.1 = Input        'Echo SIgnal
   Config PortB.2 = Output       'Trigger Signal
   Config PortB.3 = Output       'LED3
   Config PortB.4 = Output       'LED2

   LED1 Alias PortB.0             ' LED 1
   LED2 Alias PortB.4             ' LED 2
   LED3 Alias PortB.3             ' LED32
   Trig Alias PortB.2            'Trigger Signal
   EchoPin Alias PinB.1          'Echo Signal

    Dim LpCnt1 as Byte     'Loop Counter 1
    Dim PingDist as Word   'Ping Range x 2, out and back, mm
    Dim EchoSig as Byte    'Echo Signal Status, High or Low
    Dim PingCnt as Word    'Count of 1 cm, 35 uSec, Tics

   Waitms 50          'Hardware Startup Delay, (Not actually mSec!)

   Gosub SetClock     'Set Clock 1.2 MHz

   Gosub FlashLEDs    'Startup Flash LEDs

   Reset Trig        'Init Trigger Signal Low

   'Now set the Target Range, in cm,
   'If less than this then turn on the LED
   'NOTE: PingDist = TWICE the distance to the target, ie out and back, in cm
   'So to light up LED for target < 10 cm, PingDist = 20 cm
   'So to light up LED for target < 5 cm, PingDist = 10 cm (5 out, 5 back)
   PingDist = 10    '5  cm out, 5 cm back  = 5 cm target distance, 10 cm ping travel distance

   'Gosub Flash1Hz   'Test routine

   'Take a range measurement about once / second
   'Flash a heartbeat / taking a measurement LED
   'Turn ON the Target-in-range LED as indicated
   'Target range, in cm, is set above.

      Set LED1       'Heartbeat, taking a reading
      Waitms 100
      Reset LED1

      Gosub Ping     'Take a Range to Target measurement

      If PingCnt <= PingDist then
         'Target is within range, turn ON LED
         Set LED2
         Reset LED2
      End If

      Waitms 900

   Loop         'Forever

   'Use FUSES to set the micro to Int 4.8 MHz clock
   'Then run this to enable the Div / 4 to get a
   'clock of 1.2 MHz.
   clkpr = 128      'Enable Clock Prescale Register
   Clkpr = 2       'Clock Div / 4

   'Trigger a Ping
   'Watch for the Echo Signal to go High
   'Count 35 uSec Tics, (~ = 1 cm Ping travel)
   'On Exit have: PingCnt
   'Timeout at about 4 meters, 14 mSec, Ping Distance, out and back.

   'First fire the Trigger Pulse, > 10 uSec High
   Set Trig        'Trigger Pulse High
   Waitus 10      '
   Reset Trig     'Trigger Pulse Low

   'Now wait for Echo Signal to go high
   EchoSig = EchoPin
   While EchoSig = 0
      EchoSig = EchoPin

   'Now count 35 uSec Tics, each one = 1 cm Ping travel
   'Timeout at Range of 4 meters, 400 cm,  Tics = 400
   'Ignore loop overhead for the moment.
   PingCnt = 0
   EchoSig = EchoPin
   While EchoPin = 1
      Set LED3                   'Scope timing
      PingCnt = PingCnt + 1
      If PingCnt > 400 then
         Exit While
      End If
      Reset LED3                 'Scope timing
      Waitus 5
   Reset LED3                     'Force LED3 Off if Timeout

   'Flash the LEDs on startup
   For LpCnt1 = 1 to 5
     Set LED1
     Waitms 50
     Set LED2
     Waitms 50
     Set LED3
     Waitms 50
     Reset LED1
     Waitms 50
     Reset LED2
     Waitms 50
     Reset LED3
     Waitms 50
   Next LpCnt1

   'Flash an LED at ~ 1 Hz to test the clock.
   'Uses timed delays, not ISR.
      Set LED2
      Waitms 100
      Reset LED2
      Waitms 900
   Return      'Never






  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jay, you are too generous! A real asset to AVRFreaks. I think that this contribution also deserves to be saved in the projects area for future reference. Agree?

Ross McKenzie, Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Ross,


Always good to hear from you.


It was a fun little project.


I hope to get an A in class!


I can repost it in the Projects section, or you can move it.

I don't mean to make work for you, however.


Take care,



  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately Jay I don't have the "god-like" permissions to move it. I could copy it but then it would appear as my project which it isn't. So it appears that you will have to put down the scalpel for a moment and do it yourself. cheeky

Ross McKenzie, Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

valusoft wrote:
I think that this contribution also deserves to be saved in the projects area for future reference. Agree?

I can also agree.


But I'd like to add a note for OP trying to deal with the original question, and the "magic number" that seems to govern the 'trip', and makes it "doesn't work":

 Sometimes it just isn't convenient or practical or possible to hang on a full debugger, or a 'scope, or LA.  In a sanity-check situation such as this, I've been known to use what I call the Poor Man's Datalogger.  Almost all AVR models have onboard EEPROM.  All (or almost all) models will have the capability to Read EEPROM with the ISP facilities.  So, set up some code to log n values to EEPROM.  Depending on the app, it might be the first n passes, or it might be triggered by e.g. button press, or similar.  EEPROM space will soon run out so it needs a limit, generally.


What to log?  In this case it would be "duration", the echo value.  First do it with the "working" clock speed.  Maybe a couple times, since this is a sanity check.  Then do it with the "don't work" clock speed.  Now, how do the values relate?  Was the new magic number made with e.g. division vs. multiplication?  Think that out first.


[edit] Oh, yeah, this will give you practice at decoding a hex dump or similar screenshot of the read-back values and finding the offset of the logging array and marking with a red pen. :)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Fri. Apr 23, 2021 - 01:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great explanation, friend! Thank you.