Not "linear" pwm output value from arduino nano clone.

Hello to the community. This is my first post in this forum. I’m a newbie with electronics,too. If my post is in the wrong category(i was between this and ProjectGuidance), please move it to the appropriate one. :slight_smile:

I like rc things and i m trying to revive an old really cheap rc plane i bought. I am using an arduino nano clone(banggood) for the project to do 4 things : a)monitor lipo's voltage b)turn on a couple of status leds c)read 2 channels of a 2.4GHZ rc receiver d)output a pwm value related to the throttle input of the receiver to control the plane’s dc motor(using mosfet). So to my problem.

When the program runs and i m trying to control the dc motor, the pwm value is not “linear”. I don’t have an oscilloscope. I connected a multimeter on the output pin and the voltage(pwm value) is not stable. It goes up and down 0.3v - 0.4v. Like it’s trying to output the value and it doesn’t have the strength to do so. So the motor works with strong oscillations. Same with the led. The board cannot turn it on fully. Only to dim it. The board can detect the voltage of the lipo just fine and it’s reading the pulse from the rc receiver, so those parts are ok.

The program runs fine in an original Uno i have. The board is powered with ~7volts from a LM317 regulator which i think is fine. My simple code is below. Do you have any suggestions or ideas ? Why these clones have a so bad performance and all the time issues?

// Based on the 'YMFC-3D_receiver' code, written by Joop Brokking

//Declaring Variables
byte last_channel_1, last_channel_2;
int THROTTLE, GEAR;
unsigned long timer_1, timer_2;
int mosfetGate = 5;
int pwmValue = 0;

float Vs = 0.0;
int statusLed1 = 7;
bool armed = 0; 

int counter = 0;
float vsum = 0.0;
unsigned long REFRESH = 250000;  // It's in micros() -> 250 millis
unsigned long lastRefreshTime = 0;


//////////////////////// Setup routine ///////////////////
void setup() {
  Serial.begin(19200);

  analogReference(EXTERNAL);

  pinMode(statusLed1, OUTPUT);
  pinMode(mosfetGate, OUTPUT);
  
  PORTD = B00000000;    //set all the portD pins low to prevent floating values
  PORTB = B00000000;    //set all the portB pins low to prevent floating values

  //Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs
  PCICR |= (1 << PCIE2);    // set PCIE2 to enable PCMSK2 scan

  PCMSK2 |= (1 << PCINT18);  // set PCINT18 (digital input 2) to trigger an interrupt on state change
  PCMSK2 |= (1 << PCINT19);  // set PCINT19 (digital input 3)to trigger an interrupt on state change

  while (GEAR < 1500){
    counter++;
    
    if(counter == 125){
      digitalWrite(statusLed1, !digitalRead(statusLed1));
      counter = 0;
    }
    delay(2);   // Delay 2 milliseconds before the next loop in order for the "blinking" to work
  }

  armed = 1;  // Arm the receiver and it's ready to fly
  Vs = analogRead(A4) * 0.01354 ;
  digitalWrite(statusLed1, LOW);
  counter = 0;
}

//////////////////////////Main program loop///////////////////////////////
void loop() {

  if(GEAR < 1500){
    armed = 0;
    pwmValue = 0;
    analogWrite(mosfetGate, 0);
  }
  else armed = 1;

  if(armed == 1){
    pwmValue = map(THROTTLE, 1000, 2020, 1, 255);
    if(pwmValue < 0) pwmValue = 0;
    if(pwmValue > 255) pwmValue = 255;
    analogWrite(mosfetGate, pwmValue);
  }

  // Complementary filter used to reduse noise.
  Vs = Vs * 0.6 + (analogRead(A4) * 0.01354) * 0.4;
  vsum = vsum + Vs;
  counter++;

  if(micros() - lastRefreshTime >= REFRESH){
    
    lastRefreshTime = lastRefreshTime + REFRESH;
    Serial.print(vsum / counter);
    Serial.print("\t");
    Serial.print(counter);
    Serial.print("\t");
    Serial.println(vsum);

    counter = 0;
    vsum = 0.0;
  }
  
}

