Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 23:31 02 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Micromite V5.04.09 Beta 19

     Page 3 of 5    
Author Message
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 11:00am 19 May 2018
Copy link to clipboard 
Print this post

SOMETHING'S WRONG WITH PWM AND INTERRUPT ON V19!

I used a modified version of this code (Decoding DIGOO remote temperature sensor) for reading my old rain sensor WS7058 (many thanks to disco4now and tassiejim!!!).

Until now I used the V5.04.09 Beta 3 version which worked without problems. The WS7058 rain sensor has shorter bits and another start- and stop behaviour as DIGOO and sends 44 bytes.

Amazingly, the DIGOO sensor still works under Beta 19 - but all I get back from my rain sensor is garbage! I have flashed the PIC several times with Beta 19 and Beta 3 - always with the same result - Beta 3 works perfect, Beta 19 does not work (with the same code)!

I always get less bytes than expected and they are usually wrong!

Here is my code:


' Credits: Tassie Jim for initial decoding code and Gerry Allardice

Dim ProgTitle$ = "Lacrosse RAIN DECODER" '
Dim ProgVer$ = "v1.0.0" '
Dim ProgDate$ = "11-Mai-2018" '
'------------------------------------------------------------------------------'
' The Lacrosse RAIN sensor sends code to the console station via 433.92MHz ASK code.
' It can be decoded by using a 433.92 reciever connected to a digital pin eg(16).

'***
Option Explicit
Option Default NONE
'====================================================================================
' Data Variables
'====================================================================================
Dim tick As INTEGER, tock As INTEGER
Dim code$,codeinv$
Dim D01 As INTEGER
Dim D02 As INTEGER
Dim D03 As INTEGER
'====================================================================================
' Program Initialization
'====================================================================================

Print "Starting " + ProgTitle$ + ": " + ProgVer$ + " - " + ProgDate$

PWM 1, 100000, 50 '100000' this is out high resolution timer which gets connected
'to pin 15
SetPin 15, CIN
SetPin 16, INTL, blip ' triggers on a high to low transition

'====================================================================================
' Main program loop
'====================================================================================

Do
'IF INKEY$<>"" THEN
'PRINT code$
'ENDIF
Loop

End

Sub blip
tock=tick
tick = Pin(15)

Select Case tick-tock

Case > 3000
If Len(code$)=43 Then

Print Mid$( code$, 1, 3);
Print" ";
Print Mid$( code$, 4, 4);
Print" ";
Print Mid$( code$, 8, 4);
Print" ";
Print Mid$( code$, 12, 4);
Print" ";
Print Mid$( code$, 16, 4);
Print" < ";
Print Mid$( code$, 20, 4);
Print" ";
Print Mid$( code$, 24, 4);
Print" ";
Print Mid$( code$, 28, 4);
Print" ";
Print Mid$( code$, 32, 4);
Print" ";
Print Mid$( code$, 36, 4);
Print" > ";
Print Mid$( code$, 40, 4);
Print" - ";


D03 = Val("&b"+Mid$( code$, 20, 12))
Print D03


EndIf
code$=""
codeinv$=""


Case > 2800
code$=""
codeinv$=""

Case > 220
code$ = code$ + "0"
codeinv$= codeinv$+"1"
Case > 110
code$ = code$ + "1"
codeinv$= codeinv$+"0"
Case Else
code$=""
codeinv$=""
End Select

If Len(code$)>44 Then
code$=""
codeinv$=""


Frank
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3292
Posted: 07:56am 20 May 2018
Copy link to clipboard 
Print this post

  Frank N. Furter said  I was irritated by the example on page 36 (I think this example is wrong).
I have not received the error "Error": Variable not declared" but always "Error: Variable type not specified" on the DIM line...

Now I think it should be "DIM INTEGER" Nbr, Incr, Total" in the example are called.....
Frank

I'm a bit confused here. The example on page 36 works as it should, there is no need to declare the variables as integers (they default to floats). The only part of the example that is wrong is the error message which, in later versions, now would be Error: Function or array NR not declared.

