#include <stdio.h> #include <avr\io.h> #include <avr\interrupt.h>
#define LcdDATA_DDR DDRD // Portul pe care conectam firele de date la LCD-ul #define LcdDATA_PORT PORTD #define LcdDATA_PIN PIND
#define LcdCMD_DDR DDRD // Portul pe care conectam firele de comenzi la LCD #define LcdCMD_PORT PORTD #define LcdCMD_PIN PIND
#define LcdD4 PD0 // Pin-ul pentru firul de date D4 de pe LCD #define LcdD5 PD1 // Pin-ul pentru firul de date D5 de pe LCD #define LcdD6 PD2 // Pin-ul pentru firul de date D6 de pe LCD #define LcdD7 PD3 // Pin-ul pentru firul de date D7 de pe LCD
#define LcdRS PD4 // Pinul pentru selectare operatie (LCD) #define LcdRW PD5 // Pinul pentru Read/ Write (LCD) #define LcdE PD6 // Pinul de Enable (LCD)
#define LCD_INSTR_4wire 0x28 // 4 fire date, font 5x8 #define LCD_INSTR_display 0x0C // Display On, Cursor On, Blinking On ( 1 Display Cursor Blink ) #define LCD_INSTR_clearDisplay 0x01 // Clear Display #define LCD_INSTR_returnHome 0x02 // Return Cursor and LCD to Home Position #define LCD_INSTR_nextLine 0xC0 // Return Cursor and LCD to Home Position #define LCD_INSTR_gotoCGRAM 0x40 // go to Character Generator RAM
#define OFF 0 #define ON 1 #define HISTORY_LEN 1700 #define ZERO_ABS 127 #define nop() asm volatile("nop")
#define MAX_VOL 4//160 #define MIN_VOL 1//32
#define MAX_COUNT 2000
int FLAG_DISTORT;
int FLAG_ECHO;
int FLAG_CHORUS;
int FLAG_TREMOLO;
int vol=1,direction=0;
unsigned char freq[]={30,50,70,90};
int pas_curr = 0;
int index_freq = 0;
int count = 0; int gain = 0;
unsigned char history[HISTORY_LEN];
void initHistory(){ int i; for(i = 0;i<HISTORY_LEN;i++) history[i] = ZERO_ABS; }
void addHistory(unsigned char amp){ int i; for(i = HISTORY_LEN-1;i>0;i--) history[i] = history[i-1]; history[0] = amp; }
unsigned char getHistory(int idx){ return history[idx]; }
void LCD_init(); // Initializare modul LCD.. trebuie apelata inainte de a se face orice operatie cu LCD-ul void LCD_writeInstruction(unsigned char _instruction); // Trimite o instructiune catre lcd (vezi datasheet) void LCD_writeData(unsigned char _data); // Trimite date catre LCD pentru afisare void LCD_write(unsigned char _byte); // trimite un bute catre LCD la modul general (nu conteaza daca e instructiune sau date) void LCD_waitNotBusy(); // Asteptam pana cand lcd-ul devine disponibil pt o noua comanda void LCD_waitInstructions(unsigned char _instructions); // Asteapta un numar de cicli de tact.. loop void LCD_print2(char* _msg1, char* _msg2); void LCD_print(char* _msg); // tine definitiile caracterelor pentru progress bar
// initializarea convertorului analog digital void ADC_init() { // AVCC cu condesator pe AREF; PA7 ca input single ended; rezultat left-adjusted (8 biti de date) ADMUX |= _BV(MUX0); ADMUX |= _BV(MUX1); ADMUX |= _BV(MUX2); ADCSRA |= _BV(ADEN); ADCSRA |= _BV(ADSC); ADMUX |= _BV(ADLAR); ADMUX |= _BV(REFS0);
// activeaza ADC si intreruperea de conversie. Prescaler de ceas la maximum ADCSRA |= _BV(ADPS0); ADCSRA |= _BV(ADPS1); ADCSRA |= _BV(ADPS2); ADCSRA |= _BV(ADIE); // pune pe input pinul intrarii de ADC (fara a modifica starea celorlalti pini) DDRA &= ~(_BV(PA7)); }
void SOUND_OUTPUT_init(){
/* Pun pe output pinii PORTC0..7 */ DDRC |= _BV(PC0); DDRC |= _BV(PC1); DDRC |= _BV(PC2); DDRC |= _BV(PA3); DDRC |= _BV(PC4); DDRC |= _BV(PC5); DDRC |= _BV(PC6); DDRC |= _BV(PC7); } /* Initializarea intrarilor(butoanele ce selecteaza efectul */ void SELECTOR_INPUT_init(){ /* pun pe input pinii PORTB0..7 */ DDRB = 0x00; /* activez rezistentele de pull-up */ PORTB = 0xFF; /* initializez flag-urile */ FLAG_DISTORT = OFF; FLAG_ECHO = OFF; FLAG_TREMOLO = OFF; FLAG_CHORUS = OFF; } unsigned char to_char(int a){ if(a>255) return 255; if(a<0) return 0; return a; } /* efectele implementate */
/* efectul de echo */ unsigned char echo(int amplitude){ int a = amplitude; a-=127; a +=(getHistory(HISTORY_LEN-1)-127)/4; a+=127; if(a>255) return 255; if(a<0) return 0; return a;
}
/* efectul de chorus */ unsigned char chorus(int amplitude){ long a = amplitude; a-=127; a+=(getHistory(0)-127)/16; a+=(getHistory(7)-127)/32; a+=(getHistory(2)-127)/16; a+=(getHistory(4)-127)/16; a+=127; if(a>255) return 255; if(a<0) return 0; return a; }
unsigned char compression(int amplitude){ int a = amplitude; a = a-127; if((a>=-40)&&(a<=40)) return 127; return a+127; }
unsigned char tremolo(int amp){
long a = amp; count++; if(count == MAX_COUNT) { count = 0; if(direction == 1) gain++;
else gain--; } if((gain>50) && (direction==1)) direction = 0; if((gain< -50) && (direction==0)) direction = 1; a+=gain; return to_char(a); /* alta varianta */ /*long a = amp; pas_curr++; if(pas_curr==freq[index_freq]){ pas_curr = 0; index_freq++; index_freq = index_freq%4; if(direction ==1) vol++; else vol--; if(vol >= MAX_VOL) direction=0; else
if (vol ⇐ MIN_VOL)
direction=1;
} a-=127; if(vol==1) a*=-2; if(vol==2) a/=-2; if(vol==3) a/=2; if(vol==4) a*=2; a += 127;
return to_char(a);*/ }
unsigned char distortion(int amplitude){ int a; a = amplitude; a-=127; a*=2; a+=127; return to_char(a); }
int adjustInputVolume(int a){
if(a>255) a = 255; if(a<0) a = 0; /*atenuam semnalul de intrare */ a-=127; a/=4; a+=127; return to_char(a); }
// intreruperea de conversie SIGNAL(SIG_ADC) { int amp = 0; int a = 0; //amp = amplitudinea de la intrare amp = ADCH; //a = amplitudinea de la intrare a = adjustInputVolume(amp); unsigned char tPINB; //nop(); tPINB = PINB; /* Actualizez flagurile daca este cazul */ /* PINB0 - distors */ /*primul buton este distortion */ if(tPINB & (1<<0)) FLAG_DISTORT = ON; else FLAG_DISTORT = OFF; /* PINB1 - compres */ /* al 2-lea buton este compressor */ if(tPINB & (1<<1)) FLAG_TREMOLO = ON; else FLAG_TREMOLO = OFF; /* PINB2 - echo */ /* al 3-lea buton este echo */ if(tPINB & (1<<2)) FLAG_ECHO = ON; else FLAG_ECHO = OFF; /* PINB3 -chorus */ /* al 4-lea buton este chorus */ if(tPINB & (1<<3)) FLAG_CHORUS = ON; else FLAG_CHORUS = OFF; if(FLAG_DISTORT){ a = distortion(amp); addHistory(amp); goto ret; } if(FLAG_TREMOLO){ a = tremolo(amp); addHistory(amp); goto ret; } if(FLAG_CHORUS){ a = chorus(a); addHistory(a); goto ret; } if(FLAG_ECHO){ a = echo(a); addHistory(echo(a)); goto ret; }
ret: PORTC = to_char(a); //PORTC = 200; /* ADIE este bitul de Enable pentru întrerupere. Aceasta va fi generata automat la fiecare conversie daca bitul respectiv este setat.*/ ADCSRA |= _BV(ADIE); }
int main() { // int i; //LCD_init();
//LCD_writeInstruction(LCD_INSTR_clearDisplay); //LCD_print2("Guitar ","Effects "); /* Initializare convertor analog-digital */ ADC_init(); /* Initializare iesire digitala (catre DAC) */ SOUND_OUTPUT_init(); /* Initializare intrarile ce selecteaza efectele */ SELECTOR_INPUT_init(); /* initializare history */ initHistory(); /* Activare intreruperi */ sei(); /* Bucla programului */ for(;;) { // cer ADC-ului sa faca o conversie /* scrierea acestui bit pe 1 va genera automat o conversie de pe intrarea selectata. */ ADCSRA |= _BV(ADSC); } return 0; }
/************************************************************************ * IMPLEMENTARE API LCD.. implementare este in partea de jos a fisierului ************************************************************************/
void LCD_init() { LcdDATA_DDR |= (1<<LcdD4)|(1<<LcdD5)|(1<<LcdD6)|(1<<LcdD7); // setam pinii de date ca pini de iesire LcdCMD_DDR |= (1<<LcdRS)|(1<<LcdRW)|(1<<LcdE); // setam pinii de comenzi ca pini de iesire
LCD_waitNotBusy(); LcdCMD_PORT &= ~(1<<LcdRS); // Setam linia RS pe low LcdCMD_PORT &= ~(1<<LcdRW); // Setam linia RW pe low (acum suntem in modul de trimis instructiuni) LcdDATA_PORT &= ~(1<<LcdD4)&~(1<<LcdD6)&~(1<<LcdD7); // Specificam ca vrem 4 fire de date, prima comanda (LcdD5 activ, restul nu) LcdDATA_PORT |= (1<<LcdD5); // setam pinii de comenzi ca pini de iesire LcdCMD_PORT |= (1<<LcdE); // Setam linia E(nable) pe high; aceasta ii specifica LCD-ului sa preia datele LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdCMD_PORT &= ~(1<<LcdE ); // Setam linia E(nable) pe low; transferul s-a terminat
LCD_writeInstruction(LCD_INSTR_4wire); // Incarcam comanda: 4 bit data, 2 lines, 5x8 font LCD_writeInstruction(LCD_INSTR_display); // Display On, Cursor On, Blinking On LCD_writeInstruction(0x06); // Increment, no shift LCD_writeInstruction(0x01); // Clear Display }
void LCD_writeInstruction(unsigned char _instruction) { LCD_waitNotBusy(); // asteptam ca LCD-ul sa fie liber sa primeasca comenzile LcdCMD_PORT &= ~(1 << LcdRS); // setam pinul RS pe low.. low=instructiuni, high=date LcdCMD_PORT &= ~(1 << LcdRW); // setam pinul RW pe low (suntem in modul de comenzi acum) LCD_write(_instruction); // apelam procedura ce trimite byte-ul pe firele de date }
void LCD_writeData(unsigned char _data) { LCD_waitNotBusy(); // asteptam ca LCD-ul sa fie liber sa primeasca comenzile LcdCMD_PORT |= (1 << LcdRS); // setam pinul RS pe high LcdCMD_PORT &= ~(1 << LcdRW); // setam pinul RW pe low (suntem in modul de comenzi acum) LCD_write(_data); // apelam procedura ce trimite byte-ul pe firele de date }
void LCD_write(unsigned char _byte) { unsigned char _byte2; _byte2 = _byte>>4;
LcdDATA_PORT &= ~(1<<LcdD4); if ( bit_is_set( _byte2, 0 ) ) LcdDATA_PORT |= (1<<LcdD4); LcdDATA_PORT &= ~(1<<LcdD5); if ( bit_is_set( _byte2, 1 ) ) LcdDATA_PORT |= (1<<LcdD5);
LcdDATA_PORT &= ~(1<<LcdD6); if ( bit_is_set( _byte2, 2 ) ) LcdDATA_PORT |= (1<<LcdD6);
LcdDATA_PORT &= ~(1<<LcdD7); if ( bit_is_set( _byte2, 3 ) ) LcdDATA_PORT |= (1<<LcdD7);
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdDATA_PORT &= ~(1<<LcdD4); if ( bit_is_set( _byte, 0 ) ) LcdDATA_PORT |= (1<<LcdD4); LcdDATA_PORT &= ~(1<<LcdD5); if ( bit_is_set( _byte, 1 ) ) LcdDATA_PORT |= (1<<LcdD5);
LcdDATA_PORT &= ~(1<<LcdD6); if ( bit_is_set( _byte, 2 ) ) LcdDATA_PORT |= (1<<LcdD6);
LcdDATA_PORT &= ~(1<<LcdD7); if ( bit_is_set( _byte, 3 ) ) LcdDATA_PORT |= (1<<LcdD7);
LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low }
void LCD_waitNotBusy() { unsigned char _loop = 1;
while (_loop) { LcdDATA_DDR &= ~(1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Setam pinii de date de la LCD pe in pt a citi busy flag LcdDATA_PORT &= ~(1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Dezactivam pullup resistor pentru pinii de in LcdCMD_PORT &= ~(1<<LcdE); // Setam pin-ul e pe low; ar trebui sa fie deja low, doar ne asiguram LcdCMD_PORT &= ~(1<<LcdRS); // Setam pinul RS pe low LcdCMD_PORT |= (1<<LcdRW); // Setam pinul RW pe high (acum suntem in modul de interogare busy/adr) LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high LCD_waitInstructions(6); // Asteptam o perioada de timp T _loop = LcdDATA_PIN & (1<<LcdD7); // Citim busy flag-ul LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdCMD_PORT |= (1<<LcdE); // Setam Pinul E pe high LCD_waitInstructions(6); // Asteptam o perioada de timp T LcdCMD_PORT &= ~(1<<LcdE); // Setam Pinul E pe low
LcdDATA_DDR |= (1<<LcdD4 | 1<<LcdD5 | 1<<LcdD6 | 1<<LcdD7); // Setam Portul de LCD ca port de iesire la loc } }
void LCD_printDecimal2u(unsigned int _n) { unsigned char tmp=0; // Extragem sutele while(_n>=100) _n-=100;
while(_n>=10){ tmp++; _n-=10; }
LCD_writeData(tmp+'0'); LCD_writeData(_n+'0'); }
void LCD_printHexa(unsigned int _n) { unsigned char _tmp = _n>>4; if (_tmp>9) _tmp += 'A'-10; else _tmp += '0'; LCD_writeData( _tmp ); _tmp = _n & 0x0F; if (_tmp>9) _tmp += 'A'-10; else _tmp += '0'; LCD_writeData( _tmp ); }
void LCD_print(char* _msg) { unsigned char i=0; for( ; _msg[i]!=0 && i<16; i++) LCD_writeData( _msg[i] ); }
void LCD_print2(char* _msg1, char* _msg2) { LCD_writeInstruction(LCD_INSTR_clearDisplay); LCD_print(_msg1); LCD_writeInstruction(LCD_INSTR_nextLine); LCD_print(_msg2); }
void LCD_waitInstructions(unsigned char _instructions) { while (_instructions--) ; }