PIC: Code for a timer pulses with pause/resume ability - Page 1
Forum section: electronics / general

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 30, 2022, 03:55:59 pm
content: Hi,I want to make a timer that can make pulses in intervals, with the ability to continue from last state he was on before the (Run signal) became 0V (After an initial delay that should be after any Run signal become 5V) you see the whole idea in picture attached.I will use any PIC microcontroller, but I need to understand how to make the code program first, I'm an absolute beginner!- The numbers in the image are in seconds, they are for demonstration only.- Timers ONs and OFFs should be adjustable.- The timer will be set in seconds, from 0.5 second to 1000 seconds approximately.- The code would be written in C language, using MikroC software.- I'm following some courses in PIC programming, but I am in the first stages.If you want more information I'm ready, thank you!I'm an Arabic speaker; so please forgive my lack of right expression, this is kind of what I want in other words, as Mr ledtester wrote:1. a timer is set up to produce a clock signal on a GPIO pin2. when the run signal is HIGH the timer operates normally3. when the run signal is LOW the timer operation is paused and the GPIO pin is brought LOW4. when the run signal returns to HIGH the timer operation resumes and the GPIO pin returns to the state is was in at the time the run signal was brought LOW

author: jpanhalt
author_rank: Super Contributor
timestamp: January 30, 2022, 04:10:41 pm
content: In what language? Have you learned timers and interrupts? For convenience, are those relative delays in ms, us, or or something else like Tcy (system clock ticks)?

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 30, 2022, 05:18:00 pm
content: Thank you for your reply, I've included answers to your questions in the first thread.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 30, 2022, 05:46:52 pm
content: Thanks. I don't code in C so can't contribute to your code. Nevertheless, I still don't understant what you want to do.Consider this:"I want to make a timer thatcan make pulses in intervals, with the ability tocontinue from last state he was on before the (Run signal) became 0"1) The first condition doesn't explain why or what controls the different length pulses. That is, what determines when a 20 pulse or 10 pulse is made versus a 30 pulse?2) "Continue the last state before Run = 0." How much before? Look at this snippet:The state when Run = 0 is 1, yet you continue as 0?

author: perdrix
author_rank: Frequent Contributor
timestamp: January 30, 2022, 05:54:24 pm
content: If all you want to do is toggle an output pin between 0V and Vcc it's as simple as:Code:_LATA0 ^= 1; // toggle pin 2Obviously the pin needs to be configured as output!David

author: ledtester
author_rank: Super Contributor
timestamp: January 30, 2022, 06:11:17 pm
content: @Shaydzmi, is this what you mean...1. a timer is set up to produce a clock signal on a GPIO pin2. when the run signal is HIGH the timer operates normally3. when the run signal is LOW the timer operation is paused and the GPIO pin is brought LOW4. when the run signal returns to HIGH the timer operation resumes and the GPIO pin returns to the state is was in at the time the run signal was brought LOW

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 30, 2022, 07:29:48 pm
content: QuoteI've answered your questions above. Thank you.QuoteThank you, you can read my post again, I've added some information.QuoteThank you, I added your reply to my post, this pretty much what I want.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 30, 2022, 08:35:19 pm
content: First impression1) Clock suspended while RUN=0:Set up your clock. In Assembly when I want an alternating high/low you can test a pin, and if high make low and vice versa. I usually just XOR (exclusive OR). Let's say, GPIO,0 is the pin you want to toggle. If GPIO,0 = 0 and GPIO is XOR'd with 0x01, none of the other pins on GPIO will change, except GPIO,0 --> high. Now, if that is repeated, then GPIO,0 --> low and so forth.Now assume the "RUN" signal is on a pin with interrupt on change ("IOC"). Set that up to happen on a falling edge. When that interrupt fires, stop the clock, be sure to preserve its state, and make GPIO,0 low. Change the IOC to "rising edge". Now on the next interrupt restore the stored clock state on GPIO,0. The clock's previous state is preserved. Most PIC's (all of the ones with interrupts that I know of) can alternate falling edge and rising edge for IOC pins. If you set that up, you will not need to change the edge polarity during an interrupt.How you preserve the clock's state depends on how that clock is generated. It may not be necessary to do anything while operation is suspended. TMR1 acts like that. Or, you can simply copy GPIO to a register on the falling interrupt. That will preserve the clock state at the moment of interrupt. You cannot simply restore that state by moving the register to GPIO, as some of the other pins/bits may have changed. You can bit test bit <0> of that register (as given in the example above) and if high, set clock/GPIO,0 high, otherwise, set clock/GPIO,0 low. (In Assembly, there are ways to do such saves without adding a new register, but in C, they do not work because you do not know everything that happens between the two state changes.)2) If clock is not actually suspended, but simply not expressed while RUN is low, then a slightly different solution is needed.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 07:13:10 am
content: QuoteThis is should be the case.I didn't understand your answer, but I'll study it carefully if no one gives me instructions in C.Thank you.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 09:47:24 am
content: After sleeping on it myself, perhaps the question put to you is a little different than your understanding of it. As just one example, let's say the question is, "How long is RUN high?" That type of thing is easily done with PIC devices and does not require suspending and re-enabling the clock. In fact, analogies of that are quite commonly done.What led me to wonder about that was your reference to a "timer," but its pulses appear to be irregular. Can you post the actual question/challenge you are trying to answer?

