Switching issues

Rampz

Well-known member
Hello All

This is my first post, help please

I copied some of the code from a book, played with it in ways only someone with no experience can and although it does work i noticed some issues, code as below

Code:
#picaxe 08m2
#no_data
setfreq m8   ' i set to 8mhz to see if it would help
    symbol green = 4   'pin c4
    symbol light = 400  'wait 400ms
    symbol btn = pinc.3   'pin c3
  
main:
    if btn = 1 then
    high green   ' turn on green led
    pause light   ' wait 400ms
    low green     ' turn green led off after
endif
goto main
The output switches on when button is pressed and it should stay on if the button is kept pressed, but i notice with the button pressed and held there is a flicker from the LED i really wanted the led to stay on as along as the button is pressed plus 400ms.

There are 2 requirements

If the button is pressed for say 20ms then i want the output to stay on for 400ms
if the button is pressed and held on then i want the output to stay on till button released plus 400ms

This drives a motor via a mosfet and the button is a tilt switch, i don't want the quick flash i currently get, currently i use a 555 timer chip and that works well but the current draw from the timer is quite high compared to the picaxe, so hoping to get the same effect at a lower current draw and the ability to add aditional features to my project

My answer to that was to set the frequency to 8mhz which does help but maybe there is a better way of doing this?
 
Last edited:

oracacle

Senior Member
so what you need a hold loop

Code:
#picaxe 08m2
#no_data
setfreq m8                 ' i set to 8mhz to see if it would help
symbol green     = 4         'pin c4
symbol light     = 400     'wait 400ms
symbol btn = pinc.3         'pin c3

main:
    if btn = 1 then
    do
    'you can do things in this loop, but in thhis case its just a holding loop
    loop while btn = 1
    high green             ' turn on green led
    pause light         ' wait 400ms, debounce?
    low green             ' turn green led off after
    endif
goto main
or you could but the holding loop in after the "high green" command, this will turn on the LED and hold it on for as long as the button is pressed, instead of not switching it on until after it is depressed.
 

Rampz

Well-known member
Hello Oracacle

Thank you for such a quick reply, i just tried it as you have written it and it wasn't as i wanted so moved the extra line to after "high green" as i now understand you wrote underneath and works perfectly, so have removed the 8mhz line sinne no longer needed.

Yes the 400ms is both a debounce and also the minimum time that i want the output to stay on

Bit by bit i am learning

The input from my tilt switch is switched 12v + i understand this is way too high as an input i have seen several ways to interface it, a transistor can be used but i see there can be issues if power is lost to the picaxe so looking at an PC817 opto isolator as the interface, is this the best way? I did see i can use a couple of resistors as a voltage divider but can see that will involve extra programming Lol
 

oracacle

Senior Member
Yes that could work providing you use a resistor on the tilt switch side, you will need to know the forward voltage and forward current of the opto isolator diode. alternativly you could just use a simple relay, the coild switch by your tilt switch and the switch side for the picaxe. Both of these options completely isolate the picaxe from the higher voltage

Now you could use a transistor, but it get a bit more complex. For started the ground need to be connected, and depending on the chosen transistor you may have to operate it a in a type of NOT gate arrangemnt. This means that the programme would have to look for a 0 on the switch both the if commamnd and the loop. As you maybe able to understand, this option does not completely isolate the picaxe from the higher voltage.

which way you go will depend on what the circuit requirements are. High speed switching, then either the opto of transistor will be favoured, if speed is not an issue then relay will be fine. The relay will also draw a fair amount more current than the other options which maybe something that you need to consider.
 

Rampz

Well-known member
Thank you Oracacle.

Normally the project will be running from a 12v 10ah battery being maintained by a Ctek 3.8ah charger, in mains fail situation i need to have the setup last as long as possible so really need to keep away from relays, i have attached my proposed circuit diagram, you will see features that currently i'm not using, there is a voltage divider setup for monitoring the battery later stages of the project, and an LED on the serial output so i can see the program downloading and for future indication of status.

Thoughts please

Regards Simon
 

Attachments

inglewoodpete

Senior Member
My interpretation of what you want is for the output to turn 'on' when the button is pressed. The output is to turn 'off' when the last of either 400mS-after-the-start-event or the switch being released (Ie whichever occurs last).

If that is the case, the folowing code should do this: 1) Activate the output when the button is pressed. 2) Turn the output off when the button is released but only after 400mS.
Rich (BB code):
#picaxe 08m2
#no_data
symbol green = 4   'pin c4
symbol light = 400  'wait 400ms
symbol btn = pinc.3   'pin c3
symbol TimeFlag = bit0

Init: setfreq m8           ' i set to 8mhz to see if it would help
Main: if btn = 1 then
         if TimeFlag = 0 then
            high green     ' turn on green led
            pause light    ' wait 400ms once only per press
            TimeFlag = 1
         endif
      else
         low green         ' turn green led off after
         TimeFlag = 0
      endif
      goto Main
 

Rampz

Well-known member
inglewoodpete

Thank you for your reply

I will give that a try later and see what happens, see if the operation is the same as the previous answer.

Its interesting to see that there can be several solutions to the same puzzle

Regards Simon
 

Rampz

Well-known member
Ok

I have had chance to play with both versions of code as ammended by Inglewoodpete and Oracacle and i have tried both frequencies and they behave slightly differently if the button is pressed many times quickly then there are presses where the LED is off for a split second, with Oracacle's code changes it gets better ie less breaks when pressed quickly when the frequency is set to 8mhz, whereas the opposite is the case with Inglewoodpete's code changes the effect gets worse as the clock speed is set to 8mhz.

Maybe i have 3 states to consider

1) button pressed and held and delay of 400ms after button released
2) button pressed for say 20ms and released we want the time to be a minimum of 400ms or 20ms + 400ms for this example
3) button pressed rapidly the LED needs to just stay on till pressing finished and then plus 400ms

A bit about the project and how i will use the picaxe

The project uses a tilt switch to operate a motor that is used to apply tension to the mechanism of a church clock, over time the clock uses the tension to operate and as trension is released in the sring the tilt switch operates and re-tensions the spring, in this case the tilt switch operates once ever 10 mins or so, but the setup that operates the chimes side of the clock can run for upto 60 seconds when the clock strikes the hour, the motor tends to pulse diferently depending on the different types of clock and its gearing, so all 3 states could happen.

