我正在尝试在 atmega164 上制作一个简单的吉他调谐器,但我无法在 CodeVisionAVR 上编写读取频率的代码

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

我正在为我的代码寻找一些指导。

#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();
      }
}

我只需要一个可以从 atmega164 的 PINA1 读取频率的函数,仅此而已,但我不知道如何构建它。非常感谢所有帮助。在此处发布之前,我已经尝试了两个多星期来找到使我的代码正常工作的答案,但我无法做到。 代码无法从作为频率的 PINA1 读取值

代码现在可以比较一个本应作为输入频率的值,并将其与 6 个不同节点(e、B、G、D、A、E)的 6 个频率进行比较。该程序未能完成的是从 PINA1 读取输入频率。

一个简单(粗略,但可能会奏效)的解决方案是随时间计算过零次数。我不确定 CodeVision 库提供的计时器支持,但我假设您有 1 毫秒的分辨率滴答计数和 1 毫秒的分辨率延迟。如果没有,您将不得不使用定时器外围设备提供您自己的。

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 ;
}

dc_offset参数是对应无信号(静音)的静态ADC读数。您可以通过在没有拨弦的情况下随时间取平均值来单独测量它。一种更复杂的方法是使用具有非常低截止频率的高通 IIR 滤波器(隔直滤波器)来实时消除信号中的偏移。

读数之间的 1 毫秒延迟有望足以防止由于读数中的高频谐波和噪声而导致的错误计数,但您必须进行试验。弹拨弦的波形很复杂,可能会破坏这种简单的方法。 理想情况下,输入端有一个模拟抗混叠滤波器,截止频率约为 500Hz;通过移除这些高频组件将使其更加可靠。

更复杂的数字信号处理 (DSP) 方法包括:

  • 快速傅立叶变换 (FFT) 并找到峰值频率。
  • 为每个字符串频率创建一个数字带通滤波器并测量每个频率的响应。

第二种方法的优点是您实际上可以通过弹奏开放和弦来同时调整所有琴弦。在这种情况下,虽然您不是在测量频率,而是在该频率下测量信号电平。你需要一个非常窄的频带和良好的抑制,坦率地说,ATMega 可能达不到它。