Cannot read input from pins PIC - c

I'm facing a really struggling issue with input reading.
I just wanted to use a push button to active several led but i don't know why the specific PORT doesn't change to 0 to 1 when i press the button.
I've seen that it could be related to the analog but i turned it to digital
PIC16F18875
Using Mplabx v5.40
Here is the code
#define _XTAL_FREQ 4000000
#define button TRISDbits.RD7
#include <xc.h>
ledLoop(void){
char run = 1;
while(1){
if(PORTDbits.RD7==1){
LATB=run;
run *= 2;
__delay_ms(200);
}
else{
LATB=0;
}
}
}
void main(void)
{
ANSELDbits.ANSD7=0;
TRISDbits.TRISD7=1;
TRISA=0;
LATA=0x00;
ledLoop();
}
Also my push button is connected as it follow:
3V -> LED -> 10 Ohm resistance -> push button -> to mass and to RD7 port
EDIT
The 4 leds works if the if condition for RD==0 so its working. And for the button part, if i press on the button the led works, but dont change PORTDbits.RD7 to 1

You need to connect the "high" side of the button to RD7, and the "low" side of the button to ground:
That way the high level of 3,3V gets to the input pin if the button is open. When you press the button, the low level of ground gets to the input pin.
(The correct statement for this would sound different, but I wanted to say it as simple as possible.)

Is your schematic look like this ? LEDs:3v -> LEDs -> 10R -> PORTB and BUTTON:0v -> BUTTON -> RD7 Perhaps add a Pullup between Button/RD7 to avoid electric floating value

Related

PIC18 Global Interrupt Enable bit toggling when keypad button pressed

