This is an embedded systems project written in PIC assembly language for the PIC16F873 microcontroller. The current implementation functions as a digital voltmeter with an LCD display, with the ultimate goal of evolving into a hygrometer with memory storage capabilities.
Author: David Robert (david@ombrepixel.com)
Microcontroller: PIC16F873
Language: Assembly (MPASM)
- Processor: PIC16F873
- Clock Frequency: High-Speed Oscillator (HS_OSC) - 4 MHz to 20 MHz range
- Power-up Timer: Enabled (PWRTE_ON)
- Watchdog Timer: Disabled (WDT_OFF)
- Brown-out Detect: Disabled (BODEN_OFF)
- Low Voltage Programming: Disabled (LVP_OFF)
- Code Protection: Disabled (CP_OFF)
- RA0-RA5: Configured as analog inputs (bits 0-5 as inputs)
- RA2: ADC input channel (configured in ADCON0)
- Uses internal voltage reference
- RB4-RB7: LCD data lines (4-bit mode)
- RB2 (bLCD_RS): LCD Register Select
- RB3 (bLCD_E): LCD Enable signal
- All configured as outputs
- All pins configured as inputs (TRISC = 0xFF)
- Interface Type: 4-bit mode
- Configuration: 2 lines, 5×7 dot matrix characters
- Connection: PORT B (upper nibble for data, RB2/RB3 for control)
- Resolution: 10-bit (0-1023)
- Channel: RA2 (Channel 2)
- Clock Source: Internal RC with predivider ÷8
- Voltage Reference: VDD (5V typical)
- Acquisition Time: ~80µs (4× 20µs delays)
1. System Initialization
├── Configure I/O ports
├── Set up interrupts (prepared but not used)
├── Initialize ADC
└── Clear RAM
2. LCD Initialization
└── Configure 4-bit mode, 2-line display
3. Main Loop (infinite)
├── Acquire analog signal (ADC conversion)
├── Convert raw ADC value to voltage
├── Display voltage on LCD
├── Wait (temporal delay)
└── Repeat
The core application logic containing:
-
System Configuration
- Register definitions (OPTION_REG, INTCON, PIE1, PIE2)
- Port direction setup
- Interrupt handlers (framework present but unused)
-
Data Acquisition (
acquire)- Configures ADC for channel 2 (RA2) with predivider ÷8
- Waits for acquisition time (80µs)
- Starts conversion and polls GO bit
- Reads 10-bit result from ADRESH:ADRESL into auxreg1:auxreg2
-
Voltage Calculation (
voltage)- Converts raw 10-bit ADC value to voltage representation
- Uses bit-shifting and arithmetic operations
- Formula approximates:
Voltage = (ADC_Value × 5V) / 1024 - Result stored in auxreg1:auxreg2 (scaled for display)
-
Display Formatting (
LCD_ShowAcq)- Positions cursor at line 1
- Displays "Ascii : " label
- Converts voltage to ASCII decimal (XXX.XX format)
- Appends "V" unit suffix
-
Timing (
tempo)- Triple-nested loop delay routine
- Provides ~262ms delay between readings
LCD control and communication routines:
-
LCD_Init_Display: Initializes LCD in 4-bit mode- Sends initialization sequence
- Configures 2-line, 5×7 character display
- Enables display, disables cursor
-
LCD_SendCMD: Sends commands to LCD (RS=0)- Splits byte into two nibbles
- Toggles enable pin for each nibble
-
LCD_SendCHAR: Sends characters to LCD (RS=1)- Similar to SendCMD but with RS=1 for data
-
LCD_Clear: Clears display content -
LCD_ShowLogo: Displays "Hello!" welcome message
Number formatting and conversion routines:
-
HEX16_2_ASCII: Converts 16-bit binary to 5-digit ASCII decimal- Input: auxreg1:auxreg2 (16-bit value)
- Output: aBCD0:aBCD1:aBCD2:aBCD3:aBCD4 (ASCII characters)
- Implements binary-to-BCD conversion via bit testing
- Suppresses leading zeros
-
BCD_normalize: Handles decimal carry during conversion -
Timing Functions:
__Delay_5uS: 5 microsecond delay__Delay_20uS: 20 microsecond delay__Delay_50uS: 50 microsecond delay__Delay_Nx: Variable delay (N × 50µs)
Utility macros for cleaner code:
- Comparison Macros: JE, JNE, JL, JG, JLE, JGE, JZ, JNZ
- Data Movement: MOVLF, MOVFF
- LCD Macros: CHR_LCD (send character), INS_LCD (send instruction)
- Bank Selection: F_BANK
User variables:
test,table[10]: General purposecmpt1,cmpt2,cmpt3: Counter variables for delaysasciibit: Binary-to-ASCII conversion helperTEMP0,TEMP1: Voltage calculation temporariesauxreg1,auxreg2: ADC result and intermediate calculations
Accessible from all banks:
w_temp,status_temp,FSR_temp,PCLATH_temp: Interrupt context savingaBCD0-aBCD4: ASCII decimal representation (5 digits)dlyLSD,dlyMSD: Delay loop countersLCD_Char: LCD character buffer
Reserved for future expansion (currently unused).
-
ADC Configuration
- Selects analog input channel 2 (RA2)
- Configures clock source with predivider ÷8
- Sets right-justified result format
-
Conversion Sequence
Acquisition Time → Start Conversion → Poll Status → Read Result (80µs) (GO bit) (GO=0) (10 bits) -
Voltage Calculation Algorithm The
voltagesubroutine performs fixed-point arithmetic:V = ADC_Value / 1024 × 5V Implementation (optimized shifts and adds): - Right shift 2 bits (÷4) - Subtract from original - Right shift 5 bits (÷32) - Add back original - Right shift 1 bit (÷2) Net effect: V ≈ ADC × 0.0048828 (approximately ADC × 5/1024) -
Display Format
- Converts to ASCII decimal: "XXX.XX V"
- Leading zeros suppressed as spaces
- Fixed 2 decimal places
- Example: " 3.25 V" or " 4.98 V"
Line 1: "Ascii : XX.XX V"
Line 2: (unused)
- ADC Conversion Time: ~20µs (at Fosc/8 prescaler)
- Display Update Rate: ~262ms (controlled by
temporoutine) - Effective Sampling Rate: ~3.8 samples/second
The code includes a comprehensive interrupt handling framework (currently unused):
- Timer 0 (TMR0): General purpose timer
- RB0/INT: External interrupt
- RB4-RB7: Port change interrupt
- ADC: Conversion complete
- USART: Serial communication (RX/TX)
- SSP: Synchronous serial port
- CCP1/CCP2: Capture/Compare/PWM modules
- TMR1/TMR2: Additional timers
- EEPROM: Write complete
- Bus Collision: I²C collision detection
All interrupt handlers are present as stubs but return immediately. This provides a foundation for future enhancements.
According to the project header comments, planned enhancements include:
-
Hygrometer Functionality
- Replace voltage measurement with humidity sensing
- Integrate appropriate humidity sensor (capacitive/resistive)
-
Data Logging
- Utilize internal EEPROM (present macros: REEPROM, WEEPROM)
- Store min/max readings or time-series data
- Implement timestamp functionality
-
Enhanced User Interface
- Use second LCD line for additional information
- Display min/max values, trends
- Add menu system for configuration
-
Real-Time Features
- Enable timer interrupts for precise sampling
- Implement interrupt-driven ADC conversion
- Add alarm thresholds
- Assembler: MPASM (Microchip PIC Assembler)
- IDE: MPLAB X IDE or compatible
- Programmer: PICkit, ICD, or similar device
pic_voltmeter.asm- Main programpic_voltmeter.mcp- MPLAB Classic projectpic_voltmeter.mcw- MPLAB workspacelcd.inc- LCD driver librarymacro.inc- Macro definitionsascii.inc- Conversion utilitiesp16F873.inc- PIC16F873 register definitions (Microchip standard)
# Using MPASM command line
mpasm pic_voltmeter.asm /p16F873
# Or use MPLAB X IDE:
# 1. Open pic_voltmeter.mcp
# 2. Build → Build Main Project
# 3. Program device with generated .hex file| Parameter | Value |
|---|---|
| Microcontroller | PIC16F873 |
| Flash Memory | 4K words (8KB) |
| RAM | 192 bytes (4 banks × 48 bytes + 16 common) |
| EEPROM | 128 bytes |
| ADC Resolution | 10-bit (1024 levels) |
| Input Voltage Range | 0V to VDD (typically 5V) |
| Voltage Measurement Resolution | ~4.88 mV/step (5V / 1024) |
| Display Update Rate | ~3.8 Hz |
| Operating Frequency | 4-20 MHz (HS oscillator) |
v
- Language: Comments (original documentation)
- Naming: Mixed case for variables, uppercase for macros
- Indentation: Tab-based alignment
- Bank Management: Explicit bank switching using BANK0/BANK1/BANK2/BANK3 macros
- Page Management: Inter-page jump macros (GOTOX, CALLX) for programs >2K
-
No LCD Display
- Check PORT B connections (RB2=RS, RB3=E, RB4-7=Data)
- Verify LCD contrast adjustment
- Confirm 5V power supply
-
Incorrect Voltage Readings
- Verify RA2 input within 0-5V range
- Check ADC reference voltage (VDD)
- Calibrate using known voltage source
-
Erratic Behavior
- Ensure stable power supply
- Add decoupling capacitors (0.1µF near VDD/VSS)
- Check for proper grounding
-
Build Errors
- Verify all
.incfiles are in project directory - Ensure
p16F873.incis in MPASM include path - Check for MPASM version compatibility
- Verify all
This project was created by David ROBERT on February 29, 2004, as an educational/hobbyist embedded systems project. The code demonstrates fundamental PIC microcontroller programming techniques including:
- ADC signal acquisition
- LCD interfacing (4-bit mode)
- Binary-to-ASCII conversion
- Fixed-point arithmetic
- Assembly language optimization
For additional information, refer to:
- PIC16F873 Datasheet (Microchip DS30292C)
- MPASM User's Guide (Microchip DS33014)
- LCD HD44780 Controller Datasheet (Hitachi/compatible)
- MPLAB X IDE Documentation
Author: David ROBERT
Project Date: February 29, 2004
Last Updated: October 8, 2025 (Documentation)