In my other post – PIC10F322 XC8 Analog-to-Digital Converter (ADC) Getting Started.
I went over the basics of getting up and going with the ADC on the PIC10F322. The code read the value from a potentiometer and if the value was over a certain range – turn on the LED.
In this code, we are going to read the value from the potentiometer connected to RA1 and then use that value to control the brightness of the LED directly connected to RA0.
If you wanted to control a larger load – say a motor. You could (with the right values) throw a transistor on the output of RA0 and drive something larger. I will save that for another blog post.
The only thing I want to point out in the code is that I am taking the value from the pot , which is only an 8 bit value, and multiplying that by 4 to get a 10bit number for the PWM.
The Circuit

And now… for the code.
/*
* File: adc_pwm.c
* Author: Jamie
*
* Created on 9/14/2021, 8:04 PM
*/
#include <xc.h>
#include <stdint.h>
//Device Configuration
#pragma config FOSC = INTOSC // Oscillator Selection
#pragma config BOREN = ON // Brown-out Reset
#pragma config WDTE = OFF // Watchdog Timer
#pragma config PWRTE = ON // Power-up Timer
#pragma config MCLRE = OFF // MCLR Pin Function Select bit->MCLR pin function is digital input, MCLR internally tied to VDD
#pragma config CP = OFF // Code Protection
#pragma config LVP = OFF // Low-Voltage Programming
#pragma config LPBOR = ON // Brown-out Reset Selection bits
#pragma config BORV = LO // Brown-out Reset Voltage Selection
#pragma config WRT = OFF // Flash Memory Self-Write Protection
//Used to calculate the delay time - Change depending on processor Speed
#define _XTAL_FREQ 16000000 //16Mhz
//Prototypes
void setup(void);
uint8_t ADC_Read(void);
void set_dutycycle(volatile uint8_t* pDutyCycleHigh, volatile uint8_t* pDutyCycleLow, uint16_t dutyValue);
void setup(void){
//Set the System Clock - You can change this to match the setting you are looking for
OSCCONbits.IRCF = 0b111; //Set System Clock to 16Mhz
//Pin LED is connected to
TRISAbits.TRISA0 = 0; //Make pin Output A.0
ANSELAbits.ANSA0 =0; //Disable Analog A.0
set_dutycycle(&PWM1DCH,&PWM1DCL,0); //Clear Duty Cycle for PWM1
PR2 = 0xFF;
T2CONbits.T2CKPS = 0b00;
T2CONbits.TMR2ON = 0x01;
PWM1CONbits.PWM1OE = 0x01; //PWM1 Turn on
PWM1CONbits.PWM1EN = 0x01; //PWM1 Enable Output
TRISAbits.TRISA1 = 1; //Make pin Input A1
ANSELAbits.ANSA1 =1; //Enable Analog A1
//Set Analog conversion clock FOSC/32, since we are running 16Mhz, we need to have a conversion time at or greater 1uS
//FOSC/32 will give us 2uS
ADCONbits.ADCS = 0b010;
//Select the Analog channel - A1 or AN1
ADCONbits.CHS = 0b001;
//Turn on the ADC module
ADCONbits.ADON = 1;
}
void main(void)
{
setup();
while(1){
uint8_t ADC_Value = 0;
ADC_Value = ADC_Read(); //Read the ADC Value
uint16_t ADC_adj_Value = ADC_Value * 4; //PWM is running at 10bits. ADC is 8bits. We will fluff it up some
set_dutycycle(&PWM1DCH,&PWM1DCL, ADC_adj_Value); //Set the Duty cycle of PWM1
__delay_ms(500); //Wait .5 second and do it again
}
}
uint8_t ADC_Read(){
//Starts the ADC read and waits until a conversion is complete before returning
//Returns the ADC value
ADCONbits.GO_nDONE = 1; //Start the conversion
while (ADCONbits.GO_nDONE == 1){
NOP();
}
return ADRES;
}
void set_dutycycle(volatile uint8_t* pDutyCycleHigh, volatile uint8_t* pDutyCycleLow, uint16_t dutyValue)
/*Sets the duty value of the supplied registers.
*Usage set_dutycycle(&PWM_duty_register_high,&PWM_duty_register_low, duty_value)
*Valid range for 10bit resolution is 0 - 1023
*TO convert percent to value, lets say we want 33%. 1023 x .33 = 337.59 round it to 338.
*338 would be the value we enter for the duty. */
{
*pDutyCycleLow = (uint8_t)((dutyValue & 0b11) << 0x06); //Get the LSB
*pDutyCycleHigh = (uint8_t)(dutyValue >> 0x02); //Get the MSB
}
Have a Project or Idea!?
I am Available for Freelance Projects
I am always looking for opportunities to put my technical skills to work.
I am always looking to connect with like minded people.
Want to connect? – Drop me a message