PDA

View Full Version : Delay without using pause



Scampy
- 26th April 2015, 18:40
I'm developing one of my old projects and I've hit a stumbling block. The old code simply read 4 x DS18B20's and use the data to control the out put to a heat via Henrik's PID routine. It's been working fine for 5 years now, but I want to add 4 x AM2302's to monitor the humidity and also monitor the temperature in its location. The code includes DT's interrupts, DS18B20, and all digital "library files", and thus a lot of the timings for the period each heater is on is done in the background, and the main code consists of a simple loop that reads the sensors and does the maths.

However with four sets of information for each of the four viavriums the 20 x 4 LCD is becoming a little crowded. So what I really want to do is to display Viv(x), temp1, humidity1, temp2 on a single line on the LCD. No problem in coding the line to do this, but as the program runs so fast through the data it's impossible to read. The simple way is to add a pause statement so for example the code pauses for 2 seconds before retuning to the main program loop and advancing on to the next set of data. But this then delays the speed at which the probes are monitored and by the time the loop is back to probe 1 the temperature could of gone past the set point, as it's not monitored in real time.

My hair is now white, and I'm half bald trying to resolve this - the nearest I came was to use some form of counting loop within the main loop, that when it tripped over a set value it increased the value of viv(x) by one, so in essence the main code ran at real time speed, but the LCD was only updated every second or so and thus wouldn't hold up the realtime monitoring. Unless any of you guys can come up with a better suggestion

Archangel
- 26th April 2015, 19:30
Hi Malcom,
Real time in Human terms is as fast as you can read. Who cares if the machine detects something faster, you cannot respond that fast, so the LCD is much like watching the evening news. What you "might" do is allow "the machine" to run several cycles and then report via LCD the average of those cycles.

Tabsoft
- 26th April 2015, 20:15
Malcolm,

I think you're on the right track.

something like this?



LCDCount_Max con 3000 'Set to what you want

LCDCount var word
LCDUpdate var bit

goto Main

UpdateLCD:
'do your LCD Update stuff here

return

Main:
LCDCount = 1 'Used to display the first time

CycleLoop:
if LCDUpdate then
gosub UpdateLCD
LCDUpdate = 0
endif

''do your normal polling stuff here

'' Then do the LCD test stuff here
LCDCount = LCDCount - 1
if LCDCount = 0 then
LCDCount = LCDCount_Max
LCDUpdate = 1
endif


goto CycleLoop

Scampy
- 26th April 2015, 20:34
Cheers Ken,

I'll have a play..... failing that I'll look for an 40 x 4 LCD which might make things easier :)

Acetronics2
- 26th April 2015, 20:57
Hi, Malc

I don't remember your program, but why not use the time the DS1820s make their measure/conversion to update the LCD, instead of waiting for conversion complete ???

Alain

Tabsoft
- 30th April 2015, 00:53
Malcolm,

You could also do this via a Timer Interrupt using DT's Instant Interrupts.
Say, Timer2 (8bit timer) with both a Prescaler and Postscaler, then in the ISR decrement a word variable that is preset to a number that gets you to 3 seconds or whatever time you want. When the var reaches zero set a flag to run the display routine and reset the word var back to your preload value. In your main loop test for the flag and call the display routine if set and then clear the flag.

This would allow you to hit a time-based delay much easier.

Dave
- 30th April 2015, 18:07
Why not just count the number of data updates and after so many, Update the display with a different set of data? That way you won't slow down the data taking and control timing and you will get a "cycling" data display you want. That way there is no need for a delay of any type.

Scampy
- 30th April 2015, 19:40
Thanks for the suggestions guys.

Dave, your suggestions sounds simple enough for me to understand. I guess I could have a variable that is updated every time the program goes around the main loop, then when it reaches a certain value display one set of data for the 1st probe, then when reaches another it displays the second set etc... I'll have a look at implementing that. I guess that provided the program doesn't loop more than 65535 times in 8 seconds then I will be able to use a word variable and each update would be visible for 2 seconds

Archangel
- 1st May 2015, 02:42
Thanks for the suggestions guys.

Dave, your suggestions sounds simple enough for me to understand. I guess I could have a variable that is updated every time the program goes around the main loop, then when it reaches a certain value display one set of data for the 1st probe, then when reaches another it displays the second set etc... I'll have a look at implementing that. I guess that provided the program doesn't loop more than 65535 times in 8 seconds then I will be able to use a word variable and each update would be visible for 2 seconds
And . . . . if you average several samples of each you would see it displayed longer, side bonus a "flier" reading would not upset you as much when averaged than it will if not averaged or discarded.

rsocor01
- 1st May 2015, 14:40
I guess that provided the program doesn't loop more than 65535 times in 8 seconds then I will be able to use a word variable and each update would be visible for 2 seconds

Since you are using DT interrupts, another approach would be to use a variable to count every time the program goes to the interrupt routine. After so many hits, then you update the LCD display. Depending on how long you set the time intervals for the interrupts, this might be a "cleaner" solution.

Scampy
- 1st May 2015, 17:06
Guys, thanks for your continued input.

I've hit a hurdle and it's doing my head in. In the original code the readings from the 4 sensors were displayed constantly on the LCD, so within the main program loop there is a for next loop which runs through and reads the 4 DS18B20's and puts the results into a 4 line array. This results in a fast response in updating the display when temperatures change. Now that I'm also reading an AM2302 and want to display data from that too, the LCD looks cluttered if I follow the same method, hence my idea of displaying the readings from each vivarium on a single line, which would overwrite the values for each vivarium every few seconds. The problem is that if I opt to change this so the for next loop which reads the sensors is changed so that it reads sensor 1 and then goes to a subroutine to display the results for two or three seconds it means that it can take 8 - 12 seconds to go round the loop to read all four sensors, which defeats the object of having fast response times, and in 12 seconds the temp in the vivarium could become dangerously high as this would effect the PID timings.

I think to only option is to use two 20 x 4 LCD's or one 40 x 4 LCD, or possibly a GLCD

Tabsoft
- 1st May 2015, 19:13
Can you post a mockup of your display in text and how you use it and how you see using it?

Scampy
- 1st May 2015, 20:28
This was the best match, but I have no room to display the time.

7808

This is what I'm trying to achieve

7809

With line 2 being updated with data for Viv2, Viv3 etc

Art
- 2nd May 2015, 08:34
"which would overwrite the values for each vivarium every few seconds. “