When using my 555 timer setup i get all 3 states covered without issue, i think both version will work ok, but just wondering if i can improve further?
 

inglewoodpete

Senior Member
Ok

I have had chance to play with both versions of code as ammended by Inglewoodpete and Oracacle and i have tried both frequencies and they behave slightly differently if the button is pressed many times quickly then there are presses where the LED is off for a split second, with Oracacle's code changes it gets better ie less breaks when pressed quickly when the frequency is set to 8mhz, whereas the opposite is the case with Inglewoodpete's code changes the effect gets worse as the clock speed is set to 8mhz.

Maybe i have 3 states to consider

1) button pressed and held and delay of 400ms after button released
2) button pressed for say 20ms and released we want the time to be a minimum of 400ms or 20ms + 400ms for this example
3) button pressed rapidly the LED needs to just stay on till pressing finished and then plus 400ms

A bit about the project and how i will use the picaxe

The project uses a tilt switch to operate a motor that is used to apply tension to the mechanism of a church clock, over time the clock uses the tension to operate and as trension is released in the sring the tilt switch operates and re-tensions the spring, in this case the tilt switch operates once ever 10 mins or so, but the setup that operates the chimes side of the clock can run for upto 60 seconds when the clock strikes the hour, the motor tends to pulse diferently depending on the different types of clock and its gearing, so all 3 states could happen.

When using my 555 timer setup i get all 3 states covered without issue, i think both version will work ok, but just wondering if i can improve further?
Just had a thought. The 08M2's native speed is 4MHz, so "Pause 400" will only give 400mS at 4MHz. If you double the clock speed, you need to double the number used for the Pause statement. The code we have all been posting, above would give 200mS delays!

From what you are now saying, you want the output to stay on for 400mS more than the button release time. You want rapid pressing and releasing of the button to merge the pulses into a long one, provided the button is pressed again prior to 400mS after the previous release.

That complicates the code required. Still do-able but you have the understand more about how the PICAXE 08M2 works and how your code needs to be configured. What happens when the Pause statement is executing? Basically nothing - the Pause statement is generally considered to be a blocking statement, so the PICAXE will not be looping or checking the state of the button while the Pause is executing. While interrupts can cause a Pause statement to truncate, I would not advocate using interrupts in an 08M2 for your task.

How critical is your 400mS delay period? Can it be +/- 10, 20 or 50mS? I'm thinking that a loop counter-based delay would be a better solution.

Unfortunately, I have a busier day today and won't be able to put together some code for you.
 

Rampz

Well-known member
Just had a thought. The 08M2's native speed is 4MHz, so "Pause 400" will only give 400mS at 4MHz. If you double the clock speed, you need to double the number used for the Pause statement. The code we have all been posting, above would give 200mS delays!
I had read that i need to increase the time with running frequency but completly forgot about it, its all good learning

Regards the time delay 400ms isn't critical but i would like to be able to extend or decrease depending on what's needed.

I did re-do my primitive testing and still found that the alteration by Oracacle still gave the best results if button is pressed rapidly or more slowly but still being under the 400ms (800 setting for 8mhz clock), or my best attempt to

Its also intresting what you say about nothing happening during the pause period, i did see the 08m2 can run upto 4 parallel tasks, so maybe thats a route to check the input during the pause period?

Regards Simon
 

lbenson

Senior Member
i did see the 08m2 can run upto 4 parallel tasks
For someone of your evident skill level (way above what beginners are looking for in parallel tasking), it's unlikely that the pseudo-"parallel task" method will accomplish what you want better than the method you're pursuing.
 

Rampz

Well-known member
Hello Ibenson

I am experienced in what I'm trying to achieve as currently its being done with a 555 timer, but I am very new to picaxe and microcontrollers, I have no programming experience, I am learning as I go, learning the limitations too, I'm hoping picaxe will be able to replace my 555 timer functions and allow me to add other features more easily than adding circuits through programming

Simon
 

oracacle

Senior Member
If you really need to do things while that instead of pausing, there is a way, but will also depend on if you need 400ms pause or will 1 second be OK
Code:
#picaxe 08m2
#no_data

symbol green    = 4                'pin c4
symbol light    = w0             'This is timer variable - 1 second intervals @ 4 mhz
symbol btn         = pinc.3        'pin c3

main:
    if btn = 1 then
        high green
        do
        'you can do things in this loop, but in thhis case its just a holding loop
        loop while btn = 1
    pause 50                'debounce
    let light =  time + 1        'store the current time and add 1 for a 1 second delay
    'this can go before the debounce loop to start timing at the moment the button is pushed
    endif

    'do other stuff in main programme loop here
    
    if time >= w0 then        'check to see if time is higher than the store turn off time
        low green                 'turn green led off after
    end if
    
goto main
With this code, you get the debounce hold as before, but instead of waiting for 400ms, it stores what the time should be in 1 second (limitations of the command) and then checks the time every instance of the main code loop.
time - BASIC Commands - PICAXE
There are problems with this, like if somemthing else take longer than 1 second in the loop the LED will be on for longer.
Also the command only increments the time variable in 1 second increments, 2s @ 8mhz, 1s@16mhz and 0.5@32mhz.
 

Goeytex

Senior Member
Hi,

This should act as a resetable One-Shot.

When the button is pressed the LED turns On and a counter starts. As long as the button is released the counter will increment until it reaches the value defined by LoopTime. So adjust the "LoopTime" constant to get the correct time that the LED is on after the Switch is released. If at any time the switch is pressed before the counter reaches looptime, the counter restarts from 0. So repeated pressed will cause the LED to stay on until the switch is released for LoopTime ( 400 ms)

The LoopTime value will be less than 400 due to processor overhead. I would start With a value of 300 and go from there.

Code:
#picaxe 08m2
#no_data

Symbol BTN = PinC.3  '// Switch
Symbol LED = C.4
Symbol Counter = W0
Symbol Pressed = 1
Symbol Released = 0

Symbol LoopTime  = 300

