Embedded Systems Fundamentals with PIC

Simón Aulet · PIC16F18875 · Assembly · Embedded C

Academic projects in assembly and C for PIC16F18875 microcontrollers, focused on direct hardware manipulation and transition toward abstractions using Microchip Code Configurator.

PIC16F18875 Assembly Embedded C Microcontrollers MCC

Implemented Projects

This series of projects represents a journey from direct hardware control in assembly to the implementation of abstract drivers in C, establishing critical understanding of operation costs and hardware limitations.

Basic LED control implementation through direct register manipulation in assembly, without high-level abstractions.

Source Code: https://github.com/SimonAulet/portfolio/tree/main/PIC/blink.X

Expand code: Blink in Assembly (blink.s)
PROCESSOR 16F18875
                  LIST
                  #include 
                  ////////////////////////////////////////////////////////////////

                  ; PIC16F18875 Configuration Bit Settings

                  ; Assembly source line config statements

                  ; CONFIG1
                  ;  CONFIG  FEXTOSC = ECH         ; External Oscillator mode selection bits (EC above 8MHz; PFM set to high power)
                  ;  CONFIG  RSTOSC = LFINT        ; Power-up default value for COSC bits (LFINTOSC)
                  ;  CONFIG  CLKOUTEN = OFF        ; Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
                  ;  CONFIG  CSWEN = ON            ; Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
                  ;  CONFIG  FCMEN = ON            ; Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)

                  CONFIG  FEXTOSC = OFF        ; Disable external oscillator
                  CONFIG  RSTOSC = HFINT1      ; Use internal high-frequency oscillator (1 MHz)
                  CONFIG  CLKOUTEN = OFF       ; Disable clock output
                  CONFIG  CSWEN = ON           ; Allow frequency change at runtime
                  CONFIG  FCMEN = OFF          ; Disable Fail-Safe Clock Monitor (no longer needed)

                  ; CONFIG2
                    CONFIG  MCLRE = ON            ; Master Clear Enable bit (MCLR pin is Master Clear function)
                    CONFIG  PWRTE = OFF           ; Power-up Timer Enable bit (PWRT disabled)
                    CONFIG  LPBOREN = OFF         ; Low-Power BOR enable bit (ULPBOR disabled)
                    CONFIG  BOREN = ON            ; Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
                    CONFIG  BORV = LO             ; Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
                    CONFIG  ZCD = OFF             ; Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
                    CONFIG  PPS1WAY = ON          ; Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software)
                    CONFIG  STVREN = ON           ; Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)

                  ; CONFIG3
                    CONFIG  WDTCPS = WDTCPS_31    ; WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
                    CONFIG  WDTE = ON             ; WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
                    CONFIG  WDTCWS = WDTCWS_7     ; WDT Window Select bits (window always open (100%); software control; keyed access not required)
                    CONFIG  WDTCCS = SC           ; WDT input clock selector (Software Control)

                  ; CONFIG4
                    CONFIG  WRT = OFF             ; UserNVM self-write protection bits (Write protection off)
                    CONFIG  SCANE = available     ; Scanner Enable bit (Scanner module is available for use)
                    CONFIG  LVP = ON              ; Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)

                  ; CONFIG5
                    CONFIG  CP = OFF              ; UserNVM Program memory code protection bit (Program Memory code protection disabled)
                    CONFIG  CPD = OFF             ; DataNVM code protection bit (Data EEPROM code protection disabled)

                  ///////////////////////////////////////////////////////////////
                  PSECT resetVec,class=CODE,delta=2
                  resetVec:
                      PAGESEL main
                      goto    main

                  PSECT code
                  main:
                      CLRF   TRISA        ; Configure PORTA as output

                  START:
                      MOVLW  00000000B    ; Turn off LED on RA3
                      MOVWF  PORTA

                      CALL Retardo        ; Call delay

                      MOVLW  11111111B    ; Turn on LED on RA3
                      MOVWF  PORTA

                      CALL Retardo        ; Call delay

                      GOTO   START        ; Repeat cycle

                  ;-------------------
                  ; Delay Subroutine
                  ;-------------------
                  Retardo:
               	    MOVLW   0xFF
               	    MOVWF   0x20

               	    MOVLW   0xFF
               	    MOVWF   0x21

               	    MOVLW   0x16
               	    MOVWF   0x22

               	Loop1: ;decrement 20
               	    DECFSZ  0x20, F
               	    GOTO    Loop1
               	Loop2: ;decrement 21
               	    MOVLW   0xFF
               	    MOVWF   0x20 ;reset reg 1
               	    DECFSZ  0x21, F
               	    GOTO    Loop1
               	Loop3: ;decrement 22
               	    MOVLW   0xFF
               	    MOVWF   0x20 ;reset reg 1
               	    MOVLW   0xFF
               	    MOVWF   0x21 ;reset reg 2
               	    DECFSZ  0x22, F
               	    GOTO    Loop1
               	    RETURN
                      END main
                