It sounds like you just need to overwrite the appropriate value into the 4 line buffer instead of updating the whole display buffer for every variable,
or update the LCD location directly, but I would do the former, and write a complete screen every time.

Art
- 2nd May 2015, 11:48
Does viv mean vivarium? Before you listen to me you should see how professional my setup is :D
I like the way the LCD doesn’t have a backlight so I faked it with an LED.

http://img.photobucket.com/albums/v186/ArtArt/LightRig5_zps0gvtvusv.jpg

http://img.photobucket.com/albums/v186/ArtArt/Picture%20006_zpszwcwd6fq.jpg

Scampy
- 2nd May 2015, 12:38
Nice Beardie -

yes Viv is for vivarium, currently have a custom unit of three vivs, plus an incubator as my to royals have been locked several times over the past few months. Here's the incubator, and the existing controller, which is a bit neater than your set up :) - but hey if it works for you that's the main thing :)

http://www.micro-heli.co.uk/inc.jpg

Art
- 2nd May 2015, 18:43
Well it did six yrs ago :D

Can you post the main code that prints to LCD?

There are a lot of ways to solve it.
I think I only now properly understand the issue.

Padding has already been suggested and is one good way.
Using a word variable you could mean average quite a few
temperature readings.

Scampy
- 2nd May 2015, 21:34
LOL - same time as I did mine - so you have no excuses :)

I've messed around with the version where I was trying to get a single line for the data from each vivarium that's it's all over the place. So I've posted the previous version which displays the data for all four vivariums, 1 per line of the LCD



;-----------------------------------------------------------------------------
; ***** MAIN PROGRAMMING LOOP *****
;-----------------------------------------------------------------------------

Main:


SetPoint1 = normtemp1
SetPoint2 = normtemp2
SetPoint3 = normtemp3
SetPoint4 = normtemp4

gosub FlushBuffer:

If SetButton=0 then ; jump to programming
Gosub SetButtonRelease
goto mainmenu
endif

If DecButton=0 then
Gosub SetButtonRelease
goto lightoveride ; manual overide of light
endif

If IncButton=0 then
Gosub SetButtonRelease
goto cancelalarm ; manual overide of alarm
endif

gosub read_dht ; Go and read the AM2302 sensor for humidity

FOR pid_Channel = 0 TO 3 ; cycle thru all sensors
GOSUB SelectSensor
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Convert ; start a temperature conversion
GIE = 1 ; enable interrupts after 1-wire
NEXT pid_Channel

FOR TempWD = 0 TO 1000
IF RCIF=1 THEN GOSUB coms ; Check to see id PC application connected
PAUSE 1
NEXT TempWD

FOR pid_Channel = 0 TO 3 ; cycle thru all sensors
GOSUB SelectSensor
DS1820_Error = 0 ; clear any previous errors
DS1820_Flags = 0 ; clear status flags
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Stat ; check the sensors status
GIE = 1 ; enable interrupts after 1-wire
PAUSEUS 20
IF !DS1820_Done THEN SensorError ; if it's not done by now, error
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Read ; get the temperature result
GIE = 1 ; enable interrupts after 1-wire
GOSUB Check4Zeros

DS1820_Flags = 0
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Stat
GIE = 1 ; enable interrupts after 1-wire
IF (DS1820_Error = 0) AND DS1820_Done THEN ; if there were no errors
Temperatures(pid_Channel) = TempC
pid_Error = SetPoints(pid_Channel) - TempC
GOSUB PID
IF pid_Out.15 THEN pid_Out = 0 ; only keep positive values
IF ChannelPWR(pid_Channel) THEN
HeaterDrives(pid_Channel) = pid_Out
ELSE
HeaterDrives(pid_Channel) = 0
ENDIF
IF Temperatures(pid_Channel) > alarmhigh(pid_Channel) and Alarm = 1 then AlarmPin = 1
IF Temperatures(pid_Channel) > alarmhigh(pid_Channel) and Alarm = 0 then AlarmPin = 0
IF Temperatures(pid_Channel) <= alarmhigh(pid_Channel) then AlarmPin = 0
IF Temperatures(pid_Channel) <= alarmlow(pid_Channel) then AlarmPin = 0
if Temperatures(pid_Channel) < alarmlow(pid_Channel) and Alarm = 1 then AlarmPin = 1
if Temperatures(pid_Channel) < alarmlow(pid_Channel) and Alarm = 0 then AlarmPin = 0

GOSUB ShowLCD ; display info on LCD

ELSE
SensorError:
HeaterDrives(pid_Channel) = 0 ; turn off heater if sensor's bad
SensorActive(pid_Channel) = 0
GOSUB ShowError ; display error message
ENDIF
NEXT pid_Channel

; ---------------------------------------------------------------------------
; check lighting periods and turn lights on or off accordingly
; ---------------------------------------------------------------------------

fn = 0 ; select the first Lights
if lightover = 0 then GOSUB CheckTimes ; if manual override set to off then go compare the programed period
if lightover = 1 then progON=1 ; if manual override flag set to on then lights on flag set to 1
IF ProgON THEN ; If in the program period
IF Lights1 = 0 THEN Lights1 = 1
ELSE
IF Lights1 = 1 THEN Lights1 = 0
ENDIF

fn = 1 ; select the second Lights
if lightover = 0 then GOSUB CheckTimes ; compare the programed period
IF ProgON THEN
IF Lights2 = 0 THEN Lights2 = 1
ELSE
IF Lights2 = 1 THEN Lights2 = 0
ENDIF

; ---------------------------------------------------------------------------
; Check for night time drops - if condition matched, drop temp
; ---------------------------------------------------------------------------

fn = 0 ; select the first setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[0]=Droptemp[0] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[0]= normtemp[0] ; change the corresponding drop temperature to set point
ENDIF

fn = 1 ; select the second setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[1]=Droptemp[1] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[1]= normtemp[1] ; change the corresponding drop temperature to set point
ENDIF

fn = 2 ; select the third setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[2]=Droptemp[2] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[2]= normtemp[2] ; change the corresponding drop temperature to set point
ENDIF

fn = 3 ; select the fouth setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[3]=Droptemp[3] ; change the corresponding set point to the drop temperature
ELSE
Setpoints[3]= normtemp[3] ; change the corresponding drop temperature to set point
ENDIF

