Skip to content

Commit dbca497

Browse files
committed
Initial Commit with floating point
0 parents  commit dbca497

12 files changed

Lines changed: 1484 additions & 0 deletions

File tree

PWM.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Copyright (c) 2012 Sam Knight
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7+
of the Software, and to permit persons to whom the Software is furnished to do
8+
so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
*/
20+
21+
/*
22+
This library is built to support two of the AVR Architecture 'groups' that Arduino uses
23+
a) ATmega48/88/168/328,
24+
b) ATmega640/1280/1281/2560/2561
25+
*/
26+
27+
#ifndef PWM_H_
28+
#define PWM_H_
29+
30+
#include "avr/pgmspace.h"
31+
#include "math.h"
32+
33+
#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
34+
#include "utility/ATimerDefs.h"
35+
#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
36+
#include "utility/BTimerDefs.h"
37+
#endif
38+
39+
#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
40+
// 16 bit timers
41+
extern uint32_t GetFrequency_16(const int16_t timerOffset);
42+
extern bool SetFrequency_16(const int16_t timerOffset, float f);
43+
extern uint16_t GetPrescaler_16(const int16_t timerOffset);
44+
extern void SetPrescaler_16(const int16_t timerOffset, prescaler psc);
45+
extern void SetTop_16(const int16_t timerOffset, uint16_t top);
46+
extern uint16_t GetTop_16(const int16_t timerOffset);
47+
extern void Initialize_16(const int16_t timerOffset);
48+
extern float GetResolution_16(const int16_t timerOffset);
49+
50+
// 8 bit timers
51+
extern uint32_t GetFrequency_8(const int16_t timerOffset);
52+
extern bool SetFrequency_8(const int16_t timerOffset, float f);
53+
extern uint16_t GetPrescaler_8(const int16_t timerOffset);
54+
extern void SetPrescaler_8(const int16_t timerOffset, prescaler psc);
55+
extern void SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc);
56+
extern void SetTop_8(const int16_t timerOffset, uint8_t top);
57+
extern uint8_t GetTop_8(const int16_t timerOffset);
58+
extern void Initialize_8(const int16_t timerOffset);
59+
extern float GetResolution_8(const int16_t timerOffset);
60+
61+
#endif
62+
63+
#if defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
64+
65+
// 16 bit timers
66+
extern uint32_t GetFrequency_16();
67+
extern bool SetFrequency_16(float f);
68+
extern uint16_t GetPrescaler_16();
69+
extern void SetPrescaler_16(prescaler psc);
70+
extern void SetTop_16(uint16_t top);
71+
extern uint16_t GetTop_16();
72+
extern void Initialize_16();
73+
extern float GetResolution_16();
74+
75+
// 8 bit timers
76+
extern uint32_t GetFrequency_8(const int16_t timerOffset);
77+
extern bool SetFrequency_8(const int16_t timerOffset, float f);
78+
extern uint16_t GetPrescaler_8(const int16_t timerOffset);
79+
extern void SetPrescaler_8(const int16_t timerOffset, prescaler psc);
80+
extern void SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc);
81+
extern void SetTop_8(const int16_t timerOffset, uint8_t top);
82+
extern uint8_t GetTop_8(const int16_t timerOffset);
83+
extern void Initialize_8(const int16_t timerOffset);
84+
extern float GetResolution_8(const int16_t timerOffset);
85+
86+
#endif
87+
88+
// common functions
89+
90+
extern void InitTimers();
91+
extern void InitTimersSafe(); // doesn't init timers responsible for time keeping functions
92+
extern void pwmWrite(uint8_t pin, uint8_t val);
93+
extern void pwmWriteHR(uint8_t pin, uint16_t val); // accepts a 16 bit value and maps it down to the timer for maximum resolution
94+
extern bool SetPinFrequency(int8_t pin, float frequency);
95+
extern bool SetPinFrequencySafe(int8_t pin, float frequency); // does not set timers responsible for time keeping functions
96+
extern float GetPinResolution(uint8_t pin); // gets the PWM resolution of a pin in base 2, 0 is returned if the pin is not connected to a timer
97+
98+
#endif /* PWM_H_ */

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# PWM.h
2+
3+
v 5.0
4+
5+
Created by Sam Knight
6+
7+
Modify PWM frequency on AVR (arduino) platform
8+
9+
10+
11+
Modified by Terry Myers:
12+
13+
1. Modified examples to be in their own folders
14+
2. Corrected a line feed character in two of the libraries so that visual studio would not error when opening them
15+
3. Added README.MD, library.properties, and library.json files to better "integrate" to IDEs espencially Arduino IDE for begginers
16+
4. Added new example for high resolution control of an LED
17+
5. Added "{ 0, 0, 0, 0, 0 }, //TIMER1C" to line 107 in ATimerDefs.cpp as suggested by texmit from arduino forms
18+
19+
Original repository
20+
https://code.google.com/archive/p/arduino-pwm-frequency-library/downloads
21+
22+
Original Arduino Forum library post by Runnerup (Sam Knight):
23+
https://forum.arduino.cc/index.php?topic=117425.0