MAIN:

   IF BTN = Pressed then
      High LED
      Pause 30

      StartCounter:
      Counter = 0
      Do while BTN = Pressed
      Loop

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then rese timer

      Do While Counter <= LoopTime  
          Counter = Counter + 1
          Pause 1
          If BTN = Pressed then 'start over
             Goto StartCounter
          END IF
      Loop
      LOW LED
   END IF

GOTO MAIN:
 

inglewoodpete

Senior Member
(y)While I have not studied either of the above solutions in detail, they use the principle that I referred to earlier. They use only very short pause statements which allows the input button to be monitored more frequently. Either should do what you have said you require.
 

Rampz

Well-known member
Thank you to everyone that has commented with their ideas and code, i will try the 2 above counting based options later and let you know how it goes for me.
As a very new member of the forum i am amazed by the responce i have had from everyone and how quickly people have come forward with answers.

Simon
 

Jack Burns

New Member
Just been using the logic analyser, so out of interest I tested the code in posts 13 & 14 and measured the time delays of both methods.

oracacle's method (post 13)
I found this method sometimes produces a delay of less than 400 ms, and have seen delays as short as 65 ms. I suspect this is due to the time variable being read a fraction of a second before it rolls over to the next second.

25010

and here's a zoomed view
25011



Goeytex's method (post 14)
This method worked well, however the LoopTime was found to be 1.396 seconds (1396 ms), so the processor overhead is having quite a significant effect.

25007


Inreasing the Counter step value to 2 results in a time of 708 ms
Code:
Counter = Counter + 2
25008


And a Counter step value of 4 results in a time of 356.8 ms
Code:
Counter = Counter + 4
25009


Hope this helps.

Regards
Jack
 

Rampz

Well-known member
Thank you Jack Burns

Great work with the logic analyser on the last 2 sets of code, so many different was to do what i first thought was a simple task, some routes i found worked better with an increase in clock speed, But for my application the code by Goeytex seems to work the best at standard clock speed with the ability to alter the counter figures as shown by Jack's testing.

What seemed like an easy task to use a button to get an output to pulse for a set time, seemed after several attempts to be more of a compound requirement and i guess its always a case of working out exactly whats required before trying to code it.

I will build this up on a veroboard and try it driving a logic level mosfet and see how it goes, i will try everyone's program.

Thank you again to everyone that has replied to my thread, sorry if you felt i didn't know what i actually wanted its been a learning curve for me.

Regards Simon
 

Rampz

Well-known member
Hello again

Currently my project uses a 555 timer directly driving a IRLU8743PbFHE n-channel mosfet, i have been looking around for a logic level mosfet but looking at the data sheet for the one i currently use it says its RDS(on) at 4.5Vgs so i assume the picaxe will also drive this ok too? It would be best that i don't need to change the components i currently use to keep everything backwards compatible etc if possible.

Or should i look for a mosfet thats has a lower minimum turn on voltage?

I thought I should add that the 08m2 will be powered by a precision 5v voltage regulator only.
 

Attachments

Last edited:

inglewoodpete

Senior Member
Hello again

Currently my project uses a 555 timer directly driving a IRLU8743PbFHE n-channel mosfet, i have been looking around for a logic level mosfet but looking at the data sheet for the one i currently use it says its RDS(on) at 4.5Vgs so i assume the picaxe will also drive this ok too? It would be best that i don't need to change the components i currently use to keep everything backwards compatible etc if possible.

Or should i look for a mosfet thats has a lower minimum turn on voltage?

I thought I should add that the 08m2 will be powered by a precision 5v voltage regulator only.
According to the datasheet, the RDS(on) with VGS of 4.5v is 3 to 4 milliohms, which is pretty good for a switching MOSFET. The CIN (@4.9nF) is quite high, so it is probably not so good for PWM, if that is what you have in mind. If that is your plan, add a MOSFET diriver between the PICAXE and the MOSFET.

Your best bet is to measure VDS when the PICAXE output is turned on, with the MOSFET's normal load connected - just write a short routine that turns the output on (and leaves it on) for this test. Also check the temperature (with a finger) of the MOSFET when working in these conditions.
 

Rampz

Well-known member
Thank you Inglewoodpete

I'm not using it for PWM control, switching speed will be at most twice a second, i have found a formula for working out switching speed and its shows i should fine, but i will do just as you suggest and see if it gets warm under load etc

Simon
 

Goeytex

Senior Member
To mitigate the effect of processor overtime ..

1) Operate the Picaxe at a higher clock speed using "setfreq". Try 16 or 32 Mhz
2) Eliminate the pause in the counter loop altogether. Then adjust the "LoopTime" constant (Symbol LoopTime = X) to get the delay time that you require.

I think a combination of #1 and # 2 above is probably the best solution since the processor overhead is dominating the delay time. This way we are using the processor overhead for the delay. With a word value as the counter there can be up to 65535 loop counts.

If , for example, 1 loop takes 100 us, for a delay of 400 ms we will need (400,000us /100us) loops or 400 loops for a delay of 400 ms. Since we don't really know how long 1 loop takes, some testing is necessary. The faster the chip operates the better the resolution will be.

In any case I would not use steps in the counter loop. Adjust the LoopTime constant instead.
 

Rampz

Well-known member
Thank you Goeytex

I don't currently understand why altering the time constant is better than increasing the counter number, I have played with both and both seem to alter the pulse time really well.

Attached is my vero board setup including the programming port, I have added a LED to to C0 so I can see it programming and I have added C0 to follow the output so I know what's happening too.
For the next part of my project I will start a new thread, since this thread seems a good source of information on switching.

Regards Simon
 

Attachments

Goeytex

Senior Member
I don't currently understand why altering the time constant is better than increasing the counter number, I have played with both and both seem to alter the pulse time really well.
It is no better or no worse. I find it convenient to use a constant at the start of code instead of hunting down a routine somewhere in code to change a variable, especially useful in large programs. So it is a personal preference. Use whatever works for you.

Here is a similar routine ( same general method), however I used a decrementing counter instead of an incrementing counter. I eliminated the pause inside the loop, and eliminated the LoopTime constant, and bumped the Chip Frequency up to 16 Mhz . Decrementing counters are the most used method for delays in Assembly Language. Just an example of how it can be done in different ways.

