Help needed on 08m2 code

Visser

Well-known member
Good day
Somebody a long while ago helped me with this code to toggle 2 outputs every 5 minutes and keep it high for 1sec
I need to find out if there is a way to use a resistive pot or resistors to adjust the time from 5 minutes to about an hour and in between as it wont be possible to reprogram it every time
I think somebody helped me before on something similar but I cannot find it anywhere under my old posts
Thank you in advance
Regards
Vissie
I cant remember how to post the code so I copied and past it here

#Picaxe 08M2
#No_Data
DO
HIGH C.0 ;outputc.0 goes HIGH
PAUSE 1000 ;PAUSE 1 SEC
LOW C.0 ;output c.0 goes LOW
for b1 = 1 to 5 ;5 loops
pause 60000 ;wait 60 secondS
next b1
HIGH C.4 ;output C.4 goes HIGH
PAUSE 1000 ;PAUSE 1 SEC
LOW C.4 ;output c.4 goes LOW
for b1 = 1 to 5 ;5 loops
pause 60000 ;wait 60 secondS
next b1
LOOP
 
Last edited:
My attempt :-

Connect a 10K pot. across the power supply, with the Wiper connected to Pin C.1

Rich (BB code):
#Picaxe 08M2
#No_Data

#terminal 4800

symbol CurrentADC = W12
symbol InitialADC =W13
symbol Loops = b23

symbol PotPin = C.1

      pause 1000                    ;affects responsiveness to change of Pot position
      sertxd (cr,lf,"START PROGRAM");but is mainly to make sure debug message appears.
      
      readadc10 PotPin,CurrentADC   ;read voltage at pot. wiper
      
      Loops = CurrentADC /19 + 5    ;value of CurrentADC will be 0 to 1023, depending on pot position.
                                    ;convert to 5 to 58.
      InitialADC = CurrentADC       ;save ADC reading
      sertxd (cr,lf,"Loops=",#Loops)

DO
      HIGH C.0                      ;output c.0 goes HIGH
      PAUSE 1000                    ;PAUSE 1 SEC
      LOW C.0                       ;output c.0 goes LOW
      
      for b1 = 1 to Loops           ;5 to 60 times round the one minute loop
            
            for b2 = 1 to 60        ;one minute loop
                  readadc10 PotPin,CurrentADC ; read voltage at pot. wiper

                  if CurrentADC <> InitialADC then
                        sertxd (cr,lf,"CurrentADC:",#CurrentADC," InitialADC:",#InitialADC)
                        
                        RESET       ;change of pot position - Restart the program 
                        
                  endif
                        
                  pause 1000        ;wait 1 second
            next b2
      next b1

      HIGH C.4                      ;output C.4 goes HIGH
      PAUSE 1000                    ;PAUSE 1 SEC
      LOW C.4                       ;output c.4 goes LOW
      
      for b1 = 1 to 5               ;5 loops
            pause 60000             ;wait 60 secondS
      next b1
LOOP

I hope I've not confused anyone, by editing this several times to remove a bug :unsure:
 
Last edited:
There is a small but significant bug, in that the ADC reading may vary by "1", every time it is read (or it may just be I have a dodgy pot.) This should be allowed for, but I leave as "an exercise for the student" :)
 
Even a few minute out wont matter
This is to use on a lathing relay that swop charge and drive batteries
 
To make it responsive, I put a reset statement inside a one minute loop. The idea being, that if you move the pot. it will notice sooner rather than later. In response to that change, it aborts the current delay and restarts the program.

Obviously, if things haven't 'really' changed, that is the wrong behaviour. A small software tweak (basically, to add some hysteresis) should be straight forward - but I'm going in search of food now :)
 
Morning . To simulate i made all values shorter and C1 to 0
Initially C0 goes high at 9 and 14 but that wont be a problem for my application
It seems to me like its running very smooth and correct
The only way I know to test it is to set it up and connect a buzzer to the 2 outputs
Will do that now
What are the times on this now. From 5 min to 60 minutes?
Thank you
 
Last edited:
What are the times on this now. From 5 min to 60 minutes?

5 to 58 ("about an hour" ;) ) and all values in between.

The ADC value returned, when the pot. is sampled will be from 0 to 1023 (min to max position).

