"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;`
Related
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);.
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.
In my code, I have two interruptions, one is coming from the overflow of the TMR0, and the other one is when a button is pressed.
this is the code in MikroC :
int compt = 0;
int seconds = 10 ;
int enable = 0;
void interrupt(){
if (INTCON.INTF) {
PORTD = 9;
enable = 1;
seconds = 10;
INTCON.INTF = 0;
}
if (INTCON.TMR0IF) {
compt++;
INTCON.TMR0IF = 0;
TMR0 = 0x06;
}
}
void main() {
TRISB = 0x01;
PORTB = 0;
PORTD = 0;
TRISD = 0x00;
INTCON = 0xB0;
OPTION_REG = 0x44;
TMR0 = 0x06;
while(1){
if (compt == 625){
if (enable) seconds--;
compt = 0;
}
if (seconds > 0 && enable == 1) {
PORTD = seconds;
PORTB.RB1 = 1;
} else {
enable = 0;
PORTB.RB1 = 0;
PORTD = 0;
}
}
}
what I am trying to achieve with my code is as shown in the following picture :
When I press one of the push buttons, the countdown starts and the LED illuminates until the countdown ends, and if the user pressed the button while the countdown still didn't hit 0, it starts over, until the countdown hits 0 again, then the LED should turn off.
What I'm facing here, is that the interruption from RBIE works only once, the second time I press the button, nothing happens.
I am not sure if the TMR0F has something to do with that or not, tried many things, but couldn't make it to work.
I Hope that you could see something i didn't notice, and help me.
The code as posted compiles without warnings or errors with MikroC.
The code runs using the simulator in MLPAB v8.92 and when using the simulator stimulus to assert the INT0 interrupt it is handled correctly each time.
Your circuit diagram looks like it was created using Proteus, perhaps there are issues with how that simulator works.
The only suspicious setting I can find is that the weak pull-ups are enabled for PORTB yet your circuit diagram has a 10K ohm pull-down in the INT0(RB0) pin.
I would suggest setting bit 8 of the OPTION_REG to one to turn off the PORTB pull-ups.
Sorry my answer is not more definite but I cannot reproduce your problem from the information posted.
Seem like this question was asked on StackExchange too.
You have enabled internal weak pull up resistor and also connected pull down resistor on pin RB0, external resistor is not needed, also you need to provide some amount of delay (about 300ms) after the button is pressed.
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.
I'm using MikroC to try and program my PIC16f62 Microcontroller. I've managed to get my outputs working (I can have LEDs turn on, etc) but I can't seem to get the inputs work.
Here is my current code:
void main() {
TRISB.RB0 = 0; //set Port RB0 as output
PORTB.RB0 = 1; //set Port RB0 to high (turn on LED)
TRISA = 1; //Set PORTA as inputs
for(;;){ //endless loop
if(PORTA.RA0 == 1){ //if push button is pressed
PORTB.RB0 = !PORTB.RB0; \\toggle LED
}
}
}
I don't know if the problem is that I'm not configuring the PORT correctly or if I'm checking whether or not the button is pressed incorrectly.
Any help is appreciated. Thanks.
This change may help you.
for(;;){ //endless loop
if(PORTA.RA0 == 1){ //if push button is pressed
PORTB.RB0 = !PORTB.RB0; \\toggle LED
while(PORTA.RA0 == 1);
/*wait till button released as press of a buttons take time and processor is too fast */
}
You are probably reading the port pin correctly, however because you're toggling the LED on and off when you detect a press, your eye can't see the result.
For example, a clock rate of 1Mhz will have the on/off toggle approximately 150,000 times per second (1,000,000 cycles / ~3 ASM instructions per loop / 2 loops to turn on then off).
I would suggest taking the approach of having the LED match the state of the input pin.
for(;;)
{
if(PORTA.RA0 == 1) //if button is pressed
{
PORTB.RB0 = 1; //turn on LED
}
else
{
PORTB.RB0 = 0; //turn off LED
}
}
This technique is similar to what Rajesh suggested, but provides a bit more direct feedback on whether the input pin is set or not.
If that doesn't work, then something with your setup of the TRISA is not correct. You may want to try this:
TRISA.RB0 = 1;