Test this code. Adjust the value of "Counter" variable up or down to calibrate the delay.

Code:
#picaxe 08m2
SetFreq M16

#Rem
@8Mhz  Instruction time (overhead)  is 1/2 compared to 4 Mhz
@16MHz Instruction time (overhead)  is 1/4 compared to 4 Mhz
@32Mhz Instruction time (overhead)  is 1/8 compared to 4 Mhz
@8MHz  "Pause 1" = ~500 ms
@16MHz "Pause 1" = ~250us
@32MHz "Pause 1" = ~125us
#ENDREM

#no_data

Symbol BTN = PinC.3  '// Switch
Symbol LED = C.4
Symbol Counter = W0
Symbol Pressed = 1
Symbol Released = 0

MAIN:

   IF BTN = Pressed then
      High LED
      Pause 120      '// Debounce delay / 120 = ~30 ms @16MHz 

      StartCounter:
      Counter = 300              '// Adjust this value to change delay time after button released
      Do while BTN = Pressed
      Loop

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then rese timer

      Do While Counter > 1     
          Counter = Counter - 1
            If BTN = Pressed then 'start over
            Goto StartCounter
          END IF
      Loop
      LOW LED
   END IF

GOTO MAIN:
 

tmfkam

Senior Member
Thank you Goeytex

I don't currently understand why altering the time constant is better than increasing the counter number, I have played with both and both seem to alter the pulse time really well.

Attached is my vero board setup including the programming port, I have added a LED to to C0 so I can see it programming and I have added C0 to follow the output so I know what's happening too.
For the next part of my project I will start a new thread, since this thread seems a good source of information on switching.

Regards Simon
I like to see a neat and tidy Vero Board layout.
The resistor in the very left most track appears to have no connection to anywhere? Perhaps it is linked under the board? Still thought I'd mention it before you start getting odd errors.
 

Rampz

Well-known member
The resistor in the very left most track appears to have no connection to anywhere? Perhaps it is linked under the board? Still thought I'd mention it before you start getting odd errors.
Thank you tmfkan

The resistor is connected to the track above but since there isn't enough space for the size of resistor it does appear to be connected to nothing, i do like to keep veroboards neat and compact, eventually it will be on a custom pcb and i will be able to reduce the size again, if i had taken a side shot you would see my mistake.

Regards the reply above from Goeytex i have tried the alternative program and it works just find with the alternative counter setup, i did try the default clock speed and adjusted the times and it seemed to work just as well, so not understanding the "overhead", so much to learn, i can get my head around what you are doing but not to the the extent where i could write it or modify it
 

Rampz

Well-known member
As an advancement to the project and to add diagnostics i want to try to do the following, i have attached a picture of what the programming will be used for so it gives some idea to my project, my mate makes these in his spare time and i am trying to improve the electronics.

If the output is switched on continuously for more that say 30 seconds which should never happen this would indicate a stalled motor where the microswitch is switching the ouput and the motor isn't moving, i would like 2 things to happen
1) stop the output to protect the motor untill the microswitch resets and re-triggers
2) flash C0 a couple of times and write 1 to memory for later recall

Then i would add a switch to say C1 that when its pressed the counter reads back the quantity of stalls via the C0 led, flashing the led the number of times its recorded

Then a long press of the switch to clear the memory

I'm not sure how a program should flow, do i need to monitor the microswitch a second time and "do if" something? or add an additional loops into everything? any help would be great

I have already added C0 into the program to both mimic programming and to follow the output on C4

Getting an output to flash i have already played with but i did it the long way of doing it

Edit

I assume when an event is detected I need to write to a memory location, I another event is detected then I need to read from that location and +1 and write back to previous location the new value, I assume its not writing to the eeprom unless I am asking it to?
I struggle to understand memory and what's available is there a list.

Regards reading the number of events I assume that a press of an on board switch will read from the memory location and for the value in there flash the led that amount of times after this another press of the switch reset the value stored in memory back to zero.

I know there are loads of assumed in here, I feel I can see a possible route just can't get my head around putting it down in code
 

Attachments

Last edited:

Goeytex

Senior Member
Regards the reply above from Goeytex i have tried the alternative program and it works just find with the alternative counter setup, i did try the default clock speed and adjusted the times and it seemed to work just as well, so not understanding the "overhead", so much to learn, i can get my head around what you are doing but not to the the extent where i could write it or modify it
@Rampz

By running the Picaxe faster you will be able to get better resolution. I am guessing at 16 MHz you well get a resolution of 250 microseconds or so. That means that each count through the loop take 250 us. So if 1 loop = 250 us you can easily do the math to find how many loops you need to get to 400ms. Running the Picaxe at 32 Mhz will get even better. 250 is just a guess. You need to measure the time of 1 loop to know the actual time. I have no Picaxe chips on hand right now so I can't do the measurement. Maybe Jack Burns can do some measurements??

In regards to overhead. Each Picaxe "command" takes time for the Picaxe interpreter to process and execute. Some commands take more time than others. This is the overhead we are referring to. So the faster the chip operates the less "instruction time" overhead there will be.
 
Last edited:

Rampz

Well-known member
Goeytex

Thank you for the additional explanation it all help me in my head understand exactly whats going i need this in order to apply the information, basically as you say we are counting looks, we don't just know how long a loop takes based on 'overhead' but as you say that can be decreased by increasing the clock speed, ofcourse i will need to increase the count number under the counter in symbols because as the speed increases the loop time will decrease, i get that well now, i still could code it, but i'm getting there.
For my next part of my project i was looking at how i should go about it, i did look at parallel tasks, but after much though and the speed my current loop is running, i think i can add extra code into the existing to do what i want?
I can see the best way to not slow the loop down very much will be to use a second counter, i think i need to add that at 'symbol' and its W location, then after my initial loop has finished 1 cycle i would need my new counter to also check the status of pinC.3 and start counting loops but i can see that i have a maximum count of just over 65,000 and looking at loop times taking 250 or less microseconds i will run out of count at about 6.5 seconds, so i think i need to use some maths to decrease this number, how does this work? Do i wait till the counter gets to say 0.5 seconds worth and then write say 1 to another location? I can see i need to keep the count number down to a useful number then maybe divide it against maybe 1000 to keep it in order and when the new total reachs a number specified in 'symbol' using IF then something will happen, i guess if i can read that figure out on the editor terminal i can see whats going on.
A problem i can see is that i only want to count loops where the pinC.3 is seen to = 1 and if during counting it ever sees 0 then it should reset the counter, because it would indicate the motor is doing its job and isn't in stall, it would only be the times where the status of pinC.3 is permantly =1 if that makes sense, the sort of time delay i am wanting before something would happen would be maybe 60 seconds which without some maths i think would fill the counter well before 60 seconds.
Initally i would want pin C4 to go low and stay there if the above time is reached and only reset back to normal operation when the second counter resets due to seeing a 0 on pinC.3 during a loop as would happen during the counting if a 0 is seen from pinC.3

