MicroControllers are digital devices and usually do not have built in digital to analog converters (or DACs) to output an analog signal. Some, however, do have analog input. For digital output, the voltage is one of two values. Output voltage is either 0 volts or near equal to the voltage source (‘off’ or ‘on’). Using a technique called pulse width modulation (or PWM), a microcontroller can create a ‘simulated’ analog output voltage.
Pulse width modulation turns the output on and off, each with set times at high frequencies to achieve an analog voltage. If you are unfamiliar with pulse width modulation, there are many tutorials on the internet. (Click HERE to search Google for PWM. An excellent one for the Arduino is HERE.)
Here is a short video of pulse width modulation on a PIC12F675 captured on an MSO-19 oscilloscope:
As can be seen in the video, the duty cycle (ratio of ‘on’ versus ‘off’) goes back and forth from 100% to 0%.
Here is the MPLAB XC8 C source code for creating that PWM signal on a PIC12F675:
// From: earl@microcontrollerelectronics.com // _________ __________ // | \_/ | // __| _ |__ // | | Vdd (_) Vss | | // Vdd` +5V |1 | | 8| VSS // |__| |__| // | | // __| |__ // | | ICSPDAT | | // GP5 / T1CKI |2 | | 7| GP0 / AN0 / CIN+ // CLKIN |__| |__| ICSPDAT / ULPWU // | | // __| |__ // | | ICSPCLK | | // T1G / AN3 / GP4 |3 | | 6| GP1 / AN1 / CIN- /Vref // OSC2 / CLKOUT |__| |__| ICSPCLK // | | // __| ____ |__ // | | MCLR/Vpp | | // GP3 / MCLR / VPP |4 | | 5| GP2 / AN2 / T0CKI / INT // |__| PIC12F675 or |__| COUT / CCP1 // | PIC12F629 no Analog | // |______________________| // /* PIC TIMER0 Calculator Clock Source in Mhz 4 Mhz Fosc 4000000.0 Hz Fosc / 4 1000000.0 Hz Time Period 1e-06 sec Prescaler 32 Timer0 Interrupt Period 0.008192 sec Period of Frequency Input To Timer0 3.2e-05 sec Period of Time for each Timer0 Count 0.008192 sec */ // xc8 --chip=12F675 main.c // xc8 --chip=12F629 main.c // CONFIG #pragma config FOSC = INTRCIO // Oscillator Selection bits // (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled) #pragma config MCLRE = OFF // GP3/MCLR pin function select // (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD) #pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled) #pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #include <xc.h> #define _XTAL_FREQ 4000000 #define usdelay 10 int PWM = 254; void interrupt isr(void) { if (T0IF == 1) { if (GP4) TMR0 = (unsigned int)PWM; else TMR0 = 255 - (unsigned int)PWM; #asm movlw 0b01110111 // mask xorwf GPIO,f // toggle GPIO bcf INTCON,2 // clear T0IF #endasm // T0IF = 0; } } void main(void) { OSCCAL = __osccal_val(); // Load Oscillator Calibration VRCON = 0x00; // Disable voltage reference CMCON = 0b00000111; // Disable comparator ANSEL = 0x00; // A/D disabled GPIO = 0; // Clear GPIO TRISIO = 0b00001000; // Set all GPIO (except GPIO3 as outputs WPU = 0; // Disable all weak pull up INTCON = 0b10100000; // Global Interrupt Enabled and TMR0 Overflow Interrupt Enabled TMR0 = 0 ; // Preload timer register OPTION_REG = 0b00000100; // Start Timer0 and set Prescaler to 1:32 int d = 1; while (1) { PWM += d; if(PWM == 255) d = -1; __delay_ms(usdelay); if(PWM == 0) d = 1; } }
The original code was generated with my PIC Timer0 Code Generator and Calculator for a PIC12F675:
and then modified to vary the duty cycle. An MSO-19 oscilloscope was used to capture the PWM signal. If LEDs were placed on the pins of the PIC12F675, they would be seen gradually going from bright to dim and back again to bright.
Using pulse width modulation, an output voltage can be produced anywhere between zero volts and the source voltage. Its simply a matter of math! For example, if the source voltage is 5 volts, to create a 2.5 volt output, the output pin would be ‘on’ half of the time and ‘off’ half of the time. (5 ÷ 2 = 2.5) Of course the frequency of the switching cycle has to be significant.
Recent Comments