The statement Loops = CurrentADC /19 + 5 transforms that into 5 to 58. (The smallest result returned by CurrentADC/19 is 0 and the largest 53 - integer arithmetic of course. Adding "5" moves the result from 0 to 53, to 5 to 58.

You could make it function more like a multi-way switch, than a pot. if you used a selection of case statements to group ranges together.

For example, just 5 distinct times (5,15,30,45 & 60 mins) :-
Rich (BB code):
      select case CurrentADC
            
            Case < 205
            Loops = 5               ;5 minutes

            case 205 to 410
            Loops = 15              ;15 minutes
            
            case 411 to 615
            Loops = 30              ;30 minutes
            
            case 616 to 820
            Loops = 45              ;45 minutes
            
            case > 820
            Loops = 60              ;60 minutes
      
      end select



The bug I found on my breadboard, is that the ADC return value may oscillate slightly, even though the pot. does not move.

Insert the following code to prevent it:-

Rich (BB code):
                  ;
                  ; Get difference between Current and Previous ADC readings
                  ;
                  if CurrentADC > InitialADC then
                        W10 = CurrentADC - InitialADC
                  else
                        W10 = InitialADC - CurrentADC
                  endif
                  
                  if W10 > 1 then   ;if ADC has changed by 'enough', act on it

after the 2nd readadc10, instead of
Rich (BB code):
                  if CurrentADC <> InitialADC then


[Edited out the typos :oops: ]
 
Last edited:
Thank you for all your trouble. It is amazing how people will help and spend time on strangers.

I think I get the first part but I'm not to sure where to insert it and what to remove.

I have no idea where to insert the bug code part
On the simulator when I right click on C.1 it can be changed from 0 to 255. Not 1023
(value of CurrentADC will be 0 to 1023, depending on pot position.)
Is that a setting I have wrong somewhere?
Another question. The command:
readadc10 PotPin,CurrentADC ;read voltage at pot. wiper
How does it refer to C.1 value?
Regards
Vissie
 
Last edited:
"The bug I found on my breadboard, is that the ADC return value may oscillate slightly, even though the pot. does not move. "

Will a 0.1uf capacitor over the supply of the pot not solve that problem?
 
Will a 0.1uf capacitor over the supply of the pot not solve that problem?

Possibly and if you're more comfortable fixing it in hardware than software, feel free :)
I have no idea where to insert the bug code part

...and not helped by me - introducing two typos - in five lines of code :eek:

I'll attach the fixed code, which also has a Symbol Threshold = 2 statement that you can tweak, to set the hysteresis (rather than it being hardcode as "1").

On the simulator when I right click on C.1 it can be changed from 0 to 255. Not 1023
(value of CurrentADC will be 0 to 1023, depending on pot position.)
Is that a setting I have wrong somewhere?

It's probably a vagary of the simulator. I very rarely use the simulator ...

Another question. The command:
readadc10 PotPin,CurrentADC ;read voltage at pot. wiper
How does it refer to C.1 value?

Via the symbol PotPin = C.1 statement. The advantage of using a symbol assignment, rather than a direct reference to C.1, is that you would only have to make one change to the code, if the hardware was changed.

Rich (BB code):
#Picaxe 08M2
#No_Data

#terminal 4800

symbol CurrentADC = W12
symbol InitialADC = W13
symbol Loops      = b23

symbol PotPin     = C.1

Symbol Threshold  = 2               ;amount by which ADC value has to change, to be 'significant'


      pause 1000                    ;affects responsiveness to change of Pot position
      sertxd (cr,lf,"START PROGRAM");but is mainly to make sure debug message appears.
      
      readadc10 PotPin,CurrentADC   ;read voltage at pot. wiper

;Uncomment this section, to emulate a 5 position multi-way switch

#region     
      select case CurrentADC
            
            Case < 205
            Loops = 5               ;5 minutes

            case 205 to 410
            Loops = 15              ;15 minutes
            
            case 411 to 615
            Loops = 30              ;30 minutes
            
            case 616 to 820
            Loops = 45              ;45 minutes
            
            case > 820
            Loops = 60              ;60 minutes
      
      end select
#endregion

; or use this simple assignment, to have continuously adjustable times, from 5 to 58 minutes
#region
;     Loops = CurrentADC /19 + 5    ;value of CurrentADC will be 0 to 1023, depending on pot position.
                                    ;convert to 5 to 58.
#endregion

      InitialADC = CurrentADC       ;save ADC reading
      sertxd (cr,lf,"Loops .i.e. Minutes=",#Loops)

DO
      HIGH C.0                      ;output c.0 goes HIGH
      PAUSE 1000                    ;PAUSE 1 SEC
      LOW C.0                       ;output c.0 goes LOW
      
      for b1 = 1 to Loops           ;5 to 60 times round the one minute loop
            
            for b2 = 1 to 60        ;one minute loop
                  readadc10 PotPin,CurrentADC ; read voltage at pot. wiper
                  ;
                  ; Get difference between Current and Previous ADC readings
                  ;
                  if CurrentADC > InitialADC then
                        W10 = CurrentADC - InitialADC
                  else
                        W10 = InitialADC - CurrentADC
                  endif
                  
                  if W10 > Threshold then ;if ADC has changed by 'enough', act on it
                        sertxd (cr,lf,"CurrentADC:",#CurrentADC," InitialADC:",#InitialADC)
                        
                        RESET       ;change of pot position - Restart the program 
                        
                  endif
                        
                  pause 1000        ;wait 1 second
            next b2
      next b1

      HIGH C.4                      ;output C.4 goes HIGH
      PAUSE 1000                    ;PAUSE 1 SEC
      LOW C.4                       ;output c.4 goes LOW
      
      for b1 = 1 to 5               ;5 loops
            pause 60000             ;wait 60 secondS
      next b1
LOOP
 

Attachments

Last edited:
Hallo
I also need help with this please. I’m still doing the timer one but also need to do one where I sense the battery voltage
I need to do a similar thing but this time without a timer but rather when my output battery reach 12.5V . I have a voltage divider over the 12V battery and the output will be 3v to 3.75v for battery voltage of 12v to 15v
The adc input to C1 will vary between 3v and 3.75v. So, I calculated the adc voltage will be 3.125v at battery voltage of 12.5V
I’m not sure if this is correct but it looks like at 640 bits (1024/5*3.125=640)
The 12v battery voltage will always start high and then go down to 12.5V where I need C.0 to pulse for one second. The latching relay will switch to a new full battery. When this battery reaches 12.5V I need C.4 to pulse for one second
In short:
C.1 adc will be at about 3.75v at startup
When it reach 3.125v , C.0 must pulse for 1 sec
C.1 will go high again to 3.75v
When it reach 3.125v , C.4 must pulse for 1 sec
And repeat
Regards
Vissie
 
Last edited:
;Hi,
;This is a borrowed program and modified to suit my needs.

; Elf Flasher 03.10.24 91 Bytes
;Calibadc10 nref test 28.04.19 COPY

#Picaxe 08M2
#No_data
;#No_table
#Terminal 4800
#Com 3

Sertxd("Elf Flasher 03.10.24",13,10)
Symbol nref = w2
Symbol vpsu = w3

Main:
Calibadc10 nref ;>>>>>CHECKING BATTERIES<<<<<
vpsu = 52378/nref * 2 ;3 x AA
;Sertxd ( " Vpsu = ",#w3," ", Cr, Lf ) 'Re-insert during simulation v2.2
Pause 100
'If vpsu <= 340 Then ;if supply is <= 3v4,
If vpsu <= 300 Then
Goto LowBattery
endif



'Sertxd ( " Vpsu = ",#w3," ", Cr, Lf )
High C.1
Pause 1000
Low C.1
Pause 2000
Goto Main

LowBattery:
Stop
 
"The bug I found on my breadboard, is that the ADC return value may oscillate slightly, even though the pot. does not move. "

Will a 0.1uf capacitor over the supply of the pot not solve that problem?
The problem you're facing is that digital is digital and analogue is analogue and the two can always be different. Digital measurement of analogue inputs will always be in 'steps', however small those steps might be. On the other hand, analogue levels will always have some level of noise superimposed on them, however small that variation is, resulting in an ever changing voltage. And, of course, when measuring an analogue signal with a digital input there is always a chance that the analogue signal is wavering on the cusp of two digital steps.

There are several ways of addressing this problem. One is to create a CR filter with a resistor (I'd suggest a 4.7k) between the potentiometer's wiper and the input pin and a100nF capacitor from the input pin to 0v. Another is to regularly take several ADC readings with the PICAXE and averaging them. Both of these remedies will help but not solve the analogue/digital problem

Finally, you could develop an algorythm where your counter counts upwards toward a target value. The target value would constantly change in line with the ADC readings/calculations. When the timer counter exceeds the target value, the output pin is set or reset.
 
Thank Mr Bear, but I don’t get any of that. Only see C.1 going hi
I need something like this on my own language in ?. I’m not familiar on what to do there.
Its ok to laugh at me

#Picaxe 08M2
#No_Data
DO
symbol PotPin = C.1
readadc10 PotPin,CurrentADC
If adc <= 665 ( ? that is 3.2v)
DO
HIGH C.0 ;output c.0 goes HIGH
PAUSE 1000 ;PAUSE 1 SEC
LOW C.0
readadc10 PotPin,CurrentADC
If adc <= 665 ( ? that is 3.2v)

DO
HIGH C.4 ;output c.0 goes HIGH
PAUSE 1000 ;PAUSE 1 SEC
LOW C.4
Loop
 
Last edited:
Hi,

An important question is "Are you using an accurate, regulated power supply for the PICaxe?". This may affect both of your issues, i.e. the ADC Output jitter and the Battery (divider) accuracy and stability.

By default, the ADC uses the main supply rail as its Reference Voltage, so there is no point in making the ADC input very "clean" and stable, if the supply rail is not. It's less import with the Potentiometer application because the Pot also uses the supply rail as its Reference, so the effects may cancel out. But as IWP says, there will always be some voltage levels at which the ADC Output dithers between adjacent values. The solution is to add some "Hysteresis" in either the Hardware or the Software. For the Hardware solution you can apply a tiny amount of Positive Feeback, as in a Schmitt Trigger, but here a sofware solution is more appropriate as suggested by Phil. Basically you just need to take a small amount of the previous ADC Output value to "bias" the new output value slightly towards this previous value.

But for the battery monitoring application the Supply Rail is very important. If it is accurate and stable then you can just take a READADC10 measurement of the appropriate (divider) pin and the calculation is quite simple. But if the Supply Rail is not stable, then one solution is to measure the Supply rail using the CALIBADC10 command (as in Bear's code) to "calibrate" the ADC value. Or you could use the PICaxe's Internal Fixed Voltage Reference (FVR) as the Reference Voltage for the ADC, using the ADCCONFIG and FVRSETUP commands. The value of the FVR (approximately 2 volts or 4 volts) will determine the resistor values used in your battery divider network. BTW, beware that a divider network down from a higher external battery voltage may "Phantom Power" the PICaxe (via the ADC input pin and its protection diode) when you think it should be Off.

Cheers, Alan.
 
I do have a clean regulated supply . Lm7805 with decoupling and smoothing capacitors driven from a separate battery
My problem is not about that
I need help with the code if anybody can help
Regards
Vissie
 
Last edited:
The problem you're facing is that digital is digital and analogue is analogue and the two can always be different. Digital measurement of analogue inputs will always be in 'steps', however small those steps might be. On the other hand, analogue levels will always have some level of noise superimposed on them, however small that variation is, resulting in an ever changing voltage. And, of course, when measuring an analogue signal with a digital input there is always a chance that the analogue signal is wavering on the cusp of two digital steps.

There are several ways of addressing this problem. One is to create a CR filter with a resistor (I'd suggest a 4.7k) between the potentiometer's wiper and the input pin and a100nF capacitor from the input pin to 0v. Another is to regularly take several ADC readings with the PICAXE and averaging them. Both of these remedies will help but not solve the analogue/digital problem

Finally, you could develop an algorythm where your counter counts upwards toward a target value. The target value would constantly change in line with the ADC readings/calculations. When the timer counter exceeds the target value, the output pin is set or reset.
Thank you. i now did build that low pass filter into the sense circuit
 
Hi Visser,
Believe me, I'm not laughing at you.
Like I stated, it's a borrowed program. There is no way I could have created that.
Good luck with your project.
Bear.............
 
Hi,
When it reach 3.125v , C.0 must pulse for 1 sec
When it reach 3.125v , C.4 must pulse for 1 sec
Do you mean 3.75 volts for C.4 ? I'm assuming that the relay is "Bi-Polar", i.e. A pulse on C.1 closes the contacts and C.4 opens them.

My concern with a Latching Relay is that the Program might get "Out Of Sync" with the Relay. Therefore, I have defined the Relay to have three states, i.e. Open , Closed and "Don't Know". The latter may well apply when the Program starts up, but as a "safety measure" I have shown how the state could be confirmed, for example once each hour. Similarly, I am only polling the ADC once each minute to reduce the risk of the system "dithering" between On and Off. The #IFDEF Simulating sets shorter times for easier testing and I've added SERTXD commands to report what is happening.

Note the use of <> for "Is Not" (i.e. Not equal to) so that the pulse is generated whether the present state is either "Wrong" or "Not Known". I could have defined symbols for OPEN = 2 , etc., but try to avoid programs becoming excessivley verbose. So here is my attempt at a simple program :
Code:
#Picaxe 08M2
#No_Data
#IFDEF simulating
  symbol LoopTime = 600     ; Milliseconds
  symbol ConfirmTime = 36   ; Seconds
#ELSE
  symbol LoopTime = 60000   ; Milliseconds = 1 minute
  symbol ConfirmTime = 3600 ; Seconds = 1 hour
#ENDIF

symbol Relay = b0         ;  Open = 2 , Closed = 1 , Don't Know = 0
symbol ADCnow = w1
symbol ADClast = w2
symbol PotPin = C.1
symbol UpperTrip = 768    ; 1024 * 3.75 / 5 = 768
symbol LowerTrip = 640    ; 1024 * 3.125 / 5 = 640

Low C.0                   ; Set Idle output level
Low C.4
Pause 1000                ; Allow time for voltages to stabilise
do
   ADClast = ADCnow                           ; For future development
   readadc10 PotPin,ADCnow
confirm:                                      ; Re-entry point for confimation pulse
   if ADCnow > UpperTrip AND Relay <> 2 then  ; Open
;      pulsout C.4,65535                      ; Maximum pulse time is 655 ms
      High C.4 : Pause 1000 : Low C.4         ; One second pulse
      Relay = 2
      sertxd("Open ")
   endif
   if ADCnow < LowerTrip AND Relay <> 1 then  ; Close
      High C.0 : Pause 1000 : Low C.0         ; One second pulse
      Relay = 1
      sertxd("Close ")
   endif 
  pause LoopTime                  ; Check the ADC once per minute 
   if time > ConfirmTime then     ; Confirm status
      if Relay = 2 then           ; Remember the last trip point executed
         ADCnow = UpperTrip + 1   ; Last trip point
      else
         ADCnow = LowerTrip - 1
      endif      
      Relay = 0                   ; Confirm the Relay position every hour
      time = 0                    ; Reset the hours counter
      sertxd("Confirm=")
      goto confirm
   endif
loop
Rather than just sending a "Confirmation" pulse once each hour, you could monitor whether the battery voltage is increasing or decreasing (using ADClast) and if that it not consistent with what the relay is supposed to be doing (i.e. charging or discharging) then you could Set the Relay status to zero and a "correction" pulse then will be sent.

Cheers, Alan.
 
Last edited:
Hi,

Do you mean 3.75 volts for C.4 ? I'm assuming that the relay is "Bi-Polar", i.e. A pulse on C.1 closes the contacts and C.4 opens them.

My concern with a Latching Relay is that the Program might get "Out Of Sync" with the Relay. Therefore, I have defined the Relay to have three states, i.e. Open , Closed and "Don't Know". The latter may well apply when the Program starts up, but as a "safety measure" I have shown how the state could be confirmed, for example once each hour. Similarly, I am only polling the ADC once each minute to reduce the risk of the system "dithering" between On and Off. The #IFDEF Simulating sets shorter times for easier testing and I've added SERTXD commands to report what is happening.

Note the use of <> for "Is Not" (i.e. Not equal to) so that the pulse is generated whether the present state is either "Wrong" or "Not Known". I could have defined symbols for OPEN = 2 , etc., but try to avoid programs becoming excessivley verbose. So here is my attempt at a simple program :
Code:
#Picaxe 08M2
#No_Data
#IFDEF simulating
  symbol LoopTime = 600     ; Milliseconds
  symbol ConfirmTime = 36   ; Seconds
#ELSE
  symbol LoopTime = 60000   ; Milliseconds = 1 minute
  symbol ConfirmTime = 3600 ; Seconds = 1 hour
#ENDIF

symbol Relay = b0         ;  Open = 2 , Closed = 1 , Don't Know = 0
symbol ADCnow = w1
symbol ADClast = w2
symbol PotPin = C.1
symbol UpperTrip = 768    ; 1024 * 3.75 / 5 = 768
symbol LowerTrip = 640    ; 1024 * 3.125 / 5 = 640

Low C.0                   ; Set Idle output level
Low C.4
Pause 1000                ; Allow time for voltages to stabilise
do
   ADClast = ADCnow                           ; For future development
   readadc10 PotPin,ADCnow
confirm:                                      ; Re-entry point for confimation pulse
   if ADCnow > UpperTrip AND Relay <> 2 then  ; Open
;      pulsout C.4,65535                      ; Maximum pulse time is 655 ms
      High C.4 : Pause 1000 : Low C.4         ; One second pulse
      Relay = 2
      sertxd("Open ")
   endif
   if ADCnow < LowerTrip AND Relay <> 1 then  ; Close
      High C.0 : Pause 1000 : Low C.0         ; One second pulse
      Relay = 1
      sertxd("Close ")
   endif
  pause LoopTime                  ; Check the ADC once per minute
   if time > ConfirmTime then     ; Confirm status
      if Relay = 2 then           ; Remember the last trip point executed
         ADCnow = UpperTrip + 1   ; Last trip point
      else
         ADCnow = LowerTrip - 1
      endif   
      Relay = 0                   ; Confirm the Relay position every hour
      time = 0                    ; Reset the hours counter
      sertxd("Confirm=")
      goto confirm
   endif
loop
Rather than just sending a "Confirmation" pulse once each hour, you could monitor whether the battery voltage is increasing or decreasing (using ADClast) and if that it not consistent with what the relay is supposed to be doing (i.e. charging or discharging) then you could Set the Relay status to zero and a "correction" pulse then will be sent.

Cheers, Alan.
Thank you Alan
If C.1 goes below 3.2V I need it to trigger and pulse C.0. Then C.1 will go High again as it comes from the full battery. So it has to stay in that state till C.1 gets to that low value again and than C.4 must pulse and so on in a loop
The latching relay is "Bi-Polar and needs only a small 5V pulse to trigger.
It does not matter in which state it is. It will start with both batteries high. The one will charge while the other one drives a load,
As soon as the load one reach that value I need it to switch over .
Regards
Vissie
 
Last edited:
Hi,

Ah, so there are Two Batteries (with independent charging circuits) and the ADC simply measures the input Voltage of whichever battery has been selected. The PICaxe then flips the Relay whenever the selected battery voltage is too low. That's an almost trivial program, because the Relay causes the input voltage to automatically jump up. But an issue might be "What should the Program do if the input voltage does NOT jump up" (or even falls) after the pulse is sent ?
Code:
symbol LoopTime = 10000     ; Milliseconds
symbol Relay = b0             ; Batt A = 0 , Batt B = 1
symbol ADCnow = w1
symbol PotPin = C.1
symbol PulseA = C.0           ; But I would use C.2 !
symbol PulseB = C.4
symbol LowTrip = 640        ; 1024 * 3.125 / 5 = 640

Low PulseA : Low PulseB       ; Set Idle output levels
pause 1000                    ; Allow time for voltages to stabilise
do
   readadc10 PotPin,ADCnow
   if ADCnow < LowTrip then
      if Relay = 1 then
         High PulseA : Pause 1000 : Low PulseA           ; One second pulse
         Relay = 0 : sertxd("Batt A ")    
      else
         High PulseB : Pause 1000 : Low PulseB           ; One second pulse
         Relay = 1 : sertxd("Batt B ")
      endif  
   endif
   pause LoopTime             ; Allow new battery voltage to stabilise
loop
Personally, I still consider myself primarily a Hardware Engineer and I have to say of that diagram "It's not the way that I would have designed it" :( . Firstly on the PICaxe side, I would have used C.2 for one of the pulses, so that C.0 (and C.5) can be wired as a conventional "Programming" (and Debugging) interface. It doesn't necessarily need the full 3.5 mm jack socket, just three pads for the pins of a "Legacy" programming interface (in the old PE User Manual 1). Or usually, I put the Earth as the middle pin; it can be easier to link to the PICaxe, and permits RX and TX to be swapped, since their definitions can be sometimes confused. Later, if you decide that you need an "Alarm" or similar output, then the pads/pins are already there!

But my main concern is the way that the relay contacts are wired: Typically one would wire Battery A to (say) the "Normally Closed" (NC) terminal and Battery B to the "Normally Open" terminal, with the Output Voltage from/to the "Common" (C) terminal of the Same Group of Switching contacts. Switches in general can be specified as "Break Before Make" or "Make Before Break" with the former being by far the most common. Occasionally you might use a Make-Before-Break to ensure that there always would be an output voltage. But here it is ESSENTIAL to use a Break-Before-Make, because connecting a Fully Charged battery to a nearly Discharged one (for even a millisecond) will allow an enormous current to flow and the contacts will very probably weld together permanently. We would need to look very carefully at the specifications and the mechanical construction of the Relay that you're using, because can you absolutely guarantee that ALL of the NC contacts will have opened before ANY of the NO contacts close (or vice versa) ?

Cheers, Alan.
 
Thank you
One battery charges all the time from a cap pulsar and monpole gen coils while the other battery drives a mosfet driven drive coil on a monpole rotor that does not draw a lot of current. There wont be a lot of arcing on te contacts of the relay. In this case the new battery will always be higher. This is for experiments so its not a big deal. The batteries never connect to each other
The relay is good and cannot overlap contacts
The latching relay is quite something. It old military stock from Somewhere in USA.
Its like something like the Bearden space boots. A magnet in the middle and it pivots like a see saw A coil on each side where a short pulse will pull it in and complete the magnet path and hold it on that side like memory. Look at the Flynn magnetic parallel path. It something similar
Regards
Vissie
 
I tried this morning to write a simple code to do it but it ignores my adc settings on the pic axe simulator. It just toggle the two outputs. I probably need sone more commands somewhere...ha ha but thank you. Will try your code some time in the morning


#Picaxe 08M2
#No_Data
DO
readadc C.1,b1 ;reads analog value on C.1 into variable b1
if b1<=160 then RELAY1 ;if b1 is less than 160 then goto sub-programme relay 1
RELAY1:
High C.0 ;C.0 goes high. RELAY 1 TRIGGER
PAUSE 1000 ;PAUSE 1 SEC
LOW C.0 ;output c.0 goes LOW. RELAY OFF
PAUSE 10000 ;PAUSE 10 SEC so I can adjust the adc on simulator
readadc C.1, b1
if b1<=160 then RELAY2
RELAY2:
HIGH C.4. ;output C.4 goes HIGH RELAY 2 TRIGGER
PAUSE 1000 ;PAUSE 1 SEC
LOW C.4 ;output c.4 goes LOW
LOOP
 
Last edited:
Hi,
Code:
if b1<=160 then RELAY1 ;if b1 is less than 160 then goto sub-programme relay 1     ***
RELAY1:
High C.0 ;C.0 goes high. RELAY 1 TRIGGER
       PAUSE 10000 ;PAUSE 10 SEC so I can adjust the adc on simulator    *** Pulse Width
LOW C.0 ;output c.0 goes LOW. RELAY OFF
       PAUSE 1000 ;PAUSE 1 SEC     *** Polling/Adjusting time
readadc C.1, b1
    if b1,<=160 then RELAY2         ; *** Syntax Error AND (Pointless {GOTO} Label ***
RELAY2:
    HIGH C.4. ;output C.4 goes HIGH RELAY 2 TRIGGER    ***  Syntax Error
The Structure for the IF ... commands is completely wrong (Implied GOTO instead of an ENDIF) , you have syntax errors in two lines and the 10 second PAUSE is setting the Width of the pulse, not the Polling Time. And you seem to have abandoned the READADC10s ?

Otherwise, it works for me: In PE6, go to the "Simulation" Window, select the "Values" Tab and then change the WORD field for C.1. But I do still find PE5 easier than PE6 for that simulation. ;)

Cheers, Alan.
 
(The Structure for the IF ... commands is completely wrong (Implied GOTO instead of an ENDIF)
i don't know what to do there
I also tried PE5 but the code in post 24 and this of mine just runs through no matter what value above or below 160 or 640 I make C.1
Does READADC10 refer to 1024 and READADC to 256 ?
 
Hi,

Yes, you must use WORD values with READADC10 , because the full-scale is 1024 (actually the maximum value is 1023). In PE6 you use the Simulation Words with READADC10 and Bytes with READADC. In PE5 you must use the "Generic" field to select a Word value in the Simulator.

There are two types of IF .... THEN command: The preferred construction is as below, where IF the condition is True, then all the code until the ENDIF will be executed, but if the condition is False then the program flow jumps directly to the line after the ENDIF (and this section is traditionally Indented to show that).
Code:
IF PotPin < 100 THEN
    PULSOUT  C.2, 10000    ; Do this only if the condition is true
ENDIF
; Next line to be executed
The other type uses a GOTO , but that keyword can be omitted because it is always followed by a label. One way that it can be used is to SKIP the subsequent lines until the label is reached, but note that the condition (TRUE/FALSE) must be inverted (or reversed) for example < becomes => . Thus the following will do exactly the same as the code above:
Code:
IF PotPin => 100 THEN GOTO ENDlabel    ; The GOTO keyword may be omitted
    PULSOUT  C.2, 10000    ; Do this if the condition is NOT True (because it is not skipped)
ENDlabel:
; Next line to be executed
Alternatively you can ....THEN GOTO.... to a label (e.g. routine) anywhere in the program, but then that code must send the program flow back to the main loop. Or you can use a ....THEN GOSUB label and then the program will return to the next line, when it encountedrs the RETURN line of the Subroutine.

Cheers, Alan.
 
Thank you Allen and also PhilHornby for that awesome timer code.

I read about and tried the commands above but was not very
successful. Out of frustration I tried another Main. Main2 and it seems to be working fine for what I want to achieve for now

#Picaxe 08M2
#No_Data
main: readadc C.1,b1
if b1 <=160 then flsh1
goto main
flsh1:high C.0
pause 1000
low C.0
pause 5000
main2:readadc C.1,b1
if b1 <=160 then flsh2
goto main2
flsh2: HIGH C.4
pause 1000
low C.4
pause 5000
goto main

Regards
Vissie
 
Code:
#Picaxe 08M2
#No_data

main:
        Readadc C.1,b1
    If b1 <=160 Then
        ;Goto main;
        High C.0    ;flsh1
        Pause 1000
        Low C.0
        Pause 5000
    Endif
        ;main2:
        Readadc C.1,b1
    If b1 <=160 Then
        ;Goto main2
         High C.4    ;flsh2
        Pause 1000
        Low C.4
        Pause 5000
    Endif
Goto main

I had forgotten how to add code properly .
 
Hi,

"The Butterfly Effect" :

I wasn't going to waste any more time on this trivial program, but the recent modifications happen to have introduced some features that might be useful or of interest to others. I often use them when writing my very "fast" program code for "Bit-Banging" serial data, such as for example, custom Infra Red or Radio Communications, etc., although the speed is not at all relevant to the Programs in this thread.

First, the three consecutive lines from post #30 : if b1 <=160 then flsh1 : goto main : flsh1: are "inefficient" because they can be replaced by a single instruction: if b1 > 160 then goto main . Both versions give a "Jump Backwards" and a "Fall Through" (to the next line in the Program), depending on the state of the variable (b1). The latter is a very efficient instruction because the "Fall Through" (i.e. False condition path) is fast(er) and the (True) "Jump" (GOTO) path gives us the opportunity to "Close" a program loop, without the need for a separate (Unconditional) GOTO. Programming Purists may argue that the inversion of the Condition (<= becoming >) is confusing, but they would probably agree that "One (or No) GOTOs are better than Two". ;) Thus the complete program could be written as:
Code:
#Picaxe 08M2
#No_Data
setfreq m2    ; Allows PULSOUT to generate 1 second pulses
main1:
   readadc C.1,b1
   if b1 > 160 then GOTO main1   ; Fall Through when the Battery condition is low
   pulsout C.0 , 50000           ; One second at 2 MHz clock
   pause 2500                    ; 5 seconds at 2 MHz clock
main2:
   readadc C.1,b1
   if b1 > 160 then GOTO main2
   pulsout C.4 , 50000 
   pause 2500
goto main1
It hasn't been discussed whether the maximum 0.65 ms (at 4 MHz clock) PULSOUT would be sufficient to drive the relay in practice, but for this version I've used a SETFREQ to allow PULSOUT to generate 1 second pulses. However, the original HIGH C.4 : PAUSE 1000 {; or WAIT 1} : LOW C.4 still could be used, perhaps as a "One Liner".

The program in #24 used a variable named Relay to "remember" the state of the external hardware, so that it "knew" which pulse to generate the next time. The programs in #30 and #33 achieve the same by dividing the program into two very similar parts, with the particular section being executed "remembering" which pulse is needed next. I have called this style a "Butterfly" program, because if the first main Loop were written on the Left Hand Page of a notebook, then the second Loop could be a copy with very few changes onto the Right Hand Page, with the two loops or pages being considered the "Wings" of a Butterfly. These Wings can effectively act as an "invisble" (zero execution time) "memory" for the state or progress of the Program.

Off Topic : My fast bit-banging programs often take the form of a "Butterfly", for example with the Wings handling the "(Modulated) Carrier" and "Gap" (e.g. 0/1) sections of the Program. Or sometimes even repeating a whole routine separately for Odd and Even phases (i.e. in the two Wings): This allows some time-consuming sections of the routine, such as any "Housekeeping", and the fundamental "Jump Backwards" (to close the loop), to be shared between the two phases. It may even allow bit-strings of more than 8 or 16 bits to be handled directly by single Byte or Word variables. Note that I haven't used the term SUBROUTINE anywhere, because they (or in particular the RETURN) are generally "Too Slow" Instructions to use with Bit-Banging.

Moving on to the program in post #32, note that it does not have the same "memory" embedded in the loops, it always executes both sections in sequence. Does this matter? Well Yes and No. :) When the input (b1) crosses the threshold level, there is an even (i.e. 50%) chance of which pulse will be generated, depending on which instruction is currently being executed. If it happens to be the "Wrong" Pulse (i.e. the same as last time) then nothing will happen and 5 seconds (or whatever) later, it will generate the "Correct" Pulse. Of course if the input voltage does not return across the Threshold voltage within the 5 seconds, then all these versions of the program will produce alternating A and B pulses every 5 seconds.

Cheers, Alan.
 
Last edited:
Hi,

"The Butterfly Effect" :

I wasn't going to waste any more time on this trivial program, but the recent modifications happen to have introduced some features that might be useful or of interest to others. I often use them when writing my very "fast" program code for "Bit-Banging" serial data, such as for example, custom Infra Red or Radio Communications, etc., although the speed is not at all relevant to the Programs in this thread.

First, the three consecutive lines from post #30 : if b1 <=160 then flsh1 : goto main : flsh1: are "inefficient" because they can be replaced by a single instruction: if b1 > 160 then goto main . Both versions give a "Jump Backwards" and a "Fall Through" (to the next line in the Program), depending on the state of the variable (b1). The latter is a very efficient instruction because the "Fall Through" (i.e. False condition path) is fast(er) and the (True) "Jump" (GOTO) path gives us the opportunity to "Close" a program loop, without the need for a separate (Unconditional) GOTO. Programming Purists may argue that the inversion of the Condition (<= becoming >) is confusing, but they would probably agree that "One (or No) GOTOs are better than Two". ;) Thus the complete program could be written as:
Code:
#Picaxe 08M2
#No_Data
setfreq m2    ; Allows PULSOUT to generate 1 second pulses
main1:
   readadc C.1,b1
   if b1 > 160 then GOTO main1   ; Fall Through when the Battery condition is low
   pulsout C.0 , 50000           ; One second at 2 MHz clock
   pause 2500                    ; 5 seconds at 2 MHz clock
main2:
   readadc C.1,b1
   if b1 > 160 then GOTO main2
   pulsout C.4 , 50000
   pause 2500
goto main1
It hasn't been discussed whether the maximum 0.65 ms (at 4 MHz clock) PULSOUT would be sufficient to drive the relay in practice, but for this version I've used a SETFREQ to allow PULSOUT to generate 1 second pulses. However, the original HIGH C.4 : PAUSE 1000 {; or WAIT 1} : LOW C.4 still could be used, perhaps as a "One Liner".

The program in #24 used a variable named Relay to "remember" the state of the external hardware, so that it "knew" which pulse to generate the next time. The programs in #30 and #33 achieve the same by dividing the program into two very similar parts, with the particular section being executed "remembering" which pulse is needed next. I have called this style a "Butterfly" program, because if the first main Loop were written on the Left Hand Page of a notebook, then the second Loop could be a copy with very few changes onto the Right Hand Page, with the two loops or pages being considered the "Wings" of a Butterfly. These Wings can effectively act as an "invisble" (zero execution time) "memory" for the state or progress of the Program.

Off Topic : My fast bit-banging programs often take the form of a "Butterfly", for example with the Wings handling the "(Modulated) Carrier" and "Gap" (e.g. 0/1) sections of the Program. Or sometimes even repeating a whole routine separately for Odd and Even phases (i.e. in the two Wings): This allows some time-consuming sections of the routine, such as any "Housekeeping", and the fundamental "Jump Backwards" (to close the loop), to be shared between the two phases. It may even allow bit-strings of more than 8 or 16 bits to be handled directly by single Byte or Word variables. Note that I haven't used the term SUBROUTINE anywhere, because they (or in particular the RETURN) are generally "Too Slow" Instructions to use with Bit-Banging.

Moving on to the program in post #32, note that it does not have the same "memory" embedded in the loops, it always executes both sections in sequence. Does this matter? Well Yes and No. :) When the input (b1) crosses the threshold level, there is an even (i.e. 50%) chance of which pulse will be generated, depending on which instruction is currently being executed. If it happens to be the "Wrong" Pulse (i.e. the same as last time) then nothing will happen and 5 seconds (or whatever) later, it will generate the "Correct" Pulse. Of course if the input voltage does not return across the Threshold voltage within the 5 seconds, then all these versions of the program will produce alternating A and B pulses every 5 seconds.

Cheers, Alan.
Hoo Hoo! Thanks Alan
It works beautiful and will be the version I'm using. Its professional unlike mine
Regards
Vissie
 
Back
Top