Objective
I am trying to interface a 4x3 matrix keypad and 7 segment LED display to PIC18f4550 microcontroller. When I press buttons on keypad, I want the 7 segment display to show the number accordingly.
What I have done so far
Based on my research, I can either use scanning (continuously polling) or use interrupts to interface the keypad with the MCU. I decided to use interrupts as that way the microcontroller can be free up for other operations.
The following is the connection of keypad to MCU.
I am using RB0-2 as input to MCU and RB4-7 are set as output from MCU. RB4-7 are permanently set high so when the user press on the keypad button, it will trigger the RB0-2(INT0-INT2) interrupt to process.
For simplicity in this post, I will only discuss about the Column 1 of the keypad.
This is how I initialize and setup the registers.
void main(void)
{
OSCCON = 0x72;
TRISD = 0;
LATD = 0;
ADCON1 = 0x0F;
TRISB = 0x07;
LATB = 0xF0;// keep the RB4-7 high
INTCONbits.GIE = 1;
INTCONbits.INT0IF = 0;
INTCONbits.INT0IE = 1;
INTCON2bits.INTEDG0 = 1;
while (1);
}
My interrupt handling is as below:
if(INTCONbits.INT0IF == 1)
{
for(char scan=0x10; scan>=0x80; scan <<= 1) // send 1 to each row starting from RB4 till RB7
{
LATB = scan;
if (PORTBbits.RB0 = 1)
{
if(scan == 0x10)
{
display_number(1);
}
if(scan == 0x20)
{
display_number(4);
}
if(scan == 0x40)
{
display_number(7);
}
}
}
LATB = 0xF0;
INTCONbits.INT0IF == 0;
My problem
When I run the simulation, I noticed that the GIE bit keep toggling very fast between 0 and 1 as soon as I press on any button in Column 1 and no display of any number on 7segment as well. I added the watch window screenshot and highlighted the GIE bit that is toggling.
What have I done wrong? Is my logic of handling interrupt flawed?
UPDATE 1
As DavidHoadley suggested, I have changed to use use unsigned char instead of char.
I have also corrected the for loop condition.
What I observed was, If I keep the loop inside the interrupt routine, the loop will get stuck for some reason.
For now, I have given up trying to use loop inside the interrupt function and instead resort to have a function in main while loop to output high at each row sequentially forever and the interrupt function is only used to check the output using switch statement.
Your for loop end condition looks like the loop will immediately exit. The line:
for(char scan=0x10; scan>=0x80; scan <<= 1)
Should probably be:
for(char scan=0x10; scan<=0x80; scan <<= 1)
Can’t test this - hope it works
It is a normal behaviour for PIC micros. When PIC goes to the interrrupt vector the GIE bit reset by hardware and when it finishes servicing the interrupt, it returns with the RETFIE assembly instruction by setting the GIE bit which is not visible in C code. So there is no fault in your code for this matter, this is not even a matter.
I see in your code you are using only INT0 interrupt to detect presses and the rest of INTx pins are not activated. That's why the PIC micro will be able to detect the changes of the only first column. I suggest you to use interrupt on change (IOC) which features on RB<7:4> bits. This way you can free the INTx pins for other purposes. And you can move the 3 pins to a PORT other than PORTB. Here is the procedure or my suggestion if you interest:
Configure RB<7:4> pins as inputs and enable their IOC feature.
Configure any 3 pins as output of any port.
If you use the positive logic set the 3 pins high otherwise, low.
In your ISR poll the RBIF to know if there is a change on RB<7:4> pins.
If so make a button scan to detect the pressed key.
Unfortunately can't tell you anything for your display issue since you haven't shared the codes and the configuration of display.

MSP430 issue with button not switching off

I'm making a program for the msp430.
The incrementation runs away on first button click. It doesn't stop when the button is released.
How can incrementation be limited to one incrementation for each button click?
#include <msp430.h>
int main(void)
{
int i; //delay variable
int dimeRead=0;
int desired=1000;
volatile int total=0;
P1OUT=0; //Supposed to get rid of it hanging at the top
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
while(total<desired)
{
if((P1IN&0x16)!=0x16) // check if switch is pressed or not
{
dimeRead=dimeRead+1;
total=total + 10;
}
//Goal is to flip an out put on to turn on light when desired number is hit.
}
return 0;
}
At first write your button pins by mask like this
#define MASK PIN1 | PIN2 (1 and 2 change to your pins) it's better for visual error control.
At second statement for check all pressed buttons if ((P1IN&MASK)==MASK).
Now your statement if((P1IN&0x16)!=0x16) check that 3 pins (PIN1, PIN2, PIN4) are in Hi state and when it's false make code
{
dimeRead=dimeRead+1;
total=total + 10;
}
If you want increment when one or two buttons are pushed statement must be like this if((P1IN&MASK)!=0)
All this is true for buttons that pushed up (HI state) when pressed, for pulled down (LOW state) is if((P1IN&MASK)!=MASK).
Add some delay after increment for debounse button.
If your buttons are connected by PIN and ground, you must enable pull-up for this pins/
if((P1IN&0x16)!=0x16) ,
when buttons arent pushed this statement is true. You should change it with equal sign.
Also im not sure about where 0x16 came from, i think you should also take a second look at it.
I am not authorized comment so I'm writing as an answer. If am not mistaken, you are trying to increment in the if, every time you pressed the button. That's why it should be like this.
if((P1IN&0x16) == 0x16)
But I would like to mention the following also:
if((P1IN&0x16) == 0x16)
by writing this statement you are expecting P1.1, P1.2 and P1.4 to be high.

Stopwatch using a ATMEL 2549 Microcontroller

i am trying to understand a program but i have some questions, maybe you can help me. The microcontroller used is a ATMEL 2549 - 8bit. Thank you in advance.
Atmel-2549 8-bit AVR Microcontroller ATmega640 1280-1281-2560-2561 datasheet
Set up a stop watch with the following features:
• There are three push buttons: START, STOP, and RESET
• Your system generates an interrupt every 100ms by using Timer1.
• There is an LCD at port A. Use the usual library for controlling the
LCD!
• On the LCD, you display the time that has elapsed since the START
button was pushed. Show minutes, seconds and tenth of seconds.
• After 59 min 59.9 s, the display starts from scratch again.
#include <stdint.h>
#include <avr/io.h>
#include "lcd.h"
#include <stdio.h>
#include <avr/interrupt.h>
void timer1_config(void);
void exinterrupt_config(void);
void send_string(void);
display myLCD;
volatile char text[20];
volatile uint8_t minute=0,sekunde=0,zehnt=0;
ISR(TIMER1_COMPA_vect) { //Interrupt for a timer with minute, second and decisecond.
zehnt++; //from 0 to 59min 59,9sec. After that time is elapsed,
if (zehnt>9) { //it should be showed on LCD display.
zehnt=0;
sekunde=sekunde+1;
}
if (sekunde>59) {
sekunde=0;
minute=minute+1;
}
if (minute>59) {
minute=0;
sekunde=0;
zehnt=zehnt+1;
}
send_string();
}
ISR(INT0_vect) { //Interrupt for starting the timer.
// --- No. *1 ---
TCCR1B|= (1<<CS11);
}
ISR(INT1_vect) { //Interrupt for stopping the timer.
TCCR1B&=~((1<<CS10)|(1<<CS11)|(1<<CS12));
}
ISR(INT2_vect) { //Interrupt for resetting the timer.
minute=0; //Sets everything to 0 and shows time on LCD display.
sekunde=0;
zehnt=0;
TCNT1=0;
send_string();
}
int main(void) {
// --- No. *2 ---
DDRD&=~((1<<PIN0)|(1<<PIN1)|(1<<PIN2));
timer1_config(); //Load all three functions.
exinterrupt_config();
send_string();
lcd_init(&myLCD ,&PORTA); //Start the LCD display on port A.
lcd_send_string(&myLCD,"-------Watch-------",1,1);
sei();
for(;;){};
return(0);
}
void timer1_config(void){
TCCR1B|=(1<<WGM12);
OCR1A=12499;
// --- No. *3 ---
TIMSK1|=(1<<OCIE1A);
}
void exinterrupt_config(void){
EIMSK|=((1<<INT0)|(1<<INT1)|(1<<INT2)); //Enable all 3 interrupts.
// --- No. *4 ---
EICRA|=((1<<ISC01)|(1<<ISC11)|(1<<ISC21));
}
void send_string(void){ //Sends text to LCD display.
sprintf(text,"%i.min %i.sek %i.zehnt",minute,sekunde,zehnt);
lcd_send_string(&myLCD,text,3,1);
}
1: I understand this is the command to make the timer start counting, but on the description from the datasheet it says "clkI/O/8 (From prescaler)" for setting the bit CS11 high. I cant understand it and how it works.
2: Is it setting the bits from DDRD to input (0)? If so, why is it being done if port D inst even being used?
3: I dont understand what it does!
4: The description from the datasheet says "The falling edge of INTn generates asynchronously an interrupt request", but i dont really get what it does. Whats the difference to "The rising edge of INTn generates asynchronously an interrupt request"?
Thank you again!
1: Setting CS11 High
From Table 17-6, it really sets the clock to clk(I/O)/8. That means it will increment the internal counter on every eighth tick of the internal I/O clock. Maybe you couldn't count every tick in the timer's register in a second, so you need to prescale it.
2: Setting DDRD bits to input
Those are for the buttons. The buttons must be on PIND of your panel, one bit for each button. Although the program does not read PIND, the external interrupt handler does, so the data direction must be set up accordingly.
Buttons, switches are inputs, leds are outputs. It depend's on your developer panel on which ports are they wired.
3: Setting up TIMSK1
§17.11.36
• Bit 1 – OCIEnA: Timer/Countern, Output Compare A Match Interrupt
Enable When this bit is written to one, and the I-flag in the Status
Register is set (interrupts globally enabled), the Timer/Countern
Output Compare A Match interrupt is enabled. The corresponding
Interrupt Vector (see “Interrupts” on page 101) is executed when the
OCFnA Flag, located in TIFRn, is set.
The timer peripherial can operate in different modes. This setting is related to output compare mode, and it will tell the hardware to issue an interrupt when the timer's internal counter reaches a limit (the limit is set in OCR1A).
The timer is set to CTC (Clear Timer on Compare) mode in TCCR1B (Table 17-2), so it restarts counting when the limit is reached.
4: Falling edge
A falling edge is when a signal goes from high to low. A rising edge is when the signal goes from low to high. These buttons are usually Active-LOW, so a falling edge means the button is pressed. (and a rising edge means the button is released)

Raspberry Pi | Linux | Detection of releasing a key | WASD keyboard control in C

I would like to implement a WASD control in my PI. This also works quite well so far.
#include "bcm2835.h"
#define SLEEPTIME 500
#define GPIO17 RPI_GPIO_P1_11
...
while(running) {
// get key
printf("wait for key:");
system("/bin/stty raw");
key = getchar();
system("/bin/stty cooked");
printf(" key %i pressed!\n", key);
// key-logic
switch(key) {
case 'w':
printf("set GPIO 17 HIGH");
bcm2835_gpio_write(GPIO17, HIGH);
bcm2835_delay(SLEEPTIME); // <-- wanna remove this!
break;
}
// reset GPIO
bcm2835_gpio_write(GPIO17, LOW);
printf("\n");
}
...
In my current implementation I have the following problem:
If I press the W key so it will be detected and sets the GPIO. After a short delay the GPIO is reset and it wait for the next key.
I want, however, that the GPIO is set as long as the W button is pressed. Do you have a hint on how I can achieve this? Is it a option that to detect a release of a key?
I have already thought of Interruputs but not found a suitable solution.
Thank you!
EDIT1:
I have found a solution that works great. Many thanks to Loki Software, Inc.
with John R. Hall.
Here you can get it: keycodes.c
and here the detailed instructions: Programming Linux Games
EDIT2:
I have to unfortunately withdraw my statement.
The program works under debian on a notebook. On the Rasbian with usb keyboard it will not work optimally.
While it starts without error but does not respond to the release of a key.
Does anyone know any advice?

Why does this state machine not maintain its state?

Hey there StackOverflow!
In the following code I have a simple state machine that changes the operation of some external lighting device (as the comments imply). The state is changed via the pressing of the button connected to GP1. The circuit connected to GP1 is a comparator debouncing circuit that compares VDD to 0.6VDD (I've also tried an RC/diode/schmitt trigger circuit), which then forces the signal LO. On a scope, we see a clean square wave when the button is actuated rapidly.
The current (and undesirable) behavior of the PIC10F200 is as follows:
Switch is pressed (state = 0)
State machine variable increments (state = 1)
Lighting goes to case 1, and turns on
Lighting remains on for at least a second
Lighting turns off
System remains in this state until button is actuated again or
powered off
The question is: Why does it behave like this? And how if possible, do I fix it such that a single press of the button equates to a single state increment, which the PIC then maintains for as long as the system is powered and the button is not actuated again?
#define SYS_FREQ 8000000L
#define FCY SYS_FREQ/4
#define _XTAL_FREQ 4000000
/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/
/******************************************************************************/
/* Main Program */
/******************************************************************************/
__CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC);
void main(void)
{
TRIS = 0b111110;
unsigned char state = 0;
while(1)
{
switch (state)
{
case 0: // IDLE/OFF
if (GPIObits.GP0) GPIObits.GP0 = 0;
break;
case 1: // ON
if (!GPIObits.GP0) GPIObits.GP0 = 1;
break;
case 2: // BLINK (slow)
GPIObits.GP0 = !GPIObits.GP0;
__delay_ms(100);
break;
case 3: // BLINK (fast)
GPIObits.GP0 = !GPIObits.GP0;
__delay_ms(50);
break;
case 4: // BEAT DETECT
GPIObits.GP0 = GPIObits.GP2;
break;
default:
state = 0;
break;
}
if (!GPIObits.GP1)
{
__delay_ms(250);
state++;
}
}
}
UPDATE: Since there seems to be a little confusion as to what I am trying to accomplish with this code/system, lets provide the full context. This microcontroller, the PIC10F200 is part of an overall board design for an electroluminescent (EL) wire driver. The miconcontroller simply controls whether or not the driver circuit is enabled by connecting GP0 to the EN port of the driver IC. The system has four modes of operation, the wire is constantly on, the wire is blinking, the wire is blinking faster, and the wire blinks whenever a low-frequency beat is detected (another circuit in the system). The transition from these modes of operation is governed by a pushbutton (on momentarily) switch to be mounted on the PCB. This necessitates that state in the code above remains stable between button actuations. It currently does not do this and behaves as described in the original part of this post. As the question title states, why isn't state stable currently, and how do I make it so?
UPDATE (2014-03-08): Solution
The following settings need to be set assuming GP0 is the output, GP2 is your T0CKI and you have a switch that drives the signal to LO when actuated.
TRIS = 0b111110;
OPTION = 0b11101111;
Whether or not bits 0-3 for OPTION really matter is a judgement call and whether or not you choose to use the WDT module.
Additionally, the implementation for the button release detection is a simple counter mechanism that resets upon GP2 being LO at any point during the count.
if (TMR0 > 0)
{
while (count < 20)
{
if (!GPIObits.GP2) count = 0;
__delay_ms(10);
count++;
}
TMR0 = 0;
state++;
}
You have a hardware/software design problem!
When your program is in delay loop than your key button is not
checked!
You are checking only on key press event, but you must also on key
relase.
My purpose is that you can use GP2 (T0CKI) pin instead GP1 for key buttom. This pin has schmitt trigger input if is used as counter TMR0 input. After that configure your MCPU TMR0 as counter with external clock on GP2 (T0CKI) pin. You must also set the T0SE bit to configure counter that will increment on high-to-low transition on the T0CKI pin.
In program after any loop check the TMR0 content if biger than 0 the key was pressed.
Wait some ms and check if key was relased if relased than increase the state variable and clear TMR0 content.
move your
if (!GPIObits.GP1){
if(isPressed == false){
//__delay_ms(250); //you dont need the delay
state++;
if(state == 5){state = 0;}
isPressed = true;
}
}
else{isPressed = false;}
before the switch statement. char isPressed = false; before the while loop
valter
__delay_ms(250); <-- too small delay
While you are pressing the button slowly, the loop may rotate several times. Try increasing it to 1000ms.
Update
You should run the PIC with WDT (watch dog timer) disabled, otherwise it will reset the pic in few seconds. That is similar to your observation. You can blink a LED at the beginning of main function to check if this happen or you can initialization unsigned char state = 1; and see the behavior then.
Try this __CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC & WDT_OFF);

Resources