Technical Features

  • Timing: Through triple loop in assembly
  • Configuration: Manual port setup without abstractions
  • Oscillator: Internal HFINT1 at 1 MHz
  • GPIO: Direct port A control

Educational Value: Understanding instruction cycle cost and precise timing.

2. Potentiometer Reading in Assembly

Analog acquisition system using 8-bit ADC with LED bar visualization.

Source Code: https://github.com/SimonAulet/portfolio/tree/main/PIC/potenciometro.X

Expand code: ADC Reading in Assembly (potenciometro.s)
PROCESSOR 16F18875
                  LIST
                  #include 
                  ////////////////////////////////////////////////////////////////

                  ; PIC16F18875 Configuration Bit Settings

                  ; Assembly source line config statements

                  ; CONFIG1
                    CONFIG  FEXTOSC = OFF         ; External Oscillator mode selection bits (EC above 8MHz; PFM set to high power)
                    CONFIG  RSTOSC = HFINT1       ; Power-up default value for COSC bits (LFINTOSC)
                    CONFIG  CLKOUTEN = OFF        ; Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
                    CONFIG  CSWEN = ON            ; Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
                    CONFIG  FCMEN = OFF           ; Fail-Safe Clock Monitor Enable bit (FSCM timer enabled)

                  ; CONFIG2
                    CONFIG  MCLRE = ON            ; Master Clear Enable bit (MCLR pin is Master Clear function)
                    CONFIG  PWRTE = OFF           ; Power-up Timer Enable bit (PWRT disabled)
                    CONFIG  LPBOREN = OFF         ; Low-Power BOR enable bit (ULPBOR disabled)
                    CONFIG  BOREN = ON            ; Brown-out reset enable bits (Brown-out Reset Enabled, SBOREN bit is ignored)
                    CONFIG  BORV = LO             ; Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
                    CONFIG  ZCD = OFF             ; Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
                    CONFIG  PPS1WAY = ON          ; Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software)
                    CONFIG  STVREN = ON           ; Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)

                  ; CONFIG3
                    CONFIG  WDTCPS = WDTCPS_31    ; WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
                    CONFIG  WDTE = OFF            ; WDT operating mode (WDT enabled regardless of sleep; SWDTEN ignored)
                    CONFIG  WDTCWS = WDTCWS_7     ; WDT Window Select bits (window always open (100%); software control; keyed access not required)
                    CONFIG  WDTCCS = SC           ; WDT input clock selector (Software Control)

                  ; CONFIG4
                    CONFIG  WRT = OFF             ; UserNVM self-write protection bits (Write protection off)
                    CONFIG  SCANE = available     ; Scanner Enable bit (Scanner module is available for use)
                    CONFIG  LVP = ON              ; Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)

                  ; CONFIG5
                    CONFIG  CP = OFF              ; UserNVM Program memory code protection bit (Program Memory code protection disabled)
                    CONFIG  CPD = OFF             ; DataNVM code protection bit (Data EEPROM code protection disabled)

                  ; CONFIG ADC
                    BSF ANSELA, 0        ; Configure RA0 as analog
                    BSF TRISA, 0         ; Configure RA0 as input
                    MOVLW 0x01           ; Select channel AN0 (RA0)
                    MOVWF ADPCH
                    MOVLW 0b00010101     ; ADC ON, Clock FRC, Left justified
                    MOVWF ADCON0
                    MOVLW 0b10000000     ; VDD and VSS reference, Left justified
                    MOVWF ADCON1

                  ; CONFIG LEDS
                  MOVLW   0b00001111   ; RA4 to 7 as outputs, rest as they were
                  ANDWF   TRISA, F


                  // config statements should precede project file includes.

                  ///////////////////////////////////////////////////////////////
                  PSECT resetVec,class=CODE,delta=2
                  resetVec:
                      PAGESEL main                ;Jump to Main
                      goto    main
                  PSECT code

                  main:

                  START:

                  GOTO adc
                    MOVLW  0b01010101
                    MOVWF  0x20

                    ;alternate 0x20 between ones and zeros
                    BTFSC 0x20, 7
                    MOVLW 0b00000000  ;00 L2
                    BTFSS 0x20, 7
                    MOVLW 0b11111111  ;10 L4
                    MOVWF 0x20

                  ;check potentiometer result

                    BTFSC 0x20, 7		;first bit
                    GOTO msb1
                    GOTO msb0

                  msb1:
                    BTFSC 0x20, 6		;second bit
                    GOTO nivel4
                    GOTO nivel3

                  msb0:
                    BTFSC 0x20, 6		;second bit
                    GOTO nivel2
                    GOTO nivel1

                  adc:
                      BSF ADCON0, 0        ; Start conversion
                      BTFSC ADCON0, 1      ; Wait for completion (while GO/DONE=1)
                      GOTO $-1

                      MOVF ADRESH, W       ; I will only be interested in the 2 MSBs
                      MOVWF 0x20

                      RETURN

                  ;LED bits are 4, 5, 6 and 7 of port A
                  nivel0: ;0000
                    MOVF  LATA, W
                    ANDLW 0b00001111
                    MOVWF LATA

                    GOTO  START

                  nivel1: ;0001
                    MOVF  LATA, 0
                    ANDLW 0b00011111
                    IORLW 0b00010000
                    MOVWF LATA

                    GOTO  START

                  nivel2: ;0011
                    MOVF  LATA, 0
                    ANDLW 0b00111111
                    IORLW 0b00110000
                    MOVWF LATA

                    GOTO  START

                  nivel3: ;0111
                    MOVF  LATA, 0
                    ANDLW 0b01111111
                    IORLW 0b01110000
                    MOVWF LATA

                    GOTO  START

                  nivel4: ;1111
                    MOVF  LATA, 0
                    IORLW 0b11110000
                    MOVWF LATA
                    GOTO  START
                  END main
                

