Trouble Setting up 16 bit PWM on Mega2560

I'm trying to use an Arduino Mega 2560 for a simple controller for a 0-5v analog signal controlling a mass flow controller. As it is right now it works using 3 buttons: up, down, and zero.

The issue is I need smaller voltage steps than the default 8bit pwm enables so I'd like to take advantage of the 16 bit counters on my Mega chip. I've been trying to use Timer1 to do so as directed on these two pages:

https://www.pjrc.com/teensy/td_libs_TimerOne.html

[url=http://http://playground.arduino.cc/Code/Timer1

I am struggling to get either of these to work - even something basic like just attaching it to an led and using Timer1.pwm() to manually control the pwm brightness.

can someone point me in the direction of an easy way to get this enabled? Even something simple like a link to some code that enables 16 bit and sends a pwm signal thats changed manually in the code?

Below is a link to the code I would like to eventually get working as 16 bit:

const int flowUp = 4;     // the number of the pushbutton up pin
const int flowDown = 3;    // the number of the pushbutton down pin
const int flowZero = 2;    // the number of the pushbutton zero pin
const int controlPin =  13;      // the number of the flow controller pin
const int maxFlow = 255; //this can be any number - it's the number of steps between dimmest and brightest. 

// variables will change:
int flow = 0;
int interval=1;

void setup() {
  // initialize the controller pin as an output:
  pinMode(controlPin, OUTPUT);      
  // initialize the pushbutton pins as an input:
  pinMode(flowUp, INPUT);     
  pinMode(flowDown, INPUT); 
  pinMode(flowZero,INPUT);  
  Serial.begin(9600);
  Serial.println(flow*0.0588);
}

void loop(){
    if (digitalRead(flowUp) == HIGH && flow < maxFlow){ 
      flow = flow + interval; 
      //if the flow Up button is pushed, add one degree of flows to the current level
      Serial.println(flow*0.0588+.07); //for debugging purposes
    }
    if (digitalRead(flowDown) == HIGH && flow > 0){
      flow = flow - interval;
      //if the flow Down button is pushed, subtract one degree of flow from the current level
      Serial.println(flow*0.0588+.07); //for debugging purposes
    }
    if (digitalRead(flowZero) == HIGH && flow >= 0){
      flow = 0;
      //if the flow zero button is pushed, resets to zero
      Serial.println(flow*0.0588); //for debugging purposes
    }
    delay(100);
    analogWrite(controlPin, map(flow, 0, maxFlow, 0, 255));    
    //this code maps the max flow constant to the max flowrate
  
}

I'd really appreciate any help, I'm brand new to arduinos and coding so I'm trying to learn as I go.

Timer1.initialize(microseconds); // This tell the library how to set the PWM period
Timer1.setPwmDuty(11, duty); // 'duty' is a value from 0 to 1023

If you want more than 1024 steps of PWM you will need to find a different library or program the timer registers directly. Here is how you can do that on an Arduino UNO. You would need to adapt it to the Arduino MEGA:

/*
PWM16Begin(): Set up Timer1 for PWM.
PWM16EnableA(): Start the PWM output on Pin 9
PWM16EnableB(): Start the PWM output on Pin 10
PWM16A(unsigned int value): Set the PWM value for Pin 9.
PWM16B(unsigned int value): Set the PWM value for Pin 10.
 */
 
// Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
// const unsigned int TOP = 0xFFFF; // 16-bit resolution.   244 Hz PWM
// const unsigned int TOP = 0x7FFF; // 15-bit resolution.   488 Hz PWM
// const unsigned int TOP = 0x3FFF; // 14-bit resolution.   976 Hz PWM
// const unsigned int TOP = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
// const unsigned int TOP = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
// const unsigned int TOP = 0x07FF; // 11-bit resolution.  7812 Hz PWM
   const unsigned int TOP = 0x03FF; // 10-bit resolution. 15624 Hz PWM




void PWM16Begin() {
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;   // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;   // Timer/Counter1 Interrupt Flag Register
  ICR1 = TOP;
  OCR1A = 0;  // Default to 0% PWM
  OCR1B = 0;  // Default to 0% PWM


  // Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1 << CS10);


  // Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
}


void PWM16EnableA() {
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1 << COM1A1);
  pinMode(9, OUTPUT);
}


void PWM16EnableB() {
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1 << COM1B1);
  pinMode(10, OUTPUT);
}


inline void PWM16A(unsigned int PWMValue) {
  OCR1A = constrain(PWMValue, 0, TOP);
}


inline void PWM16B(unsigned int PWMValue) {
  OCR1B = constrain(PWMValue, 0, TOP);
}




