КРУТИЛКА ПОТЕНЦИОМЕТРА И ШИМ НА АТМЕГАХ

 

⚙️ Обзор программы для AVR: АЦП + ШИМ + светодиод

Эта простая, но наглядная программа на C для AVR-микроконтроллера (например, ATmega328P) реализует:

  • 🔌 Чтение аналогового сигнала с входа PC1 (ADC1)
  • 💡 Управление светодиодом на ножке PB5 (D13) в зависимости от уровня сигнала
  • 🎚️ Формирование ШИМ-сигнала (Fast PWM 8-бит) на PB1 (D9)

🔧 Инициализация АЦП (ADC)

void ADC_Init() {
   ADMUX = (1 << REFS0);
   ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
  • ⚡ Устанавливаем AVcc как опорное напряжение (5 В)
  • 🐢 Частота тактирования АЦП = 16 МГц / 128 = 125 кГц — оптимально
  • 🔛 Включаем АЦП (бит ADEN)

📥 Чтение аналогового значения

uint16_t ADC_Read(uint8_t channel) {
   ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);
   ADCSRA |= (1 << ADSC);
   while (ADCSRA & (1 << ADSC));
   return ADC;
}
  • 🎯 Выбор канала (например, channel = 1 для PC1/ADC1)
  • ⏱️ Запуск преобразования и ожидание завершения
  • 📈 Возврат 10-битного результата

🎛️ Настройка ШИМ (Fast PWM 8-bit)

void PWM_Init() {
   DDRB |= (1 << PB1);
   TCCR1A |= (1 << COM1A1) | (1 << WGM10);
   TCCR1B |= (1 << WGM12) | (1 << CS10);
}
  • 📤 Устанавливаем PB1 как выход
  • ⚡ Режим Fast PWM 8-bit (режим 5) — быстрый и простой
  • 🚀 Без предделителя (делитель = 1), максимум частоты

🧠 Главный цикл программы

while (1) {
   uint16_t adcValue = ADC_Read(1);

   if (adcValue > 512) {
       PORTB |= (1 << PB5);
   } else {
       PORTB &= ~(1 << PB5);
   }

   OCR1A = adcValue >> 2;
   _delay_ms(50);
}
  • 📡 Считываем значение с АЦП (PC1)
  • 💡 Если значение больше середины (512), включаем светодиод (PB5)
  • 🎚️ Преобразуем 10-битное значение в 8-битное (adcValue >> 2) и передаём в OCR1A для ШИМ
  • 🕒 Добавляем задержку для плавности

📦 Используемые пины Arduino Uno:

ПинНазначениеОписание
PC1 (A1) 🔍 Аналоговый вход Считывание напряжения
PB1 (D9) 📶 ШИМ-выход Выход ШИМ на нагрузку
PB5 (D13) 💡 Светодиод Индикатор превышения порога

🧪 Пример применения

Можно подключить потенциометр к A1 (PC1), и наблюдать:

  • 🔄 Светодиод D13 загорается, если напряжение выше половины
  • 📈 Выходной ШИМ на D9 изменяет скважность в зависимости от положения потенциометра

📘 Заключение

Простой и наглядный пример работы с:

  • 🧮 АЦП (Analog to Digital Converter)
  • 🌀 ШИМ (PWM)
  • 🚦 Светодиодной индикацией

Можно легко доработать под управление яркостью светодиодов, моторчиков или звукового сигнала 🎵.

 

#define CPU_F 16000000UL
#include <avr/io.h>
#include <util/delay.h>     // Настройка АЦП void ADC_Init() { ADMUX = (1 << REFS0); // Опорное напряжение = AVcc (5V) ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Включение АЦП + предделитель 128 (125 кГц) }     // Чтение значения АЦП uint16_t ADC_Read(uint8_t channel) { ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); // Выбор канала (PC1 = ADC1) ADCSRA |= (1 << ADSC); // Запуск преобразования while (ADCSRA & (1 << ADSC)); // Ожидание завершения return ADC; // Возврат результата (10 бит) }     // Настройка ШИМ (Fast PWM, 8-bit) void PWM_Init() { DDRB |= (1 << PB1); // PB1 (D9) как выход (ШИМ)   // Настройка таймера 1 для Fast PWM 8-bit на канале A (PB1) TCCR1A |= (1 << COM1A1) | (1 << WGM10); // Неинверсный ШИМ, режим 5 (Fast PWM 8-bit) TCCR1B |= (1 << WGM12) | (1 << CS10); // Режим 5, предделитель 1 (без деления) }     int main(void) { DDRB |= (1 << PB5); // PB5 (D13) как выход (светодиод) ADC_Init(); // Инициализация АЦП PWM_Init(); // Инициализация ШИМ     while (1) { uint16_t adcValue = ADC_Read(1); // Чтение с PC1 (A0)   // Управление светодиодом if (adcValue > 512) { PORTB |= (1 << PB5); // Включить PB5 } else { PORTB &= ~(1 << PB5); // Выключить PB5 }   // Установка ШИМ (берем старшие 8 бит из 10-битного значения АЦП) OCR1A = adcValue >> 2;   _delay_ms(50); // Задержка для стабильности } }