Управление яркостью светодиода при помощи потенциометра

Потенциометр — это переменный резистор, который при повороте ручки изменяет свое сопротивление.

Что требуется для проекта:

  • Arduino UNO или любой другой аналог
  • Макетная плата
  • Потенциометр
  • Светодиод
  • Резистор 220 Ом

Схема подключения на макетной плате.

Для того, чтобы регулировать яркость светодиода, подключим его к разъему, который поддерживает ШИМ, в нашем случае это цифровой пин 3. Разъемы VCC и GND потенциометра подключаем к рельсе питания и земли макетной платы. Разъем A0 подключаем к аналоговому пину A0.

После удачной сборки схемы загружаем данный скетч:

#define LED 3
#define POT A0

void setup() {
 pinMode(LED, OUTPUT); //настройка пина в режим выхода
 pinMode(POT, INPUT); //настройка пина в режим входа
}

void loop() {
 //заявляем целочисленные переменные
 int turn, brightness; 
 //считываем в turn напряжение потенциометра, его значения
 //будут варьироваться от 0 до 1023
 turn = analogRead(POT); 
 //в переменную brightness записываем значение turn,
 //деленное на 4. Будет принимать значения от 0 до 255
 brightness = turn / 4;
 //включаем светодиод с яркостью, равной значению brightness
 analogWrite(LED, brightness); 
}

Теперь попробуем написать код для этой же схемы но на чистом СИ в среде AtmelStudio 7. Выглядеть это будет так.

#include <avr/io.h>
 
int main(void)
{
    //Настроим нужные нам пины МК на входы и выходы.
    DDRC = 0<<PC0;  //настройка пина в режим входа без подтяжки
    PORTC= 0<<PC0;  //настройка пина в режим входа без подтяжки
     
    DDRD = 1<<PD3;  //настройка пина в режим выхода
    PORTD= 0<<PD3;  //настройка пина в режим выхода
      
    //Настроим АЦП модуль микроконтроллера
    ADMUX=(0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
    ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(0<<ADIF)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);   
     
    //Настроим TIMER 2                  
    TCCR2A=(0<<COM2A1)|(0<<COM2A0)|(1<<COM2B1)|(0<<COM2B0)|(1<<WGM21)|(1<<WGM20);
    TCCR2B=(0<<FOC2A)|(0<<FOC2B)|(0<<WGM22)|(1<<CS22)|(0<<CS21)|(0<<CS20);
     
    while (1) //Это главный бесконечный цикл.
    {
        OCR2B=ADCH;//управляем яркостью диода вращая потенциометр
    }
}

Теперь попробуем разобраться с этими двумя примерами. Дело в том, что  среда Arduino задумывалась для быстрого старта начинающим. Если надо помигать диодиком или пощелкать реле, то это можно осуществить за считанные минуты. Среда Arduino полностью изолированна от железа микроконтроллера и поэтому в ней все осуществляется через функции которые разработаны разработчиками данного софта. Эти функции и их внутренности сокрыты в недрах программы. Обычному пользователю остается только вызывать нужные функции для настроек аппаратных узлов МК. Казалось бы это намного упрощает программирование. В принципе это так и есть. Поэтому среда и платы Arduino очень популярны среди начинающих любителей проектов на МК. Однако есть и минусы, например те кто программируют Arduino не могут запрограммировать МК которых не поддерживает среда ПО Arduino. Например запрограммировать любую модель МК Attiny AVR представляется уже невозможным. Да и другие модели Atmega которых нету в платах Arduino, тоже остаются за бортом. Впринципе если проекты не особо сложные, так побаловатся, то и среды Arduino достаточно. Если же надо что то большое и сложное, то тут конечно рулит чистый СИ. Но тогда придется разбираться в регистрах МК, в том как работают те или иные узлы МК. Надо читать документацию, изучить и понимать сам СИ. Однако если у вас уже есть опыт написание скетчей в среде Arduino, то со временем разобраться в СИ тоже будет возможно.

Теперь попробуем рассмотреть код на СИ и поймем что это не так страшно.

К примеру строка #include <avr/io.h>
подключает заголовочный файл в котором выбирается наш нужный МК. Среда AtmelStudio 7 делает это автоматически при создании нового проекта.

DDRC = 0<<PC0;  
PORTC= 0<<PC0; 
DDRD = 1<<PD3;

PORTD = 0<<PD3;  

Эти строки настраивают нужные нам выводы платы Arduino на вход или на выход. PC0 это то же что и А0 на плате, этот вывод надо настроить на вход, так как к ней подключаетя потенциометр. И с этого вывода будет считываться значение АЦП.

Регистром ADMUX и ADCSRA настраиваем сам узел АЦП в нужный нам режим. В частности настраиваем так что АЦП будет автоматически постоянно считывать значение с вывода А0 и сохранять это значение в регистре ADCH.

В МК есть аппаратные таймеры, это тоже такие узлы которые дают возможность работать с ШИМ выводами, например ШИМ вывод ~3 к которому подключен светодиод, принадлежит внутреннему Timer2. В Atmega 328 есть еще Timer0 и Timer1. Так вот с помощью регистров TCCR2A и TCCR2B, настроим наш Timer2 на режим FAST_PWM, это дает нам возможность работать с выводом ~3 платы Arduino. Ну и в главном цикле программы сразу передаем значение из АЦП в наш Timer2. Делается это одной строчкой OCR2B=ADCH.

Вопрос только в том как залить в нашу ардуину код написанный на СИ в AtmelStudio? Сделать это можно с помощью программатора прямо из среды AtmelStudio. Правда перед этим надо из платы ардуино этим же программатором считать и сохранить загрузчик. Иначе потом плата ардуино не сможет работать со средой Arduino. В любое время можно обратно программатором вернуть загрузчик на место.