Good day,
I've been attempting to simulate an AC motor position encoder with an adjustable PWM signal. For the time being I am testing code on an UNO board but eventually I will be moving to a stand alone IC, likely ATTINY44.
The goal is to produce two identical PWM signals with adjustable frequency and a +/-90 (or 90 and 270) degree offset @ 50% duty cycle. I have had success at producing the two waveforms with a pot adjusted frequency with the offset. However, the issue I am running into now is producing the 270 (or -90) degree offset. While this can easily be done with a multiple-pole switch I would like to embed as much functionality into the software as possible as I would eventually like to install it into an automated system.
What I am working for is two digital inputs control the phase shift. For example using PWM-A as the base signal activating input 1 should shift PWM-B 90 deg out of phase while input 2 should shift it 270 (or -90). While no input is active all signals should be shut down. This will simulated the motor rotational direction (Forward, Reverse, Stationary)
Below is a code I found online to produce the offset waveform that I have then modified a bit. The potentiometer input works just fine so moving past that I set a fixed value for the frequency and put a delay to monitor the FWD and REV directions on the scope. It seems to work ok-ish but it seems very clunky and like more of a brute-force method. Is there a more practical approach to switching this phase shift around?
int rawpot = A0; // pot input
int fpot = 0; //raw pot value
int potfreq = 0; //pot value scaled to Hz
int DIRin = 2; //Direction input Pin 2
int DIR = 0; //Stored State of Direction Input
void setup() {
pinMode( 9 , OUTPUT ); // Arduino Pin 9 = OCR1A
pinMode( 10 , OUTPUT ); // Arduino Pin 10 = OCR1B
pinMode( DIRin , INPUT ); // Arduino Pin 2 = Direction Input
}
// 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
int setFWD( unsigned long freq , int shift ) {
// Both outputs in toggle mode
TCCR1A = _BV( COM1A0 ) |_BV( COM1B0 );
TCCR1B = _BV( WGM13 ) |_BV( WGM12 );
OCR1A = 0; // First output is the base, it always toggles at 0
// This assumes prescaler = 1. For lower freqnecies, use a larger prescaler.
unsigned long FWDA = (CLK / freq) / 2; // /2 becuase it takes 2 toggles to make a full wave
ICR1 = FWDA;
unsigned long FWDB = (FWDA * shift) / 180UL; // Do mult first to save precision
OCR1B = FWDB;
TCCR1B |= _BV( CS10 );
}
int setREV( unsigned long freq , int shift ) {
// Both outputs in toggle mode
TCCR1A = _BV( WGM13 ) |_BV( WGM12 );
TCCR1B = _BV( COM1A0 ) |_BV( COM1B0 );
OCR1B = 0; // First output is the base, it always toggles at 0
// This assumes prescaler = 1. For lower freqnecies, use a larger prescaler.
unsigned long REVA = (CLK / freq) / 2; // /2 becuase it takes 2 toggles to make a full wave
ICR1 = REVA;
unsigned long REVB = (REVA * shift) / 180UL; // Do mult first to save precision
OCR1B = REVB;
TCCR1B |= _BV( CS10 );
}
void loop() {
DIR = digitalRead(DIRin);
fpot = analogRead(rawpot);
potfreq = (fpot*10);
setFWD ( 500 , 90 );
delay (3000);
setREV ( 500 , 90 );
delay (3000);
}