
Objective
The objective of this laboratory is to demonstrate the basic concept of ADCs by controlling an analog input and displaying data on an OLED display. It is recommended to go through the I2C Laboratory first.
Preparation
The following schematic details the hardware setup.
Table 1 lists the components used in the schematic.
ID | Component | Manufacturer Part No. | Value | Qty. |
Base Components | ||||
IC1 | MCU | PIC24FJ256GA702-I/SP | – | 1 |
IC2 | Regulator | LM1117T-3.3/NOPB | 3.3V / 800mA | 1 |
C1 & C2 | Capacitor (tantalum) | TAP106K025SRW | 10uF / 25V | 2 |
C3 & C4 | Capacitor (ceramic) | SR155C103KARTR1 | 0.01uF / 50V | 2 |
C5 & C6 | Capacitor (ceramic) | SR155C104KARTR1 | 0.1uF / 50V | 2 |
C7 & C8 | Capacitor (ceramic) | SR151A150JARTR1 | 15pF / 100V | 2 |
C9 | Capacitor (ceramic) | FG16X7R1E106KRT06 | 10uF / 25V | 1 |
Y1 | Crystal | ABL-16.000MHZ-B2 | 16MHz | 1 |
R1 | Resistor | SFR2500001002FR500 | 10kΩ | 1 |
R2 | Resistor | SFR2500001004FR500 | 1MΩ | 1 |
J1 | Header (6-way) (PICkit 5) | 22-27-2061 | – | 1 |
Additional Components | ||||
R3 – R4 | Resistor | SFR2500001002FR500 | 10kΩ | 2 |
RV1 | Resistor (potentiometer) | RV24AF-22-15R1-B10K-3LA | 10kΩ | 1 |
IC3 | OLED | SSD1306 | – | 1 |
Refer to the following source code. Line #65 of the source code calls the SSD1306.h library, which in turn calls the ‘SSD1306_Characters.h’ library.
/* ADC (source code) */
/* MCU: PIC24FJ256GA702 */
/* Author: Michael */
/**************************** Configuration Bits ******************************/
// FSEC
#pragma config BWRP = OFF // Boot Segment Write-Protect bit (Boot Segment may be written)
#pragma config BSS = DISABLED // Boot Segment Code-Protect Level bits (No Protection (other than BWRP))
#pragma config BSEN = OFF // Boot Segment Control bit (No Boot Segment)
#pragma config GWRP = OFF // General Segment Write-Protect bit (General Segment may be written)
#pragma config GSS = DISABLED // General Segment Code-Protect Level bits (No Protection (other than GWRP))
#pragma config CWRP = OFF // Configuration Segment Write-Protect bit (Configuration Segment may be written)
#pragma config CSS = DISABLED // Configuration Segment Code-Protect Level bits (No Protection (other than CWRP))
#pragma config AIVTDIS = OFF // Alternate Interrupt Vector Table bit (Disabled AIVT)
// FBSLIM
#pragma config BSLIM = 0x1FFF // Boot Segment Flash Page Address Limit bits (Enter Hexadecimal value)
// FOSCSEL
#pragma config FNOSC = PRIPLL // Oscillator Source Selection (Primary Oscillator with PLL module (XT + PLL, HS + PLL, EC + PLL))
#pragma config PLLMODE = PLL96DIV4 // PLL Mode Selection (96 MHz PLL. Oscillator input is divided by 4 (16 MHz input))
#pragma config IESO = OFF // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)
// FOSC
#pragma config POSCMD = HS // Primary Oscillator Mode Select bits (HS Crystal Oscillator Mode)
#pragma config OSCIOFCN = ON // OSC2 Pin Function bit (OSC2 is general purpose digital I/O pin)
#pragma config SOSCSEL = OFF // SOSC Power Selection Configuration bits (Digital (SCLKI) mode)
#pragma config PLLSS = PLL_PRI // PLL Secondary Selection Configuration bit (PLL is fed by the Primary oscillator)
#pragma config IOL1WAY = OFF // Peripheral pin select configuration bit (Allow multiple reconfigurations)
#pragma config FCKSM = CSDCMD // Clock Switching Mode bits (Both Clock switching and Fail-safe Clock Monitor are disabled)
// FWDT
#pragma config WDTPS = PS1 // Watchdog Timer Postscaler bits (1:1)
#pragma config FWPSA = PR32 // Watchdog Timer Prescaler bit (1:32)
#pragma config FWDTEN = OFF // Watchdog Timer Enable bits (WDT and SWDTEN disabled)
#pragma config WINDIS = OFF // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config WDTWIN = WIN50 // Watchdog Timer Window Select bits (WDT Window is 50% of WDT period)
#pragma config WDTCMX = WDTCLK // WDT MUX Source Select bits (WDT clock source is determined by the WDTCLK Configuration bits)
#pragma config WDTCLK = SYSCLK // WDT Clock Source Select bits (WDT uses system clock when active, LPRC while in Sleep mode)
// FPOR
#pragma config BOREN = OFF // Brown Out Enable bit (Brown Out Disabled)
#pragma config LPCFG = OFF // Low power regulator control (No Retention Sleep)
#pragma config DNVPEN = DISABLE // Downside Voltage Protection Enable bit (Downside protection disabled when BOR is inactive)
// FICD
#pragma config ICS = PGD1 // ICD Communication Channel Select bits (Communicate on PGEC1 and PGED1)
#pragma config JTAGEN = OFF // JTAG Enable bit (JTAG is disabled)
// FDEVOPT1
#pragma config ALTCMPI = DISABLE // Alternate Comparator Input Enable bit (C1INC, C2INC, and C3INC are on their standard pin locations)
#pragma config TMPRPIN = OFF // Tamper Pin Enable bit (TMPRN pin function is disabled)
#pragma config SOSCHP = ON // SOSC High Power Enable bit (valid only when SOSCSEL = 1 (Enable SOSC high power mode (default))
#pragma config ALTI2C1 = ALTI2CEN // Alternate I2C pin Location (SDA1 and SCL1 on RB9 and RB8)
/************************* Configuration Bits (end) ***************************/
#define FCY 16000000 // FCY = FOSC / 2 (FCY: Instruction clock cycle) (FOSC: System clock cycle)
#include <libpic30.h> // Delay functions
#include <xc.h> // MCU pin mapping
#include "SSD1306.h" // OLED display (Solomon Systech SSD1306) library
int main(void)
{
// Set pin direction
TRISBbits.TRISB8 = 1; // MCU Pin #17 input (I2C1 SCL1)
TRISBbits.TRISB9 = 1; // MCU Pin #18 input (I2C1 SDA1)
TRISBbits.TRISB14 = 1; // MCU Pin #25 input (ADC: AN6)
/************************* configure MCU modules **************************/
// Analog Ports
ANSA = 0; // Disable A (PIC24FJ256GA702 datasheet p.126 Table 11-1)
ANSBbits.ANSB0 = 0;
ANSBbits.ANSB1 = 0;
ANSBbits.ANSB2 = 0;
ANSBbits.ANSB3 = 0;
ANSBbits.ANSB9 = 0;
ANSBbits.ANSB12 = 0;
ANSBbits.ANSB13 = 0;
ANSBbits.ANSB14 = 1; // Enable analog function (ADC: AN6) on MCU Pin #25
ANSBbits.ANSB15 = 0;
// Comparators
CM1CONbits.CEN = 0; // Disable #1 (PIC24FJ256GA702 datasheet p.310 Register 25-1)
CM2CONbits.CEN = 0;
CM3CONbits.CEN = 0;
// ADC
AD1CON1bits.ADON = 1; // Enable module
AD1CON1bits.SSRC = 0b0111; // Auto-convert mode
AD1CHSbits.CH0SA = 0b00110; // Sample A Channel 0 positive input from AN6 (MCU Pin #25)
AD1CON3bits.ADCS = 0b00000100; // 5TCY = TAD
// I2C1
I2C1BRG = 78; // Baud rate reload value (PIC24FJ256GA702 datasheet p.221 Eqn.18-1)
I2C1CONLbits.I2CEN = 1; // Enable module (PIC24FJ256GA702 datasheet p.222 Register 18-1)
I2C1CONLbits.DISSLW = 1; // Slew rate control disabled for standard speed mode (100kHz)
__delay_ms(100); // Delay to allow setup of I2C1
/********************** configure MCU modules (end) ***********************/
OLED_Setup(); // Set operating conditions for SSD1306
OLED_Clear(); // Clear display RAM (GDDRAM) of SSD1306
__delay_ms(100); // Delay to allow setup of SSD1306
uint16_t ADC_Value; // Store ADC value (0 to 1023)
uint8_t Counter;
while (1)
{
AD1CON1bits.SAMP = 1; // Start sampling
while (AD1CON1bits.DONE == 0); // Wait for conversion to finish
ADC_Value = ADC1BUF0; // Acquire ADC level after conversion complete
if (ADC_Value >= 0 && ADC_Value <= 9) // ADC value (units)
{
if (Counter == 1)
{
OLED_Clear(); // Clear OLED display of previous placeholder
}
OLED_Number(1, 1, ADC_Value);
Counter = 0;
}
if (ADC_Value >= 10 && ADC_Value <= 99) // ADC value (tens | units)
{
if (Counter == 2)
{
OLED_Clear();
}
OLED_Number(1, 1, ADC_Value);
Counter = 1;
}
if (ADC_Value >= 100 && ADC_Value <= 999) // ADC value (hundreds | tens | units)
{
if (Counter == 3)
{
OLED_Clear();
}
OLED_Number(1, 1, ADC_Value);
Counter = 2;
}
if (ADC_Value >= 1000 && ADC_Value <= 9999) // ADC value (thousands | hundreds | tens | units)
{
OLED_Number(1, 1, ADC_Value);
Counter = 3;
}
}
return 0;
}
As per the dsPIC33/PIC24 Family Reference Manual A/D Converter, p.20 Equation 51-1, the value of the ADCSx bits in the AD1CON3 register can be calculated, as shown in Equation 1. Further calculations, as shown in Equation 2, reveal the A/D clock period (TAD) is approximately 312ns, which is above the minimum required period of 300ns, as per Table 51-8 on p.59 of the datasheet.
\begin{equation}
\tag{1}
ADCSx = \frac{T_{AD} }{{T_{CY}}} -1= \frac{ 300.10^{-9} }{{\frac{ 1 }{{16,000,000}}}} -1 \approx 4
\end{equation}
\begin{equation}
\tag{2}
5T_{CY} = T_{AD} = 5.\frac{ 1 }{{16,000,000}} \approx 312 ~ns
\end{equation}
Testing
Turn the potentiometer clockwise and anticlockwise and observe the numbers on the OLED display rise from 0 to 1,023 and fall from 1,023 to 0.
Conclusion
The numbers displayed on the OLED correspond to the voltage range of 0V to 3.3V; hence, the ADC module is functioning as expected and can be used for the basis of projects.