Hi. I am in the process of assembling my first project with Arduino. It is a digital flip-flop mosfet pulse generator with a frequency counter. I am using 4046 PLL IC (a Voltage Controlled Oscillator) as a clocking input for Arduino, triggering a hardware interrupt to generate a precise pulse of 1 to 500 us of duration and frequency in 0 up to 30 kHz range. As of now it is controlled with one analog pot and 3 buttons. The value from the pot is used to set 2 digital potentiometers (MCP41010 and MCP41050) controlling the 4046 IC frequency and range for finetunning and pulse width as well. Output from VCO is going to pin nr 2 (triggering a hardware interrupt) and to pin 5 for hardware measuring of number of pulses from VCO to determine the frequency by checking the counter every second using a software interrupt. Output goes directly to a dual mosfet driver (ILC7667) and then to logic level mosfets (5V gate drive). Hope my code helps. Greetings from Poland...
#include <LiquidCrystal.h>
#include <MsTimer2.h>
// Initialize the library with the numbers of the interface pins
LiquidCrystal lcd(0, 1, 3, 4, 6, 7); // LiquidCrystal lcd(rs, enable, d4, d5, d6, d7);
volatile boolean fetToggle = false; // mosfet flip flop flag , a varible changed from within the interrupt function
unsigned int count;
unsigned int pulses;
unsigned long duration = 0; //
unsigned int frequency = 0; // frequency of operation
unsigned int pulseWidth = 0; // initial minimal value
unsigned int pulseTime = 0; // duration of a single pulse in microseconds
unsigned long past = 0;
const int period = 1000; // timer interrupt set to 1 second
int bL; // states of buttons connected to analog inputs
int bM;
int bR;
const int abLPin = 3; // analog input pin numbers for 3 buttons
const int abMPin = 4;
const int abRPin = 5;
const int analogPot0 = 0; // analog input pin number for pot
int plsValue = 0;
int frqValue = 127;
int rngValue = 127;
const int ftAPin = 9; // OUTPUT: mosfet driver pin
const int ftBPin = 10; // OUTPUT: mosfet driver pin
const int intPin = 2; // interrupt enabled input pin triggered with VCO 4046 OUTPUT
const int plsPin = 5; // pin cannot be changed - using hardware counter on pin 5
const int frqPin = 8; // 10k digital pot VCO frequency controlling pin (CS)
const int rngPin = 11; // 50k digital pot VCO range controlling pin (CS)
const int clkPin = 12; // SPI clock pin (SCK)
const int spiPin = 13; // SPI data pin (SI)
const byte cmd_Write = B00010001; // Binary values for sending WRITE command to single IC pot
///////////////////////// INITIALISATION /////////////////////////
void setup() {
pinMode(ftAPin, OUTPUT);
pinMode(ftBPin, OUTPUT);
digitalWrite(ftAPin, HIGH); // set pins to HIGH because of inverting mosfet driver
digitalWrite(ftBPin, HIGH);
pinMode(frqPin, OUTPUT);
digitalWrite(frqPin, HIGH); // puts digital pot on hold
pinMode(rngPin, OUTPUT);
digitalWrite(rngPin, HIGH); // puts digital pot on hold
spi_out(frqPin, cmd_Write, 127); // set default values
spi_out(rngPin, cmd_Write, 127);
pinMode(clkPin, OUTPUT);
pinMode(spiPin, OUTPUT);
pinMode(intPin, INPUT); // interrupting input from VCO
pinMode(plsPin, INPUT); // input from VCO
digitalWrite(plsPin, HIGH); // hardware counter setup for counting input pulses
lcd.begin(16, 2); // Set the display to 16 columns and 2 rows
lcd.clear(); // Clears the LCD display
lcd.setCursor(0, 0);
lcd.print("R( )");
lcd.setCursor(2, 0);
lcd.print(rngValue);
lcd.setCursor(7, 0);
lcd.print("P: us");
lcd.setCursor(10, 0);
lcd.print(pulseWidth + 1);
lcd.setCursor(0, 1);
lcd.print("F( )");
lcd.setCursor(2, 1);
lcd.print(frqValue);
lcd.setCursor(7, 1);
lcd.print(" Hz");
lcd.setCursor(7, 1);
lcd.print(frequency);
// timer2 used to measure pulses to determine frequency
MsTimer2::set(period, update);
MsTimer2::start();
// reset timer/counter control register & starting the clock counting pulses from pin 5 input
TCCR1A=0;
getCount();
// running analog pot input with high speed clock (set prescale to 16)
bitClear(ADCSRA,ADPS0);
bitClear(ADCSRA,ADPS1);
bitSet(ADCSRA,ADPS2);
// enables INT0 interrupt on Pin 2 input to execute mosfet turn ON/OFF cycle
attachInterrupt(0, trigger, CHANGE);
}
/////////////////////////// MAIN LOOP ///////////////////////////
void loop() {
// button state reading
bL = analogRead(abLPin);
bM = analogRead(abMPin);
bR = analogRead(abRPin);
// frequency range setting
if (bL >= 1000) {
rngValue = analogRead(analogPot0) / 4;
spi_out(rngPin, cmd_Write, rngValue);
lcd.setCursor(0, 0);
lcd.print("R( )");
lcd.setCursor(2, 0);
lcd.print(rngValue);
}
// pulse width setting
if (bM >= 1000) {
plsValue = analogRead(analogPot0);
if (plsValue >= pulseTime) {
pulseWidth = (pulseTime / 2) - 1;
}
else {
pulseWidth = plsValue / 2;
}
lcd.setCursor(7, 0);
lcd.print("P: us");
lcd.setCursor(10, 0);
lcd.print(pulseWidth + 1); // 1 us is the minimal pulse value at 0 setting
}
// frequency setting
if (bR >= 1000) {
frqValue = analogRead(analogPot0) / 4;
spi_out(frqPin, cmd_Write, frqValue);
lcd.setCursor(0, 1);
lcd.print("F( )");
lcd.setCursor(2, 1);
lcd.print(frqValue);
}
// Display actual frequency on LCD every second
if ((millis() - past) >= 1000) {
pulseTime = (1000000 / frequency);
lcd.setCursor(7, 1);
lcd.print(" Hz");
lcd.setCursor(7, 1);
lcd.print(frequency);
past = millis();
}
delay(100);
} ////////////////////// End of the MAIN LOOP //////////////////////
// flip-flop mosfet pulsing, routine executed on interrupt 0 triggered by VCO output
void trigger() {
if (fetToggle) {
bitClear(PORTB, ftAPin - 8); // quickly pulse channel A directly using hardware registers
if (pulseWidth != 0) {
for (int i=1; i <= pulseWidth; i++) {
bitClear(PORTB, ftAPin - 8);
bitClear(PORTB, ftAPin - 8);
}
}
bitSet(PORTB, ftAPin - 8);
fetToggle = false;
}
else {
bitClear(PORTB, ftBPin - 8); // quickly pulse channel B directly using hardware registers
if (pulseWidth != 0) {
for (int i=1; i <= pulseWidth; i++) {
bitClear(PORTB, ftBPin - 8);
bitClear(PORTB, ftBPin - 8);
}
}
bitSet(PORTB, ftBPin - 8);
fetToggle = true;
}
}
// executed every second with a timer interrupt for accuracy of frequency measurement
void update() {
frequency = getCount(); // frequency measurement by pulse counting
}
// returns the current count of pulses from pin 5, resets the count, and starts counting again
unsigned long getCount() {
TCCR1B = 0; // Gate Off / Counter Tn stopped
count = TCNT1;
TCNT1 = 0;
bitSet(TCCR1B ,CS12); // Counter Clock source is external pin
bitSet(TCCR1B ,CS11); // Clock on rising edge
bitSet(TCCR1B ,CS10); // you can clear this bit for falling edge
return count;
}
// tranfers analog pot setting values to digital pot via bit banging technique
void spi_out(int CS, byte cmd_byte, byte data_byte) {
digitalWrite(CS, LOW); // Set the passed ChipSelect pin to low to start programming
spi_transfer(cmd_byte); // Send the passed COMMAND BYTE
delay(2);
spi_transfer(data_byte); // Send the passed DATA BYTE
delay(2);
digitalWrite(CS, HIGH); // Set the passed ChipSelect pin to high to end programming
}
// bit banging technique
void spi_transfer(byte working) {
for (int i = 1; i <= 8; i++) { // Set up a loop of 8 iterations (8 bits in a byte)
if (working > 127) {
digitalWrite (spiPin, HIGH); // If the MSB is a 1 then set MOSI high
}
else {
digitalWrite (spiPin, LOW); // If the MSB is a 0 then set MOSI low
}
digitalWrite(clkPin, HIGH); // Pulse the CLKdpot high
working = working <<= 1 ; // Bit-shift the working byte
digitalWrite(clkPin, LOW); // Pulse the CLKdpot low
}
}