PIC16F648A programming - some functions don't work - c

I have problems with successful pic programming work.. As i'm new in pic programming i started with lighting up 8-segment display LED one by one. Everything went well except RB4 output LED didn't light up (its not broken because i checked it with 5v through resistor). I thought its a problem but not so major so i went on. Next aim was to light up all segments of display right up after stratup with code:
#include <htc.h>
void main()
{
TRISB=0X00;
PORTB=0X00;
TRISA = 1;
while(1)
{
PORTB=0XFF;
}
}
This wasn't successful - only 2 segments light up in startup and then immediately disappeared and then none of LED lighted up afterwards.
I went even further after that problem - i wanted to turn on output when switch is pressed (High Input) and another time it was unsuccessful. RB7 LED was on all the time. Switch pressing didn't do anything. Code :
#include <htc.h>
void main()
{
TRISB=0X00;
PORTB=0X00;
TRISA = 1;
while(1)
{
if (RA4 == 1) //Even tried TRISA4 ==1 //RB0 Dont light up, RB7 do light up all the time
{
RB0 = 1;
}
else
{
RB7 = 1;
}
}
}
Can somebody please tell why i have these problems? Any solutions?
Btw - fuses were : WDT OFF, BODEN ON, MCLRE OFF, Code protect OFF, PWRTE OFF, LVP ON, CPD OFF
Im using K150 PIC Programmer
1 : PIC pins
2 : Circuit

I don't know what's going on with the first snippet. The second one fails because
TRISA = 1
sets only RA0 as input. The rest of A pins (including RA4) are still output. You need something like
TRISA = 0x10;

RB4 is influenced by LVP. In the "CONFIG – CONFIGURATION WORD REGISTER":
LVP: Low-Voltage Programming Enable bit
1 = RB4/PGM pin has PGM function, low-voltage programming enabled
0 = RB4/PGM is digital I/O, HV on MCLR must be used for programming
which I'm guessing is why RB4 did not light up.
Reading RA4, clearly you need to set TRISA4. Though I think it's in that state at power-up. RA4's full name is RA4/T0CKI/CMP2. At power-up the T0CS bit of the OPTION register is '1', which is:
T0CS: TMR0 Clock Source Select bit
1 = Transition on RA4/T0CKI/CMP2 pin
0 = Internal instruction cycle clock (CLKOUT)
so clearing that might help.
The comparator stuff seems to wake up with the CMCON register all zeros, which puts CM2=CM1=CM0=0, which is "reset". It's not clear to me how that affects RA4. But it might be worth setting the comparators "off", ie CM2=CM1=CM0=1.
As far as the other effects you are seeing are concerned, I dunno :-( It would be interesting to see what the little fragments of code compile to.

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.

ADC giving strange output for PIC16F15325

I was trying to read analog voltage on pin RC3 on PIC16F15325. I have 3.23V across potentiometer and its output is nearly 1.65V which goes to pin RC3 of PIC microcontroller. For configuration and libraries I used MPLAB Code Cofigurator. Code is as follows:
#include "mcc_generated_files/mcc.h"
void main(void)
{
// initialize the device
SYSTEM_Initialize();
EUSART1_Initialize();
ADC_Initialize();
adc_result_t val1 = 0;
// When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
// Use the following macros to:
// Enable the Global Interrupts
//INTERRUPT_GlobalInterruptEnable();
// Enable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptEnable();
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
// Disable the Peripheral Interrupts
//INTERRUPT_PeripheralInterruptDisable();
while (1)
{
// Add your application code
val1 = ADC_GetConversion(19); // selected channel RC3
printf("Value - %hu \n",val1);
DELAY_milliseconds(1000);
}
}
For voltage I mentioned above, I expected value near "511". Anything beyond 1023 [i.e. (2^10) - 1] is strange as PIC has 10-bit ADC.However uotput I get is:
Kindly, help me solving this issue.
Actually, output was correct but was looking strange only because of format. Just now I looked into datasheet which said about 2 ways of ADC result formatting.
PIC16(L)F15325/45 Datasheet page-228
and inside ADC_Initialize(); ADCON1 = 0x10 which means ADFM is left shift. I just did val1 = val1 >> 6; after ADC_GetConversion(19); and it worked as expected.

PIC programing Interrupt malfunction.

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.

Program Working on Old Device and New Device's Simulator but not on New Device

I'm hitting a roadblock in porting over a program I previously wrote for the PIC10F200 (see this related SO question). Turns out another component on the board needed to be swapped out for something that needed to be communicated with through I2C, so ergo, I'm porting the program to the PIC12LF1552.
This is how the program currently works (at least on the PIC10F200)
Program starts at IDLE (no lights on)
Press the button, the T0CKI pin (in the PIC12LF1552's case, RA2) is already pulled up to VDD (~3.3V) by an external pull-up resistor, the button is connected to ground and the pin, ergo pulling T0CKI's signal to LO.
TMR0 increments (supposedly)
After a time period where PORTAbits.RA2 settles, state increments
switch block moves to turn the external LED on, in the previous version of the circuit, this would also activate the IC this pin is connected to.
Rinse repeat for the other 3 states.
I have re-verified this functionality through using MPLAB X's simulator where I fired T0CKI (again, configured as RA2, again confirmed by the simulator) to HI and then to LO to engage the TMR0 code. state increments, and everybody is happy.
When I program the device using either MPLAB X connected to my PICkit3 or the included standalone programmer MPLAB IPE, the program does not work as intended. I have re-verified all connections, the programming port is connected as it should be. The button is attached the right pin. The test LED is attached to the right pin. For the time being we are not considering any I2C communication, I just want to see my status LED (RA4) toggle.
I know that now that I've transitioned to a midrange PIC, I can use the interrupt features, but for the time being I want to get what I know has worked on a much simpler device working on the current one.
My question then is, why doesn't this program work when programmed to the PIC12LF1552, but yet works on the PIC12LF1552 simulator AND its previous incarnation worked on the PIC10F200 (both programmed and simulated)?
Thanks in advance everyone!
The following is the entire program:
#if defined(__XC)
#include <xc.h> /* XC8 General Include File */
#endif
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#include <stdlib.h>
/******************************************************************************/
/* Defines */
/******************************************************************************/
//#define SYS_FREQ 16000000L
//#define FCY SYS_FREQ/4
#define _XTAL_FREQ 500000
__CONFIG
(
MCLRE_ON &
CP_OFF &
BOREN_OFF &
WDTE_OFF &
PWRTE_OFF &
FOSC_INTOSC
);
void main(void)
{
TRISA = 0b101111;
OPTION_REG = 0b01111111;
APFCONbits.SDSEL = 1;
unsigned char state = 0;
unsigned char count = 0;
while(1)
{
switch (state)
{
case 0: // IDLE/OFF
if (LATAbits.LATA4) LATAbits.LATA4 = 0;
break;
case 1: // ON
if (!LATAbits.LATA4) LATAbits.LATA4 = 1;
break;
case 2: // BLINK (slow)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(100);
break;
case 3: // BLINK (fast)
LATAbits.LATA4 = !LATAbits.LATA4;
__delay_ms(50);
break;
case 4: // BEAT DETECT
LATAbits.LATA4 = LATAbits.LATA5;
break;
default:
state = 0;
break;
}
if (TMR0 > 0)
{
while (count < 20)
{
if (!PORTAbits.RA2) count = 0;
__delay_ms(10);
count++;
}
TMR0 = 0;
state++;
}
}
}
Some of the pins may be configured as Analog Inputs.
From the Datasheet for this device
"The operation of pin RA4 as analog is selected by setting the ANS3
bit in the ANSEL register which is the default set-ting after a
Power-on Reset".
If you do not set the ANSEL register the pin cannot be used as output as it is configured as an analog input.
This applies to all the pins that can be A/D inputs.
I do not see any configuration bit setup in your code.
Setting ANSEL and ANSELH to 0 should do the trick.
According to the this documentation , on page 93 about the ANSELA register
"The ANSELA bits default to the Analog mode after Reset. To use any
pins as digital general purpose or peripheral inputs, the
corresponding ANSEL bits must be initialized to ‘0’ by user software."
If you don't plan to use analog inputs, you may add something like ANSELA=0;

8051 c programming, interrupt progblem

I'm programming an Intel 8051 (C8051F312) microcontroller. I just want to make a blinking led program by using interrupts. It compiles, but the led does not blink. Any ideas I would appreciate. Thank you!
My code is:
#include <C8051F310.H>
#include <stdio.h>
sbit led = P2^7; //LED connected to D7 of Port2
void timer(void) interrupt 1 //interrupt no. 1 for Timer 0
{
led=~led; // toggle LED on interrupt
TH0=0xFC; // initial values loaded to timer
TL0=0x66;
}
void main(void)
{
TMOD = 0x01; // mode1 of Timer0
TH0 = 0xFC; // initial values loaded to timer
TL0 = 0x66;
EA = 1; // global interrupt enable
ET0 = 1; // enables Timer 0 interrupt
TR0 = 1; // start timer
while(1); // do nothing
}
Like Mike Jablonski above said, you need to knock down your interrupt rate. Your original code is interrupting at 3.0625MHz / 12 / 922 ~= 277Hz. Part of your CKCON addition disables scaling to the timer (by setting T0M), so now you're interrupting at ~3.3kHz. You won't be able to see that.
Seeing anything presumes that you have a functional circuit. You're not configuring your output pin. You said your LED is on "now", but hopefully not meaning that it wasn't before. That wouldn't make a lot of sense since you didn't change anything about what the pin is doing.
Get rid of your CKCON line to keep the /12 scaling, and reload TH0 and TL0 with 0x00 on interrupt. That will get you interrupting at a little less than 4Hz, much more visible.
Make that pin push-pull:
P2MDOUT = 0x80;
XBR1 = 0x40;
Start reading the datasheet to your micro.

Resources