Just to be clear, below is a listing of the code and the error message.

> LIST
Option EXPLICIT
Dim Nbr, Incr, Total
Nbr = 1234
Incr = 2
Total = Nr + Incr

> RUN
[5] Total = Nr + Incr
Error: Function or array NR not declared
>


EDIT: I just noticed that the error message should read Error: Function or variable NR not declared. That is something I will investigate but, regardless, you do not need integer variables.

Geoff
Geoff Graham - http://geoffg.net
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3292
Posted: 08:12am 20 May 2018
Copy link to clipboard 
Print this post

  panky said  MMBasic picks up the first argument in a single line multi argument statement but does not pick up subsequent arguments

Thanks, well spotted. I will fix it in the next beta.

Geoff
Geoff Graham - http://geoffg.net
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3292
Posted: 09:05am 20 May 2018
Copy link to clipboard 
Print this post

  Frank N. Furter said   SOMETHING'S WRONG WITH PWM AND INTERRUPT ON V19!
Amazingly, the DIGOO sensor still works under Beta 19 - but all I get back from my rain sensor is garbage! I have flashed the PIC several times with Beta 19 and Beta 3 - always with the same result - Beta 3 works perfect, Beta 19 does not work (with the same code)!

I always get less bytes than expected and they are usually wrong!

Hmm, nothing has changed with both the PWM and interrupt functionality. I will check through the source in detail but I cannot see what could be the issue.

I think that you are going to have to investigate further, one possibility could be that the interrupts are coming too fast and some small change between versions has marginally slowed down the code in your interrupt sub. For example, your interrupt sub has a lot of code in it including PRINT statements - that is not good, interrupts should always be very short. With all that code in there it is quite possible that the interrupts are coming too fast for the program to work reliably

BTW, I could not find the END SUB for your interrupt sub.

Geoff
Geoff Graham - http://geoffg.net
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 12:00am 21 May 2018
Copy link to clipboard 
Print this post

From the MicroMite bible:

"Thou shalt not hang around in interrupts."

What I have taken to doing in interrupts, is just set a flag and exit. That keeps the interrupt very short, and the main loop can just check the flag to see if it needs to do anything. I did learn this the hard way, after making interrupts run the code I wanted to have happen on the interrupt. That is the way your brain wants to do it, but you have to rethink when it comes to interrupts. When I used to do it that way, I had all sorts of odd errors and things not working as they should. Changed it all to just setting flags and exit and have the main loop act on the condition of the flags, and everything then works perfectly.
Smoke makes things work. When the smoke gets out, it stops!
 
GoodToGo!

Senior Member

Joined: 23/04/2017
Location: Australia
Posts: 188
Posted: 03:16am 21 May 2018
Copy link to clipboard 
Print this post

So Grogs, once your main loop has checked for a flag set by an interrupt sub, do you branch it off to another sub where the code is or do you just put it all the code in the main loop?

Cheers,

GTG!
...... Don't worry mate, it'll be GoodToGo!
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2170
Posted: 04:46am 21 May 2018
Copy link to clipboard 
Print this post

  GoodToGo! said   So Grogs, once your main loop has checked for a flag set by an interrupt sub, do you branch it off to another sub where the code is or do you just put it all the code in the main loop?

Cheers,

GTG!


That is one of the great debates and depends on your own programming style

Personally, if a piece of code is only going to be used once, I really don't like having it as a SUB or FUNCTION. It can improve readability of the program though, especially if the relevant bit of code is long.

do what works for you.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 07:53am 21 May 2018
Copy link to clipboard 
Print this post