//This routine is called every time input 2 or 3 changed state
ISR(PCINT2_vect) {
  //Channel 1===========PIN2=========Throttle==============================
  if (PIND & B00000100) {                               // Is input 2 high ?
    if (last_channel_1 == 0) {                          //Input 2 changed from 0 to 1
      last_channel_1 = 1;                                 //Remember current input state
      timer_1 = micros();                                 //Set timer_1 to micros()
    }
  }
  else if (last_channel_1 == 1) {                       //Input 2 changed from 1 to 0
    last_channel_1 = 0;                                 //Remember current input state
    THROTTLE = micros() - timer_1;                      //Channel 1 is micros() - timer_1
  }
  //Channel 2===========PIN3=========Gear switch (arm)=====================
  if (PIND & B00001000) {                               // Is input 3 high ?
    if (last_channel_2 == 0) {                          //Input 3 changed from 0 to 1
      last_channel_2 = 1;                                 //Remember current input state
      timer_2 = micros();                                 //Set timer_2 to micros()
    }
  }
  else if (last_channel_2 == 1) {                       //Input 3 changed from 1 to 0
    last_channel_2 = 0;                                 //Remember current input state
    GEAR = micros() - timer_2;                          //Channel 2 is micros() - timer_2
  }
  
}
// Function for displaying the receiver signals
// If needed for debugging
void print_signals() {
  Serial.print("Throttle:");
  Serial.print(THROTTLE);

  Serial.print("\t");
  Serial.print(pwmValue);
  Serial.print("\t");

  Serial.print("  Gear sw:");
  Serial.println(GEAR);
}

I bet you are using a digital multimeter instead of an analog multimeter. Don't you realize the digital meter is a sampling device and when you sample a square wave sometimes the sample will mot be insync with the square wave, so will get varying values.

You really need an oscilloscope if you are working with PWM stuff.

Paul

Hi,
Welcome to the Forum.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Please include power supplies and the RC receiver.

Have you got suitable capacitors close to t he LM317 to help with stability?

Thanks.. Tom.. :slight_smile:

Thank you for your replies.

@Paul_KD7HB
I know i need an oscilloscope. That's why i wrote that i don't have one.

@TomGeorge
I wil draw one, maybe in Fritzing, and will post it. No i don't use capacitors near the LM317 cuz i thought that the nano has already another regulator onboard and don't need them. I use capacitors only on a 7805 that i use to provide the external analog reference.
I will post the circuit the moment i will finish it.

Hi,
Please please do not use Fritzy unless you can label and number pinouts and label component part numbers.

A pen/pencil and paper, and a camera can do lots better.

If you want a simple CAD try ExpressPCB;
https://www.expresspcb.com/free-cad-software/

It downloads easy, it has no hang on programs or special offers as you download or install.

Tom... :slight_smile:

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Please include power supplies and the RC receiver.

The schematic is the attached one.
The rc receiver can be powered either form the LM317 or the 7805 regulator. That's why it's not connected anywhere.

C3 cap is there for filtering and cleaner lipo voltage values.

Also the led can be placed in any pin.This isn't my priority.

schem_schem.pdf (771 KB)

Microprocessors are not some device that can simply be used in a normal analogue, real world application. we need to consider the real world needs, and then with additional components interface the microprocessor to the real world. just connecting a mosfet to an output pin of a micro without additional components that should be used with the mosfet is going to give unreliable results.

Generally, I would not use an arduino for non trivial PWM projects.

DO NOT connect an external power supply to the Aref pin, unless you are SURE Aref is always <= than the 5volt supply of the Nano. That includes during bootup and shutdown.
You might already have damaged the internal Aref switch.
I doubt an external 5volt supply would be better than the default 5volt Aref.
If you want a better/stable Aref for voltage measurements, then use the internal 1.1volt Aref.

Change the 1k8:1k divider into a ~12k:1k divider, remove that 7805, and set the Aref to INTERNAL.
Leo..

Hi;
OPs circuit.


Tom.. :slight_smile:

The most "not linear" component will be your motor. If you want to control its speed (rpm) you need according feedback, e.g. from a rotary encoder.