Technical Features

  • ADC: 8-bit on channel AN0 (RA0)
  • Processing: The 2 most significant bits determine LED bar level
  • Visualization: Visual representation on RA4–RA7
  • Resolution: 4 discrete levels (2 bits)

Educational Value: Understanding the A/D conversion process and value mapping.

3. LCD Integration in C

Transition to structured programming in C using libraries and abstractions through Microchip Code Configurator.

Source Code: https://github.com/SimonAulet/portfolio/tree/main/PIC/LCD_CON_I2C.X

Expand code: LCD Integration in C (main.c)
#include "mcc_generated_files/mcc.h"
                  #include "seri_lcd.h"

                  /*
                                           Main application
                   */
                  void main(void)
                  {
                      // initialize the device
                      SYSTEM_Initialize();

                      // 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();
                    __delay_ms(500);
                      lcd_start();
                      int valor;
                      while (1)
                      {

                        char buffer[17];

                        __delay_ms(50);
                        lcd_delete();
                        valor = ADCC_GetSingleConversion(POT);
                        sprintf(buffer, "%d", valor);
                        lcd_writemessage(1, 1, buffer);
                      }
                  }
                

Technical Features

  • Abstraction: Through Microchip Code Configurator
  • Display: 16x2 character LCD with I2C interface
  • Architecture: Maintenance of functional core with abstract drivers
  • Libraries: Use of standardized APIs for peripherals

Educational Value: Transition from low-level to structured programming with abstractions.

Technical Specifications

Summary of components and configurations used in the projects.

Component Specification Project Language
Microcontroller PIC16F18875 All ASM/C
Oscillator HFINT1 @ 1MHz Blink Assembly
ADC 8-bit, Channel AN0 Potentiometer Assembly
Display 16x2 Character LCD LCD Integration C
Tool Microchip MCC LCD Integration C
GPIO Port A (RA0-RA7) All ASM/C
Communication I2C for LCD LCD Integration C

Value of Fundamentals

These projects establish critical understanding of operation costs and hardware limitations. The experience of writing delays in assembly and manually configuring registers illuminates the internal workings of microcontrollers.

Educational journey: The journey from bit-by-bit control in assembly to abstract drivers in C aids in complete understanding of the embedded software stack.

The progressive transition between abstraction levels enables:

  • Cost understanding: Evaluation of each operation's impact on clock cycles
  • Conscious optimization: Informed decision-making about resource usage
  • Effective debugging: Ability to diagnose problems at multiple levels
  • Tool selection: Criteria for choosing between direct control or abstractions
Fundamentals Direct Hardware Abstraction Embedded Stack Optimization