MSP430 issue with button not switching off - c

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.

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 LaunchPad | Assign double click on button

I am using MSP-EXP430F5529LP. I can already blink the red led using
#pragma vector=TIMER2_A0_VECTOR
__interrupt void Timer_A2(void)
{
P1OUT ^= 0x01;
}
and
TA0CCR0 = 25000;
TA0CCTL0 |= CCIE;
TA0CTL |= TASSEL_2 | ID_3 | MC_1 | TACLR;
I would really like some assistance in making a double click check on
#pragma vector=PORT1_VECTOR
so i can distinguish it from single click. I just want to use simple if's in there and do some staff based on single or double click.
Your code to blink the LED through the use of a timer hardware is already a good starting point towards detecting the double-press to a button. I suggest using a timer to implement the basics of a debounce function, which are simply up/down counters that process some event such as button input.
The thing about buttons is they are noisy. If you sample the input pin of the MSP430 from the button fast enough you will find it will toggle more than once for a simple press-and-hold event. Releasing the button produces noise too. So you can expect a lot of noise for the double-press event. It is possible to create external hardware circuits to filter out the noise part of the press, but software is cheaper so most implementations go this route.
The idea behind a debounce function is the timer is used to measure events from the button input to deal with the noise. Here is a starting point for detecting single button press. This can be modified easily for the double (or tripple) press!
// Define button status and the button variable
typedef enum {BUTTON_STATUS_NOTPRESSED, BUTTON_STATUS_HOLDING, BUTTON_STATUS_RELEASED} button_status_t;
button_status_t button = BUTTON_STATUS_NOTPRESSED;
// Define button state values (if inverted then swap the values, assume input at bit 1)
typedef enum {BUTTON_STATE_NOTPRESSED = 0, BUTTON_STATE_PRESSED = BIT1} button_state_t;
// Setup timer hardware for 1 ms ticks
TA0CCR0 = 125;
TA0CCTL0 = CCIE;
TA0CTL = TASSEL_2 | ID_3 | MC_1 | TACLR;
// Process the button events for every timer tick
#pragma vector=TIMER2_A0_VECTOR
__interrupt void Timer_A2(void) // Better name would be Timer_A0_2_ISR
{
// Local variable for counting ticks when button is pressed
// Assume nobody will ever hold the button for 2^32 ticks long!
static uint32_t counter = 0;
// Constant for measuring how long (ms) the button must be held
// Adjust this value to feel right for a single button press
const uint32_t BUTTON_PRESSED_THRES = 50;
// Check status of button, assume P2.1 input for the button
// Note once the button enters release status, other code must change back to not pressed
switch (button)
{
case BUTTON_STATUS_NOTPRESSED:
// Increment if pressed, else reset the count
// This will filter out the noise when starting to press
if ((P2IN & BIT1) == BUTTON_STATE_PRESSED) counter += 1;
else counter = 0;
if (counter > BUTTON_PRESSED_THRES) button = BUTTON_STATUS_HOLDING;
break;
case BUTTON_STATUS_HOLDING:
// Decrement if not pressed, else set the count to threshold
// This will filter out the noise when starting to release
if ((P2IN & BIT1) == BUTTON_STATE_NOTPRESSED) counter -= 1;
else counter = BUTTON_PRESSED_THRES;
if (counter == 0) button = BUTTON_STATUS_RELEASED;
break;
}
}
// Your other code to detect when the button has been pressed and release
if (button == BUTTON_STATUS_RELEASED)
{
// do something
// Must reset after detecting button has been release
button = BUTTON_STATUS_NOTPRESSED;
}

Cannot read input from pins PIC

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

How to create a timer/clock that can send its value back,stored in a variable, ONLY made with delays in C & on mikroC

As a C beginner, I struggle alot to solve this problem of mine :
I am working on a project where I basicly have to program a PIC (microchip) in C using the mikroC platform.
What I'm trying to achieve is with only one switch/button, I'll have to switch from three different "modules" (as I call them "modules", they correspond to different lighting effects created by LEDs) depending on the time spent pressing the switch/button. In my case, after 500 ms module 1 is up, after 1500 ms module 2 goes up and after 3500 ms module 3 is up (and the whole thing has to be in an infinitely repeating loop since I have to be able to change a module at ANYTIME during the operation).
My only problem is getting the timer/clock to start runnning at the beginning of the program and keep counting time until it reaches a stop signal (like the end of a loop or something).
This may not be appropriate to ask to this community but here I am nonetheless.
I am concious that this is more of a 'algorithmics/logic' problem than anything but I have been trying for the last week without any clue on how to get past this problem...
No results since the code isn't ready at all.
There is a mikroC library for handling button presses. The following example (from the link.) provides a skeletal example of detecting a button push...
bit oldstate; // Old state flag
void main() {
ANSEL = 0; // Configure AN pins as digital I/O
ANSELH = 0;
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
TRISB0_bit = 1; // set RB0 pin as input
TRISC = 0x00; // Configure PORTC as output
PORTC = 0xAA; // Initial PORTC value
oldstate = 0;
do {
if (Button(&PORTB, 0, 1, 1)) { // Detect logical one
oldstate = 1; // Update flag
}
if (oldstate && Button(&PORTB, 0, 1, 0)) { // Detect one-to-zero transition
PORTC = ~PORTC; // Invert PORTC
oldstate = 0; // Update flag
}
} while(1); // Endless loop
}
There is also a collection of MicroE Examples which include timer examples such as these, and this one. Each of these provide code base examples that might be adapted to create a function that can be wrapped around sections in the button press code to obtain time durations.
I hope this helps.
When the button gets pressed, you need to initialize timer module of respective microcontroller check the interrupt flag, and put it in a loop. increment the value until the button is released, and after that compare the resultant value with the specified limits, this was you can decide for how long a button is pressed, and consecutively you will be able to switch your output. This is the only way if you want to precisely monitor the delay without interrupting the current execution of the program.

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