#include <math.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include "Buttons.h"
Buttons Button1(A0, INPUT_PULLUP);
Buttons Button2(A1, INPUT_PULLUP);
Buttons Button3(A2, INPUT_PULLUP);
Buttons Button4(A3, INPUT_PULLUP);
long frequency = 1;
byte table[256];
word smp;
word wav;
int curs;
bool irq = true;
unsigned long timer;
void setup()
{
Serial.begin(38400);
lcd.init();
lcd.clear();
lcd.backlight();
DDRD |= B11110000;
DDRB |= B00001111;
cli(); //disable interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // set entire TCCR1B register to 0
OCR1A = int(16000000 / 1 / smp / frequency) - 1 ; //set compare match register ??khz to start
TCCR1B |= (1 << WGM12); //turn on CTC mode
TCCR1B |= (1 << CS10); // Set CS10 bit for 1 prescaler
TIMSK1 |= (0 << OCIE1A); // enable timer compare interrupt
pinMode(2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(2), button_interrupt_handler, FALLING);
sei(); //enable interrupts
// OCR1A: minimum = 255 (256-1) z.B (16000000 / (smp 1) / (frequency 62500)) -1 = 255
// OCR1A: maximum = 65535 (65536-1)
display(0);
}
ISR(TIMER1_COMPA_vect)
{
static int t = -1;
t++; if (t >= smp)
{
t = 0;
}
PORTD = table[t] << 4;
PORTB = table[t] >> 4;
analogWrite(3, table[t]);
}
void button_interrupt_handler()
{
irq = true; bitClear(TIMSK1, 1); timer = millis();
}
void loop()
{
if (irq)
{
buttons();
samples();
release();
}
}
void buttons()
{
static word incr = 1;
int i;
i = Button1.longpress0(50, 200);
if (i)
{
wav++;
;
if (wav > 3)
{
wav = 0;
}
display(1);
}
i = Button2.longpress0(50, 200);
if (i)
{
frequency -= incr;
;
if (frequency < 1)
{
frequency = 1;
}
display(2);
}
i = Button3.longpress0(50, 200);
if (i)
{
frequency += incr;
;
if (frequency > 62500)
{
frequency = 62500;
}
display(2);
}
i = Button4.longpress0(50, 200);
if (i)
{
curs++;
;
if (curs > 4)
{
curs = 0;
}
incr = round(pow(10, curs));
;
display(4);
}
}
void samples()
{
static word rate = 0;
if (frequency <= 16000000 / 65536)
{
smp = 256;
}
else
{
smp = 16000000.0 / float(frequency) / 256.0;
}
if (rate != smp)
{
rate = smp; display(3);
}
}
void release()
{
if (!digitalRead(2))
{
timer = millis();
}
else if (millis() - timer > 500)
{
Tabelle(); irq = false; OCR1A = int(16000000.0 / frequency / smp ) - 1; ; bitSet(TIMSK1, 1);
}
}
void Tabelle()
{
static int s = -1;
static int w = -1;
if (s == smp)
{
if (w == wav)
{
return;
}
}
s = smp;
w = wav;
int i;
int j = smp;
char q[99]; sprintf(q, "wav: %1d smp: %3d\n", wav, smp); Serial.print(q);
switch (wav)
{
case 0: //sinus
for (i = 0; i < j; i++)
{
table[i] = round(127.5 + 127.5 * sin(2 * M_PI * i / j));
}
break;
case 1: //triangle
for (i = 0; i < j; i++)
{
table[i] = round(127.5 + 255.0 * asin(sin(2 * M_PI * i / j)) / M_PI);
}
break;
case 2: //sawtooth
for (i = 0; i < j; i++)
{
// table[i] = round(127.5 + 255.0 * (atan(1 / tan((2 * M_PI * i / j) / 2 ))) / M_PI);
table[i] = round(127.5 + 255.0 * (atan( tan((2 * M_PI * i / j) / 2 ))) / M_PI);
}
break;
case 3: //square
for (i = 0; i < j; i++)
{
table[i] = 255 * (1 - round(float(i) / float(j)));
}
break;
}
}
void display(int q)
{
static char wavform[ 9];
static char display[17];
switch (wav)
{
case 0: snprintf(wavform, 9, "sinewave"); break;
case 1: snprintf(wavform, 9, "triangle"); break;
case 2: snprintf(wavform, 9, "sawtooth"); break;
case 3: snprintf(wavform, 9, "square.."); break;
}
lcd.noCursor();
switch (q)
{
case 0:
sprintf(display, "%s %05uHz", wavform, frequency);
lcd.setCursor(0, 0);
lcd.print(display);
sprintf(display, "samplerate = %3u", smp);
lcd.setCursor(0, 1);
lcd.print(display);
break;
case 1:
sprintf(display, "%s", wavform);
lcd.setCursor(0, 0);
lcd.print(display);
break;
case 2:
sprintf(display, "%05uHz", frequency);
lcd.setCursor(9, 0);
lcd.print(display);
break;
case 3:
sprintf(display, "samplerate = %3u", smp);
lcd.setCursor(0, 1);
lcd.print(display);
break;
case 4:
// dummy (set cursor)
break;
}
lcd.setCursor(13 - curs, 0);
lcd.cursor();
}