Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
110 views
in Technique[技术] by (71.8m points)

c - I am trying to make a simple guitar tuner on a atmega164 and i cannot make the code for reading a frequency on CodeVisionAVR

I am looking for some guidance for my code.

#include <mega164a.h>

// Declare your global variables here
#define BUTTON1 PINC7
#define Freq_e 0xEF
#define Freq_B 0x9F
#define Freq_G 0xDE
#define Freq_D 0xBD
#define Freq_A 0xF7
#define Freq_E 0xCF

// Standard Input/Output functions
#include <stdio.h>
#include <delay.h>
#include <stdbool.h>
void USARTInit()
{
    // USART0 initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART0 Receiver: On
    // USART0 Transmitter: On
    // USART0 Mode: Asynchronous
    // USART0 Baud rate: 9600
    UCSR0A = 0x00;
    UCSR0B = 0xD8;
    UCSR0C = 0x06;
    UBRR0H = 0x00;
    UBRR0L = 0x81;

    #asm("sei")
}
 bool button_state()
{
  if (!((PINC & (1 << BUTTON1)) >> BUTTON1))
  {
    delay_ms(30);
   if (!((PINC & (1 << BUTTON1)) >> BUTTON1))
     return true;
  }
  return false;
}
  unsigned char SelectedFreq=0;
/*unsigned char readanalog()
{
    unsigned short val=0;
    while(ADCSRA&(1<<ADSC));
    val=ADCL;
    val+=(ADCH<<8);
    return ADCL;
}
*/
float val1=0.0;
float desirefreqe=329.63;
float desirefreqB=246.94;
float desirefreqG=196;
float desirefreqD=146.83;
float desirefreqA=110;
float desirefreqEs=82.41;
void compfreq(unsigned char SelectedFreq)
{
    float tempfreq=0;
  if(SelectedFreq==0){
     tempfreq=desirefreqe;
  }
  else if(SelectedFreq==1){
     tempfreq=desirefreqB;
  }
   else if(SelectedFreq==2){
     tempfreq=desirefreqG;
  }
   else if(SelectedFreq==3){
     tempfreq=desirefreqD;
  }
   else if(SelectedFreq==4){
     tempfreq=desirefreqA;
  }
   else if(SelectedFreq==5){
     tempfreq=desirefreqEs;
  }
  if(val1>(tempfreq+2)){
   PORTB=0x9c;
  }
  else if(val1<(tempfreq-2)){
   PORTB=0xE2;
  }
  else{
  PORTB=0x81;
  }
}
void closefreq(){
    if(val1>=(desirefreqe-((desirefreqe-desirefreqB)/2))){
       PORTD=Freq_e;
    }
    else if(val1>=(desirefreqB-((desirefreqB-desirefreqG)/2))){
        PORTD=Freq_B;
    }
    else if(val1>=(desirefreqG-((desirefreqG-desirefreqD)/2))){
        PORTD=Freq_G;
    }
     else if(val1>=(desirefreqD-((desirefreqD-desirefreqA)/2))){
        PORTD=Freq_D;
    }
     else if(val1>(desirefreqA-((desirefreqA-desirefreqEs)/2))){
        PORTD=Freq_A;
    }
     else {
        PORTD=Freq_E;
    }
}
/*unsigned char read_adc(unsigned char adc_input) {

    ADMUX = adc_input | ADC_VREF_TYPE;
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    // Start the AD conversion
    ADCSRA |= (1 << ADSC);
    // Wait for the AD conversion to complete
    while ((ADCSRA & (1 << ADIF)) == 0);

    ADCSRA |= (1 << ADIF);
    return ADCH;
}
*/
unsigned char read_adc1(void)
{
    ADCSRA |= 0b01000000;  //start conversion;
    while (ADCSRA&(0b01000000)); //wait conversion end
    return ADCH;
}
void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
PRR &= ~(1 << PRADC);
//ADMUX=ADC_VREF_TYPE;
ADMUX = 0b10100111; // set ADC0
ADCSRA = 0b10000111; //set ADEN, precale by 128
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

