Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

HC-SR04 on 328p

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR
View previous topic :: View next topic  
Author Message
autoguider

Bascom Member



Joined: 24 Sep 2007
Posts: 82
Location: Aachen

germany.gif
PostPosted: Fri Sep 06, 2019 12:23 am    Post subject: HC-SR04 on 328p Reply with quote

Dear all,
I want to measure a distance in the range < 1m. Accuracy is not the issue.
The hardware is a 328p on Arduino board
My idea is to use Timer 1 to measure the length of the echo signal.
Echp pin is pind.2 working so that I can use Int0.
Int 0 is configured on change.
In the ISR Timer 1 is started. When the echo is received pin d2 becomes 0 and the interrupt 0 is started.
So far my idea.
for some reason the measured distance - the counter value is 0.

Can you help me to find my error please ?
Here the code:



Code:

$lib "mcs.lbx"
$regfile = "m328pdef.dat"                ' Specify The Used Micro "       ' specify the used micro
$crystal = 16000000                     ' used crystal frequency 0 error in UART
$baud = 19200                           ' use baud rate
$hwstack = 100                          ' default use 32 for the hardware stack
$swstack = 32                           ' default use 10 for the SW stack
$framesize = 150
$dbg

dim W_Distance as word     'Measured result
dim L_Average as long       'Averaging MeAsuring
dim B_counter as byte
dim B_InValid as byte
dim B_Invalid_Counter as byte ' How often invalid
dim W_Upper_limit as word     ' Limit for counter
dim loopcounter as word


config int0 = change
On Int0 Measuring_isr Nosave



config timer1= counter, edge = rising
on timer1 overflow_isr nosave

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

config portd.6 = output
trigger alias portd.6

config pinD.2 = input
Echoes Alias Pinb.2


goto main








main:
      B_counter = 0
      b_InValid=0
      B_Invalid_Counter =0
      W_Upper_limit = 50000
      Loopcounter =0
      enable interrupts
      enable int0
      enable Timer1
      Print "Initialized"


Do
   Trigger = 0                          'Definitely on 0
   Waitms 200
   Trigger = 1                          'Put the trigger on
   Waitus 15                            'Keep signl for 15 µs
   Trigger = 0                          'Trigger signal on 0
   Loopcounter = Loopcounter + 1
   Waitms 1                             'sufficient for 2 m distance



   If W_distance > W_upper_limit Then   ' Measure value too big
      B_invalid =1
      B_Invalid_counter = B_Invalid_counter +1
      else
      B_invalid=0
      B_invalid_counter =0
   end if

   If B_invalid_counter = 8 Then        'after 8 cosecutive too big values there is something wrong
      Print " Max. Dist. Exceeded"
      B_invalid_counter =0
   end if


   if b_invalid=0 then
      If B_counter < 5 Then             'adding 4 correct maeasurements
       l_average =L_average + W_distance
       b_counter = b_counter+1
      end if
      Print "W= ";
      Print W_distance;
      Print " ";
      Print Loopcounter

    end if


    if b_counter =5 then
       Shift L_average , Right , 2      'Divide by 4
       b_counter =0
       print l_average
       l_average=0
       b_counter =0
    end if

    B_invalid=0

loop






$asm
Measuring_ISR:

   push r15                          'r 15 to Stack
   in r15,sreg                       'Read Statusregister  R15
   push r15                          'Statusregister to Stack
   push r16                          'r 20 to Stack
   push r30                          'Z- Register
   push r31






!in r16,PortD              ' Load PortD
Andi r16,&b00000100                     ' Mask PD2

cpi r16,&B000000100        ' Bit High ?
brne    stop_timer         ' Bit Low -> Stop Timer
ldi r16,0
!out TCNT1H, R16           ' Counter registers =0
!out TCNT1L, R16
LDI r16, &B000000010
!out TCCR1B, r16                        ' Start Timer1; Prescale=8
jmp end_Measuring_ISR      ' jmp to end of ISR

stop_timer:
ldi r16,0
!out TCCR1B, r16                        ' Timer1 stopped
Loadadr W_distance, Z      ' Copy TCNT to W_distance
!in r16, TCNT1L
St Z  ,r16
!in r16, TCNT1H
st Z+1, r16