I have an IF/THEN(ELSE) as part of the main loop, and if the flag is set, the IF/THEN(ELSE) picks up on that, and executes that code. You can have multiple IF/THEN(ELSE) routines inside the main loop, to pick up and act on any of the flags set in any of the interrupts. If the code is really big, then the IF/THEN(ELSE) can call a sub to deal with it, but mainly I just have all I need inside the IF/THEN(ELSE). Or, I have several small subs that you can call one after the other inside the IF/THEN(ELSE) if you need to keep it neat.
Smoke makes things work. When the smoke gets out, it stops!
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 10:02am 21 May 2018
Copy link to clipboard 
Print this post

If something is time consuming you can break it up in several 'states'.
You set a counter to 0 on the beginning and execute some code, then increase the counter. In a loop you check the counter and this will determine which 'state' has to be processed. Each time a step has been done you increase the counter or even set the counter to a specific value to repeat or skip steps.

Especially good if there are large loops and cpu intensive code as you can then easily divide it into smaller blocks. The other parts of the program then also get time to process. It is a way to simulate multi tasking and if it is done quick enough the user will experience it like that.


Microblocks. Build with logic.
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 10:56am 21 May 2018
Copy link to clipboard 
Print this post

@Geoff:

...you are right, there was a copy/paste error in my code. My original code has these two lines at the end:

EndIf

End Sub


Now I can say "MMBasic Ver 5.04.09 Beta 16" works also without problems!!! I can see nothing unusual with my logic analyzer or oscilloscope on the 100Khz PWM and Beta 19...

Did you have another version of MMBASIC which I could try? ...or did you have another idea? Beta 19 does not work every time...
You say you haven't changed anything in the PWM and interrupt functionality - maybe at the counter input?

Frank
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3292
Posted: 02:27pm 21 May 2018
Copy link to clipboard 
Print this post

  Frank N. Furter said  or did you have another idea?

Yes... you should reduce the amount of code in the interrupt.

If I understand the protocol correctly there can be less than 700uS between interrupts which is not enough time to execute all the code that you have in there. Increasing the CPU speed to 48MHz might help but you really need to fix the core problem.

GeoffEdited by Geoffg 2018-05-23
Geoff Graham - http://geoffg.net
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 05:34pm 21 May 2018
Copy link to clipboard 
Print this post

Hi Geoff,

Thanks for the advice! Increasing the CPU speed helps, my old code is now running on Beta 19 (but Beta 16 works without CPU 48). I tried to reduce the code - with the dubious success that the telegrams are received more unstable (many faulty transfers):

' Credits: Tassie Jim for initial decoding code and Gerry Allardice

Dim ProgTitle$ = "Lacrosse RAIN DECODER" '
Dim ProgVer$ = "tst_v1.0.3" '
Dim ProgDate$ = "21-Mai-2018" '
'------------------------------------------------------------------------------'
' The Lacrosse RAIN sensor sends code to the console station via 433.92MHz ASK code.
' It can be decoded by using a 433.92 reciever connected to a digital pin eg(16).

'***
Option Explicit
Option Default NONE
'====================================================================================
' Data Variables
'====================================================================================
Dim tick As INTEGER, tock As INTEGER
Dim code$,codeinv$,completecode$
Dim INTEGER D01,codeok
'Dim INTEGER TrueA=1
'Dim INTEGER FalseA=0
'====================================================================================
' Program Initialization
'====================================================================================

Print "Starting " + ProgTitle$ + ": " + ProgVer$ + " - " + ProgDate$

PWM 1, 100000, 50 '100000' this is out high resolution timer which gets connected
'to pin 15
SetPin 15, CIN
SetPin 16, INTL, blip ' triggers on a high to low transition

'====================================================================================
' Main program loop
'====================================================================================
codeok=0
Do
If codeok=1 Then
Print Mid$( completecode$, 1, 3);
Print" ";
Print Mid$( completecode$, 4, 4);
Print" ";
Print Mid$( completecode$, 8, 4);
Print" ";
Print Mid$( completecode$, 12, 4);
Print" ";
Print Mid$( completecode$, 16, 4);
Print" < ";
Print Mid$( completecode$, 20, 4);
Print" ";
Print Mid$( completecode$, 24, 4);
Print" ";
Print Mid$( completecode$, 28, 4);
Print" ";
Print Mid$( completecode$, 32, 4);
Print" ";
Print Mid$( completecode$, 36, 4);
Print" > ";
Print Mid$( completecode$, 40, 4);
Print" - ";

