Updating PWM Duty Cycle from ADC Sensor Reading

Last modified by Microchip on 2023/11/10 11:09

AVR®: Updating PWM Duty Cycle from ADC Sensor Reading

In this video:

  • Update the PWM duty cycle based upon the ADC result register.
  • Open AVR_PWM.c from a previous video.
  • Copy relevant PWM_init_LED() function, defines, and interrupt service routines back into this project.
  • Verify that we can change the LED brightness by varying the POT connected to the ADC.
  • Find the user guide and schematics for the I/O1 Xplained Pro (ATIO1-XPRO) from the product page.
  • Connecting the I/O1 Xplained Pro to the ATmega328P Xplained Mini.
  • Verifying that we are now able to change the LED brightness as the light sensor reading changes.

Now that we are familiar with some of the AVR® peripherals, it is time to start pulling them together.  In this lesson, we will combine the ADC with the PWM so that we can control the duty cycle with a light sensor.  The Light Sensor will be an from the I/01 Xplained Pro that we will connect to the Xplained Mini.  You can add these changes to the previous lesson's main.c file or create a new project and copy/pasted the entire contents of the AVR_ADC main.c file into it.

Back to Top

Procedure

Update the Interrupt Service Routine

Remove the LED_TOGGLE macro from the ISR(ADC_vect) and add the following.

uint16_t duty = ADC;
OCIE1B = duty;

We are going to use the LED again so we need to set that as an output.  Place the following line in your main loop above the ADC_init() function.

DDRB |= (1 << DDB5);

Back to Top


Copy Over CPU frequency from Previous Lesson

Open the AVR_PWM main.c file or open the AVR_PWM project in MPLAB® X IDE.  Now we can start pulling out the pieces that we need.  Starting with

Copy over the F_CPU declaration and put it at the top of our new main.c file.

#define F_CPU 16000000UL

Back to Top


Copy the PWM_Init() Function

Copy the PWM_Init() function from the previous PWM lesson and paste it just below the Interrupt Service Routine. The PWM_Init() looks like this...

void PWM_Init(void)
{
    TCCR1B |= (1 << CS10) | (1 << WGM12);  //No Prescaler & set mode to CTC
   TIMSK1 |= (1 << OCIE1A) | (1 << OCIE1B); //Enable the CTC interrupt
   OCR1A = 800;
    OCR1B = 400;
}

Call it from the main while loop like this...

PWM_Init();

Back to Top


Move over the ISRs from the PWM main.c file

Move these Interrupt Service Routines to our new project.  Place them just above the ISR for the ADC.

ISR(TIMER1_COMPA_vect)
{
   LED_ON;
}

ISR(TIMER1_COMPB_vect)
{
   LED_OFF;
}

Back to Top


Full Code Listing

Review the code below to make sure it matches your main.c file.  Connect the potentiometer with the wiper on PC1 and the other two connections on VCC and GND.

#include <avr/io.h>
#include
<avr/interrupt.h>
#define F_CPU 16000000UL

#define LED_ON  PORTB |= (1<<PORTB5)
#define LED_OFF PORTB &= ~(1<<PORTB5)
#define LED_TOGGLE  PINB |= (1<<PINB5)


ISR(TIMER1_COMPA_vect)
{
   LED_ON;
}

ISR(TIMER1_COMPB_vect)
{
   LED_OFF;
}

ISR(ADC_vect)
{
   uint16_t duty = ADC;
    OCR1B = duty;
}

void PWM_Init(void)
{
    TCCR1B |= (1 << CS10) | (1 << WGM12);  //No Prescaler & set mode to CTC
   TIMSK1 |= (1 << OCIE1A) | (1 << OCIE1B); //Enable the CTC interrupt
   OCR1A = 800;
    OCR1B = 400;
}

void ADC_init(void)
{
   ADMUX |= (1 << REFS0) | (1 << MUX0);   //AVCC equal to VCC and ADC1 input
  ADCSRA |= (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
   sei();
}


int main(void) {
   
    DDRB |= (1 << DDB5);
    ADC_init();
    PWM_Init();
   
   while (1) {
    }
}

Back to Top


Program the Device

Press the Make and Program Device button.

Program the Device

You should observe that the LED gets dimmer and brighter depending on which direction the potentiometer is turned.

Back to Top


Connect the PWM to a Light Sensor

Locate the documentation for the light sensor within the I/01 Xplained User Guide.  From the schematic we see that the light sensor is connected to Pin 3.  We can access GND through PIN 2 and VCC through Pin 20.  Remove the potentiometer and make these connections to the light sensor.

Connect the PWM to a Light Sensor

You should observe that when you wave your hand over the light sensor and and block the light, the LED get brighter.

Back to Top