Last active
June 16, 2018 01:08
-
-
Save jeremyblow/e68c4b5af63c8a2b4aed08ab6e8e623c to your computer and use it in GitHub Desktop.
ATmega328p 20kHz PWM for control of Delta THB1748BG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
// Core clock runs at 16MHz, three different timers can divide this freq | |
// by using a prescalar factor. Different PWM modes are available for each | |
// timer. We are using Fast PWM, which has the counter count from 0 to TOP. | |
// Thus, timer frequency would be 16MHz / prescalar / TOP count. The output | |
// turns on when the timer is at 0, and turns off when reaches the compare | |
// register value. As the compare register approaches TOP, the duty cycle | |
// approaches 100%. Since 0 is included in the high state, the effective | |
// counts in the high state will be the register value + 1. | |
// | |
// Timer to pin pairs: | |
// OC0A 6 | |
// OC0B 5 * use | |
// OC1A 9 | |
// OC1B 10 * use | |
// OC2A 11 | |
// OC2B 3 * use | |
// Note: Timer 0 will affect functions using user time e.g. millis() and | |
// delay(). We will be using A to set TOP, so we can only use B in each | |
// pair. | |
// Set data direction to output for relevant pins | |
pinMode(3, OUTPUT); | |
pinMode(5, OUTPUT); | |
pinMode(10, OUTPUT); | |
// Reset existing configuration and counters | |
TCCR0A = 0; | |
TCCR0B = 0; | |
TCCR1A = 0; | |
TCCR1B = 0; | |
TCCR2A = 0; | |
TCCR2B = 0; | |
TCNT0 = 0; | |
TCNT1 = 0; | |
TCNT2 = 0; | |
// Set waveform generation mode bits WGM to FAST PWM using OCRnA for TOP. | |
// Timer 0 & 2: | |
// Mode WGMn2 WGMn1 WGMn0 TOP Description | |
// 3 0 1 1 0xFF Fast PWM | |
// 7 1 1 1 OCRnA Fast PWM | |
// Timer 1: | |
// Mode WGM13 WGM12 WGM11 WGM10 TOP Description | |
// 5 0 1 0 1 0xFF Fast PWM, 8bit | |
// 15 1 1 1 1 OCRnA Fast PWM | |
// | |
// Set COMnA/B to 10 provides non-inverted PWM to outputs A and B | |
// COMnA1 COMnA0 Description | |
// 0 0 OCnA disabled | |
// 0 1 WMGn2 = 0: Normal, WGMn2 = 1: Toggle OCnA on Match | |
// 1 0 Non-inverted mode | |
// 1 1 Inverted mode | |
// COMnB1 COMnB0 Description | |
// 0 0 OCnB disabled | |
// 0 1 Reserved | |
// 1 0 Non-inverted mode | |
// 1 1 Inverted mode | |
// | |
// Prescalar is a 3 bit value stored in last three LSB of the register | |
// as CSn0, CSn1, CSn2. Timer 0/1 and 2 have different value mappings for these | |
// three bits: | |
// Timer 0 - 001:1, 010:8, 011:64, 100:256, 101:1024 | |
// Timer 1 - 001:1, 010:8, 011:64, 100:256, 101:1024 | |
// Timer 2 - 001:1, 010:8, 011:32, 100:64, 101:128, 110:256, 111:1024 | |
// | |
// Note: _BV() is a macro function defined in avr-libc which performs | |
// _BV(x) (1 << x). | |
// | |
// To achieve 20kHz, we solve for a reasonable prescalar that will give | |
// us a high enough count to fit the level of precision desired, e.g. if | |
// we wanted a 100 point control scale: | |
// 16000000 / n / 100 = 20000 | |
// n = 16000000 / 100 / 20000 | |
// n = 8 | |
// Prescalar 8 is the same for all Timers: 010 or CSn1 | |
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); | |
TCCR0B = _BV(WGM02) | _BV(CS01); | |
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10); | |
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11); | |
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); | |
TCCR2B = _BV(WGM22) | _BV(CS21); | |
// Use OCRnA to set TOP limit for all timers (99 has a count of 100) | |
OCR0A = 99; | |
OCR1A = 99; | |
OCR2A = 99; | |
// Set starting compare registers to ~5% duty cycle (you may use OCRnB directly, also). | |
analogWrite(3, 5); | |
analogWrite(5, 5); | |
analogWrite(10, 5); | |
// References: | |
// * pg. 94, 95, 99, 100, 104 | |
// http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf | |
// * http://www.righto.com/2009/07/secrets-of-arduino-pwm.html | |
// * https://sites.google.com/site/qeewiki/books/avr-guide/pwm-on-the-atmega328 | |
} | |
void loop() { | |
// Control goes here | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment