Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] PIC12F683 pin high problem

Status
Not open for further replies.

Veketti

Full Member level 3
Joined
Sep 14, 2014
Messages
164
Helped
0
Reputation
0
Reaction score
0
Trophy points
16
Activity points
1,700
Dear All,

I'm once again turning to you with one issue that I'm not able to solve by my self. I'm using PIC12F683 which reads through ADC voltage and blinks led in various frequencies. That part works like it should in the code. Then there is a part which should control relay NC contacts (through transistor, RelayOutput at GP1_bit) when input GP3 is high. Program should turn GP1 high when short is sensed and retry 6 times turning GP1 low in 10 seconds intervals. 6th time it will exit the loop and switch GP1 permanently on.

This is is sort of working. But GP3 when turned on inside the loop is switched on and off by 29khz frequency. See below screenshot.
actual_program.png

I've tried numerous things and then tested to comment the if shorted -clause and tested inside the loop by RelayOutput = ~RelayOutput; to see what would the frequency then be and it was arund twice faster.
Testing_output.png

I really don't get it why is that GP3 behaving like this. Please help.

Here's the complete mikroC code:

Code:
 bit Timer, PermanentShort;
 char RetryTimerCounter=0, RetryCounter = 0, PreviousRetryCounter = 0;
 double PressureReading = 0.0;
 sbit LEDOutput at GP2_bit;
 sbit RelayOutput at GP1_bit;
 sbit Shorted at GP3_bit;


// Initializing registers
void InitMain(void) {
     ANSEL = 0b00010001;         // Set input to digital
     TRISIO = 0b00111001;      // input Pin 7 ADC, 4 Short circuit ind. Output Pin 5 LED, 6 Relay
     OPTION_REG = 0b10000000; // GPPU disabled
     INTCON = 0b11000000;        // GIE and PEIE enabled
     PIE1 = 0b00000001;      // Enable Timer1 interrupt
     T1CON = 0b00111101;  //Timer1 Registers Prescaler= 8 - TMR1 Preset = 0 - Freq = 1.91 Hz - Period = 0.524288 seconds
     TMR1H = 0;             // preset for timer1 MSB register
     TMR1L = 0;             // preset for timer1 LSB register
     ADCON0 = 0b10000001;
}
// Interrupt handling
void interrupt(void)
{
    if (TMR1IF_bit) // If timer1 is interrupting
    {
      Timer = 1;
      TMR1IF_bit = 0; // Reset timer1 Interrupt
      if ((RetryTimerCounter > 20) && Shorted ) // ~10 seconds and short is present
      {
         RetryTimerCounter = 0;
         Retrycounter++;
      } else if (Shorted) //
        {
         PreviousRetryCounter =  Retrycounter;
         RetryTimerCounter++;
        }
    }
}
// Read the pressure
double ReadPressure (void) {
      double analogvalue = 0.0;
      ADCON0.f1 = 1;                              // Enable conversion
      while (ADCON0.f1);                          // Wait for conversion to end
      analogvalue = (ADRESH << 8 ) + ADRESL;      // Store results
      analogvalue = (analogvalue/1024.00)*5.0; //calculate actual voltage across the sensor
      return analogvalue;
}

void HandleShort(void) {
    RelayOutput = 1;
    if (RetryCounter > 5)
    {
       RetryCounter = 0;
       PermanentShort = 1;
       LEDOutput = 1;
    } else if (PreviousRetryCounter != Retrycounter) RelayOutput = 0;
}

unsigned int HandleLedBlinking(double BlinkCase) {
   unsigned int BlinkInterval1;
   
   if (BlinkCase > 1.8) Blinkinterval1 = 3740;    // 5 hz
   else if (BlinkCase > 0.89) Blinkinterval1 = 6233;  // 3 hz
   else if (BlinkCase > 0.544) Blinkinterval1 = 9350; // 2 hz
   else if (BlinkCase > 0.2) Blinkinterval1 = 18700;  // 1 hz
   else if (BlinkCase < 0.2) BlinkInterval1 = 0;     // Led off

   return BlinkInterval1;
}