for x = 0 to 3
LOOKUP x,[5,9,13,17],Bvar ; Find location [$80,$C0,$89,$C9]
LCDOUT $fe,$80,"Set"
LCDOUT $fe,$80+Bvar,#setpoints(x)dig 2,#setpoints(x)dig 1 ; print to LCD
LCDOUT $DF
next x
;-----------------------------------------------------------------------------
; ***** MAIN PROGRAMMING LOOP END *****
;-----------------------------------------------------------------------------


GOTO Main

;------------------------------------------------------------------------------


Then this is the subroutine which displays the data on the LCD



;----[Display temperatures, time and set points on LCD]------------------------
ShowLCD:

LCDOUT $FE,$C0,"Hot"
LCDOUT $FE,$C0+5 ; print to LCD
TempWD = TempC : GOSUB TempToLCD ; display TempC
LCDOUT $DF ; deg symbol

I2CRead SDApin,SCLpin,$D0,$00,[RTCSec,RTCMin,RTCHour,RTCWDay,RTCDay,RTCMonth,RTCY ear,RTCCtrl] ; read DS1307 chip
If RTCHour.6=1 then

CounterA=(RTCHour>>4)&$01 ' Work-Out 12 or 24 hour Display for Hours
else
CounterA=(RTCHour>>4)&$03
endif
CounterA=CounterA*10+(RTCHour&$0F) ' Display Hours appropriately for 12 or 24 hour Mode

'********* to display time on LCD ***************** Commented out as there is no room on the LCD
'If RTCHour.6=1 then
'LCDOut $FE,$C0+9,"Time ",#CounterA
'else
'LCDOut $FE,$C0+9,"Time ",#CounterA Dig 1,#CounterA Dig 0
'endif
'LCDOut ":",#(RTCMin>>4)&$0F,#RTCMin&$0F
'************************************************* **

timeH=(RTCHour>>4) 'convert the BCD format of the hours register and store in variable timeH
timeH=(timeH &$03)*10
timeH=timeH+(RTCHour&$0F)

timeM=(RTCMin>>4)
timeM=(timeM &$07)*10
timeM=timeM+(RTCMin&$0F) 'convert the BCD format of the mins register and store in variable timeM

;----[ Time matching - Nighttime temp drop routine ]-----

CheckTimes2:
TimeCmpFlags = 0 ; clear flags first

; if the Start and Stop times are the same, then Always OFF
if (StartHour[fn]=StopHour[fn]) AND _
(StartMin[fn]=StopMin[fn]) then AlwaysOFF2

; is it past the Start time?
if (timeH>StartHour[fn]) OR _
(timeH=StartHour[fn] AND timeM >= StartMin[fn])then PastStart2=1

; is it past the Stop time?
if (timeH>StopHour[fn]) OR _
(timeH=StopHour[fn] AND timeM >= StopMin[fn])then PastStop2=1

; does the period end the following day?
if (StopHour[fn]< StartHour[fn]) OR _
(StopHour[fn]=StartHour[fn] AND StopMin[fn] < StartMin[fn]) then NextDay2=1

if !NextDay2 then ; same day, use AND
if PastStart2 AND !PastStop2 then ProgON2 = 1
else ; next day, use OR
IF PastStart2 OR !PastStop2 then ProgON2 = 1
endif

AlwaysOFF2:
return

CheckTimes:
TimeCmpFlags = 0 ; clear flags first

; if the Start and Stop times are the same, then Always OFF
if (lightsetHR[fn]=lightoffHR[fn]) AND _
(lightsetMN[fn]=lightoffMN[fn]) then AlwaysOFF

; is it past the Start time?
if (timeH>lightsetHR[fn]) OR _
(timeH=lightsetHR[fn] AND timeM >= lightsetMN[fn])then PastStart=1

; is it past the Stop time?
if (timeH>lightoffHR[fn]) OR _
(timeH=lightoffHR[fn] AND timeM >= lightoffMN[fn])then PastStop=1

; does the period end the following day?
if (lightoffHR[fn]< lightsetHR[fn]) OR _
(lightoffHR[fn]=lightsetHR[fn] AND lightoffMN[fn] < lightsetMN[fn]) then NextDay=1

if !NextDay then ; same day, use AND
if PastStart AND !PastStop then ProgON = 1
else ; next day, use OR
IF PastStart OR !PastStop then ProgON = 1
endif

AlwaysOFF:
RETURN


The two subroutines that deal with displaying the non presence of a 18B20 and read the AM2302



;----[Display Sensor Error]-------------------------------------------------

ShowError:
LOOKUP pid_Channel,[5,9,13,17],Bvar ; Find location;LOOKUP pid_Channel,[$83,$C3,$8B,$CB],Bvar [$80,$C0,$89,$C9]
LCDOUT $FE,$C0+Bvar,"N/C" ; print to LCD ;LCDOUT $FE,Bvar," N/C "
RETURN

;----[Read humidity sensor]-------------------------------------------------

read_dht:

for loopcount = 0 to 3
AM2302_Sensor_Num = loopcount+1
gosub AM2302_Read
LOOKUP loopcount,[5,9,13,17],Bvar ; Find location [$80,$C0,$89,$C9]
LCDOUT $fe,$94,"Hum"
LCDOUT $fe,$94+Bvar,dec AM2302_Hum/10,"% "' ".",dec AM2302_Hum//10,"% " ; print to LCD
LCDOUT $fe,$D4,"Cold"
LCDOUT $fe,$D4+Bvar,dec AM2302_Temp/10
lcdout $DF
next loopcount

Return


I hope that's enough for you to be going on with. ?

Malc

Art
- 3rd May 2015, 04:11
You were saying if the program is allowed to go it’s hardest the temps change so fast you can’t read them,
and your mock display only shows integer values which means the sensor moves back & forth several entire degrees each reading?

If you let it go with no unneeded pauses, how many times would you guess the LCD is updated in one second?

To clarify, you check for death temperatures, and print to LCD straight after, so the temps are degrees C by that time?
That would be a good place for a FIFO buffer to store several previous values for averaging.

From what I understand the problem, if you had no deliberate pause statements,
everything would be great if the temp sensors didn’t give values all over the place
because even thought the LCD updated fast the temps wouldn’t change much?

Scampy
- 3rd May 2015, 12:39
I discovered what was happening. As I only have one DS18B20 used for testing, the code was running the fore next loop to read the sensors and then printing them to the screen, but as the last three were not fitted it would jump out to the sensor error and display N/C for the for vivs 2, 3 and 4. I also removed the decimal for the temps and humidity simply to make things fit on the display.

