0

我正在通过 CodeVisionAVR 设计吉他调音器,并为我的大学项目使用 ATmega164 微芯片。如果我将样本数设置为高于 4,则芯片 LED 将持续闪烁,并且代码不会超过该过程的引脚读取阶段(在每行代码后点亮 LED 进行测试以查看它停止的位置)。

大学强迫我使用 DFT 通过 CVAVR 设计代码。我已经(在对最近一个问题的回答的大力帮助下)编写的代码比原来的代码小了近 18 倍。我不知道如何使它更容易运行,以便它可以容忍超过 4 个样本 ( #define N 4)

#define M_PI 3.1415926f
#define N 4

unsigned char read_adc(void)
{
ADCSRA |= 0b01000000;  //start conversion;
while (ADCSRA&(0b01000000)); //wait conversion end
return ADCH;
}

float computeDft()
{      
    unsigned char x[N] = {0};
    float max = 0;   
    float maxi = 0;
    float magnitude = 0; 
    int k = 0;
    int n = 0;
    float re = 0;
    float im = 0;          
    for (k = 0; k < N; k++)
    {       
        x[k] = read_adc();            
    }
    for (n = 0; n < N; n++)
    {
        for (k = 0; k < N; k++)
        {       
            re += x[k] * cos(n * k * M_PI / N);
            im -= x[k] * sin(n * k * M_PI / N);
        }
        magnitude = sqrt(re * re +  im * im);
        if (magnitude > maxi) 
        {
            maxi = magnitude;
            max = k;   
        }
    }                                     
    return max;   
}


/*
 * main function of program
 */
void main (void)
{          
float F = 0;
Init_initController();  // this must be the first "init" action/call!
#asm("sei")             // enable interrupts
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef OPTIMIZE_SIZE
#pragma optsize+
#endif

TWCR=0x00;
//adc init
ADMUX = 0b10100111; // set ADC0
ADCSRA = 0b10000111; //set ADEN, precale by 128
while(TRUE)
{
    wdogtrig();         // call often else processor will reset
    F = computeDft();    
    L2 = 1;
    if(F > 20 && F < 100)
    {
        L3 = 1;
    }
}  


}// end main loop 

由于 Nyquist-Shannon 采样定理,一个调音器通常应该能够使用至少 800 个样本,并且高 E 吉他弦在 380 Hz 左右(不记得确切)。

/* initialization file */

#include <mega164a.h>
#include "defs.h"


/*
 * most intialization values are generated using Code Wizard and depend on clock value
 */
void Init_initController(void)
{
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;

// Port B initialization
PORTB=0x00;
DDRB=0x00;

// Port C initialization
PORTC=0x00;
DDRC=0x00;

// Port D initialization
PORTD=0b00100000; // D.5 needs pull-up resistor
DDRD= 0b01010000; // D.6 is LED, D.4 is test output

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 19.531 kHz = CLOCK/256
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off

TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;

// 1 sec = 19531 counts = 4C41H counts, from 0 to 4C40 
// 4C40H = 4CH (MSB) and 40H (LSB)
OCR1AH=0x4C;
OCR1AL=0x40;

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=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// 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=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0,1,2 Interrupt(s) initialization
TIMSK0=0x00;
TIMSK1=0x02;
TIMSK2=0x00;

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

// USART1 initialization
// USART1 disabled
UCSR1B=0x00;


// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR1=0x00;

// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/2048  
#pragma optsize-
#asm("wdr")
// Write 2 consecutive values to enable watchdog
// this is NOT a mistake !
WDTCSR=0x18;
WDTCSR=0x08;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

}
4

2 回答 2

1

1.

float re = 0;
float im = 0;  

移动声明,或者不要忘记在嵌套循环之前在循环内将这些值重置为零。

2. Nyquist-Shannon 定理(也称为 Kotelnikov 定理)是关于采样率的。要传输高达 F 的频率,您必须具有至少 2*F 的采样率。这与样本数量无关。如果您的 MCU 以 16MHz 运行,我可以假设您的采样率约为 9kHz = 16MHz / 128(ADC 的预分频器)/14(每个样本的 ADC 时钟周期)

3. 什么是Init_initController();?您的代码中没有这样的功能。它在做什么?为什么呢must be the first "init" action/call!?大概有问题。看着wdogtrig();我可以假设某处看门狗定时器已初始化。由于浮点数学需要很长时间,因此看门狗在循环完成之前就过期了。

禁用看门狗,或放入wdogtrig();循环中computeDft();,以便更频繁地重置看门狗定时器。

4. 可以申报

unsigned char x[N] = {0};

全局,将其移出函数,内存将被分配一次,并且不会在每次函数调用时重新填充堆栈

5. 如果您提出问题,请提供问题中的所有信息:您期望什么、您得到什么、所有自定义函数和不起作用的确切代码。

于 2019-05-22T10:01:53.320 回答
0

堆栈大小是多少?您x[N]在堆栈上被实例化,并且可能没有足够的空间容纳足够大小的数组。

静态分配它以避免堆栈溢出:

static unsigned char x[N] = {0};

即使这样,ATmega164 总共也只有 1K RAM。您可以创建一个 800 个样本缓冲区,但在这种情况下,您的堆栈必须不超过 200 字节左右。但是,您不需要那个大小的缓冲区;您将样本数与每秒样本数混淆了。DFT 所需的只是合理数量的循环即可达到所需的精度。以 Hz 为单位的分辨率将等于 F s /N,因此 256 个样本缓冲区将产生大约 3Hz 的精度,这可能足够准确。

于 2019-05-21T21:43:13.693 回答