D01 = Val("&b"+Mid$( completecode$, 20, 12))
Print D01
codeok=0
EndIf
Loop

End

Sub blip
tock=tick
tick = Pin(15)
If codeok=0 Then
Select Case tick-tock

Case > 3000 'end condition
If Len(code$)=43 Then
completecode$=code$
codeok=1
EndIf
code$=""
codeinv$=""

Case > 2800 'start condition
code$=""
codeinv$=""

Case > 220 'read BITs
code$ = code$ + "0"
codeinv$= codeinv$+"1"
Case > 110
code$ = code$ + "1"
codeinv$= codeinv$+"0"
Case Else
code$=""
codeinv$=""
End Select

If Len(code$)>44 Then 'to much BITs
code$=""
codeinv$=""
EndIf
EndIf
End Sub


This is what I get with this code:
Starting Lacrosse RAIN DECODER: tst_v1.0.3 - 21-Mai-2018
100 1010 1010 1100 1001 < 0000 0011 0111 0000 0011 > 0110 - 55
000 1010 1010 1100 1001 < 0000 0011 1000 0000 1011 > 0111 - 56
000 1010 1010 1100 1001 < 0000 0011 1001 0000 0011 > 0111 - 57
000 1010 1010 1100 1000 < 0100 0011 1010 0000 0011 > 1001 - 1082
000 1010 1010 1100 1001 < 0000 1011 1011 0000 0011 > 1010 - 187
000 1010 1010 1100 1000 < 0000 0011 1100 0000 0011 > 1010 - 60
000 1010 1010 1100 1011 < 0000 0011 1101 0000 0011 > 1100 - 61
001 1010 1010 1100 1001 < 0000 0011 1110 0000 0011 > 1101 - 62
000 1010 1010 1100 1000 < 0010 0011 1111 0000 0011 > 1101 - 575
000 1010 1010 1100 1001 < 0000 0100 0000 0000 0101 > 0001 - 64
000 1010 1010 1100 1000 < 0001 0100 0001 0001 0100 > 0001 - 321
000 1010 1010 1100 1000 < 0000 1100 0010 0000 1100 > 0010 - 194
100 1010 1010 1100 1001 < 0000 0100 0111 0000 0100 > 0101 - 71
000 1010 1010 1100 1000 < 0000 0100 1100 0000 0101 > 0100 - 76
100 1010 1010 1100 1001 < 0000 0100 0101 0001 0100 > 0110 - 69
000 1010 1010 1100 1001 < 0000 0100 0110 0000 0100 > 0111 - 70


...the last number should be 55 to 70...

My problem is that I have to wait for the start and end condition, the correct telegram length and the different lengths of "1" and "0"...

If I use the variables "TrueA" for "1" and "FalseA" for "0" instead of "codeok=1" and "codeok=0", the transmission no longer works stable at all!

How can I make this interrupt routine shorter?

Little update:
Case > 3000 'end condition
If Len(code$)=43 And codeok=0 Then
completecode$=code$
codeok=1
EndIf
code$=""
codeinv$=""

works better than "If codeok=0 Then"...

I AM VERY GRATEFUL FOR MORE OF EVERYONE'S TIPS!

Frank
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 06:10pm 21 May 2018
Copy link to clipboard 
Print this post

You could use a FIFO and PUSH values to an array and SHIFT values out of the array.
Your interrupt code will then be very small
[code]
SUB Blip
tock=tick
tick = Pin(15)
Push(tick-tock)
END SUB
[/code]

You would of course have to write some code to make a FIFO or circular buffer, there are lots of examples on internet for that.