end_Measuring_ISR:



  pop r31
  pop r30                          'Z- Register
  pop r16                          'Stack to r20
  pop r15                          'Statusregister from Stack
 !out sreg , r15                        'Write R15 to Statusregister, r15
  pop r15                          'Reestablish r15

reti
$end asm






Overflow_isr:

B_invalid_counter = B_invalid_counter + 1

Return

End
 


BR
Christian

(BASCOM-AVR version : 2.0.8.1 , Latest : 2.0.8.2 )
Back to top
View user's profile
Netzman

Bascom Expert



Joined: 25 Nov 2005
Posts: 131
Location: Graz

austria.gif
PostPosted: Fri Sep 06, 2019 9:08 am    Post subject: Reply with quote

The timer is configured in Counter mode, which counts external pulses. You'd want to use it in Timer mode.

But I find the description of the HC-SR04 misleading. On trigger, they send out an ultrasonic chirp at 40 KHz with 8 periods, then the echo pin is asserted. When the receiver receives the first pulse of the chirp back (confirmed with the scope, here I am not quite sure, maybe the controller waits for the second pulse to check if they match 40KHz), the echo pin is deasserted. So that really means, the pulse duration of the echo pin goes from the END of the TX burst to the BEGINNING of the RX burst. But the time it takes for the chirp to travel through the air is measured between the start of TX and start of RX.
So the pulse proportional to the distance is shortened by the time it takes to send the chirp (8 periods @ 40 KHz = 0.2 mS @ 340 m/S => 6.8 cm). So far my theory, I still have to confirm this with a test stand.

Br

_________________
LCD Menu | Proportional Fonts
Back to top
View user's profile Visit poster's website
autoguider

Bascom Member



Joined: 24 Sep 2007
Posts: 82
Location: Aachen

germany.gif
PostPosted: Fri Sep 06, 2019 2:40 pm    Post subject: Reply with quote

So there may be a systematic error in the measurement.
I was searching in the internet but it is still not clear to me.

Thanks for the advice with the timer.
Then I can understand why I receive the value of 0.
I just need the function that the timer starts counting.

In case you have some experience with the sensor:
Can I connect 3-4 sensors with their Echo -pins to start Int0 ?
They will be triggered with a time lap of 500ms between each sensor.

BR
Christian
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 2262

blank.gif
PostPosted: Fri Sep 06, 2019 7:28 pm    Post subject: Reply with quote

Netzman wrote:
The timer is configured in Counter mode, which counts external pulses. You'd want to use it in Timer mode.

That's not the issue, he switches to timer mode within the ISR:
Code:
LDI r16, &B000000010
!out TCCR1B, r16                        ' Start Timer1; Prescale=8

This is not true, at least in Earth's atmosphere:
Code:
Waitms 1                             'sufficient for 2 m distance

It would be sufficient for 17cm.

I suggest to use PulseIn(), watch the values returned and then build up the ISR-version.
Back to top
View user's profile
hgrueneis

Bascom Member



Joined: 04 Apr 2009
Posts: 902
Location: A-4786 Brunnenthal

austria.gif
PostPosted: Tue Sep 10, 2019 10:17 am    Post subject: SR04 Reply with quote

The SR04 has to be triggered with a minimum of a 10us positive pulse. Then it sends eight pulses. When the pulses are sendt, it waits to receive the eight pulses, if it does not, then it errors out after 25 milliseconds. It should only be retriggered every 50 ms. The echotime is output as a positive pulse and needs to be divided by two, to give a very accurate pulsetime, which can be calculated fairly simple into distance. Functionality is usually between 1 cm and 4 m (some 4.5 m). In comparison, the SR05 has five pins instead of four (extra out-pin). Bascom is also fast enough to not need any ASM, actually for me a mcu clock of 8MHz and a timer prescale of eight works well for me.
The echo will also vary in time with altitude, humidity, temperature and a changing airpressure.
If it needs to be perfect, all sensors for these functions need to be implemented.
Best regards
Hubert
Back to top
View user's profile
autoguider

Bascom Member



Joined: 24 Sep 2007
Posts: 82
Location: Aachen

germany.gif
PostPosted: Wed Sep 11, 2019 9:37 pm    Post subject: Reply with quote

many thanks for your replies.
As you may see I modified the code using your advice.
Code:

$lib "mcs.lbx"
$regfile = "m328pdef.dat"                ' Specify The Used Micro "       ' specify the used micro
$crystal = 16000000                     ' used crystal frequency 0 error in UART
$baud = 19200                           ' use baud rate
$hwstack = 100                          ' default use 32 for the hardware stack
$swstack = 32                           ' default use 10 for the SW stack
$framesize = 150
$dbg

dim W_Distance as word     'Measured result
dim L_Average as long       'Averaging MeAsuring
dim B_counter as byte
dim B_InValid as byte
dim B_Invalid_Counter as byte ' How often invalid
dim W_Upper_limit as word     ' Limit for counter
Dim Loopcounter As Word
Dim W_interrupt_counter As Word


Declare Sub Init
Config Int0 = Change

On Int0 Measuring_isr Nosave
'On Int0 Measuring_2



config timer1= timer, clear Timer =1, compare_a = disconnect
on oc1a overflow_isr nosave

Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

config portd.6 = output
trigger alias portd.6

config pinD.2 = input
Echoes Alias Pinb.2


goto main

Sub Init
      B_counter = 0
      B_invalid = 0
      B_invalid_counter = 0
      W_interrupt_counter = 0
      W_upper_limit = 50000
      Compare1a = 50000

      Loopcounter = 0
      enable interrupts
      Enable Int0
      Enable Timer1
      Enable Compare1a
      Print "Init ok."



End Sub







Main:

Call Init

Do
   Trigger = 0                          'Definitely on 0
   Waitms 500

   Trigger = 1                          'Put the trigger on
   Waitus 15                            'Keep signal for 15 µs
   Trigger = 0                          'Trigger signal on 0
   Loopcounter = Loopcounter + 1
   Waitms 100                           'sufficient for 2 m distance



   If W_distance > W_upper_limit Then   ' Measure value too big
      B_invalid =1
      B_Invalid_counter = B_Invalid_counter +1
      else
      B_invalid=0
      B_invalid_counter =0
   end if

   If B_invalid_counter = 8 Then        'after 8 cosecutive too big values there is something wrong
      Print " Max. Dist. Exceeded"
      B_invalid_counter =0
   end if


   if b_invalid=0 then
      If B_counter < 5 Then             'adding 4 correct maeasurements
       l_average =L_average + W_distance
       b_counter = b_counter+1
      end if
      Print "W= ";
      Print W_distance;
      Print " Loop = ";
      Print Loopcounter
      Print "ISRs  = ";
      Print W_interrupt_counter
    end if


    if b_counter =5 then
       Shift L_average , Right , 2      'Divide by 4
       b_counter =0
       print l_average
       l_average=0
       b_counter =0
    end if

    B_invalid=0

loop







Measuring_isr:

 $asm
   push r15                             'r 15 to Stack
   in r15,sreg                       'Read Statusregister  R15
   push r15                          'Statusregister to Stack
   push r16                          'r 20 to Stack
   push r30                          'Z- Register
   push r31
   cli

'(
TCCR1A

 Bit      7      6     5      4    3 2   1     0
0x80  COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
          0     0     0       0    0 0  0      0    ')




'TCCR1B  for CTC Mode
'Bit     7     6    5   4     3     2    1   0
' (0x81) ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
'         0     0   0  0 (1)  1     0   1    0
 ')
$end Asm

W_interrupt_counter = W_interrupt_counter + 1

$asm

!in r16,PortD              ' Load PortD
Andi r16,&b00000100                     ' Mask PD2

cpi r16,&B000000100        ' Bit High ?
brne    stop_timer         ' Bit Low -> Stop Timer
ldi r16,0
!out TCNT1H, R16           ' Counter registers =0
!out TCNT1L, R16

!in r16,tccr1b
orI r16, &B000000010
!out TCCR1B, r16                        ' Start Timer1; Prescale=8
jmp end_Measuring_ISR      ' jmp to end of ISR

stop_timer:
in r16,tccr1b
andi r16,&B11111000        'set CS12,CS11,CS10 to 0-> stop
!out TCCR1B, r16                        ' Timer1 stopped
Loadadr W_distance, Z      ' Copy TCNT to W_distance
!in r16, TCNT1L             ' Low-Byte 1st read
St Z  ,r16
!in r16, TCNT1H             ' High-Byte 1st read
st Z+1, r16              '