Am i heading in the right direction with this idea? I guess it doesn't matter much if i use an increasing counter or a decreasing counter

Any help would be great and any help with code would be great too, i can see little bits all over that do small bits of what i want just can't bring it all together otherthan basic things like altering the 'symbol' part and numbering my counters
 

Rampz

Well-known member
Thank you Jack Burns your work on my problem is really useful, a quick caculation would show that i shouldn't go above 8mhz for my delay for the next part of my project, at 8mhz i divided 60s by 0.472 and * that by 300 to give 38,135 which from reading up on the subject is below the 65,535 limit
 

Rampz

Well-known member
Code:
#picaxe 08m2
#no_data
setfreq m8 'to reduce overhead

Symbol BTN = PinC.3  '// Switch via pc817 optocoupler, 10k to ground and 1k input
Symbol LED = C.4 'to mosfet via 330 ohm resistor
symbol LED1 = C.0 'to led via 1k resistor
Symbol Counter0 = W0
symbol counter1 = W1 'new counter for delay
Symbol Pressed = 1
Symbol Released = 0

Symbol LoopTime0  = 300 'was set at 300 but can adjust
symbol looptime1 = 38000 '
MAIN:

   IF BTN = Pressed then
      High LED 'this is the mosfet drive pin
    High LED1 'an idication of programming and output
      Pause 30

      StartCounter0:
      Counter0 = 0
      Do while BTN = Pressed
      Loop

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then reset timer

      Do While Counter0 <= LoopTime0
          Counter0 = Counter0 + 1 '1-6 works fine, was set at 1
          Pause 1
          If BTN = Pressed then 'start over
             Goto StartCounter0
        END IF
    END IF
    Loop
        IF BTN = Pressed then 'my attempt to use the above loop counting to give a delay, i have altered symbols and named counters
        Pause 30
    
     StartCounter1:
              Counter1 = 0
              Do while BTN = Pressed
             read W1+1 'syntax error here, really have no clue at this point

                'missing loads in here
        IF BTN = 0 'syntax error here too, i'm just lost
        counter1 = 0 ' trying to reset counter if BTN = 0
            
        IF W1 = Looptime1 'thinking this could be ok
        'also stop counting further?
        low led ' this needs to stay low till counter is reset by BTN = 0


      LOW LED 'mosfet drive pin
    LOW LED1 'status led and programing
   END IF

GOTO MAIN:
Me trying to write in basic to do my loop counting, i have tried to write plenty of comments, Help please, i'm looking through all the manuals trying to get ideas as well as examples

Ok i am making some progress or the syntax errors seem to be moving about, i get rid of one and then seems i have another in a different place, i guess this is as the program goes through its cycle?
 
Last edited:

AllyCat

Senior Member
Hi,

It may help if you use the indenting "correctly", i.e. a constant number of spaces (or TABs) between IF ... ENDIF and DO ... LOOP , etc.. sections. Also, there are two forms of the IF ... command, a single-line IF .... THEN {GOTO} <label> and the IF ... THEN : <NEWLINE> any number of commands : <NEWLINE> ENDIF . You can indeed put a GOTO inside the IF .... ENDIF if you wish, but it's not a structure to be encouraged. ;) . So the main part of your program could/should start as:

Code:
   IF BTN = Pressed THEN
      High LED                              'this is the mosfet drive pin
      High LED1                             'an indication of programming and output
      Pause 30
StartCounter0:
      Counter0 = 0
      DO : LOOP while BTN = Pressed      ; Alternative structure which may better emphasise that it's an "empty" loop
'// If here then switch released
      DO WHILE Counter0 <= LoopTime0                   '//  Time Out after 400 ms
          INC Counter0                                                ; Alternative command may clarify intent
          Pause 1
'// If another Press detected then reset timer
          IF BTN = Pressed THEN GOTO StartCounter0              'start over   [THEN EXIT might be a "preferred" command (by some)
;         END IF                                                          ; Not required in alternative (optional) GOTO format
      LOOP                                                                ; Moved higher to improve structure (indent same as DO)
   ENDIF                                                                 ; Indented to match its IF
For large/long counter/timer functions you can simply "Nest" loops, for example FOR w1 = 0 to 65535 : FOR w2 = 0 to 65535 : NEXT w2 : NEXT w1 can give a 32 bit delay, or about 3 months (at 4 MHz) :) Later, the READ command is used (only) to Read data from the EEPROM/DATA section of memory, so cannot be used in the format you showed.

The execution times of most of the simpler PICaxe instructions are "known" and reasonably predictable (but may be different by +/- 20% between various members of the PICaxe "family") : For example HIGH <pin> and INC <variable> , take about 400 us (at 4 MHz) and , IF ... , GOTO ... , * (multiply) , / (divide) and many others are all around 1 ms. But a "gotcha" is that although the PULSOUT and PAUSEUS , etc. commands are specified in increments of 10 us (at 4 MHz) they have an "overhead" of around 700 us (i.e. with a small parameter such as 0 , 1 , etc.). There are also some Instructions that are "constructed" by the Program Editor, so may take longer than expected, for example the WORD qualifier and SWAP , BINTOASCII and PWMDUTY , etc. (a clue can be the number of bytes that they add to the PE "Syntax Check"). Again, not really relevant to this thread, but I have included programs in the Code Snippets section of the forum which can measure the Execution times of nearly all the PICaxe commands without any additional hardware (except for a "real" PICaxe, not the Simulator).

