ШИМ штука не сложная, по крайней мере, не сложнее чем мигание светодиодом. Принцип тот же: включаешь - выключаешь, и никаких сложных протоколов с контрольными суммами. В июле у меня был пост про таймер в CTC режиме, там если в прерывании начать переключать GPIO то получится вполне полноценный ШИМ. Такой способ хорош тем, что в ШИМ можно превратить любой свободный пин GPIO. Тогда получается, что частота ШИМ будет равна частоте переполнения счетчика, т.е. для 8-битного таймера: (частота кварца)/(предделитель_таймера * 256). Вобще-то, если ШИМ делать вручную, то частоту можно повысить, если в качестве значения таймера брать остаток от деления, но тогда и разрядность ШИМ соответственно понизится. Пример для двухкратного увеличения: (2 % 127)== (129 % 127) == 2.
Однако, есть в AVR аппаратные ШИМ когда все обходится без прерываний, и работает все с двух строчек кода. Называется он Fast PWM.
Для его настойки пондобится лишь контрольный регистр таймера TCCR2:
В нем нужно будет выставить биты WGM20 и WGM21:
Частоту по собственному вкусу:
и режим OC2 пина: выключено, нормальный режим, инверсный
и еще... нужно включить пин в push-pull режиме.
Простой код для проверки работы ШИМ
#include <util/delay.h> #include <uart.h> #include <avr/io.h> static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); int main(void) { //---- init init_uart(); DDRB |= (1<<PB5); // led indicator // init 8-bit timer in Fast PWM mode TCCR2 = (1<<WGM21)|(1<<WGM20)|(1<<COM21)|(1<<CS21); // fastPWM; frequent = 1/(256*8); non-inverting mode //---- ready indication blink13(3); stdout = &mystdout; printf("Ok, I'm ready!\n"); //---- main body uint8_t pwm; pwm=0; DDRB |=(1<<PB3); for (;;) { _delay_ms(2000); pwm+=10; OCR2=pwm; printf("PWM value: %u\n", pwm); }; return 0; }
Самым простым способом проверить ШИМ является подключение светодиода с резистором. Самым простым способом подключить вентилятор - использовать биполярный транзистор. Я подключал по схеме взятой отсюда
Хотя, использовать можно и что-то вроде H-моста