Solar tracker based on delay() and millis()

I created these two new sets of codes for my Arduino Uno R3 using the Cytron MD10C motor driver powering a 12v wiper motor.

I require a 15khz PWM frequency for the motor per previous tests with dc speed controllers.

I've tested the delay() and millis() functions and all works well.

For now though I just want feedback on my coding. I've run both through an emulator with a simulated LED and all works well.

I've tried previous codes and have found I have the frequency off and then the duty cycle off as well which causes motor whine and awful results from over torque and none at all.

I've also attached another version using delay() only but using TCCR1A and TCCR1B coding, so not using the Timer one.h library.

Appreciate any and all advice and feedback. Patrick

So main inquiries are:

  1. is my coding legit for PWM frequency and duty cycle on the two sketches using the TimerOne.h library to generate an almost 15khz frequency and 24% duty cycle.

  2. is my coding legit for PWM frequency and duty cycle on the one sketch modifying timer1 by tweaking TCCR1A, TCCR1B,etc to generate an almost 15khz frequency and 24% duty cycle?

//Using Timer one.h library and delay() function only
// code below uses Timer1.initialize(67) which sets frequency to 14925hz
// (1/15000*1000000) = 66.67 but need integer so 1/67*1000000 = 14925

#include <TimerOne.h>
void setup() {

  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);
  Timer1.initialize(67); // sets frequency to 14925hz
  Timer1.pwm(9, 0); // sets pin 9 to duty cycle of 0%

}

void loop() {

for (int i=0; i < 28; i++) {

  delay(898636UL); // motor A off for 15 minutes less 1.364 seconds
  digitalWrite(13, HIGH); // control motor A spins clockwise
  Timer1.setPwmDuty(9, 246); // sets duty cycle to 24% of max of 1023
  delay(1364); // rotate at 24 percent power 1.364 seconds in clockwise direction
  Timer1.setPwmDuty(9, 0); // sets duty cycle to 0% or off

  }

  // change direction to reset to east facing
  delay(61161814UL); // motor A off for 17 hours less east rotation
  digitalWrite(13, LOW);  // control motor A spins anti-clockwise
  Timer1.setPwmDuty(9, 246); // sets duty cycle to 24% of max of 1023
  delay(38186UL); // rotate at 24 percent power 38.186842 seconds in anti-clockwise direction
  Timer1.setPwmDuty(9, 0); // sets duty cycle to 0% or off
  
  }

This version is using Timer one.h library and millis() and delay() functions:

#include <TimerOne.h>
unsigned long rotateStartMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long rotatePeriod = 898636;  //15 minutes less 1.364 seconds
byte numRepeats = 0;
byte maxRepeats = 28;

void setup()
{
  Serial.begin(115200);  //start Serial in case we need to print debugging info
  rotateStartMillis = millis();  //initial start time

  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);
  Timer1.initialize(67); //sets frequency to 14925hz
  Timer1.pwm(9, 0); //sets pin 9 to duty cycle of 0% or off

}

void loop()
{
  currentMillis = millis();  //get the current time
  
  if (numRepeats == 28)
  {
    byte newRepeats = 28-numRepeats;
    numRepeats=newRepeats;
  }

  if (numRepeats < maxRepeats)
  {
      if (currentMillis - rotateStartMillis >= rotatePeriod)  //test whether the period has elapsed
  {

  digitalWrite(13, HIGH); //control motor A spins clockwise
  Timer1.setPwmDuty(9, 246); //sets duty cycle to 24% of max of 1023
  delay(1364); //rotate at 24 percent power 1.364 seconds in clockwise direction
  Timer1.setPwmDuty(9, 0); //sets duty cycle to 0% or off

    numRepeats ++;

    rotateStartMillis = millis();  //resets start time
  }
  }

  // change direction to reset to east facing
  if (numRepeats == 28)
  {
    delay(61161814UL); //motor A off for 17 hours less east rotation
    digitalWrite(13, LOW);  //control motor A spins counter-clockwise
    Timer1.setPwmDuty(9, 246); //sets duty cycle to 24% of max of 1023
    delay(38186UL); //rotate at 24 percent power 38.186842 seconds in counter-clockwise direction
    Timer1.setPwmDuty(9, 0); //sets duty cycle to 0% or off
    rotateStartMillis = millis();  //resets start time
  }
}

This version is not using the TimerOne.h library and just modifying the TCCR1A and TCCR1B,etc and using delay() functions only and still using the two const byte definitions because I haven't gotten around to eliminating them: everything good?

const byte PWM_PIN  =9; // The Arduino UNO R3 pin connected to the PWM pin Cytron MD10C
const byte DIR_PIN  =13; // The Arduino UNO R3 pin connected to the DIR pin Cytron MD10C

void setup() {

  TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);     // Set fast PWM and prescaler of 8 on timer 1
  ICR1 = 1066;                                     // Set the PWM frequency to 15Khz: 16MHz/15000 = 1066
  OCR1A = 0;  // Set the duty-cycle to off

  pinMode(PWM_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);

}