Cheers, Alan.
 

Jack Burns

New Member
Rampz, I'm starting to get a bit confused by your exact requirements and keep finding the need to constantly scroll up and down the posts looking for information. Please can you list your exact (and possible future requirements) in a simple list as that should help us to help you.

I believe these are your requrements...
  1. If the button is pressed for say 20ms then I want the output to stay on for 400ms
  2. If the button is pressed and held on then I want the output to stay on till button released plus 400ms
  3. If the output is switched on continuously for more that say 30 seconds, then treat it as a stalled motor, so stop the output to protect the motor until the microswitch resets and re-triggers. Also flash C0 a couple of times and write 1 to memory for later recall.
Question: Do you know how short the pulse may be from the microswitches? because you could probably add some small capacitor to the inputs to extend the switching time. Having a longer switch pulse might enable you to have simpler code.

Test this code. Adjust the value of "Counter" variable up or down to calibrate the delay.
I have modified the code from Goeytex as a test. Currently the fault indicator LED will come on after 6 seconds of the button being continually held down. The flashing light and memory storage hasn't been implemented because I've run out of time and need to go out.

Try this...
Code:
#picaxe 08m2
SetFreq M16

#Rem
@8Mhz  Instruction time (overhead)  is 1/2 compared to 4 Mhz
@16MHz Instruction time (overhead)  is 1/4 compared to 4 Mhz
@32Mhz Instruction time (overhead)  is 1/8 compared to 4 Mhz
@8MHz  "Pause 1" = ~500 ms
@16MHz "Pause 1" = ~250us
@32MHz "Pause 1" = ~125us
#ENDREM

#no_data

Symbol BTN = PinC.3  '// Switch
Symbol LED = C.4
Symbol LED2 = C.0 ' <<<<<<<<<<<<<<< Add new line
Symbol Counter = W0
Symbol Pressed = 1
Symbol Released = 0
symbol MaxRunTime = 6 '//Adjust MaxRunTime (see notes below) 6 Secs @ 16Mhz
'// MaxRunTime is used with the "Time" function, so clock speed will have an effect.
'
'// Effect of increased clock speed:
'// The time function will work correctly at 4MHz or 16 MHz.
'// At 2MHz or 8MHz the interval will be 2s
'// At 32MHz the interval will be 0.5s

MAIN:

   IF BTN = Pressed then
      High LED
      Pause 120      '// Debounce delay / 120 = ~30 ms @16MHz

      StartCounter:
            Time = 0 ' <<<<<<<<<<<<<<< Add new line
      Counter = 501 ' was 300              '// Adjust this value to change delay time after button released
      Do while BTN = Pressed and Time < MaxRunTime ' <<<<<<<<<<<<<<< Ammended line
            Loop
       
            if Time >= MaxRunTime then MotorStalled

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then reset timer

      Do While Counter > 1    
          Counter = Counter - 1
            If BTN = Pressed then 'start over
            Goto StartCounter
          END IF
      Loop
      LOW LED
   END IF

GOTO MAIN:


'// <<<<<<<<<<<<<<< Everything below here is new code
MotorStalled:
    low LED '// Turn motor drive off
    high LED2 '// Turn fault light on
    do while BTN = pressed '// Wait for switch to be released
    loop
    '// If here then switch has been released
    low LED2 '// Turn fault light off
    goto MAIN
Edit: I'm not sure why the formatting is all over the place as it looked correct in the Editor.
 
Last edited:

Rampz

Well-known member
Jack Burns

Thank you for your time and input on my project, i can see i was going in completly the wrong direction and reading Allycat's comments i have no idea what i am doing either, i guess i didn't understand how the program flows, assumin i had to fit my new requirements into the existing code, when i can see you have added it at the end with a small ammended line in the previous code

I tried the program and it runs very well just as i want, if BTN is held on it times out after 6 seconds and BTN is pulsed it ignores the timeout, just amazing work.


I believe these are your requrements...
  1. If the button is pressed for say 20ms then I want the output to stay on for 400ms
  2. If the button is pressed and held on then I want the output to stay on till button released plus 400ms
  3. If the output is switched on continuously for more that say 30 seconds, then treat it as a stalled motor, so stop the output to protect the motor until the microswitch resets and re-triggers. Also flash C0 a couple of times and write 1 to memory for later recall.
Sorry i throught it best to build a project in stages.

I would prefer to not have an external capacitor on the microswitch (this is infact a tilt switch, which can be a mecury one or a metal ball one) i have found the capacitor can cause sticking in metal ball tilt switches or i have had no further problems when capacitor removed when using my previous 555 timer version

Back to my full project requirements

  1. If the button is pressed for say 20ms then I want the output to stay on for 400ms
  2. If the button is pressed and held on then I want the output to stay on till button released plus 400ms
  3. If the output is switched on continuously for more that say 30 seconds, then treat it as a stalled motor, so stop the output to protect the motor until the microswitch resets and re-triggers. Also flash C0 a couple of times and write 1 to memory for later recall.
  4. disable C4 if voltage is seen to be below 10.4v for a set time say 10secs to protect motor and battery
  5. when voltage returns to a higher level say 11.5v wait 1 hour for battery to charge enough to power the motor again
  6. each time C4 is disabled due to low voltage write 1 to memory for later recall
I am using a presision voltage regulator good to 1%, i understand the higher the reference voltage used the better the resolution

Regards item 5 in testing the motor when mains power returns i find that all power is going to charge battery and motor just sits in stall position, currently i am using the comparator in a second 555 timer with a pot on the trigger pin to set cut off voltage, to save power i replaced the relay for 2x p-channel mosfet.

I would think recall would be a press of a button next to the 08m2 and the led on C0 would flash the number of times for stall followed by a gap and then flash the number of times for low battery then if its easier the counters just reset.
 
Last edited:

Rampz

Well-known member
While searching the forum for information on measuring external voltage i came across 'Voltage Divders Made Easy' by Marks, which looking through it seems to use the supply rail as reference which i think is fine for me, it has some form of calibration and the ability to read the measured voltage back to the terminal in the editor, it uses READADC10 which i understand splits the reading into 1023 parts from what i can work out each step is about 15.6mv.