The reason for doing this is that you spend very little time in the interrupt routine.
The processing of the data is done elsewhere. As long as your processing is quick enough the FIFO buffer will not overflow. If there is a pause between messages then that will be great as that time can be used to process it.



Microblocks. Build with logic.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 11:56pm 21 May 2018
Copy link to clipboard 
Print this post

  MicroBlocks said   If something is time consuming you can break it up in several 'states'.
You set a counter to 0 on the beginning and execute some code, then increase the counter. In a loop you check the counter and this will determine which 'state' has to be processed. Each time a step has been done you increase the counter or even set the counter to a specific value to repeat or skip steps.

Especially good if there are large loops and cpu intensive code as you can then easily divide it into smaller blocks. The other parts of the program then also get time to process. It is a way to simulate multi tasking and if it is done quick enough the user will experience it like that.



Very clever idea. I will have to remember that one for when simple flags don't do it for me!
Smoke makes things work. When the smoke gets out, it stops!
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3292
Posted: 01:09am 22 May 2018
Copy link to clipboard 
Print this post

Frank,

One possible solution would be to reduce the speed of the PWM. At 100KHz the counting input is kept quite busy counting the input pulses and reducing it to (say) 10KHz would leave more time for the CPU to run your interrupt code. You would also have to reduce the size of the compare constants. For example:
Case > 300 'end condition

Another help would be to make all variables integers (OPTION DEFAULT INTEGER) as integers are about 25% faster than floats in calculations.

Rather than use tick/tock to track the amount of time you can reset the count input to zero just by issuing the SETPIN command again and this would save a little time. For example:
Sub blip
tick = Pin(15)
SetPin 15, CIN
If codeok=0 Then
Select Case tick


For a robust solution I really like MicroBlocks' suggestion. It removes all the intensive code from the interrupt sub. To expand on his code you could use a circular buffer and implement something like this for the interrupt sub.

CONST bufsize = 2000
DIM buf(bufsize), bhead = 0, btail = 0

SUB Blip
buf(bhead) = Pin(15)
SetPin 15, CIN
bhead = bhead + 1
IF bhead = bufsize THEN bhead = 0
END SUB


Then your main program loop would look something like this:
DO
IF bhead <> btail THEN
tick = buf(btail)
btail = btail + 1
IF btail = bufsize THEN btail = 0

SELECT CASE tick
Case > 3000 'end condition
If Len(code$)=43 Then
completecode$=code$
codeok=1
EndIf
code$=""
codeinv$=""

Case > 2800 'start condition
... etc, etc ...


With a buffer size of 2000 interrupts you should be able to keep up with a lot of data. There are a lot of examples of circular buffers on the internet. For example: https://en.wikipedia.org/wiki/Circular_buffer

Note that it is not feasible to debug this code on the forum. If you want to implement this you will have to work out the details yourself.

Geoff
Geoff Graham - http://geoffg.net
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 07:10am 22 May 2018
Copy link to clipboard 
Print this post

@Geoff & Microblocks:

Thank you for your ideas - I will try to put these ideas into practice...

(...and thanks to Geoff for pointing out that "OPTION DEFAULT INTEGER" makes the calculations faster...)

FrankEdited by Frank N. Furter 2018-05-23
 
MikeO
Senior Member

Joined: 11/09/2011
Location: Australia
Posts: 275
Posted: 10:55am 22 May 2018
Copy link to clipboard 
Print this post

I have been reading with interest all the extra tips regards buffers etc. I have also been experimenting with this sensor but as I was adding it to a project that was already processing various other sensors , communications etc I wasn't keen on trying to add the external(from interrupt) circular buffer idea.

I decided to pursue the interrupt processing the pulse timing/storage and found I could reduce the interrupt time by a reasonable amount by making various changes (some of the tips above have also helped).