In trying to get the LCD to display the data for viv 1 for a few seconds, then viv 2 etc I tried using case statements, and the Cvar as a counter. The idea being if the counter is between 1 and 10 it jumps to a case statement which displays data for viv 1, if it's between 11 and 20 viv 2 etc. Again that didn't work because it had to be a sub routine in order to jump back and test for sensor error.

The problem I have in using pause statements is in order to maintain stable temperatures in the vivs, the original code was designed to run through the reading of the sensors, calculating the PID (which was based on real life testing to calibrate the values) and drive the heaters. This works well and I would like to retain that precision, and any pause statements end up delaying the read, display and update process which means the precision is lost.

The DS18B20 and AM2302 are precise to within 0.5c so the data is stable. As we are only talking + or minus a degree or so being the difference between the PID pulsing correctly or being fully on or completely off, any delay between the read sensor cycle could mean that the heater stays on longer and the temperature overshoots. The result would be that the swing between pulses would be similar to a standard on/off thermostat rather than a pulse proportional one.

Scampy
- 3rd May 2015, 14:17
Even basic logic doesn't seem to work !!!

I have set Cvar as byte and to run from 1 to 40. I then have the following



if Cvar => 1 or Cvar =< 10 then
viv=0
goto showLCD1
endif

if Cvar =>11 or Cvar =< 20 then
viv=1
goto showLCD2
Endif


Then the following for the display



ShowLCD1:

LCDOUT $FE,$C0,"Viv",DEC1 viv +1," " ; print to LCD
LCDOUT $fe,$94,dec cVar
goto check

ShowLCD2:

LCDOUT $FE,$C0,"Viv",DEC1 viv+1," " ; print to LCD
LCDOUT $fe,$94,dec cVar
goto check


So the LCD should in theory display VIV1 and then when Cvar =11 VIV2. It doesn't !!!

Cvar is counting up at around 1 second intervals, and there is an If Cvar >20 then Cvar =1 so it loops round, which it does. So why the hell does it ignore the IF THEN statement to match the condition and goto the correct LCD display section ! - Sometimes I hate PBP !!!!

EDIT... seems it likes if Cvar =>11 and Cvar =< 20 then... rather than OR

Tabsoft
- 3rd May 2015, 15:10
Malcolm,

Try using () in the tests. Ie. "If (Cvar => 11) And (Cvar <= 20) then"

Scampy
- 3rd May 2015, 16:59
Thanks for the tip.

I have it working to a degree, and test so far are encouraging

Here's the main code



;-----------------------------------------------------------------------------
; ***** MAIN PROGRAMMING LOOP *****
;-----------------------------------------------------------------------------

Main:

if Cvar >12 then Cvar=0

LCDOUT $fe,$80+5,"Hot",$fe,$80+10,"Cool",$fe,$80+16,"Hum"

Cvar=Cvar+1

SetPoint1 = normtemp1
SetPoint2 = normtemp2
SetPoint3 = normtemp3
SetPoint4 = normtemp4

gosub FlushBuffer:

If SetButton=0 then ; jump to programming
Gosub SetButtonRelease
goto mainmenu
endif

If DecButton=0 then
Gosub SetButtonRelease
goto lightoveride ; manual overide of light
endif

If IncButton=0 then
Gosub SetButtonRelease
goto cancelalarm ; manual overide of alarm
endif

gosub displaytime ; update the clock and display the time

FOR pid_Channel = 0 TO 3 ; cycle thru all sensors
GOSUB SelectSensor
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Convert ; start a temperature conversion
GIE = 1 ; enable interrupts after 1-wire
NEXT pid_Channel

FOR TempWD = 0 TO 1000
IF RCIF=1 THEN GOSUB coms ; Check to see id PC application connected
PAUSE 1
NEXT TempWD

FOR pid_Channel = 0 TO 3 ; cycle thru all sensors
GOSUB SelectSensor
DS1820_Error = 0 ; clear any previous errors
DS1820_Flags = 0 ; clear status flags
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Stat ; check the sensors status
GIE = 1 ; enable interrupts after 1-wire
PAUSEUS 20
IF !DS1820_Done THEN SensorError ; if it's not done by now, error
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Read ; get the temperature result
GIE = 1 ; enable interrupts after 1-wire
GOSUB Check4Zeros

DS1820_Flags = 0
GIE = 0 ; disable interrupts before 1-wire
@ DS1820_Stat
GIE = 1 ; enable interrupts after 1-wire
IF (DS1820_Error = 0) AND DS1820_Done THEN ; if there were no errors
Temperatures(pid_Channel) = TempC
pid_Error = SetPoints(pid_Channel) - TempC
GOSUB PID
IF pid_Out.15 THEN pid_Out = 0 ; only keep positive values
IF ChannelPWR(pid_Channel) THEN
HeaterDrives(pid_Channel) = pid_Out
ELSE
HeaterDrives(pid_Channel) = 0
ENDIF
IF Temperatures(pid_Channel) > alarmhigh(pid_Channel) and Alarm = 1 then AlarmPin = 1
IF Temperatures(pid_Channel) > alarmhigh(pid_Channel) and Alarm = 0 then AlarmPin = 0
IF Temperatures(pid_Channel) <= alarmhigh(pid_Channel) then AlarmPin = 0
IF Temperatures(pid_Channel) <= alarmlow(pid_Channel) then AlarmPin = 0
if Temperatures(pid_Channel) < alarmlow(pid_Channel) and Alarm = 1 then AlarmPin = 1
if Temperatures(pid_Channel) < alarmlow(pid_Channel) and Alarm = 0 then AlarmPin = 0


ELSE
SensorError:
HeaterDrives(pid_Channel) = 0 ; turn off heater if sensor's bad
SensorActive(pid_Channel) = 0
ENDIF
NEXT pid_Channel

If Cvar >=1 and Cvar <=3 then GOto ShowLCD1
If Cvar >=4 and Cvar <=6 then GOto ShowLCD2 ; display info on LCD
If Cvar >=7 and Cvar <=9 then GOto ShowLCD3
If Cvar >=10 and Cvar <=12 then GOto ShowLCD4

check:


; ---------------------------------------------------------------------------
; check lighting periods and turn lights on or off accordingly
; ---------------------------------------------------------------------------

fn = 0 ; select the first Lights
if lightover = 0 then GOSUB CheckTimes ; if manual override set to off then go compare the programed period
if lightover = 1 then progON=1 ; if manual override flag set to on then lights on flag set to 1
IF ProgON THEN ; If in the program period
IF Lights1 = 0 THEN Lights1 = 1
ELSE
IF Lights1 = 1 THEN Lights1 = 0
ENDIF