examples/PWM/PWM.ino

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
3+
Mimics the fade example but with an extra parameter for frequency. It should dim but with a flicker
4+
because the frequency has been set low enough for the human eye to detect. This flicker is easiest to see when
5+
the LED is moving with respect to the eye and when it is between about 20% - 60% brighness. The library
6+
allows for a frequency range from 1Hz - 2MHz on 16 bit timers and 31Hz - 2 MHz on 8 bit timers. When
7+
SetPinFrequency()/SetPinFrequencySafe() is called, a bool is returned which can be tested to verify the
8+
frequency was actually changed.
9+
10+
This example runs on mega and uno.
11+
*/
12+
13+
#include <PWM.h>
14+
15+
//use pin 11 on the Mega instead, otherwise there is a frequency cap at 31 Hz
16+
int led = 9; // the pin that the LED is attached to
17+
int brightness = 0; // how bright the LED is
18+
int fadeAmount = 5; // how many points to fade the LED by
19+
int32_t frequency = 35; //frequency (in Hz)
20+
21+
void setup()
22+
{
23+
//initialize all timers except for 0, to save time keeping functions
24+
InitTimersSafe();
25+
26+
//sets the frequency for the specified pin
27+
bool success = SetPinFrequencySafe(led, frequency);
28+
29+
//if the pin frequency was set successfully, turn pin 13 on
30+
if(success) {
31+
pinMode(13, OUTPUT);
32+
digitalWrite(13, HIGH);
33+
}
34+
}
35+
36+
void loop()
37+
{
38+
//use this functions instead of analogWrite on 'initialized' pins
39+
pwmWrite(led, brightness);
40+
41+
brightness = brightness + fadeAmount;
42+
43+
if (brightness == 0 || brightness == 255) {
44+
fadeAmount = -fadeAmount ;
45+
}
46+
47+
delay(30);
48+
}
49+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Simple high resolution dimming example
3+
4+
The function pwmWriteHR(PIN, brightness(0-65535) replaces analogWrite()
5+
Download "PWM_lib_resolution_example.ino" to the arduino and look at the serial monitor to see examples of frequency/resolution combinations that you can use.
6+
For LED applications to get better than 8 bits of resolution, I've found that a frequency of 240hz that gives 15.1 bits works very well.
7+
Note that pwmWriteHR takes an unsigned integer from 0-65535, you won't see a change for each increment depending on the resolution.
8+
I.E at a frequency of 240hz which translates to a resolution of 15.1bits this is 35119 steps, so at most you'll only see a difference every other increment(i.e 15000 to 15002)
9+
10+
*/
11+
12+
#include <PWM.h>
13+
14+
//use pin 11 on the Mega instead, otherwise there is a frequency cap at 31 Hz
15+
int led = 9; // the pin that the LED is attached to
16+
unsigned int brightness; // how bright the LED is
17+
int fadeAmount = 32; // how many points to fade the LED by. 32 was choosen as this gives a fade over about 12 seconds on an arduino uno uC
18+
unsigned int frequency = 240; //frequency (in Hz), gives approx 15.1 bits of PWM resolution
19+
float Max = 65535.0; //Maximum of a 16bit integer which is what pwmWriteHR wants
20+
float gammaCorrection = 2.2;//
21+
22+
//============================================================================
23+
void setup()
24+
{
25+
Serial.begin(115200);
26+
27+
//initialize all timers except for 0, to save time keeping functions
28+
InitTimersSafe();
29+
30+
//sets the frequency for the specified pin
31+
bool success = SetPinFrequencySafe(led, frequency);
32+
33+
//if the pin frequency was set successfully, turn pin 13 on
34+
if (!success) {
35+
Serial.println("Failed to set frequency!");
36+
}
37+
}
38+
//============================================================================
39+
void loop()
40+
{
41+
42+
brightness = brightness + fadeAmount;
43+
44+
if (brightness == 0 || brightness == 65535) {
45+
fadeAmount = -fadeAmount;
46+
}
47+
48+
float GammaCorrectedBrightness = GammaCorrection((float)brightness);
49+
50+
//print out the current brightness
51+
Serial.print("Raw brightness="); Serial.print(brightness); Serial.print("(0-65536) Gamma corrected brightness="); Serial.print((uint16_t)GammaCorrectedBrightness); Serial.println("(0-65535)");
52+
53+
pwmWriteHR(led, (uint16_t)brightness); //use this functions instead of analogWrite on 'initialized' pins
54+
}
55+
//============================================================================
56+
float GammaCorrection(float sp) {
57+
//Perform a gamma correction. LEDs do nto have a linear brightness percieved by human vision. This helps to simulate that.
58+
//Pass in a value between 0 and Max, and a gamma corrected value will be returned
59+
return constrain(pow(sp / float(Max), gammaCorrection) * Max + 0.49, 0.0, Max); //The 0.49 is there to move the first value up a little
60+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
By default Arduino's analogWrite (and consequently pwmWrite() since it mimics analogWrite()) uses 8 bit
3+
pwm across all timers. 8 bit PWM allows for a total of 256 possible values. This library has some methods
4+
for fine tuning resolution if a higher resolution is needed:
5+
6+
void pwmWriteHR(uint8_t pin, uint16_t duty)
7+
Same a pwmWrite, except the range is 0 - 65535 (16 bit) instead
8+
of 0 - 255 (8 bit)
9+
10+
float TimerX_GetResolution() (replace X with a timer number)
11+
Gets the timer's resolution in base 2. The value returned in other words
12+
represents the number of bits required to represent the timer's range. ie
13+
the value 7 means it takes 7 bits to represent all possible pin duties at
14+
that frequency, or 7-bit resolution. Note that a float is returned, not
15+
an int.
16+
17+
float GetPinResolution(uint8_t pin)
18+
Returns the same value as TimerX_GetResolution(), but takes a pin number
19+
as a parameter so that the caller is timer agnostic.
20+
21+
There are several things to keep in mind when trying to optimize resolution:
22+
-pwmWriteHR() is only useful for 16 bit timers, since 8 bit timers are inherently limited to 8 bit pwm
23+
-The higher the frequency, the lower the resolution. pwmWriteHR() will automatically map input to the
24+
actual timer resolution
25+
-Resolution can be optimized in this way for 2 pins on the Uno (9 and 10), and 11 pins on the Mega (2,
26+
3, 5, 6, 7, 8, 11, 12, 44, 45, and 46)
27+
28+
Use the serial moniter to see output from this program
29+
This example runs on mega and uno.
30+
*/
31+
32+
#include <PWM.h>
33+
34+
//use pin 11 on the mega for this example to work
35+
int led = 9; // the pin that the LED is attached to
36+
37+
void setup()
38+
{
39+
InitTimersSafe(); //initialize all timers except for 0, to save time keeping functions
40+
Serial.begin(115200);
41+
Serial.println();
42+
43+
demonstrateFrequencysEffectOnResolution();
44+
settingHighResolutionDuty();
45+
}
46+
47+
void demonstrateFrequencysEffectOnResolution()
48+
{
49+
Serial.println("As frequency increases, resolution will decrease...");
50+
for(int i = 1; i < 10000; i+=10)
51+
{
52+
SetPinFrequency(led, i); //setting the frequency
53+
54+
uint16_t frequency = Timer1_GetFrequency();
55+
uint16_t decimalResolution = Timer1_GetTop() + 1;
56+
uint16_t binaryResolution = GetPinResolution(led); //this number will be inaccurately low because the float is being truncated to a int
57+
58+
char strOut[75];
59+
sprintf(strOut, "Frequency: %u Hz\r\n Number of Possible Duties: %u\r\n Resolution: %u bit\r\n", frequency, decimalResolution, binaryResolution );
60+
61+
Serial.println(strOut);
62+
}
63+
64+
Serial.println("...Finished");
65+
}
66+
67+
void settingHighResolutionDuty()
68+
{
69+
SetPinFrequency(led, 10); //setting the frequency to 10 Hz
70+
Serial.println("\r\npwmWrite() and pwmWriteHR() are identical except for the valid range of inputs.\r\nThe following loop calls both functions to produce the same result on the \r\nLED pin. The pin should to run 10Hz at 50% duty regardless of the function called.\r\n");
71+
72+
//the led should flicker (10Hz 50% duty) for 1 second before calling
73+
//the other function. This demonstrates the use of pwmWriteHR() and how its
74+
//use is nearly identical to pwmWrite()
75+
while(true)
76+
{
77+
//setting the duty to 50% with 8 bit pwm. 128 is 1/2 of 256
78+
pwmWrite(led, 128);
79+
Serial.println("8-Bit PWM");
80+
delay(1000);
81+
82+
//setting the duty to 50% with the highest possible resolution that
83+
//can be applied to the timer (up to 16 bit). 1/2 of 65536 is 32768.
84+
pwmWriteHR(led, 32768);
85+
Serial.println("High Resolution PWM");
86+
delay(1000);
87+
}
88+
89+
}
90+
91+
void loop()
92+
{
93+
}

0 commit comments

Comments
 (0)