View previous topic :: View next topic |
Author |
Message |
david90
Joined: 25 Feb 2006 Posts: 23
|
weird problem with simple LED output |
Posted: Thu Nov 27, 2008 12:17 pm |
|
|
I'm running this code
Code: | #include <16F676.H>
#DEVICE ADC=8
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT
#use delay(clock = 4000000)
setup_oscillator(OSC_4MHZ);
//#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1)
#include "debug.h"
#include "io_init.h"
int test;
main()
{
set_tris_c (0);
initialization();
//test
enable_interrupts(GLOBAL);
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256 );
enable_interrupts(INT_RTCC);
//
set_tris_c (0);
while(1)
{
output_high(PIN_C5);
delay_ms(1000);
output_low(PIN_C5);
delay_ms(1000);
}
}
#INT_TIMER0
void timer0_test(){
if (input(PIN_c1))
{
output_low(PIN_c1);
}
else
output_high(PIN_c1);
}
|
When I probe pin c1 without an LED connected, I could see a square wave. When I connected an LED with series 200ohm resistor, C1 stops oscillating and the voltage drops to a constant 3.0V. Why in the world would it stop oscillating and the voltage drops to 3.0V?
Normally I would expect the LED to blink but it doesn't. The LED connected to C1 stays solid because C1 stops oscillating with voltage a constant 3V.
Why does C1 stop oscillating when I connect an LED to it?
Thanks. |
|
|
david90
Joined: 25 Feb 2006 Posts: 23
|
|
Posted: Thu Nov 27, 2008 12:36 pm |
|
|
just an update. PIN C1 work like I expected if I change my code to this
Quote: | #include <16F676.H>
#DEVICE ADC=8
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT
#use delay(clock = 4000000)
setup_oscillator(OSC_4MHZ);
//#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1)
#include "debug.h"
#include "io_init.h"
int test;
main()
{
set_tris_c (0);
initialization();
//test
enable_interrupts(GLOBAL);
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256 );
enable_interrupts(INT_RTCC);
//
set_tris_c (0);
while(1)
{
output_high(PIN_C2);
delay_ms(1000);
output_low(PIN_C2);
delay_ms(1000);
}
}
#INT_TIMER0
void timer0_test(){
disable_interrupts(GLOBAL);
output_low(PIN_c1);
delay_ms(1000);
output_high(PIN_c1);
delay_ms(1000);
enable_interrupts(GLOBAL);
} |
So there must be something wrong with this code
Code: | if (input(PIN_c1))
{
output_low(PIN_c1);
}
else
output_high(PIN_c1); |
I have this problem with 16F676 TSSOP package but not with the DIL. The 16F676 DIL runs fine with the same code on a dev board. Wierd. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 27, 2008 1:09 pm |
|
|
Quote: | #include <16F676.H>
#DEVICE ADC=8
#fuses INTRC_IO, NOWDT, NOPROTECT, NOBROWNOUT
#use delay(clock = 4000000)
setup_oscillator(OSC_4MHZ);
//#use rs232(baud=9600, xmit=PIN_A0, rcv=PIN_A1) |
The line in bold above doesn't do anything. It must be inside a function
to work. Normally you would get an error for this, but in some older
versions of the compiler it won't give an error.
Quote: | #INT_TIMER0
void timer0_test(){
disable_interrupts(GLOBAL);
output_low(PIN_c1);
delay_ms(1000);
output_high(PIN_c1);
delay_ms(1000);
enable_interrupts(GLOBAL);
} |
Don't enable/disable global interrupts inside an isr. The PIC and the
compiler handle this completely for you. What you are doing is in fact
dangerous. If you had another interrupt running (such as #int_rda, etc)
then you could get an interrupt while inside your ISR. Nested interrupts
are not support in the PIC16, so your program would crash. Delete both
lines in bold.
Also, if you have warnings enabled, you would get a message about
"interrupts disabled to prevent re-entrancy". Normally we don't put
delays in an isr. If you want to do this (for a test program) then you
should create another instance of the CCS library code for delays.
This is done by adding another #use delay() statement above the isr.
Example:
Quote: |
#use delay(clock = 4000000)
#INT_TIMER0
void timer0_test(){
output_low(PIN_c1);
delay_ms(1000);
output_high(PIN_c1);
delay_ms(1000);
} |
Quote: | output_low(PIN_c1); |
Also, most C compilers are case sensitive. CCS has case sensitivity
disabled by default, so your Pin constant will compile OK with it.
But it's a good idea not to get into a bad habit. Use the correct name
of PIN_C1. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Nov 27, 2008 2:16 pm |
|
|
Referring to the original problem, that is unrelated to the other points mentioned by PCM prorammer:
You should try input_state(PIN_C1) instead of input(PIN_C1) and also may want to consult the manual about operation of input() function with default #use standard_io in effect.
Everything is correct! Just consider, that input() first sets the port to tristate and then (after a fraction of a microsecond) reads the input state. With a strong load, the state can change in between. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 27, 2008 3:26 pm |
|
|
A pin will only _read_ as high or low, if the signal actually reaches the logic thresholds for high and low respectively.
Depending on what series resistance you have feeding the LED, voltage levels around the chip, and the Vf needed for the LED, it may be 'borderline' for the driven pin to actually get to the required levels. A tiny difference in the threshold voltage between the two PICs, and you have 'it works on one, but not the other'...
Best Wishes |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Fri Nov 28, 2008 12:02 am |
|
|
You may be the victim of the Read-Modify-Write problem, inherent in 16 series PICs. This is a good link to understand what the RMW problem is:
http://www.marcansoft.com/subidos/readmodifywrite.pdf
(Don't remember who posted this link - Ttelmah or PCM - but thanks for sharing it! )
Rohit |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Nov 28, 2008 12:53 am |
|
|
I don't think it's a read-modify-write problem here. It's rather a problem of unintentionally setting the port to tristate by input() in standard_io mode.
But it can happen when stressing the port outputs up to 25 mA maximum current. You can, by the way, also use TRIS to switch the LED. It can be read back unaffected from the port voltage level. |
|
|
david90
Joined: 25 Feb 2006 Posts: 23
|
|
Posted: Fri Nov 28, 2008 7:33 pm |
|
|
FvM wrote: | Referring to the original problem, that is unrelated to the other points mentioned by PCM prorammer:
You should try input_state(PIN_C1) instead of input(PIN_C1) and also may want to consult the manual about operation of input() function with default #use standard_io in effect.
Everything is correct! Just consider, that input() first sets the port to tristate and then (after a fraction of a microsecond) reads the input state. With a strong load, the state can change in between. |
Your suggestion works. My LED now blinks but there is still a voltage level problem on that pin. The waveform osc. from 3V to 5V instead of 0V to 5V.
update: I tried to decrease the output current by using a 10kohm instead of 200ohm and that made the pin osc from 0V to 5V. Why does this happen?
The resistor that I usually use in series with my LED is 200 OHm
5-1.7V = 3.3V
3.3/200 = 16.5mA
16.5mA is way under the abs. max so I don't think I'm overloading the pin . |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Fri Nov 28, 2008 8:13 pm |
|
|
Quote: | Without the LED, the oscillation is from 0V to 5V. Why? | The pin output driver has some output impedance. Think of this as the internal resistance of a battery. When you draw a large current from the pin, some volts will be lost across the driver impedance. Without the LED, there is no current draw, therefore no voltage drop; you read 5 volts.
Quote: | I tried to decrease the output current (I use 10k) and that made the oscillation go from 0 to 5V. Why does this happen? | The voltage you measured must have been at the pin-resistor junction, and not at the resistor-LED junction. The pin will always show you close to 5 volts (as long as you don't overload it), while the voltage at the resistor-LED junction will be the forward drop of the LED.
Rohit |
|
|
david90
Joined: 25 Feb 2006 Posts: 23
|
|
Posted: Fri Nov 28, 2008 9:52 pm |
|
|
Rohit de Sa wrote: | Quote: | Without the LED, the oscillation is from 0V to 5V. Why? | The pin output driver has some output impedance. Think of this as the internal resistance of a battery. When you draw a large current from the pin, some volts will be lost across the driver impedance. Without the LED, there is no current draw, therefore no voltage drop; you read 5 volts.
Quote: | I tried to decrease the output current (I use 10k) and that made the oscillation go from 0 to 5V. Why does this happen? | The voltage you measured must have been at the pin-resistor junction, and not at the resistor-LED junction. The pin will always show you close to 5 volts (as long as you don't overload it), while the voltage at the resistor-LED junction will be the forward drop of the LED.
Rohit |
I don't think it is because of internal resistance. It has something to do with the statement` input_state().
If I get rid of this code
Code: | #INT_TIMER0
void timer0_test(){
if (input_state(PIN_C5))
{
delay_us(500);
output_low(PIN_C5);
}
else
{
delay_us(500);
output_high(PIN_C5);
}
} |
and just put this in my main loop
Code: | output_high(pin_C5);
delay_ms(50);
output_low(pin_C5);
delay_ms(50); |
C5 would oscillate from 0V to 5V just fine. |
|
|
Rohit de Sa
Joined: 09 Nov 2007 Posts: 282 Location: India
|
|
Posted: Fri Nov 28, 2008 10:07 pm |
|
|
True, the reason why the output wasn't toggling initially was because of the faulty code. But even now, with
Code: | output_high(pin_C5);
delay_ms(50);
output_low(pin_C5);
delay_ms(50); | you will see that the output is much lower than 5V with an LED attached. Without the LED the output will swing from 0 to 5v.
Rohit |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Nov 29, 2008 2:28 am |
|
|
input_state() in contrast to input() is not manipulating the TRIS register and thus should not have any influence on the output state. As previously discussed by Ttelmah and Rohit de Sa, the voltage drop due to a heavy load may be so high, that input_state() is reading a wrong level (said RMW problem). In this case, the output would stop blinking rather than showing an intermediate level.
There's apparently a misunderstanding of absolute maximum ratings. Keeping these limits can avoid damaging the chip, not guarantee normal operation: Quote: | This a stress rating only and functional operation of the device at those or any other conditions above those indicated in the operation listings of this specification is not implied. |
Normal operation of output ports is specified with maximum VOL of 0.6V at 8.5 mA output current. As a rough estimation, you can expect a linear, resistive behaviour below this corner. Somewhere above 8.5 mA, the output may show current limited (saturated) behaviour, thus it's not possible to extrapolate VOL above 8.5 mA.
When designing a circuit that operates above specified parameters, you should also consider possible exemplar and temperature dependant variations. |
|
|
|