#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
int main(void)
{
uint16_t valor_adc;
uint16_t largura_pulso;
// ==================================================
// 1. CONFIGURAÇÃO DO ADC
// ==================================================
// PC0 / ADC0 como entrada
// No Arduino Uno corresponde ao pino A0
DDRC &= ~(1 << PC0);
// Seleciona:
// REFS0 = 1: referência AVcc, normalmente 5 V
// ADLAR = 0: resultado alinhado à direita
// MUX3:0 = 0000: canal ADC0
ADMUX = (1 << REFS0);
// Configura o ADC:
// ADEN = 1: habilita o ADC
// ADPS2:0 = 111: prescaler igual a 128
//
// Clock do ADC:
// 16 MHz / 128 = 125 kHz
ADCSRA = (1 << ADEN) |
(1 << ADPS2) |
(1 << ADPS1) |
(1 << ADPS0);
// ==================================================
// 2. CONFIGURAÇÃO DO TIMER1 PARA O SERVO
// ==================================================
// PB1 / OC1A como saída
// No Arduino Uno corresponde ao pino digital 9
DDRB |= (1 << PB1);
// Timer1 em Fast PWM, modo 14
// TOP definido por ICR1
// Saída OC1A em modo não invertido
TCCR1A = (1 << COM1A1) |
(1 << WGM11);
// Completa a seleção do modo 14
// Prescaler igual a 8
TCCR1B = (1 << WGM13) |
(1 << WGM12) |
(1 << CS11);
/*
* Clock do Timer1:
*
* 16 MHz / 8 = 2 MHz
*
* Cada contagem dura:
*
* 1 / 2 MHz = 0,5 us
*/
/*
* Período desejado para o servo: 20 ms
*
* 20 ms / 0,5 us = 40000 contagens
*
* Como o contador vai de 0 até ICR1:
*/
ICR1 = 39999;
/*
* Posição inicial do servo:
*
* 3000 contagens × 0,5 us = 1,5 ms
*
* Pulso de 1,5 ms corresponde aproximadamente
* à posição central.
*/
OCR1A = 3000;
// ==================================================
// 3. SUPERLOOP
// ==================================================
while (1)
{
// Inicia uma conversão ADC
ADCSRA |= (1 << ADSC);
// Aguarda o término da conversão
// O bit ADSC volta automaticamente para zero
while (ADCSRA & (1 << ADSC))
{
}
// Lê o resultado do ADC
// Faixa: 0 a 1023
valor_adc = ADC;
/*
* Converte o valor do ADC para largura de pulso:
*
* ADC = 0 -> OCR1A = 2000 -> pulso de 1 ms
* ADC = 512 -> OCR1A ≈ 3000 -> pulso de 1,5 ms
* ADC = 1023 -> OCR1A = 4000 -> pulso de 2 ms
*/
largura_pulso =
2000 + ((uint32_t)valor_adc * 2000) / 1023;
// Atualiza a largura do pulso do servo
OCR1A = largura_pulso;
// Pequeno intervalo entre as leituras
_delay_ms(20);
}
}