95

Программный ШИМ на arduino NANO

Приветствую всех!

Сегодня я хочу затронуть тему реализации программного ШИМ на Ардуино НАНО.

Бывают такие моменты, что надо ШИМ там где его нет, например на Аналоговых пинах.. почему нет?


Что такое ШИМ я затрагивал ТУТ, Напомню в краце: ШИМ - это отношение высокого и низкого сигнала за какой-либо период, который называется частотой ШИМ.

Картинка из интернетов:

Программный ШИМ на arduino NANO Arduino Nano V3, Шим, Программирование

И вот понадобилось мне сделать ШИМ там, где его нет в Ардуине.

Да простит меня сообщество, - не вижу смысла заливать код куда либо, если там несколько строк:

Программный ШИМ на arduino NANO Arduino Nano V3, Шим, Программирование

Котэ работает на прерывании по таймеру2, так как на нем висит Аппаратный ШИМ пинов 3 и 11, то никаких критичных "базовых" функций этим не испортим.

Значит в блоке setup просто переводим таймер в режим работы по CLK, т.е. 16 мГц, и разрешаем прерывание по таймеру.

Для включения ШИМ на каком-либо пину делаем так: в массиве пинов пишем пины какие надо, через запятую,.. ну там {13, A0, A7, 5} и тд...

Затем в Массиве значений ШИМ записываем им всем начальное значение, лучше нули, ... т.е. {0, 0, 0, 0} - 4 Пина юзаем, 4 значения записали,.. хотя наверное можно вообще не писать, они и так при инициализации нулями будут..

Ну а дальше в цикле программы, когда нужно записываем в переменную нужное значение, т.е. надо на пин A0 подать 50%, - пишем PWM_pins[1] = 127; обьясняю: в 1 ячейке массива пинов записан A0,.. 127 - это половина от 255 (0-255 значения). Вот и всё.

Надеюсь кому поможет.

Arduino & Pi

1.5K поста20.8K подписчика

Правила сообщества

В нашем сообществе запрещается:

• Добавлять посты не относящиеся к тематике сообщества, либо не несущие какой-либо полезной нагрузки (флуд)

• Задавать очевидные вопросы в виде постов, не воспользовавшись перед этим поиском

• Выкладывать код прямо в посте - используйте для этого сервисы ideone.com, gist.github.com или схожие ресурсы (pastebin запрещен)

• Рассуждать на темы политики

• Нарушать установленные правила Пикабу

Вы смотрите срез комментариев. Показать все
1
Автор поста оценил этот комментарий

Я ещё не закончил с программой вашей копаться, но:

1. код в посте дает частоту сигнала ШИМ 122,6 Гц.

2. время выполнения команды analogwrite 8 мкс, digitalwrite 4 мкс.

3. digitalwrite и команда записи в порт напрямую PORTB |= (1 << 4) дают одно и тоже время.

4. переписал код, он теперь дает частоту 331.2 Гц

boolean t1=0;

unsigned long timeStart,timeEnd;

const byte PWM_pins[]={12};

#define PWM_count sizeof(PWM_pins)

volatile byte pwm_value[PWM_count]={20};

byte pwm_counter;

void setup() {


for (byte i = 0; i<PWM_count; i++)


TCCR2B=0;

TCCR2A=0;

//TCNT2 = 0;

TCCR2A |= 1<<COM2B0 | (1<<WGM21);

OCR2A=1;

TCCR2B = 1<<CS20;

TIMSK2 = (1<<OCIE2A);

}

ISR (TIMER2_COMPA_vect)

{

pwm_counter++;

for (byte i = 0; i<PWM_count; i++)

{

pwm_counter > pwm_value[i] ? analogWrite(PWM_pins[i],0): analogWrite(PWM_pins[i], 255);

}

}

void loop() {

}


5. переписал ещё раз, избавившись от аналограйт, теперь частота стала 1.305 кГц, чувствуете прирост, по сравнению с оригиналом? (хотя частота исходного ШИМ ардуиновского 490 Гц).

boolean t1=0;

unsigned long timeStart,timeEnd;


const byte PWM_pins[]={12};


#define PWM_count sizeof(PWM_pins)


volatile byte pwm_value[PWM_count]={20};


byte pwm_counter;



void setup() {


//pinMode(3, OUTPUT);


for (byte i = 0; i<PWM_count; i++)


pinMode( PWM_pins[i], OUTPUT);



TCCR2B=0;


TCCR2A=0;


//TCNT2 = 0;



TCCR2A |= 1<<COM2B0 | (1<<WGM21);


OCR2A=1;



TCCR2B = 1<<CS20;


TIMSK2 = (1<<OCIE2A);



}


ISR (TIMER2_COMPA_vect)


{


pwm_counter++;


for (byte i = 0; i<PWM_count; i++)


{


pwm_counter > pwm_value[i] ? PORTB &= ~(1 << 4) : PORTB |= (1 << 4);


}



}


void loop() {


}

6. Допилить можно дальше, так как номер пина для записи я указал вручную и есть ещё идейка как оптимизировать, но мне далеко вот до этого: http://codius.ru/articles/214 .


PS ваше объяснение причины использования analogwrite прочел, но всё равно не согласен с этим.

раскрыть ветку (4)
0
Автор поста оценил этот комментарий
Спасибо за статейку, я даже не думал, что switch так много жрет. Что касается оптимизации кода, то по факту у меня получилось +/- типа твоего... но трава уже отпустила.. =D выкинул на гитхаб. Мало ли пригодится.
по аналогу - теперь я понял что из чего сделано, и да, соглашусь, т.к. нашёл ответы на свои вопросы и всё встало на места. Надо было еще раньше исходники проштудировать =D.
раскрыть ветку (3)
0
Автор поста оценил этот комментарий

А вот ещё вопрос, у вас запись есть 0<<CS22, она же не нужна. Там и так ноль в этой ячейке, а такой формой записи мы больше ничего не добьемся, да она и не нужна.

TCCR2B = 0<<CS22 | 0<<CS21 | 1<<CS20

1<<CS20  - мы создаем маску, у нас есть число в двоичной системе 00000001, мы его сдвигаем на величину CS20, допустим на 1 влево, тогда будет 00000010. А вот 0<<CS22 нам ничего не дает, мы берем число 00000000 и сдвигаем влево на CS22, в результате все равно ноль будет.

раскрыть ветку (1)
0
Автор поста оценил этот комментарий
Да, иногда делаю так, когда экперементирую, что бы бысто вкл/выкл делать.
0
Автор поста оценил этот комментарий

Второй пост посмотрел - сделано красиво, реализация прям конфетка)

кстати, в своем коде я забыл убрать 1<<COM2B0 - это устанавливает режим ШИМ вывода 3, он не нужен, это из старой программы своей копировал.

Вы смотрите срез комментариев. Чтобы написать комментарий, перейдите к общему списку