As a matter of interest I found my RF receiver noise (I imagine fairly typical) was keeping the interrupt pretty busy , to the tune of 29-30 seconds per minute! that's 1/3 of the processors time servicing a this sensor to catch 1 result per minute. I was able to reduce this to around 17 secs a substantial improvement by the following,
1 Use If-then instead of Select Case, largest gain.
2 Remove the "Inverted" code$ from the interrupt.
3 Do the Decoding out of the interrupt in the main loop via a flag.
4 Reducing the Data clock also save a few uSecs.
Changes reduced the interrupt from ~900 uSecs down to ~500 uSecs.

I have not included it in this test code put I plan to disable the interrupt following a successful decode for say 40 secs before it looks for the next transmission leaving the program more resources to handle other tasks.

Mike.

'------------------------------------------------------------------------------'
' Micromite RF Sensor Decoding
' Credits '
' Gerry Allardice
' Tassie Jim for initial decoding code '
'
' ver 1.1
'
Option Explicit
Option Default NONE

'Global variables


'Variables for Digoo Temp/Hum Sensor
dim integer tick2 , tock2 ,blip2flag
dim code2$,digooH$,digooT$

PWM 1, 10000, 50 ' 100uSec interval timer whch gets connected to pin 15
SETPIN 15, CIN
SETPIN 16, INTL, blip2 ' triggers low transition


'main Program Loop
DO
'Digoo processing
if blip2flag=1 then
if left$(code2$,1)="1" then
if mid$(code2$,17,1)="0" then
digooH$=STR$(VAL("&B"+mid$(code2$,30,7)))
digooT$=STR$(VAL("&B"+mid$(code2$,17,12))/10)
else
digooH$=STR$(VAL("&B"+mid$(code2$,30,7)))
digooT$="-" +STR$(VAL("&B"+reverse(mid$(code2$,17,12),12))/10)
end if
blip2flag=0: code2$=""
Print time$;" Hum%:";digooH$;" Temp:";digooT$
end if
end if
LOOP

END


'Digoo Sensor Interrupt
sub blip2
tock2=tick2
tick2 = PIN(15)
if tick2-tock2 > 80 then
if len(code2$)=37 then
blip2Flag=1
else
code2$=""
end if
elseif tick2-tock2 > 35 then
code2$ = code2$ + "1"
elseif tick2-tock2 > 15 then
code2$ = code2$ + "0"
else
code2$=""
end if
'print pin(15)-tick2 'Debug , to time interrup loop
END SUB

'function to "invert" binary string
function reverse(in$,l%)as string
local x%
for x%=1 to l%
if mid$(in$,x%,1)="1" then
reverse=reverse+ "0"
else
reverse=reverse+ "1"
end if
next x%
end function

Codenquilts
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 08:26am 23 May 2018
Copy link to clipboard 
Print this post

Hi Mike,

thanks for your very important notes and your code!

Frank
 
MikeO
Senior Member

Joined: 11/09/2011
Location: Australia
Posts: 275
Posted: 09:24am 23 May 2018
Copy link to clipboard 
Print this post

My curiosity got the better of me so I ran an RF Data interrupt using the circular buffer method to store the timings using this code. I used the same method to time the interrupt as I had used previously. (PWM Clock used was same as previously at 10Khz / 100uSec period.)

SUB Blip
buf(bhead) = Pin(15)
SetPin 15, CIN
bhead = bhead + 1
IF bhead = bufsize THEN bhead = 0
print pin(15) 'Debug , to time interrup loop
END SUB


I was surprised at the the results, expecting a huge reduction compared to the code in my previous post but it was not the case. The interrupt timed at ~300uSecs ( my previous code timed at ~500uSecs) so for my purposes anyway it confirmed the gain would not be sufficient to develop the code to use this method.

MikeEdited by MikeO 2018-05-24
Codenquilts
 
PicFan
Senior Member

Joined: 18/03/2014
Location: Austria
Posts: 133
Posted: 11:16am 07 Jun 2018
Copy link to clipboard 
Print this post

Hello Geoff !

Please, can you help me with this problem ? Please look on this post. Problem

Thank you and best regards !

Wolfgang




 
     Page 3 of 5    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025