fn = 1 ; select the second Lights
if lightover = 0 then GOSUB CheckTimes ; compare the programed period
IF ProgON THEN
IF Lights2 = 0 THEN Lights2 = 1
ELSE
IF Lights2 = 1 THEN Lights2 = 0
ENDIF

; ---------------------------------------------------------------------------
; Check for night time drops - if condition matched, drop temp
; ---------------------------------------------------------------------------

fn = 0 ; select the first setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[0]=Droptemp[0] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[0]= normtemp[0] ; change the corresponding drop temperature to set point
ENDIF

fn = 1 ; select the second setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[1]=Droptemp[1] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[1]= normtemp[1] ; change the corresponding drop temperature to set point
ENDIF

fn = 2 ; select the third setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[2]=Droptemp[2] ; change the corresponding set point to the drop temperature
ELSE
SetPoints[2]= normtemp[2] ; change the corresponding drop temperature to set point
ENDIF

fn = 3 ; select the fouth setting
GOSUB CheckTimes2 ; compare the programed period
IF ProgON2 THEN
SetPoints[3]=Droptemp[3] ; change the corresponding set point to the drop temperature
ELSE
Setpoints[3]= normtemp[3] ; change the corresponding drop temperature to set point
ENDIF

;-----------------------------------------------------------------------------
; ***** MAIN PROGRAMMING LOOP END *****

GOTO Main
;-----------------------------------------------------------------------------


And here are the four LDC routines



ShowLCD1:
Pid_channel=0
LCDOUT $FE,$C0,"Viv",DEC1 Pid_channel+1," " ; print to LCD
TempC = Temperatures(pid_Channel)
gosub read_dht
LCDOUT $FE,$C0+5
TempWD = TempC : GOSUB TempToLCD ; display TempC
LCDOUT $DF
if SensorActive(pid_Channel) = 0 then lcdout $FE,$C0+5,"N/C"
LCDOUT $fe,$94,dec Cvar
goto check

ShowLCD2:
Pid_channel=1
LCDOUT $FE,$C0,"Viv",DEC1 Pid_channel+1," " ; print to LCD
TempC = Temperatures(pid_Channel)
gosub read_dht
LCDOUT $FE,$C0+5
TempWD = TempC : GOSUB TempToLCD ; display TempC
LCDOUT $DF
if SensorActive(pid_Channel) = 0 then lcdout $FE,$C0+5,"N/C"
LCDOUT $fe,$94,dec Cvar
goto check

ShowLCD3:
Pid_channel=2
LCDOUT $FE,$C0,"Viv",DEC1 Pid_channel+1," " ; print to LCD
TempC = Temperatures(pid_Channel)
gosub read_dht
LCDOUT $FE,$C0+5
TempWD = TempC : GOSUB TempToLCD ; display TempC
LCDOUT $DF
if SensorActive(pid_Channel) = 0 then lcdout $FE,$C0+5,"N/C"
LCDOUT $fe,$94,dec Cvar
goto check

ShowLCD4:
Pid_channel=3
LCDOUT $FE,$C0,"Viv",DEC1 Pid_channel+1," " ; print to LCD
TempC = Temperatures(pid_Channel)
gosub read_dht
LCDOUT $FE,$C0+5
TempWD = TempC : GOSUB TempToLCD ; display TempC
LCDOUT $DF
if SensorActive(pid_Channel) = 0 then lcdout $FE,$C0+5,"N/C"
LCDOUT $fe,$94,dec Cvar
goto check


OK it may be crude, have lots of duplication but it achieves the result I'm after. The good news is that whilst it's cycling around the loop and displaying values for say viv3, the PID still works fine for Viv1. I might then tidy the layout up a bit so I can get the decimals in for the temperatures, but I'm not that bothered about the decimal points - I mean I'm sure my pythons and boa don't care if it's 32.9 or 33.0 C

HenrikOlsson
- 4th May 2015, 06:06
Hi,

Even basic logic doesn't seem to work !!!

if Cvar => 1 or Cvar =< 10 then
Can you tell me when the above is NOT evalutated true?
When CVar is 0? When CVar is 8? When CVar is 11? When CVar is 25?


EDIT... seems it likes if Cvar =>11 and Cvar =< 20 then... rather than OR
I think YOU like it better with AND rather than OR. The compiler and the PIC likes either one equally well - and it works as expected, just not the way YOU want it to.....

/Henrik.

Art
- 4th May 2015, 08:43
You realise a zero value skips that whole block right?
Speed probably is no issue here, but you’re making it work hard!
It would matter if you’re watching a tilt sensor on a moving part or something like that.



If Cvar < 13 then
If Cvar > 9 then ShowLCD4
If Cvar > 6 then ShowLCD3
If Cvar > 3 then ShowLCD2
If Cvar != 0 then ShowLCD1
endif // Cvar < 13

Art
- 4th May 2015, 09:04
The only difference between the ShowLCDx commands is x constant?


Pid_channel=x


I had a play with every consideration for the micro, and no consideration for the Human :D



i var byte; bonus loop counter
x var byte; initial value to subtract 3 from


x = 9
If Cvar < 13 then
for i = 3 to 0 step -1
If Cvar > x then
Pid_channel=i
LCDOUT $FE,$C0,"Viv",DEC1 Pid_channel+1," "
TempC = Temperatures(pid_Channel)
gosub read_dht
LCDOUT $FE,$C0+5
TempWD = TempC
GOSUB TempToLCD
; if nothing else calls TempToLCD it can go straight in here
LCDOUT $DF
if SensorActive(pid_Channel) = 0 then lcdout $FE,$C0+5,"N/C"
LCDOUT $fe,$94,dec Cvar
goto check
; I don’t see check in what you’ve posted
; but you can drop it straight here if nothing else goes there
endif
x = x - 3
next i
endif;

Scampy
- 4th May 2015, 12:01
Art,

Thanks for the suggestion.... like I said my original code was bulky and crude, but worked, but I know it could be made simpler, but after 10 hrs of coding I think my brain just gave up :)

Art
- 4th May 2015, 15:16
It was really just a play... It's not simpler for the Human to read six months later.
Wherever there's not likely to be a performance problem,
and thinking of the possibility of having to adjust those constants later,
I'd avoid the above code like the plague!
but would personally go for the smaller block directly above that.