It seems to be a good basis for part of what i want my project to do, protect the motor and battery (during mains fail)

Marks project uses a different chip to mine so i had to adjust a few bits and it simulates fine, the corrected output in the terminal is great for setup

I don't think i would need to sample the external voltage on every loop, i would think every 1s is fine?


Code:
#picaxe 08M2
'#terminal 19200
SETFREQ M16
SYMBOL ADCvalue      = W3
SYMBOL Volts         = W4

Main:
ReadADC10  C.2,ADCvalue
ReadADC10 C.2,Volts
IF ADCvalue = Volts THEN ConvertV ' display equal ADCvalues
GOTO main

ConvertV:
Volts = Volts **64064       ' Convert 1023 to 1000 steps (**64064) for 5.00v reference
  'Volts = Volts **64333      ' tweaked a little 7805 output actually 5.021v /5.00 *64064

Volts = Volts *16           ' Multiply by Vin (Fullscale 16v)(R1 22K)(R2 10K)

'Displaytest:
'Sertxd (13,10,"ADCvalue ",#ADCvalue,"  ",#Volts," Volts ")' 016 resolution

  DisplayV:
  Volts = Volts /100
  BinTOASCII Volts, b3,b2,b1 : IF  b3 = "0" THEN : b3 = " " : ENDIF' leading zero blanking 
  Sertxd (13,10," ",b3,b2,".",b1," Volts")  ' 0.1 resolution
 
PAUSE 1000
goto main
Below is my attempt to put the above code into my project (all code is by Goeytex, Marks and Jack burns), it simulates fine and when tried on the AXE091 board seems ok, i haved tried the resistor divider setup yet but have tried in previously with different code, so i see no problems.

I did notice the C0 led was flickering all the time and i came to the conclusion that this is because the picace is constantly sending data to the terminal in the editor, i proved it to myself by adding ' before it, so thats fine.

Is this the way forward for my project and have i put things in the right places?


Code:
#picaxe 08m2
SetFreq M16

    'code by Goeytex

#Rem
@8Mhz  Instruction time (overhead)  is 1/2 compared to 4 Mhz
@16MHz Instruction time (overhead)  is 1/4 compared to 4 Mhz
@32Mhz Instruction time (overhead)  is 1/8 compared to 4 Mhz
@8MHz  "Pause 1" = ~500 ms
@16MHz "Pause 1" = ~250us
@32MHz "Pause 1" = ~125us
#ENDREM

#no_data

Symbol BTN = PinC.3  '// Switch
Symbol LED = C.4
Symbol LED2 = C.0 ' <<<<<<<<<<<<<<< Add new line
Symbol Counter = W0
Symbol Pressed = 1
Symbol Released = 0
SYMBOL ADCvalue      = W3 'copied and paste during my attempt
SYMBOL Volts         = W4 'copied and paste during my attempt
symbol MaxRunTime = 6 '//Adjust MaxRunTime (see notes below) 6 Secs @ 16Mhz
'// MaxRunTime is used with the "Time" function, so clock speed will have an effect.
'
'// Effect of increased clock speed:
'// The time function will work correctly at 4MHz or 16 MHz.
'// At 2MHz or 8MHz the interval will be 2s
'// At 32MHz the interval will be 0.5s

MAIN:

   IF BTN = Pressed then
      High LED
      Pause 120      '// Debounce delay / 120 = ~30 ms @16MHz

      StartCounter:
            Time = 0 ' <<<<<<<<<<<<<<< Add new line
      Counter = 501 ' was 300              '// Adjust this value to change delay time after button released
      Do while BTN = Pressed and Time < MaxRunTime ' <<<<<<<<<<<<<<< Ammended line
            Loop
       
            if Time >= MaxRunTime then MotorStalled

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then reset timer

      Do While Counter > 1    
          Counter = Counter - 1
            If BTN = Pressed then 'start over
            Goto StartCounter
          END IF
      Loop
      LOW LED
   END IF
       


ReadADC10  C.2,ADCvalue       'copied and paste during my attempt
         ReadADC10 C.2,Volts       'copied and paste during my attempt
         IF ADCvalue = Volts THEN ConvertV ' display equal ADCvalues, i pasted

GOTO MAIN:

'// <<<<<<<<<<<<<<< Everything below here is new code, code by Jack Burns
MotorStalled:
    low LED '// Turn motor drive off
    high LED2 '// Turn fault light on
    do while BTN = pressed '// Wait for switch to be released
    loop
    '// If here then switch has been released
    low LED2 '// Turn fault light off
    goto MAIN
   
                                        'all below copied and paste during my attempt

ConvertV:
  Volts = Volts **64064       ' Convert 1023 to 1000 steps (**64064) for 5.00v reference
  Volts = Volts **64333      ' tweaked a little 7805 output actually 5.021v /5.00 *64064

  Volts = Volts *16           ' Multiply by Vin (Fullscale 16v)(R1 22K)(R2 10K)

'Displaytest:
 'Sertxd (13,10,"ADCvalue ",#ADCvalue,"  ",#Volts," Volts ")' 016 resolution

DisplayV:
  Volts = Volts /100
  BinTOASCII Volts, b3,b2,b1 : IF  b3 = "0" THEN : b3 = " " : ENDIF' leading zero blanking 
  Sertxd (13,10," ",b3,b2,".",b1," Volts")  ' 0.1 resolution
 
goto main
 
Last edited:

Rampz

Well-known member
Hello All

I have tested the above to the point where the terminal in editor gives a reasonable voltage and the circuit still does as you all wrote it for me, the displayed voltage is about 0.37v lower than the actual input voltage as showing by the power supply and my Fluke DMM, do i calibrate or do i make that allowance when using the voltage to stop my motor working at a set voltage?

I have attempted to add code to stop the output working below a voltage, 2 issues,

Firstly the set point i want is 10.4v and i can't use that, seems integers only and i can't get my head around it, but i could use the inaccuracy in my voltage measuring to do that being 0.37v wrong and set my cut off at 10v ?

And secondly i can't get the output to stop when voltage goes below the setpoint for some reason

But i have no syntax errors which is amazing