// Port B initialization
// Function: Bit7=In Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
DDRB=(0<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
// State: Bit7=T Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Port C initialization
// Function: Bit7=In Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
DDRC=(0<<DDC7) | (1<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0);
// State: Bit7=T Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
PORTC=(1<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

// Port D initialization
// Function: Bit7=In Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
DDRD=(0<<DDD7) | (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2) | (1<<DDD1) | (1<<DDD0);
// State: Bit7=T Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=(0<<EXCLK) | (0<<AS2);
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20);
TCCR2B=(0<<WGM22) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=(0<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (0<<TOIE1);

// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=(0<<OCIE2B) | (0<<OCIE2A) | (0<<TOIE2);


// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: Off
// Interrupt on any change on pins PCINT16-23: Off
// Interrupt on any change on pins PCINT24-31: Off
EICRA=(0<<ISC21) | (0<<ISC20) | (0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
EIMSK=(0<<INT2) | (0<<INT1) | (0<<INT0);
PCICR=(0<<PCIE3) | (0<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);


// USART1 initialization
// USART1 disabled
UCSR1B=(0<<RXCIE1) | (0<<TXCIE1) | (0<<UDRIE1) | (0<<RXEN1) | (0<<TXEN1) | (0<<UCSZ12) | (0<<RXB81) | (0<<TXB81);

// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
ADCSRB=(0<<ACME);
// Digital input buffer on AIN0: On
// Digital input buffer on AIN1: On
DIDR1=(0<<AIN0D) | (0<<AIN1D);

// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);

// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);

// TWI initialization
// TWI disabled
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);
USARTInit();


while (1)
      {
     // readanalog();
      val1 = read_adc1();
      if( button_state())
      {
        SelectedFreq++;
        SelectedFreq=SelectedFreq%6;
        delay_ms(60);
      }
      if(SelectedFreq==0)
      {
        PORTC=Freq_e;
      }
      else if (SelectedFreq==1)
          {
            PORTC=Freq_B;
          }
      else if (SelectedFreq==2)
          {
            PORTC=Freq_G;
          }
      else if (SelectedFreq==3)
          {
            PORTC=Freq_D;
          }
      else if (SelectedFreq==4)
          {
            PORTC=Freq_A;
          }
       else if (SelectedFreq==5)
          {
            PORTC=Freq_E;
          }
       compfreq(SelectedFreq);
       closefreq();
      }
}

All i need is a function that can read a frequency from the PINA1 of the atmega164 and thats all but i don't have a clue how to build it. All the help is much appreciated. Before posting here i`ve tried for more than two weeks to find the answer to make my code work but i am not been able to do it. The code fail at reading the value from the PINA1 which is a frequency

The code can now compare a value that is meant to be an input frequency and compare it to 6 frequencies for 6 different node (e, B, G, D, A, E). What the program fails to do is to read the input frequency from the PINA1.

question from:https://stackoverflow.com/questions/65943472/i-am-trying-to-make-a-simple-guitar-tuner-on-a-atmega164-and-i-cannot-make-the-c

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A simple (crude, but might just work) solution is to count zero-crossings over time. I am not sure what timer support the CodeVision library provides, but I'll assume you have a 1 millisecond resolution tick count and a 1 millisecond resolution delay. If not you'll have to provide your own using a timer peripheral.

int measureFrequency( int dc_offset )
{
    int zero_x_count = 0 ;
    
    delayms(1) ;  // align to the tick boundary
    int start = tickms() ;
    int previous_sign  = read_adc1() = dc_offset < 0 ? -1 : 1 ;
    
    // Count zero x for 1 second
    while( tickms() - start < 1000 )
    {
        delayms(1) ;
        int sign  = read_adc1() = dc_offset < 0 ? -1 : 1 ;

        if( sign != previous_sign )
        {
            zero_x_count++ ;
        }
    }
    
    // Frequency = zero-x / 2
    return zero_x_count >> 1 ;
}

The dc_offset argument is the quiescent ADC reading corresponding to no signal (silence). You could measure that separately, by taking an average over time while no string is plucked. A more sophisticated method is to use high pass IIR filter with a very low cut-off frequency (a DC-blocking filter) to remove the offset from the signal in real-time.

The 1ms delay between readings is hopefully sufficient to prevent false counts due to higher-frequency harmonics and noise in the reading but you will have to experiment. The waveform for a plucked string is complex and may defeat this simple approach. Ideally you's have an analogue anti-aliasing filter on the input with a cut-off frequency of about 500Hz; that will make it more reliable by removing these higher-frequency components.

A more sophisticated digital signal processing (DSP) approaches include:

  • Fast Fourier Transform (FFT) and find the peak frequency.
  • create a digital band-pass filter for each string frequency and measure the response at each frequency.

The advantage of this second approach is you can in fact tune all strings simultaneously just by strumming an open chord. In this case though you are not measuring the frequency, but the signal level at that frequency. You need a very narrow band and good rejection and frankly the ATMega is probably not up to it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...