Scampy
- 4th May 2015, 15:50
It's not simpler for the Human to read six months later.
Wherever there's not likely to be a performance problem,
and thinking of the possibility of having to adjust those constants later,
I'd avoid the above code like the plague!
but would personally go for the smaller block directly above that.

That's the thing, I can see the need for tight compact code in a commercial arena where costs etc matter, but for home projects I like things more simpler to follow. As mentioned, it might not be the best way, but if it gets the end result I'm after, and there is little impact on speed then I'm happy. If it means I have to throw an overkill PIC at it to maintain the performance, or to have enough memory to hold my bloated code then so be it :)

stanon1
- 4th August 2015, 00:38
hi all, i have been scratching my head thinking of how to avoid pbp pause in my routines bcos the command;

1) seems to change system registers (correct me if i'm wrong),
2) is the main cause of many problems i have had with ISR's in the past
3) is blocking, i dont want to waste cycles

i have been trying to make sense of the previous posts in this thread. pls can someone help with a robust snippet.

i think of a delay based on an interrupt timer that serves as the heartbeat with a resolution of say 1us. in the isr, multiple regs (each loaded when needed from various routines) are decremented to act as counters, when anyone hits zero a corresponding flag is set etc...

am i making any sense? i think this is simillar to how some rtos work. is there a better way?

HenrikOlsson
- 4th August 2015, 08:29
Hi,

> 1) seems to change system registers (correct me if i'm wrong),

What do you mean with system registers? If you mean the PBP system variables then yes, it has to use something to keep track of time - in the same way as you suggest in your method and the compiler uses its internal variables for that. But I don't really see the problem, are you using the system variables in your code?


> 2) is the main cause of many problems i have had with ISR's in the past

How are you "doing" your interrupts and what problems are we talking about?
If you're spending a lot of cycles in your ISR then a PAUSE in the main program won't be accurate because the main program isn't really executing at the desired speed due to the interrupt "stealing" time away from it. If you're using a PAUSE in the ISR then of course the main program will "halt" during that period.

> 3) is blocking, i dont want to waste cycles

It is. Just like all PBP commands.

> i think of a delay based on an interrupt timer that serves as the heartbeat with a resolution of say 1us. in the isr, multiple regs (each loaded when needed from various routines) are decremented to act as counters, when anyone hits zero a corresponding flag is set etc...

The overall idea is doable but forget 1us resolution. Even at 64MHz there would only be 16 instructions between each interrupt - perhaps you could manage ONE timer if written in tight ASM but then there wouldn't be much time left for anything else. Depending on the oscillator speed and the number of timers you want to maintain 100us or 1ms might be more appropriate, 10ms certainly doable.

/Henrik.

stanon1
- 5th August 2015, 10:12
Thank so much Henrick,

i am so glad that someone understood what i was trying to say. Elated to hear that it is doable even in the ms range.

But to answer some of your questions:

1) By system registers i was thinking that pbp must setup some timers for counting during pause. And this might affect my timers usage.

2) how i am doing my interrupts. I use DEFINE INTHAND _MYISR1

Then after saving contexts in asm i do an endasm and gosub a pbp routine. I don't know how to upload a code yet. I would have shown you.

But at any rate, the results are usually erratic and it seems as if the code is making jumps to the wrong places. On certain ocassions i found out that if i use a timer interupt to delay something rather than pause, the system will work better.

3) Now since pause is blocking, "just like all pbp commands" (never thought if this) if i can get a way to rig up a macro that i can use such as

@ myPAUSE msec,SUBNAME

where msec is the no of ms to delay and SUBNAME is used to keep track of the specific registers to use (i.e the sub that is calling for a delay).

My problem is: can i call a pbp routine inside asm macro.

I like to use pbp if statements to in a state-machine-like manner, makes programming more structured. If i can have another type of PAUSE that will simply load a reg and move... i think this will make code more efficient

Thanks so much.

HenrikOlsson
- 5th August 2015, 11:00
Hi,

1) By system registers i was thinking that pbp must setup some timers for counting during pause. And this might affect my timers usage.
No, not at all. The PAUSE and PAUSEUS commands does not use any hardware peripherals (ie timers) on the PIC, it's done in software which is why it's blocking. Basically it sits in a loop, counting cycles.


2) how i am doing my interrupts. I use DEFINE INTHAND _MYISR1

Then after saving contexts in asm i do an endasm and gosub a pbp routine. I don't know how to upload a code yet. I would have shown you.

But at any rate, the results are usually erratic and it seems as if the code is making jumps to the wrong places. On certain ocassions i found out that if i use a timer interupt to delay something rather than pause, the system will work better.
OK, so there's your problem I think. If you use ASM for your interrupt service routines you can (generally) not use PBP code within the ISR (using a GOSUB does not matter). Why? Because PBP uses its internal system variable for its various commands, if your main program is in the middle of comlex math operation it stores intermediate results in its internal variables and along comes an interrupt. If you then place PBP commands in the ISR chanses are that code wants to use the same internal system variables which will the corrupt the complex math operation that the main program was in the middle of calculating.

If you want to use PBP within your interrupt servie routine you need to either:

A) Use ON INTERRUPT - with its drawbacks.
B) Write the code for the handler, compile and assemble it. Examine the .lst file and determine which of the system variables are being used and then add code to save and restore those registers on ISR entry/exit.
C) Use Darrel Taylors Instant Interrupt routines. What it does is save and restore ALL PBP system variables on entry/exit. It comes at a cost of interrupt latency (it takes time to save all the registers).

I've used all three of the above aproaches. By far, option C is "the best". I very very rarely use A. B I've used for stuff where the ISR is simple and I've really needed the speed. Just remember that with option B you need to be very careful, any change to ISR and you need to re-examin the generated code to see if any new PBP system variables are beinng used.


3) Now since pause is blocking, "just like all pbp commands" (never thought if this) if i can get a way to rig up a macro that i can use such as

@ myPAUSE msec,SUBNAME

where msec is the no of ms to delay and SUBNAME is used to keep track of the specific registers to use (i.e the sub that is calling for a delay).

My problem is: can i call a pbp routine inside asm macro.
I don't quite follow you with the macro thing (I truly suck at the ASM stuff) but if you mean calling a PBP subroutine from within an ASM interrupt service routine then generally NO, absolutely not.

/Henrik.

stanon1
- 5th August 2015, 11:50
THIS IS AN EYE OPENER.