void loop() {

for (int i=0; i < 28; i++) {

  delay(898636UL); // motor A off for 15 minutes less 1.364 seconds
  digitalWrite(DIR_PIN, HIGH); // control motor A spins clockwise
  OCR1A = 256;  // Set the duty-cycle to 24% power
  delay(1364); // rotate at 24 percent power 1.364 seconds in clockwise direction
  OCR1A = 0;  // Set the duty-cycle to off
  
  }

  // change direction to reset to east facing
  delay(61161814UL); // motor A off for 17 hours less east rotation
  digitalWrite(DIR_PIN, LOW);  // control motor A spins anti-clockwise
  OCR1A = 256;  // Set the duty-cycle to 24% power
  delay(38186UL); // rotate at 24 percent power 38.186842 seconds in anti-clockwise direction
  OCR1A = 0;  // Set the duty-cycle to off
  
  }

Why not test the codes for proper operation, rather than asking people to guess what might happen?

Issue I have is the motor I am using is high torque and need it to be at 24% power otherwise it creates so much havoc on my 200lb solar array. To the point it almost rips the mounts off and strips the chain. I've tried many other versions of the code and keep getting the frequency close, but the duty cycle either too low or way too high.

Tweaking the code won't fix electromechanical/hardware design problems with your solar tracker.

If you want help with that, post the details on the motor and motor controller.

Really my main goal is to make sure with the codes I have submitted that the frequency is correct and duty cycle is correct. I just felt posting the whole code might help. You are correct though, I know the delay() and millis() functions work exactly as written, just need help with the frequency and duty cycle.

The correct choices for PWM frequency and duty cycle depend on the motor, the motor controller and the motor power supply and have to be determined by experiment. Forum members can't help without the details for those parts.

In the original post I mentioned I'm using the Cytron MD10C motor driver. I did fail to mention that I'm using a 12v wiper motor. I had initially used a DC speed controller that I had set at 24% power and it puts out a PWM frequency of 15,000 HZ. I would like to make sure I match that setup. All I need is to be able to put out a PWM frequency of 15KHZ and a duty cycle of 24%.

Use an oscilloscope to verify PWM frequency and duty cycle.

So basically you are saying is that by looking at the code(s) I provided; you are unable to determine the PWM frequency from Timer1 nor the duty cycle?

Sorry, I have no interest in looking at untested code.

If you do get around to testing it and find that it doesn't do what it should, post the details and people might be willing to help.

Have fun!

I did just update my post to clarify that I only need feedback on the sections of code that have to do with PWM frequency and duty cycle. Additional feedback is appreciated but the main focus of my post is to make sure I'm getting as close to 15khz PWM frequency and 24% duty cycle. Thanks all.

Power to your motor is ONLY based on the pulse width, NOT the frequency. When the pulse is high then power is applied to the motor. When pulse is low there is no power applied. When the time of the high pulse is equal to the time of the low, then 50% power is applied. Changing those ratios will change the power to your motor. That is how PWM works.

Ok. I originally had Arduino send power to the controller which we all know Pin 9 puts a out a PWM frequency of around 500hz. That created motor whine which is not good. I need a PWM frequency of 15khz to maximize my motors current. I understand the difference between duty cycle and pulse width. I need to know if my code for Timer1 is correct at outputting just under 15khz.

That will create a huge reactance from your motor windings. Are you sure you can force any power to the motor at that frequency?

Yes. Perhaps I need to update my original post. It's a 12v wiper motor. I was running it off a DC speed controller outputting 15khz which is spot on for the motor. I then ran the speed controller at 24% speed. Which typically lowers the duty cycle. I'm just trying to match that as close as possible.

Hi, @p4cosmic
Sorry I had to spread your post out.

Spreading out your text and in some sort of point from, makes it easier to read and more forum members will take the time to read it.

Tom.... :smiley: :+1: :coffee: :australia:
PS. Always read back your posts before sending and see how it flows.

LOL. Thank you. I'll edit the post.

That is highly misleading. High frequency PWM is often less effective for the reason you stated in your next post, and you can't have it both ways.

That will create a huge reactance from your motor windings. Are you sure you can force any power to the motor at that frequency?

Power "to" is irrelevant. Power "transferred" is the goal, among other considerations, and frequency is relevant.

Trial and error, or careful measurements of the motor parameters and informed engineering are required to determine the most effective PWM characteristics for a given motor and intended operating regime.

Let me apologize to yourself and everyone I may have gotten a bit krass with. It's been a couple decades since I've been on a forum and I just need to have patience and take everything with a grain of salt. I had assumed someone would look at my code regarding the frequency and duty cycle I was presenting and say yes that works the way you wrote it or that I'm way off and here's the best solution or present some insight into why my timer1 coding is or isn't working; however, not everyone thinks like me. I'm very linear in my thinking. A straight to B. Thanks again.

It seems OK to me when I drop it into this simulation:

... and move the wires around a bit, shorten the delays to something not too boring, and adjust the scope sampling time down to 10us: