DIY Function Generator

Moderators: mdrjr, odroid

DIY Function Generator

Unread postby odroid » Tue May 19, 2015 11:37 am

We need a function generator to test the GPIO interrupt driver on the C1.
So I made a retangular wave form generatror with the ODUINO.

It supports below frequencies.
100Hz
200Hz
400Hz
1KHz
2KHz
3KHz
4KHz
10KHz
100KHz
500KHz

Up / Down keys can adjust the frequencies.
The pulse output is available on Pin-10.

This Arduuino code is very dirty and there is no optimization.
Code: Select all
#include <LiquidCrystal.h>
/*******************************************************
 * This program will test the LCD panel, the buttons
 * and the retangular wave output on Pin10
 * Version : 0.1
 * Date : 5-May-2015
 * By Hardkernel
 ********************************************************/
// Global variables
unsigned long elapsed_time;
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

//unsigned long duty1,duty2;
// Duty Cycle in terms of a percentage.
//unsigned long plus;
// Value read from A1, in case plus mode is activated
float xxx;
// Float numbers to calculate duty for PWM 1 and PWM 2
float yyy;
unsigned long pwm1, pwm2; // PWM duty cycle output in terms // of 0-5V

unsigned char old_freq=1;
unsigned char new_freq=0;

unsigned int freq_table[10] = {
  10000,// 100Hz
  5000, // 200Hz
  2500, // 400Hz
  1000, // 1000Hz
  500,  // 2000Hz
  333,  // 3000Hz
  250,  // 4000Hz
  100,  // 10000Hz
  10,   // 100000Hz
  2     // 500000Hz 
};

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;   
  return btnNONE;  // when all others fail, return this...
}

void setup()
{
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);
  lcd.begin(16, 2);              // start the LCD library

  elapsed_time = millis()/1000; // Returns the number of milliseconds since the Arduino board began running the current program.

  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);  // Real output for the function generator
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) ; // phase and frequency correct mode. NON-inverted mode
  // TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(COM1A0) | _BV(COM1B0) ;
  //phase/frequency correct mode. SELECT THIS FOR INVERTED OUTPUTS.
  TCCR1B = _BV(WGM13) | _BV(CS11);
  // Select mode 8 and select divide by 8 on main clock. 
}

void loop()
{
  lcd.setCursor(0,1);            // move to the begining of the second line     
  lcd.print("KEY :");     
  lcd.setCursor(6,1);            // move to the begining of the second line
  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnRIGHT:
    {
      lcd.print("RIGHT ");
      Serial.println("RIGHT ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("LEFT   ");
      Serial.println("LEFT ");     
      break;
    }
  case btnUP:
    {
      lcd.print("UP    ");
      Serial.println("UP ");
      if(new_freq<9)      new_freq++;
      break;
    }
  case btnDOWN:
    {
      lcd.print("DOWN  ");
      Serial.println("DOWN ");
      if(new_freq>0)     new_freq--;
      break;
    }
  case btnSELECT:
    {
      lcd.print("SELECT");
      Serial.println("SELECT ");     
      break;
    }
  case btnNONE:
    {
      lcd.print("NONE  ");
      break;
    }
  }
 
  delay(200); // delay 200 msec.

  if(old_freq != new_freq)
  {
    ICR1 = freq_table[new_freq];
    old_freq = new_freq;

    pwm1 = 512; // 50:50
    pwm2 = 512; // 50:50
    xxx = float(pwm2);
    // Turn read values from the POTs to float for mathematical
    // adjustment.
    yyy = float(pwm1);
    xxx = xxx * ICR1;
    // Multiply with ICR1 and divide by 1023 to give required percentage
    yyy = yyy * ICR1;
    xxx = xxx / 1023;
    yyy = yyy / 1023;
    //Assign values to OCR Registers, which output the PWM duty cycle.
    OCR1B = int(xxx);
    OCR1A = int(yyy);
   
    lcd.setCursor(0,0);            // move cursor to second line "1" and 9 spaces over
    lcd.print("Freq: ");
    lcd.print((double)(1000.0/(double)(ICR1)));
    lcd.print(" KHz   ");
   
  }
}


I refered this document and it was quite helpful.
https://sites.google.com/site/scidiy/di ... quency-pwm


Note that the Pin-10 is also connected to the back-light driver.
So I must cut the pin-10 of header on the LCD shield.
User avatar
odroid
Site Admin
 
Posts: 28863
Joined: Fri Feb 22, 2013 11:14 pm
languages_spoken: English
ODROIDs: ODROID

Return to ODUINO One

Who is online

Users browsing this forum: No registered users and 1 guest