void main() {
     unsigned int BlinkInterval = 0, i = 0;
     InitMain();
     Timer = 0;
     PermanentShort = 0;
     LEDOutput = 0;
     RelayOutput = 0;

     while(1)
     {
      if (Timer)
      {
       Timer = 0;
       PressureReading = ReadPressure();
       BlinkInterval = HandleLedBlinking(PressureReading);
      }
      // Check whether there is short circuit
      if (Shorted)
      {
         HandleShort();
      } else RelayOutput = 0;

  //    RelayOutput = ~RelayOutput; // Testing the frequency
  
      // Short circuit is persistent. Exit loop.
      if (PermanentShort) break;
      
      if (BlinkInterval) {     // Blink led through various frequency
         if (i > BlinkInterval) {
            LEDOutput = ~LEDOutput;
            i = 0;
         }
         i++;
      } else LEDOutput = 0;
      
     }
   RelayOutput = 1; // Turn relay on as there is permanent short
}
 
Last edited:

I'm finding that hard to follow, can you show a flow chart please. Also, why do you convert the ADC reading to a voltage then compare it to a series of fraction values instead of using the ADC readings directly? It seems to complicate the code and make it bigger and less accurate for no reason. What happens if the voltage returned is 0.2V?

Brian.
 
You're correct, no need to convert the ADC reading to voltages, I could use as well the ADC readout directly. It just made it easier for me to undestand the voltage directly instead.. That part actually is working ok.

This works so that Timer1 will interrupt every 0.5 seconds. Inside timer there is counters for led blink intervals, GP1 on every 10 seconds, GP1 on tries counter and flag for timer interrupt for taking ADC readout. In main there is if which checks the timer flag and if set it will take the ADC readout in volts and blink interval for corresponding voltages. Voltage below 0.2 led (GP2) is off. Next if check whether GP3 is high or low. If high it will turn relay output on (GP1). Also in that procedure (HandleShort) it tries every 10 seconds to turn off GP1 until 6 times tried and still GP3 high it will turn the led on and set flag for permanent off.

Next in main it will exit the loop if GP3 has been high for ~60 seconds. Next if clause in main will blink the led in every 3740 to 18700 rounds depending the ADC readout.

I'd see that the issue is within these as these are the only ones which handle the RelayOutput (GP1).
Code:
void interrupt(void)
{
    if (TMR1IF_bit) // If timer1 is interrupting
    {
      Timer = 1;
      TMR1IF_bit = 0; // Reset timer1 Interrupt
      if ((RetryTimerCounter > 20) && Shorted ) // ~10 seconds and short is present
      {
         RetryTimerCounter = 0;
         Retrycounter++;
      } else if (Shorted) //
        {
         PreviousRetryCounter =  Retrycounter;
         RetryTimerCounter++;
        }
    }
}
......
void HandleShort(void) {
    RelayOutput = 1;
    if (RetryCounter > 5)
    {
       RetryCounter = 0;
       PermanentShort = 1;
       LEDOutput = 1;
    } else if (PreviousRetryCounter != Retrycounter) RelayOutput = 0;
}
......
if (Shorted)
      {
         HandleShort();
      } else RelayOutput = 0;

I did this relay control first and then the led control. I'm pretty certain that it worked before... But how could that led control part mess it up.. Now that I was writing this I was doubting this:
Code:
else if (PreviousRetryCounter != Retrycounter) RelayOutput = 0;
in the code. But I've tried that commented and still same output from GP1. Also after 6 retries it will break from the loop, turn led on and GP1 on. When it's outside of the loop GP1 stays on without any frequency.
 

