I am trying to keep PIC32 in sleep mode on boot up. And when the power button is pressed the Pic32 should exit the sleep mode and wake up.
I am able to put PIC32 in sleep mode but I am not sure how I can trigger it to wake up on button press.
Is it possible if I can trigger an interrupt whenever the user presses the power button and thus wake the PIC32?
I am using microchip harmony framework and am quite new to this can someone please suggest how I can achieve this?
To put PIC32 I am using the PowerEnterMode function of harmony. To wake up PIC32 I have tried using the watch dog timer following the sample project provided with microchip harmony but couldn't get it to work.
I also read that I can use external interrupt to set it up but I don't know how to set it up.
I have added my code below.
void APP_Initialize ( void )
{
DRV_ADC_Open();
DRV_ADC_Start();
PLIB_ADC_Enable(ADC_ID_1);
SPIHandle = DRV_SPI_Open(DRV_SPI_INDEX_0, DRV_IO_INTENT_READWRITE );
DelayMs(100);
SYS_DEVCON_PowerModeEnter(SYS_POWER_MODE_IDLE);
appData.state = APP_STATE_POWER_UP;
}
void APP_Tasks (void)
{
switch ( appData.state )
{
case APP_STATE_POWER_UP:
{
uint8_t pwrButton;
pwrButton = PWR_BTNStateGet() ;
if (npwrButton == 0) // If button is pressed
{
PwrButtonDebounce += 1; // Increment the pressed timer
DelayMs(10);
} else
{
PwrButtonDebounce = 0; // Clear the Debounce Timer
}
if (PwrButtonDebounce == MAX_DEBOUNCE) // Debounced....
{
// Here Wake up routine on button press
appData.state = APP_STATE_INIT;
}
}
}
I expect that whenever I press the power button the Pic32 should come in the APP_STATE_POWER_UP state and on debounce go in the initialization state but It never comes in this state.
Can someone suggest how I can set this up?
You should use Change Notification interrupt.
Enable the CN interrupt on the pin that you have your button and it will wake your device when pressed.
Related
I have a switch button that is connected to RB1. This button acts as a reset but it needs to be pressed twice for it to work. If the second press happens after 500 ms (relative to the initial press), it will do nothing.
I think I should make use of timers or ccp module but I am not sure how to implement those. What do you suggest?
Edit (My ISR):
void interrupt ISR(void){
GIE = 0;
if(INTF){
INTF = 0;
if(reset_press == 0){
TMR1 = 0x0BDC; // counter starts counting at 0x0BDC (3036)
TMR1ON = 1; // Turns on Timer1 (T1CON reg)
}
reset_press++;
}
else if(TMR1IF==1){ // checks Timer1 interrupt flag
TMR1IF = 0; // clears interrupt flag
if(reset_press == 2){
reset_count(); // reset function
}
TMR1ON = 0; // Turns off Timer1 (T1CON reg)
reset_press = 0;
}
GIE = 1;
}
Setup the timer or CCP for 500ms once in initialisation, but don't fire it. (You may have to use an additional byte to achive to hold a value that corresponds to 500ms depending on the osc freq).
After you enter main's superloop, detect the button press; either use a flag or a counter to count the button press. As soon as you detect the first press,fire the 500ms timer.
If the 500ms time has relapsed (you can detect it in the interrupts), that means that you will do nothing, so reset everything; button press counter, fired timer etc.
Meanwhile before the 500ms has not been relapsed, if you detect a second press; that is the press counter value must be 2, then you execute what you wish and then reset everything for the next twice button press detection.
I am trying to do very simple interrupt code in STM32F401RE where I press the button and LED2 should turn on based on external interrupt triggered by the button.
I am using the user button(blue button) in nucleo board F401 which corresponds to PC13 according to the board datasheet pinout.
I tried different options but LED2 is still off, here is the code i am using:
int main(void)
{
sysconfig();
Interrupt_config();
while(1)
{
if(flag)
{
GPIOA->ODR |= (1<<5);
}
}
}
I used polling method (without interrupt) and the LED2 turns on fine when the button is pressed using only LED_initialize(); Button_init();
Haven't checked your IRQ setup code, but the handler you need for PC13 is EXTI15_10_IRQHandler.
Edit:
Another issue: EXTICR is 4 words long. This is incorrect: SYSCFG->EXTICR[4] |=(1<<5);.
"I'm trying to use the button that when it is pressed, it triggers to send a string message via UART, but upon running the code, it always detect the button to be "always pressed" which is not ideal. I need help fixing my code.
Thank you very much.
I'm using EasyPIC fusion v7. The device is P32MX795F512L #80MHz. I'm using the MikroC pro for PIC32 as my IDE."
"Button and UART library is used for this code."
char read;
unsigned int oldstate;
void main() {
AD1PCFG = 0XFFFF; //SETTING AN INPUTS AS DIGITAL I/O
JTAGEN_bit = 0; //disable JTAG
UART2_Init(9600);
Delay_ms(1000);
TRISA = 1; //setting All portA as inputs
UART_Set_Active(&UART2_Read, &UART2_Write, &UART2_Data_Ready, &UART2_Tx_Idle); //Sets UART2 as active
UART_Write_Text("UART is now ready.");
UART_Write(13);
UART_Write(10);
while(1)
{
if (Button(&PORTA, 15, 1 ,1)) //detect if button is pressed
{
UART_Write_Text("Button is pressed.");
UART_Write(13);
UART_Write(10);
oldstate = 1;
}
if (oldstate && Button(&PORTA, 15, 1, 0)) //detect from logic 1 to 0
{
UART_Write_Text("Button is pressed again.");
UART_Write(13);
UART_Write(10);
oldstate = 0;
}
}
}
"I've only learned how UART works and how the Button library works.
I expect the output to be 'Button is pressed' when the button is pressed first, then "Button is pressed again" when I press the same button again.
The output for the code is always 'Button is pressed' and prints continuously"
The main problem with your code is that this line:
UART_Write_Text("Button is pressed again.");
should in fact read:
UART_Write_Text("Button is RELEASED.");
Other than that you might be having a hardware issue if you're not tying your RA15 pin to GND through a pull-down resistor. You could also use the internal pull-ups on your PIC.
The problem is here:
TRISA = 1;
This is simular to TRISA = 0x0001; and will only make the Port A0 an input. You had to write:
TRISA = 0xFFFF;`
I'm new to PIC programming and I'm using MPLAb. I have a question regarding interrupt..
so What I want to do, when I push a button then I want to turn on LED 0, and if I release the button then turn on LED 1. I thought the code I wrote making sense but it didn't work.
Here is what happens. Let say the initial state of interrupt pin is low (0), when a button is pushed. Then the LED 0 is on, and when I release the button then LED 1 is on. When I push the button again, I expect LED 0 is on, but LED 1 stays on, and never change the state.
I added last line to see the state of interrupt pin, and once the interrupt is high, it never change it to low.. Can you please advise me what is my misunderstanding?
Thanks in advance!
Here is my code:
void interrupt ISR(void)
{
if(INTCONbits.INTF)
{
nextLED = 1;
LATC = Output_Code_Buffer[nextLED];
__delay_ms(250);
}
else
{
nextLED = 0;
LATC = Output_Code_Buffer[nextLED];
__delay_ms(250);
}
nextLED = INTCONbits.INTF + 2;
LATC = Output_Code_Buffer[nextLED];
__delay_ms(250);
}
// Interrupt Enable settings
INTCONbits.INTE = 1;
INTCONbits.TMR0IE = 1; // Enable TMR0 interrupts
INTCONbits.TMR0IF = 0; // Clear TMR0 interrupt flag
INTCONbits.GIE = 1; // Enable global interrupts
You need to reset the interrupt flag in the ISR function or it will just keep triggering. Please read the datasheet, it should mention if this is necessary. So just add INTCONbits.INTF = 0; to the ISR and it should work as expected.
When setting up any peripheral or function of the mcu, you should go through the datasheet and use the description of the registers and what to set them. You'll also need to be careful with analogue ports, which often default to analogue instead of digital, causing interrupt not to fire as expected or causing unexpected interrupts. It's best to first setup the MCU config bits, set the TRIS and analogue selection registers (ANSELx or ANSELAx etc), then the registers for any peripheral you want to use. Then setup the interrupts, always reset all the interrupt flags you're going to use to start with a known state.
You also set TMR0IE = 1, which will do the same thing, trigger an interrupt. If you don't reset the TMR0 flag it will keep triggering, locking up your mcu or slow it down.
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);