author: ledtester
author_rank: Super Contributor
timestamp: January 31, 2022, 10:36:31 am
content: Quote from: jpanhalt on January 31, 2022, 09:47:24 amWhen the RUN signal is constant the pulses appear to be very regular -- for instance see the latter portion of the signal graph in the first post.Here is my interpretation of the problem expressed in Arduino-ish code. In a real implementation you would want to use hardware timers and perhaps interrupts.Code:void main() {pinMode(RUN_SIGNAL:, INPUT);pinMode(OUTPUT_GPIO, OUTPUT);digitalWrite(OUTPUT_GPIO, 0);bool running = 0;bool gpio_state = 0;uint timer = MAX_TIMER;while (1) {if (running) {if (--timer == 0) {// toggle the output and reset the timerdigitalWrite(OUTPUT_GPIO, !digitalRead(OUTPUT_GPIO));timer = MAX_TIMER;}if (!digitalRead(RUN_SIGNAL)) {running = 0;gpio_state = digitalRead(OUTPUT_GPIO);digitalWrite(OUTPUT_GPIO, 0);}// maybe delay here for a while?} else {if (digitalRead(RUN_SIGNAL)) {running = 1;digitalWrite(OUTPUT_GPIO, gpio_state);}}}}

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 11:10:42 am
content: Quote from: ledtester on January 31, 2022, 10:36:31 amThat's not what I see. First "half," clock high = 20; second "half," clock high = 30.I still think a clear description of the actual question is needed.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 11:50:19 am
content: I agree with Mr. Ledtester, the Clock pulses should be regular, it is my mistake in the graph.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 12:16:14 pm
content: My interpretation is that you are simply trying to measure the RUN time (that is, the length of time RUN is high). PIC's that have a CCP or ECCP module (Compare,Capture,PWM) allow a process called "capture" for Timer1. That allows a timer to run continuously and "capture" time stamps for a defined event. In your case, that would be alternate rising and falling edges of RUN. One can also start and stop TMR1, but I prefer the continuous run mode.Reading TMR1 on the fly, that is without capture while it is running, is a little more complicated as you need to take extra steps to ensure a rollover was not pending. For example, if you read the low register first, then the high register, you need to check that the low register didn't rollover during the time it took to read the high register. Starting and stopping TMR1 can introduce similar lost counts. In Assembly, that can be accounted for by adding a constant. I don't think that would work well in C.Capture is what I would do. If TMR1 is 16-bit, you can set your pre- and post-scaling so as to have not more than one rollover during the timed interval. Rollovers are handled by the math. If you cannot do that, then you need to count rollovers. Rollovers can be detected by an interrupt or interrupt flag.At this point, it might help to know which PIC you are using. A previous post (see:perdrix) refers to the LAT (latch) registers. Not all PIC's have them.EDIT: BTW, TMR1 can run from the system clock or external clock (e.g., a lower frequency clock crystal). Since the periods you are measuring are long compared to what the system clock probably is, you probably want an external clock for TMR1.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 01:06:33 pm
content: Quote from: jpanhalt on January 31, 2022, 12:16:14 pm1- Thank you for following along.2- I think that you have forgotten the fact that I am an absolute beginner in this field, so 95% of your writing is not understood to me.3- I think that you have gone too far from what I need to do.4- What I need to do is to run an oil pump lubricator in intervals while the machine is running. The machine doesn't have a constant running, it may stop after 1 hour, sometimes it stops after just 30 seconds, or even less.I hope that I am clear now.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 01:23:05 pm
content: That could be really simple. Just set the lubricator to be driven by timed pulses (done). Start and stop whatever is driving the lubricator by sensing whether the pump is running (done). Obviously, you do not want to lubricator to run when the pump is not running.However, I see no reason it needs to recognize and recover its state when the pump stopped. Just stop it and restart it from the stopped state.I mistakenly thought this was a school assignment to introduce you to doing accurate timings.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 02:11:57 pm
content: No, it's a pump lubricating a machine. A simple timer won't work a I want it to be. Say I set it like this:5 minutes OFF.0.5 minutes ON.So when the machine stops often before reaching 5 min, will be no oil. Because the timer will start from OFF state every time. If I make the timer start ON first, will go too much oil to the machine.So, the right thing to do is continue counting from where it stopped.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 02:59:30 pm
content: OK, I get it. My experience was with motors that effectively had continuous lubrication or needed lubrication much less frequently, say twice a year.Problem 1: How to tell the microcontroller (MCU) the pump is on or off. For that, I don't have a solution. Some options could be a current monitor or extra set of contacts on the motor relay. In any event, I would probably use an interrupt. That is an interrupt when pump goes on and another when it turns off. Your interrupt service routine (ISR) would need to determine whether the pump was turning on or off. Simply relying on alternating states may be more susceptible to noise. You could also use polling as this seems to be a mostly dedicated MCU.Problem 2: How to run the lubricator. Here is where a timer comes into play. It would be quite simple to program a 30 second "on" and 5 minute "off" cycle. One could simply do that by delays, but such simple delays are called "blocking" as the MCU is 100% occupied with doing the counting. A better way is to use a timer, such as Timer 1 (TMR1). It's 16-bit on lower end PIC's. A 32.768 kHz crystal for clocking the timer will give 2-second "rollovers" (2^16 = 65536 = 2x32,768). Each rollover can fire an interrupt. 5 min = 300 seconds = 150 rollovers. 30 second = 15 rollovers. Just keep track of the rollovers and start or stop the lubricator alternately as indicated.Now, if you start and stop TMR1 (bit<0> in T1CON register), it and whatever register you use to keep track of rollovers will retain their counts. So, for instance, if the lubricator had been running 15 s before it was stopped, then it will start and run 15 s more. If it had been off for 3 minutes, before the pump stopped., it will start with a 2 minute wait before starting to pump lubricant. A nice thing about TMR1 is that you can write to its registers, THR1H:THR1L. You can also write to the rollover count register. Let's say time had run 3 minutes (off period) before being turned off and on again. You could adjust the subsequent delayed start time , if you wanted to.If you go a little more complex, TMR1 also operates in power saving modes and can wake the MCU on a rollover.Problem 3: Interface between MCU and lubricator. You can use a relay or mosfet switch. The relay requires more current, so you may want to use a latching relay to avoid having to keep that pin asserted.Hope that helps. Note, interrupts are helpful, but are not required. Pretty much anything they do can also be done by polling.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 03:44:35 pm
content: I need to explain my words again:i have two things: 1 A machine needs to be oiled every now and then.2- An Oiler oiling the machine.I need to program an MCU to get this job (oiling) done.(Forget about the lubricator and the pump)QuoteThe machine has a relay contact that closes when it's running, I will use it to tell the MCU that the machine is running when it is doing so.QuoteThe oiler has an input that makes it inject oil when it (the input pin) is high, so the MCU will do this job via an intermediate.QuoteIt is an easy job, I'll take care of this myself. The problem is the code.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 03:55:24 pm
content: Also, I want to be able to adjust On/Off times via pushbuttons and see the setting and the counting on a 7-segment display.

author: jpanhalt
author_rank: Super Contributor
timestamp: January 31, 2022, 04:03:46 pm
content: Your first posts gave the impression that you wanted to do it yourself in C but didn't know where to start. I was trying to give you some direction of where to start. Now, if you want someone to do the coding for you and add an adjustable user interface, I cannot do that for you in C. Maybe someone else will.Good luck.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: January 31, 2022, 04:13:23 pm
content: No, I do want to do it myself, I need guidance only along the way.QuoteThank you very much, I appreciate your help, I hope you don't stop it.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 31, 2022, 05:26:54 pm
content: As your time scale is sloooow, and I'm assuming it doesn't need to be super exact, I'd suggest you start by writing an infinite while(1) loop, inside which you call a blocking delay function (like _delay_ms(1000) in AVR library; I'm sure something pre-existing is available on PIC, too, but I don't personally PIC).Then, turn general purpose output pins high and low in that loop and see what happens.Add a variable likeint32_t count = 0;andcount++;on every round.Start adding if-else logic like if (count > 10), to turn the outputs on and off as you like.Work from there, little by little.

author: NorthGuy
author_rank: Super Contributor
timestamp: February 01, 2022, 04:32:27 pm
content: The logic is very simple:Code:while (1) { // do what is inside brackets foreverif (run) { // do what is inside brackets if run is high, don't do it if it's lowoutput_pin = 1; // turn the output ondelay (on_time); // wait the "on time" keeping the output highoutput_pin = 0; // turn the output offdelay (off_time); // wait the "off time" keeping the output low}}This will do it. The minor difference to your scheme is this: if the run signal goes low during the on-pulse, the on-pulse will run to the end. If this is a problem, you can correct this when you become more familiar with the programming.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 20, 2022, 09:37:09 pm
content: Hi,It has been a longtime worth of thinking and learning, but still I didn't succeed in achieving my goal!To simplify the problem, I'll try to blink the LED while using the push button (BTN) as a control.I want to do a code that can turn an LED ON and OFF as the following:while BTN=0 : LED_OFF xx secondsLED_ON xx secondsif BTN=1 : LED_OFF immidiatly , but when BTN=0 again, LED resumes its blinking from last state it was upon before BTN=1, not counting from the beginning.For example:LED off 100s.LED on 10s.If the LED had been OFF 60 s before BTN=1, then it will be OFF for 40 s more when BTN=0. If the LED had been ON 7 s before BTN=1, then it will be ON for 3 s more when BTN=0.This is one of my tries:Code:#define LED PORTA.F0#define BTN PORTB.F0unsigned int cnt;//Timer0//Prescaler 1:64; TMR0 Preload = 6; Actual Interrupt Time : 8 msvoid InitTimer0(){OPTION_REG= 0x05;TMR0= 6;INTCON= 0b10110000;}void Interrupt(){if (TMR0IF_bit){cnt++;TMR0IF_bit= 0;TMR0= 6;}}void main() {OPTION_REG= 0x05;INTCON= 0b10110000;TRISA.F0=0;TRISB.F0=1;TRISB.F1=0;TRISA.F1=0;PORTA.F1=0;LED=0;do {if(BTN==0) LED=0;if(BTN==1 && cnt==125) LED=0;if(BTN==1 && cnt==250) LED=1;if(cnt==500) cnt=0;}while(1) ;}Can you help me about what's wrong with this code? And how to solve the problem?

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 21, 2022, 12:11:40 pm
content: What you want is probably very easy, it's just that your description and pictures doesn't seem to match accurately, causing confusion.Do you need a constant clock, gated by RUN signal, but delayed 10s after RUN goes high? (First picture, "gated")Or do you want the clock to be paused by RUN signal? Then, when RUN goes high, delay 10s resume it? (Second picture, "paused")

author: Ian.M
author_rank: Super Contributor
timestamp: March 21, 2022, 04:01:21 pm
content: Our O.P. has already stated its an oiler for a machine that needs to operate for some proportion of the machine's runtime, but the machine itself is operated intermittently. Therefore, when the machine is not running, the oiler must be effectively frozen in time (in practice: pump off, with its sequencing paused).However there are other issues that deserve consideration. E.g. if its not a positive displacement pump, how long does it take to prime? If the answer is of the order of a second or longer, I'd bet that if the machine stops while the oiler is on, with a short oil on time left to run, it would be better to defer the remaining oil runtime and extend the next one rather than blip the oiler when the machine restarts, which will deliver less oil than intended. Alternatively if it cant be deferred, it may help to extend the remaining oil runtime to allow for priming.Then there's the matter of the UI. Its impossible to mix simple procedural sequencing by blocking delays, and an interactive UI in a single thread of execution. If the O.P was willing to settle for a couple of potential dividers feeding ADC pins, + latching switches for any toggle settings, then procedural sequencing by blocking delays would be viable, as the control for the next part of the sequence can be read after each delay, but even that has issues e.g. if you shorten the oil on time while oiling, depending on how its implemented, it wont take effect till the next time the oiler turns on. The pause everything while the machine's off functionality would need to be implemented as an interrupt, so it can pause a blocking delay, and only return to resume the delay when the machine restarts.However doing it that way can only teach our O.P. bad habits which he will have to discard to make future progress in real-time programming, so, in the absence of a multi-threading RTOS, I would suggest a superloop with a sandwich delay to maintain a constant loop execution time, running three or for cooperating state machine tasks, one for the oiler timer, counting passes of the superloop to perform the timing, one for input, debouncing buttons and setting a flag for each valid button press (or otherwise queuing it) , one for output, managing the display, and one for supervisory control, which consumes button presses, signals for display updates and changes the interval limits being used by the oiler timer.The pause when off functionality can be simply handled by disabling the oil pump and skipping the oiler timer task, leaving it to reenable the oil pump when it resumes if it was oiling at shutdown.It gets *NASTY* if the PIC is only powered while the machine is on - preserving state in EEPROM is not for novices as there are plenty of ways to get it wrong and wear out the EEPROM prematurely (possibly in only weeks), or fail to save to EEPROM reliably, and a battery backed solution with a sleep mode requires decent knowledge of electronics and PIC MCUs to avoid excessive battery drain. Anyone can preserve state if they've got a honking big SLA + float charger providing the backup power, but to do so from a smallish supercap or coin cell requires considerable finesse.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 21, 2022, 06:57:20 pm
content: Quote from: DavidAlfa on March 21, 2022, 12:11:40 pmThank you DavidAlfa, I want this:Quote

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 21, 2022, 08:09:37 pm
content: Thank you Ian.M..QuoteI don't know what's a positive displacement pump, what I can tell is that the pump is very quick, a half a second of oiling makes a difference, so no need for extra problems.Quotewhy not more than one , even I don't understand what it means!QuoteAm I the O.P ? What does it stands for?what be the purpose of these voltage dividers and latching switches?QuoteThat is not an issue.QuoteI've tried doing this but failed.QuoteI won't be programmer anyway, I'm just trying to do my own things by myself with the help of people like you..QuoteCan you give an example code to start with?QuoteThis should be done in the code?The oiler keeps powerd on when the machine stops, so the PIC MCU, then no nood for EEPROM or batteries.QuoteAh OK, now that explains to me why almost all oilers that get power only while machine is running are now restart counting from 0 whenever the machine starts running, probably the EEPROM gone. And that's why I'm trying to learn these things.Thank you Ian.M for your time..

author: Ian.M
author_rank: Super Contributor
timestamp: March 21, 2022, 09:35:27 pm
content: Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmA positive displacement pump is one that any sustained shaft movement, even very slow produces proportionate fluid output. Types include reciprocating (piston) and swash-plate pumps, gear, full contact soft impeller, and sliding vane pumps, peristaltic pumps that fully occlude the peristaltic tube. Non-positive displacement pumps typically have an impeller that does not contact the sides of the pump chamber so some fluid is free to flow back round its edges. e.g. centrifugal pumps and ones with an axial output propeller style impeller. At low speeds they may not generate enough pressure for fluid to actually flow through the output pipe, and although flow will be some increasing function of shaft speed, it wont be a linearly proportionate relationship.Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmMost MCUs are single core processors that can only be executing a single sequence of instructions at any point in time. That executing sequence of instructions is a thread. (Formally called a 'thread of execution', usually shortened to just 'thread'.)An interrupt comes along, and the thread is paused, state is saved, and the ISR (interruptserviceroutine) starts executing. The ISR is another thread that can start at any time (if interrupts are enabled) asynchronous to the thread that was interrupted. The ISR runs to completion, the pre-ISR state restored and the previous thread resumes execution. A blocking delay is a delay during which the processor cannot do anything else (unless the delay is interrupted by the execution of an ISR, but that's another thread, and when it resumes after the ISR, the delay routine isn't aware it was paused by the ISR so the total delay gets extended by the ISR execution time).Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmO.P stands for 'originalposter', i.e. the person that started the topic (You).Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmYou'd use the potentiometers to set the run duration for the oil pump and the interval between oilings. Whenever your code needs to know how long to do something for, it would select the corresponding potentiometer's ADC channel, perform a conversion and read the ADC, giving it a number that represents the potentiometer position. Translate that into time by multiplying by whatever scaling factor is appropriate. The (optional) switches would be to select different behavior e.g. if the potentiometers are screw-adjusted presets you might have an extra one and a switch to activate it to select a higher oiling rate for use when running in new parts of the machine after maintenance, so the operator doesn't need to mess with the carefully adjusted usual settings.Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmNo, not for your specific application, as I don't use MikroC, and like nearly all the experienced members here, don't do other people's work for them if there is *ANY* chance its a student assignment, or if they are getting paid for the job they are supposed to be doing. However, if you make an attempt at it, post your code and explain where you are getting stuck, or what isn't working the way you need it to, many of us can and will help you debug and improve your code.These links should help explain the concepts:https://en.wikibooks.org/wiki/Embedded_Systems/Super_Loop_ArchitectureHere's the best 'entry level' explanation I have ever seen of combining a superloop with a sandwich delay:https://web.archive.org/web/20151026193316/http://petevidler.com/2010/06/superloop-foreground-background-scheduling. It has example code.T.I'sGeneral RTOS conceptswill give you more of the terminology and ideas behind real time programming in general.Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmWhere else would it be done? Yes, in the codeas an ISR. Although I suppose it could be done in hardware by using an external clock for the PIC and stopping it when the machine isn't running, where you simply need to wrap the timer task code in anif(<condition>){...}else{...}that tests the machine on state, and if its off, disables the oiler output. The timer task state machine goes in the other block of the if...else so it only gets executed when the machine is on, and updates the oiler output on every pass of the superloop, even if no change is required.Quote from: Shaydzmi on March 21, 2022, 08:09:37 pmGOOD! That makes this project much simpler for you.Edit: The comments struck out (strikeout) were applicable to the procedural blocking delay, with potentiometers for controls, solution discussed earliernot the non-blocking superloop version. I've added an appropriate method for the latter above, in italics. I apologise for any confusion.

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 22, 2022, 12:07:03 am
content: What's the PIC frequency?What's the required response time when RUN state changes?What's the allowable timing error when stopping or resuming?What's the required overall period accuracy?Accuracy is what complicates things most. When it can be loosen down a bit, usually development is much easier.And it's important to know such details before doing anything else.Ex. if you need microsecond accuracy, things might get a lot harder than, ex, if it's ok with 100ms.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 22, 2022, 03:46:21 pm
content: Usually you would start your project by verifying your hardware. Say, create a small program to blink a LED, then create a small program to verify that the button is working. Only when you done with these, you start writing the application.Don't expect that just because you only want to write a single program in your life and then quit, the laws of physics will give you some sort of slack.For example, a button needs a pullup. This is because when the button is not pressed, the input is floating and can switch randomly between high and low. To make sure it's always high, you need to "pull it up". You cannot connect it to VDD because then the button will short VSS with VDD. But you can connect the pin to VDD with a resistor (usually 5 to 10k). Or, instead of the resistor you can activate a built-in pull-up inside the PIC, but it'll be weaker.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 22, 2022, 06:11:04 pm
content: QuoteThank you for the valuable information..Just for clarification, I have a little comment about this:QuoteI'm not a student since 2003, and I'm not getting paid for this things, it's just out of my curiosity and love of learning how things work and how to fix them.Thank you again.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 22, 2022, 06:27:05 pm
content: Thank you DavidAlfa.QuotePIC16F628A Datasheet: [- Precision internal 4 MHz oscillator factorycalibrated to ±1%- Low-power internal 48 kHz oscillator]QuoteNot very critical.QuoteSince the oiling should be exact , the error rate should not exceed half a second. As for the stopping time, there is nothing wrong with a tolerance rate of up to 5 seconds.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 22, 2022, 06:31:09 pm
content: Quote from: NorthGuy on March 22, 2022, 03:46:21 pmThank you NorthGuy, I'm aware of that..

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 22, 2022, 11:56:40 pm
content: Edit: Simulated it using Proteus, compiled using XC8.https://pastecode.io/s/1sskbkddEdit2:The Timer0 is very basic. Needing to manually preload it causes timing accuracy errors, as the prescaler is cleared when writing to TMR0 (Up to 32 clocks), also the interrupt context saving adds more time.So I switched to Timer2. That one has interrupt on period match.That way it's free-running, not requiring any user intervention else than the T2IF flag.Every time TMR2 matches PR2, it resets and triggers the interrupt.Timer 2 also has a much finer postscaler, from 1 to 16, although not used here.You can take 1ms as the worst-case error, but accuracy is much better, only happens when RUN signal changes, the error will be the time it takes to save/restore the timer counters, in the range of 10-30us.The prescaler will reset when restoring TMR2, but being 1:4, only up to 4 clocks could be lost (4us).This could be further optimized by calibrating and adding the reading time to the counter value.When running, there's nothing to save or restore, so the output should be a perfect 30s/30s wave.Interrupt is only used for the timer, input is sampled by polling.There's a test signal in RA1, toggled on every Timer2 interrupt, you should see a 500Hz signal there.You have a debounce timer for the run (button) signal, will add a small delay when it changes (currently set to 20ms) but filter any noises getting into the input, something common when working near heavy machinery.Can be adjusted anywhere between 0ms (Disabled) and 255ms.I never used MikroC, you might need to tweak some register or bit names.Also, ensure the interrupt has the correct name or MikroC won't use it as the ISR.Attached MplabX project and proteus simulation.If you don't use MPLabX, just open main.c, everything is there.

author: IDEngineer
author_rank: Super Contributor
timestamp: March 23, 2022, 06:07:28 pm
content: This is a convoluted thread.At first, it sounded like all the OP needed was a Timer with a Gate input. Assert the Gate input and the Timer runs. Deassert the Gate input and the Timer stops, while maintaining its existing count so it "starts where it left off". But then I saw something about ten second startup delays, etc. It's not clear (at least to me) what the actual desired specs are.WRT the positive displacement pump discussion: One easy-to-understand characteristic of positive displacement pumps is that they are self-priming. In other words, they draw a vacuum at their inlet. Even if someone isn't conversant on pump technology, this is an easy way for them to quickly know if the pump they have (or need!) has positive displacement. Pumps which are not positive displacement might prime, but generally only after their volute has been manually filled (read: primed). Otherwise the impeller just free spins in air, and thus cannot generate suction to fill its own volute. Only the OP knows if he needs a self-priming pump. If the pump is submersible (for example), then positive displacement may not be required because the volute will be filled automatically.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 24, 2022, 08:29:50 pm
content: QuoteThank you very much for this wonderful work, it looks more complicated than I thought..I will study it well with care and attention so that I can learn a lot from it.. I have not seen a (struct) , nor a (union) before..I have executed the code on MPLAB X and PROTEUS and it works fine, but one thing I have noticed is that the LED blinking works sometimes when the switch is pressed and sometimes when it is not. Is the code designed to work when the switch is closed or when it is opened or randomly? Because in the real actual application, the output ON should be very short, 2 seconds max, while the OFF is in minutes.Once again, thank you very much.

author: Shaydzmi
author_rank: Regular Contributor
timestamp: March 24, 2022, 08:57:42 pm
content: Quote from: IDEngineer on March 23, 2022, 06:07:28 pmNothing should be convoluted to an Engineer like you!Thank you..

author: DavidAlfa
author_rank: Super Contributor
timestamp: March 25, 2022, 09:01:33 am
content: Don't fear the structs. You can see them as simple variables, I just used them for better organization.What LED? RA0 is the output, RA1 is just a test signal you can delete the toggling code in the interrupt.It does exactly what you said?You wanted a 30-second-high, 30-second-low wave, and save the wave status/timing whenever RUN goes low.When RUN goes high, wait 10 seconds in low state, the resume the wave in whatever the position it was.If it was low, it will resume the low state... If the LOW state had 25 second left, it will be low for 15 second after the initial 10 second delay.Otherwise, same as we spend our time in helping, also spend time in properly explaining the requirements and details