КРУТИЛКА ПОТЕНЦИОМЕТРА И ШИМ НА АТМЕГАХ
⚙️ Обзор программы для 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); // Задержка для стабильности } }