I'm working on a project requiring generating PWM for a ESC+ brushless DC motor and measuring speed from an encoder at the same time. I run the motor at rather high speed, appox. 9000RPM. The big problem is that the data i get from the encoder has too much unwanted noise. =(
I access Timer 1 directly to generate PWM on pin9. A part of my code is aimed to vary the PWM around a trim point. Please don't let you be confused with that one. It's just a part of my project requirements, and it has nothing to worry about.
To read the encoder, I use a pair of photocouples with one pin being attached to pin2 , to make an interrupt signal. micros() function is called to measure the time between every 3 successive rising edges being noticed at pin2.
I was afraid the interrupts messing up with each other, which result in those really sharp noise. But I can't figure out the reason why!
Hope someone can help! I tried to write comments as much as possible, but may not be able to avoid confusion. Sorry for i'm not a good programmer, just an aerospace student with weak background in both programming skills and electronics knowledge. But this code is a really important part in my project. I need this code to run my experiment.
Thanks for your help!
/***********************************************
This code measures angular rate response of step
input (pulse width), which is varied
periodically about trim (hovering) point.
OUTPUT: Period in every successive N cycles
(Unit: us)
***********************************************/
#include <avr/interrupt.h>
#include <Arduino.h>
#define OUTPUT_PIN 9// PWM pin (timer1)
#define PWM_PERIOD 20000//microsecond
#define PRESCALER 8
#define ENCODER_IN_PIN 2//PIN number of INT0 on the Arduino UNO
#define ENCODER_INT 0// INTO
#define NUMBER_OF_CYCLES 3// The value is updated after every ~ pulses
#define TRIM_POINT 2200//pulse width at hovering condition (from 2000 to 4000)
#define UNIT_ANGLE 36 //swept angle correspoding to 2 successive rising pulses (degree)
#define INTERVAL 3000//step signal duration (milisec)
#define DELTA 0// value of PWM around trimpoint
int outputPin = OUTPUT_PIN;
int inputPin = A0;
int i = 0;
int delta = DELTA;
double velocity;
unsigned int temp;
unsigned int time[500];// logging data into an array with 500 values
int a = 0;//array index var
volatile int x = 0;
volatile boolean NewSignal = true;
volatile boolean New_status = true;
volatile unsigned long StartPeriod;
volatile unsigned long StartInterval;
volatile unsigned long Period = 0;
void setup(){
attachInterrupt ( ENCODER_INT, calc, RISING );
//digitalWrite(ENCODER_IN_PIN, HIGH);
initPin (outputPin);
/*set prescaler=8, 0.5us/ticks => timeperiod=20ms, freq=50
mode14: FAST PWM, TOP= ICR1*/
TCCR1A = (1<<COM1A1)|(1<<WGM11);
TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11);
ICR1 = 40000; //set TOP value (ticks)
OCR1A = 2000;
Serial.begin(38400);
delay(3000);
OCR1A = TRIM_POINT;
}
void loop(){
temp = millis()-StartInterval;
//Serial.println(temp); //for debug purpose
// need two variables, one's to allow velocity to be updated(fast). Another to allow the OCR1A to vary!(slow)
if (temp >= INTERVAL){ //When an interval has been expired, change OCR1A value
if ((i%2) >0){
delta=(~delta) + 0x01;
}
OCR1A = OCR1A + delta;
StartInterval = millis();
i++;
//Serial.println(delta); //for debug purpose
}
while (New_status && NewSignal){ //Allow updating!
time[a] = Period;
a++;
New_status = false;
}
// after having recorded 500 values, stop the motor and send off the data.
if (a == 499){
for (a=0;a<500;a++){
Serial.println(time[a]);
}
OCR1A=2000;//stop the motor
}
}
//procedure to start the electronic speed controller
void initPin(int pin_number){
digitalWrite(pin_number, HIGH);
pinMode(pin_number, OUTPUT);
digitalWrite(pin_number, HIGH);
}
//calc calculates & returns the period after
//every NUMBER_OF_CYCLES successive cycles of Pulse.
void calc(){
if (NewSignal && !New_status){ //start new N cycles
StartPeriod = micros();
NewSignal = false;//to lock the main loop from updating while calculting new period is in process.<<<<<<
}
if (x==NUMBER_OF_CYCLES){
Period = (micros()-StartPeriod);//calculate period throughout N cycles
NewSignal = true;//to restart sampling the Start pivot
x=0;//reset counter
New_status = true;//let main loop calculate the velocity and send to the monitor after new period has been calculated.>>>>>
}
x++;
}
Here is the graph plotting angular rate (RPM) vs. time. The noise just goes upward in one direction. =(