end_Measuring_ISR:



  pop r31
  pop r30                          'Z- Register
  pop r16                          'Stack to r20
  pop r15                               'Statusregister from Stack
 !out sreg , r15                        'Write R15 to Statusregister, r15
  pop r15                               'Reestablish r15
  sei
reti
$end asm






Overflow_isr:

B_invalid_counter = B_invalid_counter + 1

Return

Testansw:
!cli
Print "K"
!sei
Return


End


For testing I included W_interrupt_counter in the Int0 ISR. So I can see how often the ISR is executed.

results:
Code:

=~=~=~=~=~=~=~=~=~=~=~= PuTTY log 2019.09.11 21:29:24 =~=~=~=~=~=~=~=~=~=~=~=


Init ok.
W= 0 Loop = 1
ISRs  = 4                      why 4 ?  triggered 1 time only
W= 0 Loop = 2
ISRs  = 6
W= 0 Loop = 3
ISRs  = 8
W= 0 Loop = 4
ISRs  = 10
W= 0 Loop = 5
ISRs  = 12
0
 

Getting Int0 2 times per loop is o.k. to my opinion because Int0 is programmed to external changes . ( I hope ).
So there is the rising slope when the bursts are send out and the falling slope when the echo arrives.
Does this triggering make sense ?
Still there is no distance measured. Which means that timer 1 is not started.
I may have a wrong understanding on the function of the sensor.
Triggering is done with a 15µs positive pulse every 600 ms. Which is comfortable. I do not think that r30/r31 do interefere long with the waitms command.
TCCR1B is also handled with care In case PD.2 is High CS11 bit is set to 1. The other bits of TCCR1B remain unchanged. WGM12 needs to be set to 1 to run timer 1 in CTC mode.
The 25 ms as timing out corresponds to appr. 4 m measured distance.
For the 2 x 4 meters runtime Timer 1 will count to 50000 @ 16 MHz clock and prescale 8.
Thats why I program the time out control.

There must be a logic reason why the setup does not work.
Advice is highly appreciated.

best regards
Christian
Back to top
View user's profile
laborratte

Bascom Expert



Joined: 27 Jul 2005
Posts: 299
Location: Berlin

germany.gif
PostPosted: Wed Sep 11, 2019 10:29 pm    Post subject: Reply with quote

Some notes to your code:

a) SEI and CLI are not nessesary in your ISR, they are managed by the MCU.
b) you should finish your ISR with a RETURN statement (after $end asm). The compiler may drives nuts when a RETURN is not found - the RETI will set automaticly. (Not shure if this is still a behaviour. I remember problems with that when I startet with BASCOM in 2001... dammend, I'm getting old...)
c) external INTs are very sensitive for noise. If your signal is not 100% perfect the ISR will be executed twice. This happens because the flag is cleared just at the beginning of the ISR. Any bouncing will reset the flag while the ISR is running and leads into a repeated call direct after the ISR is finished. Thats why these INTs are not usefull for pushbuttons...
d) if you are using BASCOM statements you can not use "NOSAVE", as you don't know which register are used:
Code:

(...)
Measuring_isr:
(...)
$end Asm
W_interrupt_counter = W_interrupt_counter + 1
$asm
(...)
 


last but not least:

e) you will never get the state of your PIN with reading the PORT register:

Code:
(...)
!in r16,PortD              ' Load PortD
Andi r16,&b00000100                     ' Mask PD2

cpi r16,&B000000100        ' Bit High ?
brne    stop_timer         ' Bit Low -> Stop Timer
ldi r16,0
(...)
Back to top
View user's profile
autoguider

Bascom Member



Joined: 24 Sep 2007
Posts: 82
Location: Aachen

germany.gif
PostPosted: Thu Sep 12, 2019 10:14 pm    Post subject: Reply with quote

Thanks for the advice.
What do you recommend to read the status of the pin ?

BR
Ch.
Back to top
View user's profile
autoguider

Bascom Member



Joined: 24 Sep 2007
Posts: 82
Location: Aachen

germany.gif
PostPosted: Thu Sep 12, 2019 10:20 pm    Post subject: Reply with quote

!in r16, PIND hat geholfen
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum