วันพฤหัสบดีที่ 10 พฤศจิกายน พ.ศ. 2559

Arduino analog digital pwm BY MARIOS ANDREOPOULOS — FEBRUARY 20, 2014 Fast PWM on ATmega328, up to 8MHz sacrificing duty cycle resolution to get higher frequency A couple of days earlier, a friend asked me how he could get fast PWM from an Atmel ATmega328 microcontroller —fast as in over 62.5KHz. Surpisingly I couldn't find a working code example, despite the fact there are many articles and forum posts about this. Of course one may always refer to the uC's datasheet, but the code part isn't always straightforward. So, without delay here is a sample code you can load to your Arduino Uno or directly to an AVR, which will give you a 250KHz, 6 bit resolution PWM on pin 3 (ATmega pin 5) and a 8MHz, 1 bit resolution —thus only 50% duty cycle— on pin 5 (ATmega pin 11). The duty cycle of the 250KHz PWM is rolling. // A sketch that creates an 8MHz, 50% duty cycle PWM and a 250KHz, // 6bit resolution PWM with varying duty cycle (changes every 5μs // or about every period. #include #include int main(void) { pinMode(3, OUTPUT); // output pin for OCR2B pinMode(5, OUTPUT); // output pin for OCR0B // Set up the 250KHz output TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); OCR2A = 63; OCR2B = 0; // Set up the 8MHz output TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); TCCR0B = _BV(WGM02) | _BV(CS00); OCR0A = 1; OCR0B = 0; // Make the 250KHz rolling while (1) { _delay_us(5); if ( OCR2B < 63 ) OCR2B += 5; else OCR2B = 0; } } So how does this code work? Let's talk about the uC for a bit first. Fast PWM The ATmega328 has 3 counters and usually runs at 16MHz. We will focus on counters #0 and #2 —counter #1 is a bit different. A PWM waveform is generated from a counter by counting clock ticks, a register and a comparator. The counter's purpose is to create the duty cycle resolution. One complete cycle of the counter is one period of your PWM. In most tutorials this is referred as the second clock division during PWM generation. The counter's size (and thus the duty cycle resolution) is 8 bits, which equals to 256 values. So from the get-go, your 16MHz clock gets divided by 256 —because a cycle of the counter takes 256 ticks— and may give a maximum frequency of 62.5KHz. In order to get lower frequencies, you can divide your clock by another factor, known as the first clock division. This is also called pre-scaling, because it precedes the counter. The register and the comparator are used to set and create the duty cycle output. The register sets for how long during each period the output is high. For example for a 25% duty cycle, you would set the register to 256 * 0.25 - 1 = 63. The comparator compares the register's value with the current counter value and gives high in the output if the value of the former is equal or lower from the value of the latter and low otherwise. For each counter you actually get 2 registers and 2 comparators, so you can get 2 PWM waveforms with different duty cycles but with the same frequency. If you managed to read until here, you learnt how the normal fast PWM mode of the ATmega328 works. In the datasheet it is referred to as waveform generation mode 3. Faster than Fast It should be clear by now that in order to get above 62.5KHz you have to sacrifice something; duty cycle resolution. You also have to give up one PWM output per counter. Enter waveform generation mode 7. What happens in this mode, is that you use one register and one comparator to set the top value of the counter. By controlling when your 8bit counter resets, you effectively set the frequency —remember, one cycle of the counter is one period of your PWM. Also you lower your duty cycle resolution since it depends on how may discrete values your counter has in a period. The second register and comparator pair works as always, generating the PWM output. An obvious requisite, is that the second register should be lower or equal to the first register. Code Explained Here is how we got the 250KHz waveform from timer/counter #2. The counter has control registers TCCR2A and TCCR2B which hold flags that set its mode of operation. We show only the settings for fast PWM. Also it has registers OCR2A and OCR2B, the function of which we described in the previous section (remember registers and comparators). #include #include int main(void) { pinMode(3, OUTPUT); // output pin for OCR2B, this is Arduino pin number // In the next line of code, we: // 1. Set the compare output mode to clear OC2A and OC2B on compare match. // To achieve this, we set bits COM2A1 and COM2B1 to high. // 2. Set the waveform generation mode to fast PWM (mode 3 in datasheet). // To achieve this, we set bits WGM21 and WGM20 to high. TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // In the next line of code, we: // 1. Set the waveform generation mode to fast PWM mode 7 —reset counter on // OCR2A value instead of the default 255. To achieve this, we set bit // WGM22 to high. // 2. Set the prescaler divisor to 1, so that our counter will be fed with // the clock's full frequency (16MHz). To achieve this, we set CS20 to // high (and keep CS21 and CS22 to low by not setting them). TCCR2B = _BV(WGM22) | _BV(CS20); // OCR2A holds the top value of our counter, so it acts as a divisor to the // clock. When our counter reaches this, it resets. Counting starts from 0. // Thus 63 equals to 64 divs. OCR2A = 63; // This is the duty cycle. Think of it as the last value of the counter our // output will remain high for. Can't be greater than OCR2A of course. A // value of 0 means a duty cycle of 1/64 in this case. OCR2B = 0; // Just some code to change the duty cycle every 5 microseconds. while (1) { _delay_us(5); if ( OCR2B < 63 ) OCR2B += 5; else OCR2B = 0; } } Everyone loves images This is how our PWMs look on a logic analyzer. 250KHz with rolling duty cycle: 8MHz, logic analyzer samples at 24MHz, so it can't detect accurately the duty cycle: Attribution As stated there are many articles and forum posts about the subject. The one I found really useful and have to give credit is this. Of course do not forget to read your microcontroller's datasheet. That's all folks The reason my friend needed that fast PWM is interesting on its own and I hope he will find some time to write about it in the future. Written by Marios Andreopoulos engineering Here's how you programs must initialise themselves for Arduino. sei () ; // Set Enable Interrupts. timer0_overflow_count = 0; // set timer 0 prescale factor to 64 // enable timer 0 overflow interrupt #if defined(__AVR_ATmega168__) sbi(TCCR0A, WGM01); sbi(TCCR0A, WGM00); sbi(TCCR0B, CS01); sbi(TCCR0B, CS00); sbi(TIMSK0, TOIE0); #else sbi(TCCR0, CS01); sbi(TCCR0, CS00); sbi(TIMSK, TOIE0); #endif // set timer 1 prescale factor to 64 sbi(TCCR1B, CS11); sbi(TCCR1B, CS10); // put timer 1 in 8-bit phase correct pwm mode sbi(TCCR1A, WGM10); // set timer 2 prescale factor to 64 #if defined(__AVR_ATmega168__) sbi(TCCR2B, CS22); #else sbi(TCCR2, CS22); #endif // configure timer 2 for phase correct pwm (8-bit) #if defined(__AVR_ATmega168__) sbi(TCCR2A, WGM20); #else sbi(TCCR2, WGM20); #endif // set a2d prescale factor to 128 // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. // XXX: this will not work properly for other clock speeds, and // this code should use F_CPU to determine the prescale factor. sbi(ADCSRA, ADPS2); sbi(ADCSRA, ADPS1); sbi(ADCSRA, ADPS0); // enable a2d conversions sbi(ADCSRA, ADEN); // the bootloader connects pins 0 and 1 to the USART; disconnect them // here so they can be used as normal digital i/o; they will be // reconnected in Serial.begin() #if defined(__AVR_ATmega168__) UCSR0B = 0; #else UCSRB = 0; #endif E:\Program Files\arduino-1.6.3\hardware\arduino\avr\cores\arduino>findstr TCCR * wiring.c:#if defined(TCCR0A) && defined(WGM01) wiring.c: sbi(TCCR0A, WGM01); wiring.c: sbi(TCCR0A, WGM00); wiring.c: sbi(TCCR0, CS02); wiring.c:#elif defined(TCCR0) && defined(CS01) && defined(CS00) wiring.c: sbi(TCCR0, CS01); wiring.c: sbi(TCCR0, CS00); wiring.c:#elif defined(TCCR0B) && defined(CS01) && defined(CS00) wiring.c: sbi(TCCR0B, CS01); wiring.c: sbi(TCCR0B, CS00); wiring.c:#elif defined(TCCR0A) && defined(CS01) && defined(CS00) wiring.c: sbi(TCCR0A, CS01); wiring.c: sbi(TCCR0A, CS00); wiring.c:#if defined(TCCR1B) && defined(CS11) && defined(CS10) wiring.c: TCCR1B = 0; wiring.c: sbi(TCCR1B, CS11); wiring.c: sbi(TCCR1B, CS10); wiring.c:#elif defined(TCCR1) && defined(CS11) && defined(CS10) wiring.c: sbi(TCCR1, CS11); wiring.c: sbi(TCCR1, CS10); wiring.c:#if defined(TCCR1A) && defined(WGM10) wiring.c: sbi(TCCR1A, WGM10); wiring.c:#elif defined(TCCR1) wiring.c:#if defined(TCCR2) && defined(CS22) wiring.c: sbi(TCCR2, CS22); wiring.c:#elif defined(TCCR2B) && defined(CS22) wiring.c: sbi(TCCR2B, CS22); wiring.c:#if defined(TCCR2) && defined(WGM20) wiring.c: sbi(TCCR2, WGM20); wiring.c:#elif defined(TCCR2A) && defined(WGM20) wiring.c: sbi(TCCR2A, WGM20); wiring.c:#if defined(TCCR3B) && defined(CS31) && defined(WGM30) wiring.c: sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 wiring.c: sbi(TCCR3B, CS30); wiring.c: sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode wiring.c:#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ wiring.c: sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 wiring.c: sbi(TCCR4B, CS41); wiring.c: sbi(TCCR4B, CS40); wiring.c: sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode wiring.c: sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A wiring.c: sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D wiring.c:#if defined(TCCR4B) && defined(CS41) && defined(WGM40) wiring.c: sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 wiring.c: sbi(TCCR4B, CS40); wiring.c: sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode wiring.c:#if defined(TCCR5B) && defined(CS51) && defined(WGM50) wiring.c: sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 wiring.c: sbi(TCCR5B, CS50); wiring.c: sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode wiring_analog.c: #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) wiring_analog.c: sbi(TCCR0, COM00); wiring_analog.c: #if defined(TCCR0A) && defined(COM0A1) wiring_analog.c: sbi(TCCR0A, COM0A1); wiring_analog.c: #if defined(TCCR0A) && defined(COM0B1) wiring_analog.c: sbi(TCCR0A, COM0B1); wiring_analog.c: #if defined(TCCR1A) && defined(COM1A1) wiring_analog.c: sbi(TCCR1A, COM1A1); wiring_analog.c: #if defined(TCCR1A) && defined(COM1B1) wiring_analog.c: sbi(TCCR1A, COM1B1); wiring_analog.c: #if defined(TCCR1A) && defined(COM1C1) wiring_analog.c: sbi(TCCR1A, COM1C1); wiring_analog.c: #if defined(TCCR2) && defined(COM21) wiring_analog.c: sbi(TCCR2, COM21); wiring_analog.c: #if defined(TCCR2A) && defined(COM2A1) wiring_analog.c: sbi(TCCR2A, COM2A1); wiring_analog.c: #if defined(TCCR2A) && defined(COM2B1) wiring_analog.c: sbi(TCCR2A, COM2B1); wiring_analog.c: #if defined(TCCR3A) && defined(COM3A1) wiring_analog.c: sbi(TCCR3A, COM3A1); wiring_analog.c: #if defined(TCCR3A) && defined(COM3B1) wiring_analog.c: sbi(TCCR3A, COM3B1); wiring_analog.c: #if defined(TCCR3A) && defined(COM3C1) wiring_analog.c: sbi(TCCR3A, COM3C1); wiring_analog.c: #if defined(TCCR4A) wiring_analog.c: sbi(TCCR4A, COM4A1); wiring_analog.c: cbi(TCCR4A, COM4A0); wiring_analog.c: #if defined(TCCR4A) && defined(COM4B1) wiring_analog.c: sbi(TCCR4A, COM4B1); wiring_analog.c: #if defined(TCCR4A) && defined(COM4C1) wiring_analog.c: sbi(TCCR4A, COM4C1); wiring_analog.c: #if defined(TCCR4C) && defined(COM4D1) wiring_analog.c: sbi(TCCR4C, COM4D1); wiring_analog.c: cbi(TCCR4C, COM4D0); wiring_analog.c: #if defined(TCCR5A) && defined(COM5A1) wiring_analog.c: sbi(TCCR5A, COM5A1); wiring_analog.c: #if defined(TCCR5A) && defined(COM5B1) wiring_analog.c: sbi(TCCR5A, COM5B1); wiring_analog.c: #if defined(TCCR5A) && defined(COM5C1) wiring_analog.c: sbi(TCCR5A, COM5C1); Tone.cpp:#define TCCR2A TCCR2 Tone.cpp:#define TCCR2B TCCR2 Tone.cpp: #if defined(TCCR0A) && defined(TCCR0B) Tone.cpp: TCCR0A = 0; Tone.cpp: TCCR0B = 0; Tone.cpp: bitWrite(TCCR0A, WGM01, 1); Tone.cpp: bitWrite(TCCR0B, CS00, 1); Tone.cpp: #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12) Tone.cpp: TCCR1A = 0; Tone.cpp: TCCR1B = 0; Tone.cpp: bitWrite(TCCR1B, WGM12, 1); Tone.cpp: bitWrite(TCCR1B, CS10, 1); Tone.cpp: #if defined(TCCR2A) && defined(TCCR2B) Tone.cpp: TCCR2A = 0; Tone.cpp: TCCR2B = 0; Tone.cpp: bitWrite(TCCR2A, WGM21, 1); Tone.cpp: bitWrite(TCCR2B, CS20, 1); Tone.cpp: #if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3) Tone.cpp: TCCR3A = 0; Tone.cpp: TCCR3B = 0; Tone.cpp: bitWrite(TCCR3B, WGM32, 1); Tone.cpp: bitWrite(TCCR3B, CS30, 1); Tone.cpp: #if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4) Tone.cpp: TCCR4A = 0; Tone.cpp: TCCR4B = 0; Tone.cpp: bitWrite(TCCR4B, WGM42, 1); Tone.cpp: bitWrite(TCCR4B, CS43, 1); Tone.cpp: bitWrite(TCCR4B, CS40, 1); Tone.cpp: #if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5) Tone.cpp: TCCR5A = 0; Tone.cpp: TCCR5B = 0; Tone.cpp: bitWrite(TCCR5B, WGM52, 1); Tone.cpp: bitWrite(TCCR5B, CS50, 1); Tone.cpp:#if defined(TCCR0B) Tone.cpp: TCCR0B = prescalarbits; Tone.cpp:#if defined(TCCR2B) Tone.cpp: TCCR2B = prescalarbits; Tone.cpp:#if defined(TCCR1B) Tone.cpp: TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; Tone.cpp:#if defined(TCCR3B) Tone.cpp: TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; Tone.cpp:#if defined(TCCR4B) Tone.cpp: TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; Tone.cpp:#if defined(TCCR5B) Tone.cpp: TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; Tone.cpp: #if defined(TCCR2A) && defined(WGM20) Tone.cpp: TCCR2A = (1 << WGM20); Tone.cpp: #if defined(TCCR2B) && defined(CS22) Tone.cpp: TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); wiring_digital.c: #if defined(TCCR1A) && defined(COM1A1) wiring_digital.c: case TIMER1A: cbi(TCCR1A, COM1A1); break; wiring_digital.c: #if defined(TCCR1A) && defined(COM1B1) wiring_digital.c: case TIMER1B: cbi(TCCR1A, COM1B1); break; wiring_digital.c: #if defined(TCCR1A) && defined(COM1C1) wiring_digital.c: case TIMER1C: cbi(TCCR1A, COM1C1); break; wiring_digital.c: #if defined(TCCR2) && defined(COM21) wiring_digital.c: case TIMER2: cbi(TCCR2, COM21); break; wiring_digital.c: #if defined(TCCR0A) && defined(COM0A1) wiring_digital.c: case TIMER0A: cbi(TCCR0A, COM0A1); break; wiring_digital.c: case TIMER0B: cbi(TCCR0A, COM0B1); break; wiring_digital.c: #if defined(TCCR2A) && defined(COM2A1) wiring_digital.c: case TIMER2A: cbi(TCCR2A, COM2A1); break; wiring_digital.c: #if defined(TCCR2A) && defined(COM2B1) wiring_digital.c: case TIMER2B: cbi(TCCR2A, COM2B1); break; wiring_digital.c: #if defined(TCCR3A) && defined(COM3A1) wiring_digital.c: case TIMER3A: cbi(TCCR3A, COM3A1); break; wiring_digital.c: #if defined(TCCR3A) && defined(COM3B1) wiring_digital.c: case TIMER3B: cbi(TCCR3A, COM3B1); break; wiring_digital.c: #if defined(TCCR3A) && defined(COM3C1) wiring_digital.c: case TIMER3C: cbi(TCCR3A, COM3C1); break; wiring_digital.c: #if defined(TCCR4A) && defined(COM4A1) wiring_digital.c: case TIMER4A: cbi(TCCR4A, COM4A1); break; wiring_digital.c: #if defined(TCCR4A) && defined(COM4B1) wiring_digital.c: case TIMER4B: cbi(TCCR4A, COM4B1); break; wiring_digital.c: #if defined(TCCR4A) && defined(COM4C1) wiring_digital.c: case TIMER4C: cbi(TCCR4A, COM4C1); break; wiring_digital.c: #if defined(TCCR4C) && defined(COM4D1) wiring_digital.c: case TIMER4D: cbi(TCCR4C, COM4D1); break; wiring_digital.c: #if defined(TCCR5A) wiring_digital.c: case TIMER5A: cbi(TCCR5A, COM5A1); break; wiring_digital.c: case TIMER5B: cbi(TCCR5A, COM5B1); break; wiring_digital.c: case TIMER5C: cbi(TCCR5A, COM5C1); break; Changing the Arduino PWM Frequency The default PWM frequency for PWM 3, 9, 10, & 11, at least for the Diecimila running at 16 MHz, is 488 Hz. That’s OK for dimming LEDs where you’re depending on persistence of vision, but it’s much too low when you must filter it down to DC. The relevant file is hardware/cores/arduino/wiring.c, which is buried wherever your installation put it. Turns out that the Arduino runtime setup configures the timer clock prescalers to 64, so the timers tick at 16 MHz / 64 = 250 kHz. You can fix that by setting the Clock Select bits in the appropriate Timer Control Register B to 0x01, which gets you no prescaling and a 62.5 ns tick period: TCCR0B = 0x01; // Timer 0: PWM 5 & 6 @ 16 kHz TCCR1B = 0x01; // Timer 1: PWM 9 & 10 @ 32 kHz TCCR2B = 0x01; // Timer 2: PWM 3 & 11 @ 32 kHz If you’re finicky, you’ll bit-bash the values rather than do broadside loads. However, it probably doesn’t matter, because Timer 0 runs in Fast PWM mode and Timers 1 & 2 run in Phase-Correct PWM mode, so WGMx2 = 0 in all cases. Fast PWM mode means Timer 0 produces PWM at 250 kHz / 256 = 976 Hz. However, the Arduino runtime runs the millis() function from the Timer 0 interrupt, so changing the Timer 0 prescaler pooches millis(), delay(), and any routines that depend on them. Phase-correct PWM mode means that Timers 1 & 2 count up to 0xff and down to 0x00 in each PWM cycle, so they run at 250 kHz / 512 = 488 Hz. Adroit TCCRxB setting can prescale by 1, 8, 64, 256, or 1024. Or stop the Timer stone cold dead, if you’re not careful. Before you fiddle with this stuff, you really This article is not fully compatible to Arduino Mega (or ATmega2560 microprocessor) For Arduino Mega: (tested on Arduino Mega 2560) timer 0 (controls pin 13, 4) timer 1 (controls pin 12, 11) timer 2 (controls pin 10, 9) timer 3 (controls pin 5, 3, 2) timer 4 (controls pin 8, 7, 6) TCCRnB, where 'n' is the number for the timer. TCCR2B for timer 2, TCCR3B for timer 3. Eg: TCCR2B = TCCR2B & 0b11111000 | 0x01; //sets Arduino Mega's pin 10 and 9 to frequency 31250. //code typically inserted in setup() Thanks to valerio_sperati (http://arduino.cc/forum/index.php/topic,72092.0.html) How to adjust Arduino PWM frequencies by macegr in this forum post http://forum.arduino.cc/index.php?topic=16612#msg121031 Pins 5 and 6: controlled by Timer 0 in fast PWM mode (cycle length = 256) Setting Divisor Frequency 0x01 1 62500 0x02 8 7812.5 0x03 64 976.5625 <--DEFAULT 0x04 256 244.140625 0x05 1024 61.03515625 TCCR0B = (TCCR0B & 0b11111000) | ; Pins 9 and 10: controlled by timer 1 in phase-correct PWM mode (cycle length = 510) Setting Divisor Frequency 0x01 1 31372.55 0x02 8 3921.16 0x03 64 490.20 <--DEFAULT 0x04 256 122.55 0x05 1024 30.64 TCCR1B = (TCCR1B & 0b11111000) | ; Pins 11 and 3: controlled by timer 2 in phase-correct PWM mode (cycle length = 510) Setting Divisor Frequency 0x01 1 31372.55 0x02 8 3921.16 0x03 32 980.39 0x04 64 490.20 <--DEFAULT 0x05 128 245.10 0x06 256 122.55 0x07 1024 30.64 TCCR2B = (TCCR2B & 0b11111000) | ; All frequencies are in Hz and assume a 16000000 Hz system clock. Issues from adjusting PWM frequencies and workarounds: from koyaanisqatsi in this forum post http://forum.arduino.cc/index.php?topic=16612.msg121040#msg121040 If you change TCCR0B, it affects millis() and delay(). They will count time faster or slower than normal if you change the TCCR0B settings. Below is the adjustment factor to maintain consistent behavior of these functions: Default: delay(1000) or 1000 millis() ~ 1 second 0x01: delay(64000) or 64000 millis() ~ 1 second 0x02: delay(8000) or 8000 millis() ~ 1 second 0x03: is the default 0x04: delay(250) or 250 millis() ~ 1 second 0x05: delay(62) or 62 millis() ~ 1 second (Or 63 if you need to round up. The number is actually 62.5) Also, the default settings for the other timers are: TCCR1B: 0x03 TCCR2B: 0x04 Any thought on the Arduino Mega? PWM frequencies on Timer 0, pins 5 and 6, Arduino Uno by yanngg, 02-15-2012 Timer 0 uses a prescale factor which is set to 64 by default To set the prescale factor use this line in the setup function Setting Prescale_factor TCCR0B = _BV(CS00); 1 TCCR0B = _BV(CS01); 8 TCCR0B = _BV(CS00) | _BV(CS01); 64 TCCR0B = _BV(CS02); 256 TCCR0B = _BV(CS00) | _BV(CS02); 1024 To use Fast PWM on Timer 0 Write this line in the setup function TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); And to calculate the PWM frequency, use Fast_PWM_frequency = (16 000 000)/(Prescale_factor*256); To use Phase-correct PWM on Timer 0 (half the frequency of Fast PWM) Write this line in the setup function TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); And to calculate the PWM frequency, use Phase_correct_PWM_frequency = (16 000 000)/(Prescale_factor*510); Changing the prescale factor on Timer0 will affect functions millis(), micros(), delay(),... To adjust millis(), micros(), delay(),... accordingly, You can modify a line in the wiring.c function in the Arduino program files hardware\arduino\cores\arduino\wiring.c In the beginning of wiring.c you can find: // the prescaler is set so that timer0 ticks every 64 clock cycles, and the // the overflow handler is called every 256 ticks. #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) You need to modify the prescale factor in this function to the corresponding line For fast PWM (default): #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(PRESCALE_FACTOR* 256)) For phase-correct PWM : #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(PRESCALE_FACTOR * 510)) Example: DC motor drive on the Arduino UNO, pins 5 and 6 For Fast PWM of 62.500 kHz (prescale factor of 1) Use these two lines in the setup function: TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); TCCR0B = _BV(CS00); And modify the line in the wiring.c function in the Arduino program files hardware\arduino\cores\arduino\wiring.c : #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(1 * 256)) For Phase-correct PWM of 31.250 kHz (prescale factor of 1) Use these two lines in the setup function: TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); TCCR0B = _BV(CS00); And modify the line in the wiring.c function in the Arduino program files hardware\arduino\cores\arduino\wiring.c : #define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(1 * 510)) Share I will also copy the tables here to explain: Pins 5 and 6: controlled by Timer 0 Setting Divisor Frequency 0x01 1 62500 0x02 8 7812.5 0x03 64 976.5625 0x04 256 244.140625 0x05 1024 61.03515625 TCCR0B = TCCR0B & 0b11111000 | ; Pins 9 and 10: controlled by timer 1 Setting Divisor Frequency 0x01 1 31250 0x02 8 3906.25 0x03 64 488.28125 0x04 256 122.0703125 0x05 1024 30.517578125 TCCR1B = TCCR1B & 0b11111000 | ; Pins 11 and 3: controlled by timer 2 Setting Divisor Frequency 0x01 1 31250 0x02 8 3906.25 0x03 32 976.5625 0x04 64 488.28125 0x05 128 244.140625 0x06 256 122.0703125 0x07 1024 30.517578125 TCCR2B = TCCR2B & 0b11111000 | ; All frequencies are in Hz and assume a 16000000 Hz system clock. So you can see the possible frequencies available to use and on what pins. Notice that each set of pins has different frequencies available and each set is also controlled by a different Arduino system timer. There are 3 timers that run based on the main 16MHz oscillator chip - you can change the scaler value to make each one run at a different speed. You should be careful though when changing the timer on system timer 0 which controls the PWM on pins 5 and 6, because it is also what the Arduino depends on to calculate several core functions like delay(), millis(), micros(), pulseIn(), and might mess with other things like interrupts. As far as I can tell, you can change the PWM frequency on timers 1 and 2 all day long and it doesn't seem to mess with anything else - so I usually stick to pins 3, 9, 10, and 11 if I need to change the frequency for some reason. Pins 5 and 6 can just stay at 1000Hz to keep everyone happy. In order to change the frequency, you need to put the correct code in the correct place. For example, if you wanted to change the frequency of the PWM on pins 3 and 11 to run at 32kHz, you would place the following line in your setup() function: void setup(){ TCCR2B = TCCR2B & 0b11111000 | 0x01; } The TCCR2B means that it is changing timer 2 for pins 3 and 11, not sure what the 8bit code does, but then you add the pipe character and the setting for the speed you want to use. If you refer back to the last table I pasted above, you will notice that for a frequency of 31250 Hz you must use a divisor of 1 which requires the setting "0x01". I often use this setting on these pins, because 32kHz is above the audible frequency range for humans, so you can operate your motors at this frequency without any whining noises. You might recall me saying that pins 3 and 11 have a default PWM frequency of 500 Hz - well it is actually 488 Hz and according to the chart is a divisor of 64 and uses the setting "0x04". You can also change multiple timers in the setup() function without problems. How To Apply This Code For Arduino Uno Atmega 328P SIR.. THANK YOU VERY MUCH FOR HELPING ME.. #include #include PROGMEM const uint16_t sine512[] = {250,256,262,269,275,281,288,294,301,308,314,319,326,332,339,344,350,356,362,367,374,379,384,389,395,400,404,410,414,419,423,428,433,436,440,445,449,452,455,458,463,466,468,471,474,476,478,481,483,485,487,488,490,491,493,494,495,496,496,498,499,499,499,500,500,499,499,499,498,498,496,496,495,494,493,493,492,491,489,488,487,486,484,483,481,480,478,476,474,473,471,470,468,466,465,463,460,459,457,455,453,452,450,449,447,446,445,443,442,440,439,438,436,435,434,433,432,432,431,430,430,429,428,428,428,428,427,427,427,427,427,428,428,428,428,429,430,430,431,432,432,433,434,435,436,438,439,440,442,443,445,446,447,449,450,452,453,455,457,459,460,463,465,466,468,470,471,473,474,476,478,480,481,483,484,486,487,488,489,491,492,493,493,494,495,496,496,498,498,499,499,499,500,500,499,499,499,498,496,496,495,494,493,491,490,488,487,485,483,481,478,476,474,471,468,466,463,458,455,452,449,445,440,436,433,428,423,419,414,410,404,400,395,389,384,379,374,367,362,356,350,344,339,332,326,319,314,308,301,294,288,281,275,269,262,256,250,244,238,231,225,219,212,206,199,192,186,181,174,168,161,156,150,144,138,133,126,121,116,111,105,100,96,90,86,81,77,72,67,64,60,55,51,48,45,42,37,34,32,29,26,24,22,19,17,15,13,12,10,9,7,6,5,4,4,2,1,1,1,0,0,1,1,1,2,2,4,4,5,6,7,7,8,9,11,12,13,14,16,17,19,20,22,24,26,27,29,30,32,34,35,37,40,41,43,45,47,48,50,51,53,54,55,57,58,60,61,62,64,65,66,67,68,68,69,70,70,71,72,72,72,72,73,73,73,73,73,72,72,72,72,71,70,70,69,68,68,67,66,65,64,62,61,60,58,57,55,54,53,51,50,48,47,45,43,41,40,37,35,34,32,30,29,27,26,24,22,20,19,17,16,14,13,12,11,9,8,7,7,6,5,4,4,2,2,1,1,1,0,0,1,1,1,2,4,4,5,6,7,9,10,12,13,15,17,19,22,24,26,29,32,34,37,42,45,48,51,55,60,64,67,72,77,81,86,90,96,100,105,111,116,121,126,133,138,144,150,156,161,168,174,181,186,192,199,206,212,219,225,231,238,244}; #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) //vyssi refclk == vyssi frekout const unsigned long refclk=1562960; const unsigned long refclk=781480; volatile int current_count; volatile unsigned long phase_accumulator; volatile unsigned long tword_m; volatile unsigned long stepm; volatile word count = 0; volatile byte DT = 10; volatile byte ampl = 13; volatile word offset_1 = 171; volatile word offset_2 = 341; word fnom = 5000; word fzad = 0; word boost = 600; word readpot; word calc; boolean ISR_exec_time = 1; boolean RUN = 0; byte bufclr = 0; void setup() { pinMode(6, OUTPUT); //OC4A pinMode(7, OUTPUT); //OC4B pinMode(8, OUTPUT); //OC4C pinMode(11, OUTPUT); //OC1A pinMode(12, OUTPUT); //OC1B pinMode(13, OUTPUT); //OC1C //pinMode(5, OUTPUT); //OC3A //pinMode(2, OUTPUT); //OC3B //pinMode(3, OUTPUT); //OC3C pinMode(52, OUTPUT); pinMode(53, OUTPUT); pinMode(22, INPUT_PULLUP); pinMode(23, INPUT_PULLUP); sbi (GTCCR, TSM); sbi (GTCCR, PSRASY); sbi (GTCCR, PSRSYNC); Setup_timer1(); Setup_timer2(); Setup_timer4(); //Setup_timer3(); //Setup_timer5(); TCNT1 = 0; //TCNT3 = 0; TCNT4 = 0; //TCNT5 = 0; GTCCR = 0; //Disable Timer 0 cbi (TIMSK0,TOIE0); tword_m=pow(2,32)*fzad/refclk; sbi (TIMSK4,TOIE4); Serial.begin(9600); } void loop() { while(1) { readpot = 0; for (int i=0; i <= 9; i++) { readpot = readpot + analogRead(0); } if (digitalRead(22)==0 && fzad==0) { offset_1 = 341; offset_2 = 171; } if (digitalRead(22)==1 && fzad==0 ) { offset_1 = 171; offset_2 = 341; } //=============================================== if (digitalRead(23)==1 && fzad!=readpot) { //================================================ if (fzad>readpot && TCNT2 > 10) { fzad = fzad-1; TCNT2=0; } if (fzad 10) { fzad = fzad+1; TCNT2=0; } //================================================ stepm = pow(2,32)*fzad/refclk; calc = ((1280/(fnom/100))*(fzad/100))/10; if (fzad > fnom) //*500 { calc = 128; } if (fzad < boost) { calc = 14; } cbi (TIMSK4,TOIE4); ampl = calc; //*5 tword_m = stepm; sbi (TIMSK4,TOIE4); } //=============================================== /* */ if (count > 7000) { bufclr = bufclr+1; count = 0; Serial.println(bufclr); Serial.println(fzad); Serial.println(ampl); } } } ISR(TIMER4_OVF_vect) { sbi(PORTB,ISR_exec_time); phase_accumulator=phase_accumulator+tword_m; current_count=phase_accumulator >> 23; word offs; word offs1; word offs2; offs= current_count + offset_1; offs2 = current_count + offset_2; if (offs > 511) { offs = offs - 512; } if (offs2 > 511) { offs2 = offs2 - 512; } offs = (pgm_read_word_near(sine512 + offs)*ampl) >> 6; offs1 = (pgm_read_word_near(sine512 + current_count)*ampl) >> 6; offs2 = (pgm_read_word_near(sine512 + offs2)*ampl) >> 6; if (tword_m > 0) { OCR4B = offs + DT; OCR1B = offs; OCR4A = offs1 + DT; OCR1A = offs1; OCR4C = offs2 + DT; OCR1C = offs2; } else { OCR4B = 1023; OCR1B = 0; OCR4A = 1023; OCR1A = 0; OCR4C = 1023; OCR1C = 0; } cbi(PORTB,ISR_exec_time); count = count+1; /* */ } void Setup_timer1(void) { //Clock Prescaler : 1 sbi (TCCR1B, CS10); cbi (TCCR1B, CS11); cbi (TCCR1B, CS12); // Timer1 Phase Correct PWM sbi (TCCR1A, COM1A0); sbi (TCCR1A, COM1A1); sbi (TCCR1A, COM1B0); sbi (TCCR1A, COM1B1); sbi (TCCR1A, COM1C0); //tretireg sbi (TCCR1A, COM1C1); //tretireg // Mode 1 / Phase Correct PWM sbi (TCCR1A, WGM10); sbi (TCCR1A, WGM11); cbi (TCCR1B, WGM12); cbi (TCCR1B, WGM13); } void Setup_timer4(void) { sbi (TCCR4B, CS40); cbi (TCCR4B, CS41); cbi (TCCR4B, CS42); cbi (TCCR4A, COM4A0); sbi (TCCR4A, COM4A1); cbi (TCCR4A, COM4B0); sbi (TCCR4A, COM4B1); cbi (TCCR4A, COM4C0); sbi (TCCR4A, COM4C1); sbi (TCCR4A, WGM40); sbi (TCCR4A, WGM41); cbi (TCCR4B, WGM42); cbi (TCCR4B, WGM43); } void Setup_timer2(void) { //Prescaler : 1 cbi (TCCR2B, CS20); cbi (TCCR2B, CS21); sbi (TCCR2B, CS22); // Phase Correct PWM cbi (TCCR2A, COM2A0); // clear Compare Match cbi (TCCR2A, COM2A1); cbi (TCCR2A, COM2B0); cbi (TCCR2A, COM2B1); //Phase Correct PWM cbi (TCCR2A, WGM20); cbi (TCCR2A, WGM21); cbi (TCCR2B, WGM22); } /* void Setup_timer3(void) { sbi (TCCR3B, CS30); cbi (TCCR3B, CS31); cbi (TCCR3B, CS32); cbi (TCCR3A, COM3A0); sbi (TCCR3A, COM3A1); cbi (TCCR3A, COM3B0); sbi (TCCR3A, COM3B1); cbi (TCCR3A, COM3C0); sbi (TCCR3A, COM3C1); sbi (TCCR3A, WGM30); sbi (TCCR3A, WGM31); cbi (TCCR3B, WGM32); cbi (TCCR3B, WGM33); } void Setup_timer5(void) { sbi (TCCR5B, CS50); cbi (TCCR5B, CS51); cbi (TCCR5B, CS52); cbi (TCCR5A, COM5A0); sbi (TCCR5A, COM5A1); cbi (TCCR5A, COM5B0); sbi (TCCR5A, COM5B1); cbi (TCCR5A, COM5C0); sbi (TCCR5A, COM5C1); sbi (TCCR5A, WGM50); sbi (TCCR5A, WGM51); cbi (TCCR5B, WGM52); cbi (TCCR5B, WGM53); } Setup_timer2(); void Setup_timer2() { //Prescaler : 1 sbi (TCCR2B, CS20); cbi (TCCR2B, CS21); cbi (TCCR2B, CS22); // Phase Correct PWM cbi (TCCR2A, COM2A0); // clear Compare Match cbi (TCCR2A, COM2A1); cbi (TCCR2A, COM2B0); cbi (TCCR2A, COM2B1); //Phase Correct PWM sbi (TCCR2A, WGM20); cbi (TCCR2A, WGM21); cbi (TCCR2B, WGM22); } volatile byte ms4_delay; volatile byte c4ms; if (c4ms > 25) { c4ms=0; offset_3=analogRead(0)/4; dfreq=50.0; cbi (TIMSK2,TOIE2); tword_m=pow(2,32)*dfreq/refclk; sbi (TIMSK2,TOIE2); } */ /* if(ms4_delay++ == 125) { c4ms++; ms4_delay=0; //reset count } coffs = pgm_read_word_near(sine512 + coffs2 - 1); OCR1B = ((word)coffs*99)/100; // +1 korekce */ /* */?

ไม่มีความคิดเห็น:

แสดงความคิดเห็น