Hello guys
I am facing the following problem.
I want to have a push button to turn on & off a LED .
I am not able to read the state of the pin that button is connected and the LED is always ON.. Any help would be very appreciated
What i am doing wrong ?
XC8 code:
#include <stdio.h>
#include <stdlib.h>
// PIC16F1827 Configuration Bit Settings
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
#define ButtonInput PORTBbits.RB7
#define LED_RA2 LATAbits.LATA2
#define LED_RA0 LATAbits.LATA0
#define _XTAL_FREQ 8000000L
int main() {
OSCCON = 0b01110000;
ANSELA = 0b00000000;
ANSELB = 0b00000000;
TRISA = 0b00000000;
TRISB = 0b10000000;
ADON = 0;
while (1) {
if (ButtonInput == 0) {
LED_RA2 = 1;
}
if (ButtonInput == 1) {
LED_RA2 = 0;
}
}
}
I don't know Microchip stuff, and I don't speak C, but it looks like you're only turning the LED off while the button is pushed. Letting go of the button turns it back on.
Using a while loop for this is silly. There's gotta be a way to use interrupts, so the chip is idle when you're not pushing the button instead of going full speed in the while loop.
I know that its better to use interrupts and i have also tried it.. but the problem is not solved neither..
Turn ON the power-on reset timer, unless you are using an external power-on-reset circuit, like a sequencer or power supply monitor IC (highly unlikely) or a RC circuit connected to MCLR. Make sure that the programmer is picking up and using all of those configurations that you are setting in your code: Oscillator, MCLR, WDT, POR, etc.. If these are wrong your PIC may never come to life. Sometimes the programmer goes ahead and substitutes default or last-used values for these and you might end up pulling out your hair before figuring that out.
Even though you set MCLR to off, try a pull-up resistor on that pin just in case... your PIC may be stuck in reset.
Have you succeeded in creating a flashing LED that doesn't depend on another input? Something like count down a big value and toggle the LED pin when it reaches zero.
Don't assume that the pin configurations are correct. The pins you are using are multiplexed with several other functions, like comparators, cap sense, timers, oscillators, etc. Find those functions and the registers that control them and explicitly disable those other functions.
One part of the problem is that everything in the loop happens several times a second (even hundreds, thousands etc), depending on the frequency of the microcontroller.
In your code, as soon as you press the button, the microcontroller would turn off the led, as soon as you release the button the led would turn on. Try keeping the button pressed a few seconds.
In order to work like you want, as simple modification should do it :
while (1) {
if (ButtonInput == 1) {
if (LED_RA2 ==1) {
LED_RA2 = 0;
} else {
LED_RA2 = 1;
}
}
Basically, when you press the button, flip the LED_RA2. You can also do some basic debouncing of the button by adding a counter which makes your loop not change the state of the led if not enough time has passes since last press.
unsigned int counter = 501;
while (1) {
counter++;
if (counter > 65534) counter = 501;
if ((ButtonInput == 1) && (counter > 500)) {
if (LED_RA2 ==1) {
LED_RA2 = 0; counter = 0;
} else {
LED_RA2 = 1; counter = 0;
}
}
meaning every time microcontroller goes through loop, the counter goes up by one until counter is the maximum allowed by data type, 65535 and then it resets. In the loop you only change states if the counter is above a value. If you change state, you set the counter to 0, so now there must be at least that many loops (500) before your code will again do something if the button is pressed.
How fast those loops pass depends on the microcontroller frequency, 500 loops can be done in as little as 1-2 nanoseconds I think.
*debouncing = a pushbutton is mechanical and by design, due to the spring inside and the two pieces of metal that are supposed to touch, it often happens that before you get a continuous contact you can get some break in the contact due to the metals inside flexing. So you could get something like this from the button when you press it ... 0001001101111111
If you press the button for a very short time, it's possible that in the loop you'd catch the first 1 and then on the second pass you'd read a 0 even though the button is physically still pressed at that time. So your code should keep that in mind, or you would do debouncing in hardware (add a small capacitor so that when button is pressed, the capacitor has to charge and reach the threshold voltage on pin and then microcontroller sees that as 1)
ps.
and there's really no need to use LATAbits.LA2 in this context, you can use PORTABits.RA2
and by the way, on PIC16F1827, RA2 is shared with DACOUT (DAC) and that one has priority. But it's disabled by default so it should be I/O pin. Still you could make sure by settting DACCON0 =0 before the loop.
macboy : My programmer is pickit2.
I have also tried with MCLR = ON and with a pull-up reistor.
About the blinking LED: YES i am able to create a blinking LED program.. i put inside while loop : LED_RA2 =! LED_RA2 ; __delay_ms(100);
i have also tried the following option without success:
ADCON0 = 0b00110000;
CPSCON0 = 0;
CPSCON1 = 0;
APFCON0bits.P1DSEL =1;
APFCON0bits.P2BSEL = 1;
MDCARHbits.MDCHODIS = 1;
MDCARHbits.MDCH = 1000;
What i am doing wrong ?
Take a look at the datasheet and disable all other functions on the input / output pins - I typically run a routine that explicitly puts all the pins into GPIO. This is where Microchip differs from other vendors and it creates lots of problems for new programmers.
Usually you need to disable analog and comparator functionalities first.
Also check your fuses if lvprogramming or particular output pins are set to a non-gpio mode.
mariush : I merged your debouncing code with mine but still no luck
dannyf: I have allready disabled analog and comparator with (ADCON0 = 0b00110000; , C1ON =0 , C2ON = 0;)
i have 3 days reading and reading the datasheet
Did you try:
ANSEL = 0x00;
ANSELH = 0x00;
?
Draw in paint or something similar how you connect the button to your RB7 pin.
Or snap a picture of the prototyping board and explain it.
Did you connect the button to RB7? Maybe you put it by accident on another pin?
Replace the button with a wire going straight from 5v to RB7 pin (well, it wouldn't hurt to add a 1k resistor in series), see if that works. If it does, you probably wired the button incorrectly.
Can you post the full code again, just in case you may have made a typo or something?
Arp: There is ANSELA , ANSELB on this chip that is both 0;
mariush: I have connected correctly the one pin of the button to RB7 and the other in series with a 1k resistor to 5v..
I also replace the button with just a wire from 5v to RB7 but still not working..
The updated code is this:
unsigned int counter = 501;
int main() {
OSCCON = 0b01110000;
ANSELA = 0b00000000;
ANSELB = 0b00000000;
ADCON0 = 0b00110000;
TRISA = 0b00000000;
TRISB = 0b10000000;
CPSCON0 = 0;
CPSCON1 = 0;
APFCON0bits.P1DSEL = 1;
APFCON0bits.P2BSEL = 1;
MDCARHbits.MDCHODIS = 1;
MDCARHbits.MDCH = 1000;
C1ON = 0;
C2ON = 0;
while (1) {
counter++;
if (counter > 65534) counter = 501;
if ((ButtonInput == 1) && (counter > 500)) {
if (LED_RA2 == 1) {
LED_RA2 = 0;
counter = 0;
} else {
LED_RA2 = 1;
counter = 0;
}
}
}
}
1. Make sure that you can blink RA2 first. That tells you if the issue is with reading RB7 or outputing to RA2.
2. Read the datasheet about anything impacting RB7 (if reading it is the issue). Particularly APFCON0 - there are multiple bits there that impacts PBx.
3. Disable comparators, analog and lvprogramming.
4. If everything fails, try to move it to a different pin and see if the logic works.
Reading the datasheet is painful but also most helpful. Consider it an investment in yourself.
You're using one of the ISP pins as your input. If you can, try using another pin which isn't used for ISP so that you can simplify the problem. Alternatively, try just unplugging the ISP header and see if that works. Another useful thing to do is run the in circuit debugger, but you would definitely need to choose a different pin for your button for that to run.
I have connected correctly the one pin of the button to RB7 and the other in series with a 1k resistor to 5v..
And there lies your problem - how is the pin ever going to change state to logical zero when it's pulled up by internal resistors and also when a button is pressed.
Just connect the button between input pin and ground and see if that works. If you want an active-high input you'll need a pull-down resistor to ground and a button going to Vdd.
I noticed that:
If i power one the chip directly from pickit2 then everything works fine... When i apply voltage directly to the pins (vss vdd) from a 3.7 battery then .. its not working.. Why that ?
I noticed that:
If i power one the chip directly from pickit2 then everything works fine... When i apply voltage directly to the pins (vss vdd) from a 3.7 battery then .. its not working.. Why that ?
Perhaps you have the brownout (low voltage) detection enabled and set at > 3.7V ?
When i power on the circuit from the battery pic is not working..if i just connect the PICKIT2 with the icsp cable in parallel (dont have vdd checked on pickit2 software) it works fine ...
David_AVD: I supply 3.7Volts with pickit2 .. Its the same with battery
Can you post a picture of your breadboard or a diagram of how you have wired up the PIC.
Here is a simulation of a piece of simple code on your mcu: flipping porta pins when pb7 is low. Largely follows your code.
Works as desired.
The cure to your problem was mentioned earlier in this very thread. You just need to read the datasheet and follow through.
dunnyf: In proteus its working fine.. In realtime its not ..
Believe me i have read the datasheet again and again..
In the attachment i show how i have it connected: The pickit is also connected to the MCLR,VDD,VSS,ICSPDAT,ICSPCLK .. if i give Voltage from Pickit i remove the battery..
In the attachment i show how i have it connected:
If you connected it like that the input will always be high...
In proteus its working fine.. In realtime its not ..
I can take your code as is, reproduce your problem.
I can make one change to your code, your problem is gone.
how i have it connected
Put a pull-down resistor on mclr; and add a serial resistor with the led.
In proteus its working fine.. In realtime its not ..
I can take your code as is, reproduce your problem.
I can make one change to your code, your problem is gone.
What change to the code ?
WPUA5 = 1;
I will give it a try with the pull down resistor right away..
how i have it connected
Put a pull-down resistor on mclr; and add a serial resistor with the led.
I allready have a resistor in serial with the LED . I try that you just suggest me but its not working (resistor at mclr).. If i connect RB7 in serial with a resistor to Ground everything is working fine..!! Is that ok ?
Thank you soooo much guys..!!