View previous topic :: View next topic |
Author |
Message |
autoguider
Joined: 24 Sep 2007 Posts: 82 Location: Aachen
|
Posted: Fri Sep 06, 2019 12:23 am Post subject: HC-SR04 on 328p |
|
|
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 |
|
|
Netzman
Joined: 25 Nov 2005 Posts: 127 Location: Graz
|
Posted: Fri Sep 06, 2019 9:08 am Post subject: |
|
|
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 |
|
|
autoguider
Joined: 24 Sep 2007 Posts: 82 Location: Aachen
|
Posted: Fri Sep 06, 2019 2:40 pm Post subject: |
|
|
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 |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Sep 06, 2019 7:28 pm Post subject: |
|
|
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 |
|
|
hgrueneis
Joined: 04 Apr 2009 Posts: 902 Location: A-4786 Brunnenthal
|
Posted: Tue Sep 10, 2019 10:17 am Post subject: SR04 |
|
|
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 |
|
|
autoguider
Joined: 24 Sep 2007 Posts: 82 Location: Aachen
|
Posted: Wed Sep 11, 2019 9:37 pm Post subject: |
|
|
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 |
|
|
laborratte
Joined: 27 Jul 2005 Posts: 299 Location: Berlin
|
Posted: Wed Sep 11, 2019 10:29 pm Post subject: |
|
|
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 |
|
|
autoguider
Joined: 24 Sep 2007 Posts: 82 Location: Aachen
|
Posted: Thu Sep 12, 2019 10:14 pm Post subject: |
|
|
Thanks for the advice.
What do you recommend to read the status of the pin ?
BR
Ch. |
|
Back to top |
|
|
autoguider
Joined: 24 Sep 2007 Posts: 82 Location: Aachen
|
Posted: Thu Sep 12, 2019 10:20 pm Post subject: |
|
|
!in r16, PIND hat geholfen |
|
Back to top |
|
|
|
|
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
|
|