nerdegutta.no
PIC16F690 - Day 8: Multiplexing I/O for 7-Segment or LED Control
23.11.25
Embedded
#define _XTAL_FREQ 4000000
#include < xc.h >
#include < stdint.h >
// CONFIG
#pragma config FOSC = INTRCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
const uint8_t segment_map[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
volatile uint8_t digit_values[4] = {1, 2, 3, 4};
volatile uint8_t current_digit = 0;
void __interrupt() isr(void) {
if (T0IF) {
T0IF = 0;
// Turn off all digits
PORTB |= 0xF0;
// Output segment value (invert for common anode)
PORTC = ~segment_map[digit_values[current_digit]];
// Activate current digit (RB4-RB7)
PORTB &= ~(1 << (4 + current_digit));
// Move to next digit
current_digit = (current_digit + 1) % 4;
}
}
void main(void) {
TRISC = 0x00; // Segment outputs
TRISB = 0x0F; // RB4–RB7 as outputs (digit selects), RB0–RB3 as input if needed
ANSEL = 0;
ANSELH = 0;
PORTC = 0;
PORTB = 0xF0; // Turn all digits off
// Setup Timer0
OPTION_REGbits.T0CS = 0; // Internal clock
OPTION_REGbits.PSA = 0;
OPTION_REGbits.PS = 0b010; // 1:8 prescaler
TMR0 = 0;
T0IE = 1;
PEIE = 1;
GIE = 1;
while (1) {
// Here you could change `digit_values[]` dynamically
// For example: read from EEPROM or increment a counter
}
}
Code 2: Manual Multiplexing in Main Loop (Polling)
#define _XTAL_FREQ 4000000
#include < xc.h >
#include < stdint.h >
// CONFIG
#pragma config FOSC = INTRCIO
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = OFF
#pragma config BOREN = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
const uint8_t segment_map[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
uint8_t digit_values[4] = {2, 0, 2, 5};
void display_digit(uint8_t digit, uint8_t value) {
PORTB |= 0xF0; // Turn off all digits
PORTC = ~segment_map[value]; // Invert for common anode
PORTB &= ~(1 << (4 + digit)); // Activate one digit
__delay_ms(2); // Short delay to allow display
}
void main(void) {
TRISC = 0x00;
TRISB = 0x0F;
ANSEL = 0;
ANSELH = 0;
PORTC = 0;
PORTB = 0xF0;
while (1) {
for (uint8_t i = 0; i < 4; i++) {
display_digit(i, digit_values[i]);
}
}
}