According to the data sheet, GP3 is a input only pin. (You must realise this as you only ever try to read it in your code.)
However I'm not sure if I understand you correctly about what is happening to it: are the images you have shown the GP3 signal? If so then whatever is driving it will be in your external circuit and not (necessarily - see below) your code. If those images are not GP3 then what are they?
(There is a slight possibility you are being bitten by the RMW situation that can occur which these devices. I don't have the time to try to understand all of the ways the global variables interact but the GP3 pin is read every time though the main loop and 'HandleShort' will always start by writing a '1' to the GP1 bit - this may be triggering the RMW situaiton on GP3.)
By the way, there is a logical problem with your code. If 'PermanentShort' is ever set, it wil cause a 'break' from the main loop. I'm not sure what mikroC does when the main loop exits but exiting the main loop is something that an embedded program should never do. The mikroC runtime code *may* just sit in a tight loop when the main funcito exits but, as some other compiler runtime codes does, it *may* cause a reset which will start you program running again (i.e. reinitialise everything and again call the 'main' function). Either way, this shoudl never happen.
Susan
 
Thank you both for your input so far. Sorry in my first post I wrongly wrote GP3 on those oscilloscope texts. It should have been GP1.
So GP1 is only output and that is doing that (can I call that Oscillate?). GP3 is just digital input sensing high/low.

I wasn't aware of the RMW thing. I'll try that later on eg. delay after turning GP1 on. I'm starting to believe that this is not code issue rather than something like that. Eg. if I let the GP3 float it will make GP1 oscillate. Sure floating is not ideal situation but I noticed that on breadboard...
 

Added 10us delay after every output state change and all I could find is that the positive and negative width is now 10us longer. So I guess it's not RMW then...
Also removed the break and changed it to if clause in main loop. Now if permanentShort is set it will just do nothing in main loop, except of course turn on the relay.

Any other ideas what could cause this oscillation?
 

This is getting more confusing. ADC input pin GP0 is messing up things. If I plug that GP0 to VDD, GP1 is not oscillating anymore. If plugged to GND it does oscillate (or some other low voltage in between). How come? They're two different functions in code.

Also just noticed that compiler is telling "Variable 'analogvalue' has been eliminated by optimizer". But that variable is used.. Something strange is happening.
 

Sure floating is not ideal situation but I noticed that on breadboard...
No pins should float EVER!
I can't see where anything can cause oscillation at 29KHz, especially as a square wave. The only square wave possible at that rate is from the PWM output but that is on GP2 not GP1. I know this is frustrating but it would help us if you could show a flow diagram of what you want to happen and also show us a schematic so we can look for potential problems.

The only software issue I can see is in relation to post #1, you break out of the while(1) loop and execute "RelayOutput = 1;" but where does it go from there?
Aligning the braces and indenting the routines would make it much easier to read.

Brian.
 

Try this configuration.

Code:
CMCON = 0x07;

Comparator if enabled affects GP0, GP1 and GP2 pins.
 
Try this configuration.

Code:
CMCON = 0x07;

Comparator if enabled affects GP0, GP1 and GP2 pins.

That's it! You're my hero. Thank you! Wohoo, now it's working.

That leads me to one more guestion. Since day one I started with these PIC microcontrollers it has always been bit soft to me that what registers need to be declared. There are zillion registers and every pic is different so how do you know? Of course those which you need to enable you know, but else.. Like this one. Is there any quide or quick reference for every type that you need to declare at least these registers? Or you just need to read the whole datasheet from end to end every time? Also is there any sequency what you need to use to declare these? Like for example you always need to declare INCON before PIE etc?
 

In each data sheet there is a section for each register that contains a diagram/table for the register. At the top of the table is a code for each bit that tells you if it readable and/or writable and, importantly for your question, what the 'Power On Reset' (POR) setting is.
In many data sheets there is a table that lists all of the registers, the page the are described in full on (i.e. the table mentioned above) and also the default POR settings.
After that, it is often down to experience in that there are several things that always need to be set: the CONFIG settings (sometimes called fuses), the oscillator, and if the MCU has any analog functionality, then the default for the related pins will be 'analog' mode (*) so setting the analog/digital mode is essential.
(*) - there is a 'trick' that can get new players when debugging. The debug kernel that gets loaded makes all analog capable pins 'digital' at the start. Therefore if you don't set the 'ANSELx' (or whatever the name is for your MCU) register, your app can work beautifully while debugging but fail with a 'release' build. Therefore my suggestion is to ALWAYS set the analog/digital mode of all pins you use to the way you want them.
As for other things, then my general rule is always set up before you enable - that would include setting up the interrupts the way you want them before you enable any. With some peripherals (UARTs are an example) you have to follow the sequence in the data sheet but there are peripherals in some families of devices where setting the 'enable' bit can lock in the configuration of that peripheral (although most do allow on-the-fly reconfiguration).
Of course, the above is generic advice and any particular MCU might (and probably will) have its own set of quirks.
Susan
 
Hi,

There are zillion registers and every pic is different so how do you know?
It's less than a zillion, that's the good news.
The bad news is, that you should read the whole datasheet thoroughly..maybe 300 pages, maybe more.
You don't need to store every single word in your mind, but you should have a detailed overview about all the functions to easily find the place in the datasheet.

Klaus
 

May I borrow bit this same thread even though this is bit unrelated. Do you need pull down resistor for NPN transistor base when controlling it through PIC output? I'm pretty certain that the pic has strong enough pull that it is not needed but it wouldn't be first time I'm wrong. :lol:
 

Hi,

To be true, I don't know the answer.

If I want to find the answer I need the circuit and the voltages and currents.
And I need to read the datasheets.

The same can you do. At least you could try it and ask someone to verify your thoughts.

Klaus
 

Ok, that's no brainer. PIC datasheet says sink current is as well 25mA as source current so that's plenty for most transistor base currents..
 

... but beware that if you tri-state the pin (TRISx register) it is disconnected from the driver circuit inside the PIC so it will no longer pull the base to ground. If you use that method, you should add a resistor to prevent the base floating.

Brian.
 
Hi,

Ok, that's no brainer. PIC datasheet says sink current is as well 25mA as source current so that's plenty for most transistor base currents..
Out of curiosity I had a look into the datasheet.
25mA is not an "operational" current. It is the absolute maximum, the edge to get killed.

Klaus
 
... but beware that if you tri-state the pin (TRISx register) it is disconnected from the driver circuit inside the PIC so it will no longer pull the base to ground. If you use that method, you should add a resistor to prevent the base floating.

Brian.

Sorry, got bit confused. You mean maybe in some other case eg. PIC16F1847 which has TRISA and TRISB and if those are set "1 = PORTA pin configured as an input (tri-stated)" it needs resistor? In this particular topics case I do declare initially ANSEL digital and TRISIO output and don't touch these after that, so they are either pulled high or down. Correct?



Hi,


Out of curiosity I had a look into the datasheet.
25mA is not an "operational" current. It is the absolute maximum, the edge to get killed.

Klaus

Yes, that was it. 20mA is the operating current.
 

Sorry, got bit confused. You mean maybe in some other case eg. PIC16F1847 which has TRISA and TRISB and if those are set "1 = PORTA pin configured as an input (tri-stated)" it needs resistor? In this particular topics case I do declare initially ANSEL digital and TRISIO output and don't touch these after that, so they are either pulled high or down. Correct?
The same applies to all PICs, the pins can be inputs, outputs or tri-stated. If you are using any as an output and drive it high or low, it will have the ability to source or sink current so driving a transistor through a suitable current limiting resistor is fine. However, if you use the TRIS register to tri-state a pin, it effectively becomes disconnected from the output driver circuit so in that scenario, if driving a transistor it leaves the base disconnected and floating. So if you use TRIS to control a pin, it may be wise to add a resistor to ground anyway.

Using TRIS is actually quite a clever way to control a pin, it allows open-drain parallel connections with other devices in a bus configuration and it allows for logic level translation to any voltage lower than VDD. For example, you can run the PIC from 5V but produce a 3.3V level at the output pin. Makes it easy to mix logic families that need different signal levels.

Brian.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top