hello there.
i am trying to make a function generator using atmega328 ( arduino uno ), i used a resistor ladder R-2R as a digital to analog converter and a timer to generate time event that every interrupt of it will move to the next sample and write that value to the PORTD ( where the dac is connected ) and some printing on lcd I2C.
well i wrote 2 codes, the first one using the principe of having a constant samples and changing sampling frequency ( the timer interrupt time ), it worked fine but i realised that it will put me in a disavantage when it comes to the filtering part so i tried to have a constant sampling freqency ( 160 khz ) and calculating how many samples do i need and calculating the value and finaly write it to the DAC but i can't acheive the wanted frequencies and i don't know where is the problem and i started to be tiresome so can you help me in that. the codes are down below and some pictures to show you the waves.
ps: the band width is from 1 hz to 10 Khz.
ps2: i set 1 khz in the picture.
the working code:
**** i can't post because it's to long so you will findthe codes it in this drive ***
https://drive.google.com/drive/folders/1OseUAOiTnjPPpRDj9HzEDTJw6SG71zO3?usp=sharing
its pictures:
the code which failed:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
uint8_t lcd_update = 1,lcd_update2 = 1,p = 0;
String Display = "";
//----------------------------------------------------------------------------------------------
// interrupt variable
volatile uint8_t button1 = 0,button2 = 0;
//------------------------------------------------------------------------------------------
// selecting frequency
uint8_t pointer = 0, number = 0,wave_forme = 0;
uint8_t frequency_p[4] = {0,0,0,0};
long frequency = 0;
uint8_t value2 = 0;
//------------------------------------------------------------------------------
//function
long n = 0,fs = 160000, samples = 0;
uint8_t new_sample = 0;
uint8_t function_points(uint8_t wave_forme,long p,long f,long s);
void setup() {
// put your setup code here, to run once:
//Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.setCursor(0,0); lcd.print("frequency:");
lcd.setCursor(0,1); lcd.print("wave:");
//DDRD = (1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
DDRD |= (1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
interrupt_config();
timer1_config();
}
void loop() {
// put your main code here, to run repeatedly:
frequency_p[pointer] = number;
if(frequency_p[0]==10){ frequency_p[1]=0;frequency_p[2]=0;frequency_p[3]=0; }
if(lcd_update == 1){
p = pointer;
//Serial.print("frequency: ");Serial.print(frequency); Serial.print(" | pointer: ");Serial.println(pointer);
lcd.setCursor(11,0); lcd.print(" ");lcd.setCursor(11,0);
lcd.print(frequency_p[0]);lcd.print(frequency_p[1]);lcd.print(frequency_p[2]);lcd.print(frequency_p[3]);
if(frequency_p[0]==10)p++;
lcd.setCursor(11,1); lcd.print(" ");
lcd.setCursor(11+p,1); lcd.print("_");
p = pointer;
lcd_update = 0;
}
if(lcd_update2 == 1){
lcd_update2 = 0;
lcd.setCursor(6,1); lcd.print(" ");lcd.setCursor(6,1);
if(wave_forme==0)Display = "sin";
if(wave_forme==1)Display = "squa";
if(wave_forme==2)Display = "tri";
if(wave_forme==3)Display = "pulse";
if(wave_forme==4)Display = "rampe";
lcd.print(Display);
//Serial.print("wave: "); Serial.println(Display);
}
switch(button1){
case 1: frequency = frequency_p[0]*1000 + frequency_p[1]*100 + frequency_p[2]*10 + frequency_p[3];
samples = fs/frequency; n=0;
//Serial.print("samples: "); Serial.println(samples);
pointer = 0;
lcd.setCursor(11,1); lcd.print(" ");
button1 = 0; break;
case 2: lcd_update = 1; number++;
if( number >=10 )number = (pointer == 0)? 10:9;
if(pointer != 0 && frequency_p[0] == 10 ){number = 0; }
button1 = 0;
break;
case 4: lcd_update = 1; pointer--;
if(pointer == 255)pointer = 0;
number = frequency_p[pointer];
button1 = 0;
break;
case 8: lcd_update = 1; number--;
if( number ==255 )number = 0;
if(pointer != 0 && frequency_p[0]==10){ frequency_p[0]=9;}
button1 = 0;
break;
default : button1 = 0; break;
}
switch(button2){
case 1: lcd_update = 1; pointer++;
if(pointer == 4)pointer = 3;
number = frequency_p[pointer];
button2 = 0;
break;
case 2: lcd_update2 = 1;wave_forme = 0; n=0; button2 = 0;
break;
case 4: lcd_update2 = 1;wave_forme = 1; n=0; button2 = 0;
break;
case 8: lcd_update2 = 1;wave_forme = 2; n=0; button2 = 0;
break;
case 16: lcd_update2 = 1;wave_forme = 3; n=0; button2 = 0;
break;
case 32: lcd_update2 = 1;wave_forme = 4; n=0; button2 = 0;
break;
default : button2 = 0; break;
}
if(new_sample==1){
new_sample = 0;
if(frequency != 0){ PORTD = 127*(1+sin(2*PI*n*frequency/fs)); }
else PORTD = 0;
n++;
if(n== samples) n=0;
}
}
void interrupt_config(){
DDRB &= ~(0b00111111);
DDRC &= ~(0b00001111);
PORTB |= 0b00111111;
PORTC |= 0b00001111;
PCICR |= (1<<PCIE0)|(1<<PCIE1);
PCMSK0 |= (1<<PCINT0)|(1<<PCINT1)|(1<<PCINT2)|(1<<PCINT3)|(1<<PCINT4)|(1<<PCINT5);
PCMSK1 |= (1<<PCINT8)|(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11);
}
ISR(PCINT1_vect){
button1 = ~PINC & 0b00001111;
//Serial.print("button1: ");Serial.println(button1);
// up = 2; down = 8; left = 4; ok = 1;
}
ISR(PCINT0_vect){
button2 = ~PINB & 0b00111111;
//Serial.print("button2: ");Serial.println(button2);
// right = 1; sin = 2 ; triangle = 4; pulse = 32; rampe = 4 ; square = 16;
}
/*uint8_t function_points(uint8_t wave_forme,long p,long f,long s){
uint8_t value;
switch(wave_forme){
case 0: if(f>0)value = 127*(1+sin(2*PI*f*p/160000)); else value = 0; break;
case 1: if(f>0)value = (p<s/2)? 255*p*f*2/160000:510 - (510*p*f/160000); else value = 0; break;
case 2: if(f>0)value = 255*p*f/160000; else value = 0;break;
case 3: value = (p<s/2)? 255:0; break;
case 4: value = (p<1)? 255:0; break;
default : break;
}
return value;
}*/
void timer1_config(void)
{
TCCR1A = 0; TCCR1B = (1<<WGM12)|(1<<CS10); TCNT1 = 0; OCR1A = 99;
TIMSK1 |= (1<<OCIE1A);
sei();
}
ISR(TIMER1_COMPA_vect){
//PORTD ^=(1<<PD7);
new_sample = 1;
}
its picture: