PIC microcontrollers are a popular choice in embedded systems due to their versatility, low cost, and ease of programming. These microcontrollers are used in a wide range of applications, from consumer electronics to industrial automation, making them a valuable skill set for engineers and developers. With a robust architecture and extensive support from development tools, PIC microcontrollers offer a reliable platform for creating efficient and innovative solutions.
This article provides a curated selection of interview questions designed to test your knowledge and problem-solving abilities with PIC microcontrollers. By working through these questions, you will gain a deeper understanding of key concepts and be better prepared to demonstrate your expertise in technical interviews.
PIC Microcontroller Interview Questions and Answers
1. Describe the basic architecture of a PIC microcontroller.
The basic architecture of a PIC microcontroller includes several components:
- Central Processing Unit (CPU): Executes instructions and controls other components.
- Memory: Includes Program Memory (Flash) for code storage and Data Memory (RAM) for temporary data. Some models have EEPROM for non-volatile storage.
- I/O Ports: Allow interaction with external devices, configurable as input or output.
- Timers/Counters: Used for time-based operations like generating delays or counting events.
- Analog-to-Digital Converter (ADC): Converts analog signals to digital values for processing.
- Serial Communication Modules: Enable communication with other devices via UART, SPI, and I2C.
- Interrupts: Allow immediate response to events, interrupting current execution flow.
2. Provide a code snippet to configure a GPIO pin as an output and toggle its state every second.
To configure a GPIO pin as an output and toggle its state every second on a PIC microcontroller, use the following code snippet with MPLAB X IDE and XC8 compiler:
#include// Configuration bits #pragma config FOSC = INTRC_NOCLKOUT #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = OFF #define _XTAL_FREQ 4000000 void main(void) { TRISBbits.TRISB0 = 0; // Set RB0 as output while (1) { LATBbits.LATB0 = ~LATBbits.LATB0; // Toggle RB0 __delay_ms(1000); // Delay for 1 second } }
3. Write a code example to initialize a timer to generate an interrupt every 1 millisecond.
#include// Configuration bits #pragma config FOSC = INTOSCIO #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = OFF void __interrupt() ISR() { if (TMR1IF) { TMR1IF = 0; // Clear the interrupt flag TMR1 = 65536 - 1000; // Reload the timer for 1ms } } void main() { T1CON = 0x31; // Timer1 on, prescaler 1:8 TMR1 = 65536 - 1000; // Load the timer for 1ms TMR1IE = 1; // Enable Timer1 interrupt PEIE = 1; // Enable peripheral interrupts GIE = 1; // Enable global interrupts while (1) { // Main loop } }
4. Write a code example to generate a PWM signal with a 50% duty cycle on a specific pin.
#include// Configuration bits #pragma config FOSC = INTRC_NOCLKOUT #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = OFF void main(void) { PR2 = 0xFF; // Set the PWM period CCPR1L = 0x80; // 50% duty cycle CCP1CONbits.DC1B = 0; CCP1CONbits.CCP1M = 0b1100; // Configure CCP1 for PWM mode T2CONbits.T2CKPS = 0b01; // Prescaler is 4 T2CONbits.TMR2ON = 1; // Enable Timer2 TRISCbits.TRISC2 = 0; // Set PWM pin as output while (1) { // Main loop } }
5. Provide a code snippet to send and receive data using UART.
To send and receive data using UART on a PIC microcontroller, initialize the UART module, configure the baud rate, and implement functions to send and receive data.
Example:
#include// Configuration bits #pragma config FOSC = INTRC_NOCLKOUT #pragma config WDTE = OFF #pragma config PWRTE = ON #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = OFF #define _XTAL_FREQ 4000000 void UART_Init(long baud_rate) { unsigned int x; x = (_XTAL_FREQ - baud_rate * 64) / (baud_rate * 64); if (x > 255) { x = (_XTAL_FREQ - baud_rate * 16) / (baud_rate * 16); BRGH = 1; } if (x < 256) { SPBRG = x; } SYNC = 0; SPEN = 1; TRISC7 = 1; TRISC6 = 0; CREN = 1; TXEN = 1; } void UART_Write(char data) { while (!TRMT); TXREG = data; } char UART_Read() { while (!RCIF); return RCREG; } void main() { UART_Init(9600); while (1) { char received = UART_Read(); UART_Write(received); } }
6. Write a code example to communicate with an I2C temperature sensor and read its value.
#include#include #define _XTAL_FREQ 4000000 #define I2C_WRITE 0 #define I2C_READ 1 void I2C_Init(void) { SSPCON = 0b00101000; SSPCON2 = 0; SSPADD = (_XTAL_FREQ / (4 * 100000)) - 1; SSPSTAT = 0; } void I2C_Start(void) { SEN = 1; while (SEN); } void I2C_Stop(void) { PEN = 1; while (PEN); } void I2C_Write(uint8_t data) { SSPBUF = data; while (!SSPIF); SSPIF = 0; } uint8_t I2C_Read(uint8_t ack) { RCEN = 1; while (!SSPIF); SSPIF = 0; uint8_t data = SSPBUF; ACKDT = ack; ACKEN = 1; while (ACKEN); return data; } uint16_t Read_Temperature(void) { uint16_t temperature; I2C_Start(); I2C_Write(0x90 | I2C_WRITE); I2C_Write(0x00); I2C_Start(); I2C_Write(0x90 | I2C_READ); temperature = I2C_Read(0) << 8; temperature |= I2C_Read(1); I2C_Stop(); return temperature; } void main(void) { I2C_Init(); uint16_t temperature = Read_Temperature(); while (1) { // Use the temperature value as needed } }
7. Provide a code snippet to communicate with an SPI-based EEPROM and read/write data.
#include// Configuration bits #pragma config FOSC = HS #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config BOREN = ON #pragma config LVP = OFF #pragma config CPD = OFF #pragma config WRT = OFF #pragma config CP = OFF #define CS LATBbits.LATB0 void SPI_Init() { TRISC5 = 0; TRISC4 = 1; TRISC3 = 0; SSPSTAT = 0x40; SSPCON = 0x20; } void SPI_Write(unsigned char data) { SSPBUF = data; while(!SSPSTATbits.BF); } unsigned char SPI_Read() { SSPBUF = 0xFF; while(!SSPSTATbits.BF); return SSPBUF; } void EEPROM_Write(unsigned char address, unsigned char data) { CS = 0; SPI_Write(0x06); CS = 1; __delay_ms(1); CS = 0; SPI_Write(0x02); SPI_Write(address); SPI_Write(data); CS = 1; __delay_ms(5); } unsigned char EEPROM_Read(unsigned char address) { unsigned char data; CS = 0; SPI_Write(0x03); SPI_Write(address); data = SPI_Read(); CS = 1; return data; } void main() { SPI_Init(); EEPROM_Write(0x10, 0x55); unsigned char data = EEPROM_Read(0x10); while(1); }
8. Explain how to configure and use different power management modes.
PIC microcontrollers offer several power management modes to optimize power consumption:
- Run Mode: Full-speed operation, highest power consumption.
- Idle Mode: CPU halted, peripherals active, reduced power usage.
- Sleep Mode: CPU and peripherals halted, minimal power usage, wake via watchdog timer or interrupts.
- Doze Mode: Reduced CPU clock, peripherals at full speed, balances power savings and performance.
To configure these modes, set specific control registers. For Sleep Mode, use the SLEEP
instruction; for Idle Mode, adjust the OSCCON
register.
9. Provide a code example to integrate FreeRTOS into a project and create a simple task.
To integrate FreeRTOS into a PIC microcontroller project and create a simple task:
- Include FreeRTOS header files.
- Define the task function.
- Create the task in the main function.
- Start the scheduler.
Example:
#include#include void vTaskFunction(void *pvParameters) { for (;;) { // Task code } } int main(void) { // System initialization xTaskCreate(vTaskFunction, "Task 1", 100, NULL, 1, NULL); vTaskStartScheduler(); for (;;); return 0; }
10. Provide a code snippet to initialize and use a Real-Time Clock (RTC).
#include// Configuration bits #pragma config FOSC = INTRC_NOCLKOUT #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = ON #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LVP = OFF void RTC_Init() { T1CON = 0x31; // Timer1 with external 32.768 kHz crystal TMR1H = 0x80; // Preload Timer1 for 1 second overflow TMR1L = 0x00; TMR1IF = 0; TMR1IE = 1; PEIE = 1; GIE = 1; } void __interrupt() ISR() { if (TMR1IF) { TMR1IF = 0; TMR1H = 0x80; TMR1L = 0x00; // Increment RTC seconds, minutes, hours, etc. } } void main() { RTC_Init(); while (1) { // Main loop } }