void setup() {
  Serial.begin(9600);
  PWM16Begin();
  
  // On the Arduino UNO T1A is Pin 9 and T1B is Pin 10
  
//  PWM16A(0);  // Set initial PWM value for Pin 9
//  PWM16EnableA();  // Turn PWM on for Pin 9


  PWM16B(0);  // Set initial PWM value for Pin 10
  PWM16EnableB();  // Turn PWM on for Pin 10
}


void loop() {
}

johnwasser:
Timer1.initialize(microseconds); // This tell the library how to set the PWM period
Timer1.setPwmDuty(11, duty); // 'duty' is a value from 0 to 1023

1024 steps would be totally fine for my application, with my limited coding ability I'm all about keeping it on the simpler side if possible.

Am I oversimplifying this? I'm trying to use this code just to control the pwm brigtness of an LED while I learn how to use the timer by manually changing the pwm in the code. Once I get this working I'll start messing with adapting it to my controller code.

#include "TimerOne.h"

void setup()
{
  Timer1.initialize(500000);         // initialize timer1, and set a 1/2 second period
  Timer1.setPwmDuty(11, 0);                // setup pwm on pin 11, 0% duty cycle
}

void loop()
{
   Timer1.setPwmDuty(11, 1023); 
}

as it stands right now this code doesn't work, at full PWM I'm still measuring 0v on pin 11. What is my code missing to use Timer1?

Okay for some reason I can get Timer3 to work but not timer1. This allows me to manually control the pwm out on pin 5

#include "TimerThree.h"

void setup()
{
  Timer3.initialize(2000);         // initialize timer1, and set a 1/2 second period
  Timer3.pwm(5, 0);                // setup pwm on pin 11, 0% duty cycle
}

void loop()
{
   Timer3.setPwmDuty(5, 512); 
}

In your TimerOne code, try setting pin11 pinMode(11,OUTPUT).

I think it is only set automatically by the library when you use the Timer1.pwm(pin, duty).

johnwasser:
If you want more than 1024 steps of PWM you will need to find a different library or program the timer registers directly. Here is how you can do that on an Arduino UNO. You would need to adapt it to the Arduino MEGA:

/*

PWM16Begin(): Set up Timer1 for PWM.
PWM16EnableA(): Start the PWM output on Pin 9
PWM16EnableB(): Start the PWM output on Pin 10
PWM16A(unsigned int value): Set the PWM value for Pin 9.
PWM16B(unsigned int value): Set the PWM value for Pin 10.
*/

// Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
// const unsigned int TOP = 0xFFFF; // 16-bit resolution.  244 Hz PWM
// const unsigned int TOP = 0x7FFF; // 15-bit resolution.  488 Hz PWM
// const unsigned int TOP = 0x3FFF; // 14-bit resolution.  976 Hz PWM
// const unsigned int TOP = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
// const unsigned int TOP = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
// const unsigned int TOP = 0x07FF; // 11-bit resolution.  7812 Hz PWM
  const unsigned int TOP = 0x03FF; // 10-bit resolution. 15624 Hz PWM

void PWM16Begin() {
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;  // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;  // Timer/Counter1 Interrupt Flag Register
  ICR1 = TOP;
  OCR1A = 0;  // Default to 0% PWM
  OCR1B = 0;  // Default to 0% PWM

// Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1 << CS10);

// Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
}

void PWM16EnableA() {
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1 << COM1A1);
  pinMode(9, OUTPUT);
}

void PWM16EnableB() {
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1 << COM1B1);
  pinMode(10, OUTPUT);
}

inline void PWM16A(unsigned int PWMValue) {
  OCR1A = constrain(PWMValue, 0, TOP);
}

inline void PWM16B(unsigned int PWMValue) {
  OCR1B = constrain(PWMValue, 0, TOP);
}

void setup() {
  Serial.begin(9600);
  PWM16Begin();
 
  // On the Arduino UNO T1A is Pin 9 and T1B is Pin 10
 
//  PWM16A(0);  // Set initial PWM value for Pin 9
//  PWM16EnableA();  // Turn PWM on for Pin 9

PWM16B(0);  // Set initial PWM value for Pin 10
  PWM16EnableB();  // Turn PWM on for Pin 10
}

void loop() {
}

Would adapting this code to a mega be as simple as changing the pinouts to the mega pins that correspond to T1A and T1B or is there more that I'm overlooking?

I got my code working at 10 bit using Timer3 but realized I could still use some extra resolution in my step size - basically I'm controlling a mass flow controller in an experiment that uses very small Incriments and 10 bit makes them kind of awkward (0.008 cm/s while I'd really like 0.01 cm/s steps). 12 bit would be plenty but 16 should be fine too.

Also with this code what command would I then use after initializing to send the 16 bit pwm to my pinout? PWM16A(pwm)? Or something else?