Thanks so much for explaining. Now i understand why it didnt work. I have learn a great deal from your post.

Thanks for the tips, i think option B is what I will go for. Its worth the effort.
But how can i determine from the .lst, the system variables in use.

I have used DT Interrupts and they work well (apart from inadvertenly enabling unwanted interrupts sometimes). But to avoid saving every variable all the time and save time is my goal. I need to have more speed.

Lastly, my question about macros. Can i do something like this;

Asm
MACRO myPAUSE msec,subID
movlw msec
movwf delay1
movlw subID
movwf KeepTrack
Endasm

; then concote any kind of PBP code here

@ Endm

richard
- 5th August 2015, 12:01
I modified dt's Elapsed_INT-18.bas file so I could use the "Ticks" as a millisecond counter function (like millis() in arduino C ) it rolls over every 65 seconds but using unsigned integer subtracts its very handy for short interval timing and has no blocking issues . the fairly low interrupt rate minimises effect on normal pgm throughput.

I'm sure Elapsed_INT-14.bas is easily adapted to match , but I have no copy of it





'************************************************* **************************
'* Name : Elapsed_INT-18.bas *
'* Author : Darrel Taylor *
'* Date : JUL 11, 2006 : 7/11/2010 *
'* Version : modified to use ticks useable as a millisecond counter *
'* Notes : Must have DT_INTS-18.bas loaded first *
'* ver 1.2: Now works at any OSC frequency without using the prescaler *
'************************************************* **************************
DISABLE DEBUG

; syntax = Handler IntSource, Label, Type, ResetFlag?
DEFINE Elapsed_Handler TMR1_INT, _ClockCount, asm, yes
; the above define can be used in the INT_LIST macro, if desired (optional)

Ticks VAR word ; Counts timer Overflows
T1Post VAR BYTE ; Timer1 postscaler
Seconds VAR BYTE
Minutes VAR BYTE
Hours VAR BYTE
Days VAR WORD

SecondsChanged VAR BIT ; idicates that the value has changed
MinutesChanged VAR BIT
HoursChanged VAR BIT
DaysChanged VAR BIT

GOSUB ResetTime ; initialize the Elapsed Timer

Goto OverElapsed ; skip over the routines

' -------------- calc timer reload Constants -------------------------------
ASM
T1PS = 1 ; start with 1:1 postscaler
TimerConst = ((OSC*1000000)/4/100) ; how many timer ticks will it take
while TimerConst > 65400 ; if it's more than the timer can count
T1PS = T1PS * 2 ; double the postscaler
TimerConst = TimerConst / 2 ; halve the count
endw
TimerConst = 65536 - TimerConst + 6 ; final reload value !!!!! was 8 but clk runs fast


; ----------------- ADD TimerConst to TMR1H:TMR1L -------------------------
ADD2_TIMER macro
BCF T1CON,TMR1ON, 0 ; 1 Turn off timer
MOVLW LOW(TimerConst) ; 1
ADDWF TMR1L,F, 0 ; 1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F, 0 ; 1
MOVLW HIGH(TimerConst) ; 1
ADDWF TMR1H,F, 0 ; 1
endm

; ----------------- ADD TimerConst to TMR1H:TMR1L and restart TIMER1 ------
RELOAD_TIMER macro
ADD2_TIMER
BSF T1CON,TMR1ON, 0 ; 1 Turn TIMER1 back on (8 cycles)
endm

; ----------------- Load TimerConst into TMR1H:TMR1L ----------------------
LOAD_TIMER macro
MOVE?CT 0, T1CON,TMR1ON
MOVE?CB 0, TMR1L
MOVE?CB 0, TMR1H
ADD2_TIMER
endm
ENDASM

' ------[ This is the Interrupt Handler ]-----------------------------------
T1PS CON EXT
ClockCount:
@ RELOAD_TIMER ; Reload TIMER1

T1Post = T1Post + 1

IF T1Post = T1PS THEN

T1Post = 0

Ticks = Ticks + 1

IF Ticks //100 ==0 THEN

' Ticks = 0 Seconds = Seconds + 1
SecondsChanged = 1
IF Seconds = 60 THEN
Seconds = 0
Minutes = Minutes + 1
MinutesChanged = 1
ENDIF
IF Minutes = 60 THEN
Minutes = 0
Hours = Hours + 1
HoursChanged = 1
ENDIF
IF Hours = 24 THEN
Days = Days + 1
DaysChanged = 1
Hours = 0
ENDIF
ENDIF
ENDIF
@ INT_RETURN ; Restore context and return from interrupt

'-----====[ END OF TMR1 Interrupt Handler ]====-----------------------------

StartTimer:
T1CON = 1 ; 1:1, FOSC4, TMR1ON
RETURN

; --------------------------------------------------------------------------
StopTimer:
T1CON.0 = 0 ; Turn OFF Timer1
RETURN

; --------------------------------------------------------------------------
BitSave VAR BIT

ResetTime:
BitSave = T1CON.0 ; Save TMR1ON bit
@ LOAD_TIMER ; Load TimerConst
T1CON.0 = BitSave ; Restore TMR1ON bit
T1Post = 0 ; clear the postscaler
Ticks = 0
Seconds = 0
Minutes = 0
Hours = 0
Days = 0
SecondsChanged = 1 ; indicate everything has changed
MinutesChanged = 1 ; so that 00:00:00 is processed
HoursChanged = 1
DaysChanged = 1
RETURN


OverElapsed:
ENABLE DEBUG

richard
- 5th August 2015, 12:13
Lastly, my question about macros. Can i do something like this;

Asm
MACRO myPAUSE msec,subID
movlw msec
movwf delay1
movlw subID
movwf KeepTrack
Endasm

; then concote any kind of PBP code here

@ Endm

no

macro is a assembler feature and will not accept pbp code.
pbp code needs to be compiled and then assembled

post some code and explain what you are trying to achieve

stanon1
- 5th August 2015, 16:02
THANKS TO YOU ALL FOR TRYING TO HELP.

I have thrown together some wobbly code to try and explain what i'm trying to do.

I know it might not be the best way, but i can't seem to wrap my head around the whole idea. I just want to be able to use pause in a way that I won't sit and wait for the time to elapse.

in the mainloop here, i have 4 blocks (which could be doing many different things aside from toggling pins). Each block has a pause somewhere set by the value loaded in DELAYREGx

Then in the ISR INTERUPTING EVERY 1ms;