I'm really stuck at the moment, having a brain disorder of Asperger Syndrome means i really struggle with learning, help please

Code:
#picaxe 08m2
SetFreq M16

    'code by Goeytex

#Rem
@8Mhz  Instruction time (overhead)  is 1/2 compared to 4 Mhz
@16MHz Instruction time (overhead)  is 1/4 compared to 4 Mhz
@32Mhz Instruction time (overhead)  is 1/8 compared to 4 Mhz
@8MHz  "Pause 1" = ~500 ms
@16MHz "Pause 1" = ~250us
@32MHz "Pause 1" = ~125us
#ENDREM

#no_data

Symbol BTN = PinC.3  '// Switch
Symbol LED = C.4
Symbol LED2 = C.0 ' <<<<<<<<<<<<<<< Add new line
Symbol Counter = W0
Symbol Pressed = 1
Symbol Released = 0
SYMBOL ADCvalue      = W3 'added XXXXXXXXXX
SYMBOL Volts         = W4 'added XXXXXXXXXX
symbol lowvolts = 10 'my attempt XXXXXXXXXX Really need it to be 10.4
symbol MaxRunTime = 6 '//Adjust MaxRunTime (see notes below) 6 Secs @ 16Mhz
'// MaxRunTime is used with the "Time" function, so clock speed will have an effect.
'
'// Effect of increased clock speed:
'// The time function will work correctly at 4MHz or 16 MHz.
'// At 2MHz or 8MHz the interval will be 2s
'// At 32MHz the interval will be 0.5s

MAIN:

   IF BTN = Pressed then
      High LED
      Pause 120      
    '// Debounce delay / 120 = ~30 ms @16MHz 

      StartCounter:
            Time = 0 ' <<<<<<<<<<<<<<< Add new line
      Counter = 501 ' was 300              
    '// Adjust this value to change delay time after button released
    
      Do while BTN = Pressed and Time < MaxRunTime  ' <<<<<<<<<<<<<<< Ammended line
            Loop
        
            if Time >= MaxRunTime then MotorStalled

      '// If here then switch released
      '//  Time Out after 400 ms
      '// If another Press detected then reset timer

      Do While Counter > 1     
          Counter = Counter - 1
            If BTN = Pressed then 'start over
            Goto StartCounter
          END IF
      Loop
      LOW LED
   END IF
        
        ReadADC10 C.2,ADCvalue 'i pasted here
         ReadADC10 C.2,Volts 'i pasted here
         IF ADCvalue = Volts THEN ConvertV ' display equal ADCvalues, i pasted 
        
    IF volts <= lowvolts then volttoolow 'my attempt XXXXXXXX

GOTO MAIN:

'// <<<<<<<<<<<<<<< Everything below here is new code, code by Jack Burns
MotorStalled:
    low LED '// Turn motor drive off
    high LED2 '// Turn fault light on
    do while BTN = pressed '// Wait for switch to be released
    loop
    '// If here then switch has been released
    low LED2 '// Turn fault light off
    goto MAIN
    
    
ConvertV:
    Volts = Volts **64064       ' Convert 1023 to 1000 steps (**64064) for 5.00v reference
    Volts = Volts **64884      ' tweaked a little 7805 output actually 5.064v /5.00 *64064
    
    Volts = Volts *16           ' Multiply by Vin (Fullscale 16v)(R1 22K)(R2 10K)

'Displaytest:
'Sertxd (13,10,"ADCvalue ",#ADCvalue,"  ",#Volts," Volts ")' 016 resolution

DisplayV:
   Volts = Volts /100 
   BinTOASCII Volts, b3,b2,b1 : IF  b3 = "0" THEN : b3 = " " : ENDIF' leading zero
                                                               'blanking
   Sertxd (13,10," ",b3,b2,".",b1," Volts")  ' 0.1 resolution
  
   goto main

Volttoolow:
   low led 'turn motor off due to low volts, my attempt XXXXXXXXXX
   do while volts < lowvolts
   loop
   goto MAIN
 

Aries

New Member
Firstly the set point i want is 10.4v and i can't use that, seems integers only
You are correct that you can only use integers, but the solution is to multiply your numbers by 10.
So, if you have
Code:
SYMBOL lowvolts10 = 104
SYMBOL volts10 = w5
...
volts10 = volts * 10
IF volts10 <= lowvolts10 then volttoolow
...
you will be testing for volts < 10.4
 

Jack Burns

New Member
All maths work is in integers, so the voltage measurement routine returns a value which is 10 times higher than what you expect. So 10.4v in Marks routine is represented by a "Volts" value of 104 which is the figure you need. If you need to send the output to the terminal, then it's simply a case of putting the decimal point in the correct place when sending.

Changing this:
Code:
symbol lowvolts = 10 'my attempt XXXXXXXXXX Really need it to be 10.4
to this should help
Code:
symbol lowvolts = 104 'my attempt XXXXXXXXXX This will be 10.4
However, the reason the output doesn't stop when you reach "Volttoolow:" is because you need to read the ADC value again and recalculate the voltage, otherwise it's just continually using the last known measurement before the code got to that point. As I see it you have 2 options:
  1. Add some new code for the voltage measurements into your "Volttoolow:" routine (making sure not to duplicate labels)
  2. Or restructure the existing code so the voltage measurement routine becomes a reuasable subroutine.
I have looked at option 2 myself, but keep getting into a mess as structured programming isn't my strong point.
 

Rampz

Well-known member
However, the reason the output doesn't stop when you reach "Volttoolow:" is because you need to read the ADC value again and recalculate the voltage, otherwise it's just continually using the last known measurement before the code got to that point. As I see it you have 2 options:
  1. Add some new code for the voltage measurements into your "Volttoolow:" routine (making sure not to duplicate labels)
  2. Or restructure the existing code so the voltage measurement routine becomes a reuasable subroutine.
Jack Burns

Thank you for trying to help me further, i can see option 2 being the best option to keep the program as simple as possible, structure is an area i have no understanding or feeling for yet, as a beginner with a project i want to complete i'm well over my head, i am learning and i'm sure it will help me in the long run.

I assumed the voltage was being read on every loop? The terminal in the editor fills very quickly
 
Last edited:
Top