# PIC12F675 micro controller programming

I want to use PIC12F675 to control a relay such that when a switch is pressed, it should generate an output signal which should be ON for 2 seconds and then OFF for 15 seconds.

This should continue when the switch is pressed

When the switch is released, the output should be off.

I've done a program using loops, but the problem is even though it generates an output signal which is ON for 2s and OFF for 15s, however if i release the switch and suddenly press the switch again the loop is still continue for 1 full cycle.

Say for example after 2s, I've released the switch and pressed it again suddenly, the previous loop still goes on executing and will only take the new switching condition after the 15s (second delay).

Here is the program:

#include <xc.h>
#define sw GP2
#define out GP0
#define _XTAL_FREQ 4000000

void main()
{
ANSEL = 0x40;
TRISIO = 0b00000100;
GPIO = 0x00 ;
WPU = 0x00;

if (!sw)
{
out = 1;
__delay_ms(2000);
out = 0;
__delay_ms(5000);
}
}

• I'm not entirely clear on what your actual question is. Aside from a missing while(1) loop, the code you've written will do exactly as you describe. You're only looking at the state of your button once, before the on/off cycle. If you want it to do something different then you probably have to look at the state of the button more often. But since (so me at least) this is obvious, I can't figure out what you're asking. Feb 23, 2019 at 13:31

The problem is that you are using a delay function in your code. While this is running the program is in a continuous loop and can do nothing else, including reading your button. This is bad practice but unfortunately it is promoted by all the basic tutorials on micro programming - particularly on the Arduino platform.

Here's some pseudo-code to get you thinking:

void setup(){
long t0;                // The output timer.
long onTime = 2000;     // ms
long offTime = 15000;   // ms
}

void main(){
while(1){
if (sw){                // assumes that 1 == released.
out = 0;              // output off immediately.
t0 = millis();        // assumes that there is some sort of millisecond clock in the device.
} else {
if ((millis() - t0) < onTime) {
out = 1;            // on time
} else {
out = 0;            // off time
}
if (t0 > (onTime + offTime)){
t0 = millis();        // Reset the timer.
}
}
}


Now you should be able to do other stuff while periodically checking the button status and updating the output.

Another method, that does not rely on a millis function as in @Transistor's answer (which afaik is not available in the xc8 standard library) and does not require introducing new concepts such as timers or interrupts is to 'chop' the delays into smaller pieces and checking the button state after each piece. In this example I've chosen 100mS as the resolution.

#include <xc.h>
#include <stdbool.h>
#define sw GP2
#define out GP0
#define _XTAL_FREQ 4000000

bool
delay_n_100ms(int n)
{
do
{
__delay_ms(100);
if (sw)
{
//Switch was released.
return true;
}
}
while (--n);

//Finished complete delay while switch was not released.
return false;
}

void
run(void)
{
if (sw)
{
//Switch not pressed, just return.
return;
}

//Switch pressed, begin led blinking loop.
while (1)
{
out = 1;
if (delay_n_100ms(20))
{
//Switch was released while in delay loop, abort.
return;
}

out = 0;
if (delay_n_100ms(150))
{
return;
}
}
}

void main()
{
ANSEL = 0x40;
TRISIO = 0b00000100;
GPIO = 0x00 ;
WPU = 0x00;

while (1)
{
out = 0;
run();
}
}