MYISR1:
IF DELAYREG1>0 THEN
DELAYREG1=DELAYREG1-1
IF DELAYREG1=0 THEN
DELAY1flag=1
ENDIF
ENDIF

IF DELAYREG2>0 THEN
DELAYREG2=DELAYREG2-1
IF DELAYREG2=0 THEN
DELAY2flag=1
ENDIF
ENDIF

IF DELAYREG3>0 THEN
DELAYREG3=DELAYREG3-1
IF DELAYREG3=0 THEN
DELAY3flag=1
ENDIF
ENDIF

IF DELAYREG4>0 THEN
DELAYREG4=DELAYREG4-1
IF DELAYREG4=0 THEN
DELAY4flag=1
ENDIF
ENDIF

; END OF ISR
;

Then in the mainloop,

MAINLOOP:

BLOCK0:

IF LED0_UPDATE THEN
HIGH PORTB.0 ;IS IT TIME TO UPDATE LED0?
@ myPAUSE 1000,1 ;MAKE PORTB.0 HIGH FOR 1000 ms USING DELAYREG1
LED0_UPDATE=0 ;BUT DON'T WAIT FOR THE TIME TO ELAPSE
GOTO BLOCK1
ENDIF

IF DELAY1flag THEN ;WILL BE SET IN THE ISR ATFTER 1 SECOND
LOW PORTB.0 ;HAVE WE COME TO THE END OF 1 SECOND?
ENDIF ;END OF myPAUSE


BLOCK1:

IF LED1_UPDATE THEN
HIGH PORTB.1 ;IS IT TIME TO UPDATE LED1
@ myPAUSE 4000,2 ;MAKE PORTB.1 HIGH FOR 4000 ms USING DELAYREG2
LED1_UPDATE=0 ;BUT DON'T WAIT FOR THE TIME TO ELAPSE
GOTO BLOCK2
ENDIF

IF DELAY2flag THEN ;WILL BE SET IN THE ISR ATFTER 4 SECOND
LOW PORTB.1 ;HAVE WE COME TO THE END OF 4 SECOND?
ENDIF ;END OF myPAUSE

BLOCK2:
IF LED2_UPDATE THEN
HIGH PORTB.2 ;IS IT TIME TO UPDATE LED2
@ myPAUSE 2000,3 ;MAKE PORTB.2 HIGH FOR 2000 ms USING DELAYREG3
LED2_UPDATE=0 ;BUT DON'T WAIT FOR THE TIME TO ELAPSE
GOTO BLOCK3
ENDIF

IF DELAY3flag THEN ;WILL BE SET IN THE ISR ATFTER 2 SECOND
LOW PORTB.2 ;HAVE WE COME TO THE END OF 2 SECOND?
ENDIF ;END OF myPAUSE

BLOCK3:
IF LED3_UPDATE THEN
HIGH PORTB.3 ;IS IT TIME TO UPDATE LED3
@ myPAUSE 400,4 ;MAKE PORTB.3 HIGH FOR 400 ms USING DELAYREG4
LED3_UPDATE=0 ;BUT DON'T WAIT FOR THE TIME TO ELAPSE
GOTO BLOCK0
ENDIF

IF DELAY1flag THEN ;WILL BE SET IN THE ISR ATFTER 0.4 SECOND
LOW PORTB.3 ;HAVE WE COME TO THE END OF 0.4 SECOND?
ENDIF ;END OF myPAUSE

GOTO MAINLOOP

Here is what i mean by using pbp within ASM macro;

ASM
MACRO myPAUSE msec,subID
movlw msec
movwf delay_temp
movlw subID
movwf KeepTrack
ENDASM

SELECT CASE KeepTrack

CASE 1
DELAYREG1=delay_temp
DELAY1flag=0

CASE 2
DELAYREG2=delay_temp
DELAY2flag=0

CASE 3
DELAYREG3=delay_temp
DELAY3flag=0

CASE 4
DELAYREG4=delay_temp
DELAY4flag=0

CASE ELSE

@ NOP
END SELECT

@ ENDM

I hope someone might understand and help me...

thanks.

Dave
- 5th August 2015, 19:39
Stanon1, I see where you are clearing: LED0_UPDATE=0 but where are you setting it to TRUE? I think you are on the right track but it could be made much more simplistic.

stanon1
- 5th August 2015, 21:00
Exactly! It could be made simpler. That is the crux of the matter.

You are right i didn't show where i am setting LED0_UPDATE. these flags themselves, at the right time based on certain parameters, are set by other isr running in parrallel with the heartbeat timer

thanks for the reply

amgen
- 5th August 2015, 21:14
I can suggest a little different approach which I have used...... its similar to how operating systems work ... and since you are using interrupts, you already are doing most of the work...
I will explain more unless your intent on proceeding with what you have been doing.
don

stanon1
- 5th August 2015, 21:58
I can suggest a little different approach which I have used...... its similar to how operating systems work ... and since you are using interrupts, you already are doing most of the work...
I will explain more unless your intent on proceeding with what you have been doing.
don

hi amgen, pls any suggestions you have is welcome. my aim was to let you guys understand what i'm trying to do; i am not good at coding so that is where i need help: how best to go about it to get the expected results... i will be glad if you would explain

amgen
- 6th August 2015, 02:16
before adding your code, set up a real time loop with interrupt every 100 milliseconds (that gives 10 times per second and allows for many microsecond instructions to run within main timing loop) don't use any pauses....just set/start/check counters in loop sections as each pass is exactly .1 seconds.
So program runs main loop including your individual code parts..... then waits at the bottom in a while command until the interrupt sends it back to main loop ......
as long as all your code operates within 100 milliseconds (that's many 1 and 2 microsecond machine code instructions) then the loop will always wait until retriggered after looping through your code in the while loop.
You set up a few flag type bits or bytes that get set/reset/checked for program flow.
sorry if explanation is messy.
First get the main .1 second loop working (blink/toggle an led as an indicator) then add in your code relying on the .1 second looping time.


http://www.picbasic.co.uk/forum/asset.php?fid=5526&uid=7651&d=1311957346

stanon1
- 6th August 2015, 11:45
Thanks so much amgen, i want to give this a try, looks much simpler. i am trying to convert the flowchart you posted to code, i will let u know how it turns out.

i will see if my original trial will even compile at all :-), then i will make comparisms

i want to be able to write more efficient code. one nice tool that has helped me to compare execution times of various methods of coding is DARREL TAYLOR's instruction time calculation code...