I'm trying to make a HIL simulator using 2 arduinos (later 2 arduinos and a raspberry pi).
The arduino UNO will be simulating the motor and encoder. I'd like to have it generate 2 square signals of varying frequency for testing and for the two signals to have a phase difference of either +90 or -90 (changeable in the code) to simulate both directions.
The arduino Nano would be on the receiving end to calculate the number of pulses and later on the RPM. Same will be done for the raspberry pi after I make sure the code is running and everything is good.
Now for my codes, I'm having issues.
I found one program that does something similar to what I'm looking for, but I couldn't adapt it to suit my needs. And then I found another that should be doing exactly what I want but it's not working for me.
// This code demonstrates how to generate two output signals
// with variable phase shift between them using an AVR Timer
// The output shows up on Arduino pin 9, 10
// More AVR Timer Tricks at http://josh.com
void setup() {
pinMode( 9 , OUTPUT ); // Arduino Pin 9 = OCR1A
pinMode( 10 , OUTPUT ); // Arduino Pin 10 = OCR1B
// Both outputs in toggle mode
TCCR1A = _BV( COM1A0 ) |_BV( COM1B0 );
// CTC Waveform Generation Mode
// TOP=ICR1
// Note clock is left off for now
TCCR1B = _BV( WGM13) | _BV( WGM12);
OCR1A = 0; // First output is the base, it always toggles at 0
}
// prescaler of 1 will get us 8MHz - 488Hz
// User a higher prescaler for lower freqncies
#define PRESCALER 1
#define PRESCALER_BITS 0x01
#define CLK 16000000UL // Default clock speed is 16MHz on Arduino Uno
// Output phase shifted wave forms on Arduino Pins 9 & 10
// freq = freqnecy in Hertz ( 122 < freq <8000000 )
// shift = phase shift in degrees ( 0 <= shift < 180 )
// Do do shifts 180-360 degrees, you could invert the OCR1B by doing an extra toggle using FOC
/// Note phase shifts will be rounded down to the next neared possible value so the higher the frequency, the less phase shift resolution you get. At 8Mhz, you can only have 0 or 180 degrees because there are only 2 clock ticks per cycle.
int setWaveforms( unsigned long freq , int shift ) {
// This assumes prescaler = 1. For lower freqnecies, use a larger prescaler.
unsigned long clocks_per_toggle = (CLK / freq) / 2; // /2 becuase it takes 2 toggles to make a full wave
ICR1 = clocks_per_toggle;
unsigned long offset_clocks = (clocks_per_toggle * shift) / 180UL; // Do mult first to save precision
OCR1B= offset_clocks;
// Turn on timer now if is was not already on
// Clock source = clkio/1 (no prescaling)
// Note: you could use a prescaller here for lower freqnencies
TCCR1B |= _BV( CS10 );
}
// Demo by cycling through some phase shifts at 50Khz
void loop() {
setWaveforms( 50000 , 0 );
delay(1000);
setWaveforms( 50000 , 90 );
delay(1000);
setWaveforms( 50000 , 180 );
delay(1000);
}
I'm getting the correct 50k Hz on the multimeter and I'm getting around 96603 on the nano. It's suppose to be 100,000 (2*50K). Not sure why some fell off, but I guess overhead? I'll write the code for the nano below here. I'm also getting the right 1MHz on proteus for some reason. My issue with this code right now is how to get the -90 and +90 phase difference. How to have change, say, every 5 seconds with a few second pauses.
Nano receiving code: (My post) (Original post)
unsigned long start;
const byte encoderPinA = 3;//A pin -> interrupt pin 0
const byte encoderPinB = 5;//B pin -> digital pin 4
volatile long pulse;
volatile bool pinB, pinA, dir;
const byte ppr = 12, upDatesPerSec = 2;
const int fin = 1000 / upDatesPerSec;
const float konstant = 60.0 * upDatesPerSec / (ppr * 2);
int rpm;
void setup() {
Serial.begin(9600);
pinMode(encoderPinA,INPUT);
pinMode(encoderPinB,INPUT);
attachInterrupt(1, readEncoder, CHANGE);
}
void loop() {
if(millis() - start > fin)
{
static long pulseCopy;
noInterrupts();
pulseCopy = pulse;
interrupts();
start = millis();
rpm = pulse * konstant;
//Serial.println(rpm);
Serial.println("Pulse value: "); Serial.print(pulse);
//pulse = 0;
}
}
void readEncoder()
{
pinA = bitRead(PIND,encoderPinA);
pinB = bitRead(PIND,encoderPinB);
dir = pinA ^ pinB; // if pinA & pinB are the same
dir ? --pulse : ++pulse; // dir is CW, else CCW
}
From the outside this is suppose to be what I'm looking for, but I'm having so much issues with the timer here.
By default it is set to prescaler: 8 and ICR1 set to 199. First off I'm confused by the prescaler and the ICR1. Prescaler set to 8 gives us 0.5 us which is 2000KHz, but then divided by 200. Gives us 10K period, so arduino nano should read 20k/second. However, it's receiving 5K Hz on the multimeter and 100Khz on proteus. On the nano, I'm only getting 10k and not 20K. I'm not sure why. I'm not sure why all the differences.
I changed the loop function to this
void loop () {
if (millis() >= 1000 && millis()<2000)
{
OCR1A = ICR1 - 1; //two different pulse widths almost 100% duty cycle
OCR1B = OCR1A / 2; //offset by half period
TCCR1B |= _BV(CS11);//start timer
} else{
TCCR1B &= ~(_BV(CS11));//stop timer
//TCCR1B = 0;
}
if (millis() - prevDisplay >= interval)
{
prevDisplay += interval;
noInterrupts();
long copyEncoderCount = encoderCount;
encoderCount = 0;
long copyErrorCount = errorCount;
errorCount = 0;
interrupts();
Serial.print(copyEncoderCount);
Serial.print('\t');
Serial.println(copyErrorCount);
}
}
When I tried changing the prescaler, it worked the first time, but second time it wouldn't work. Should I just add "|_BV(CS10)"
Any help would be appreciated. Thanks!