使用ATmega164的CodeVisioNaver中的吉他调谐器代码无法处理超过4个示例

使用ATmega164的CodeVisioNaver中的吉他调谐器代码无法处理超过4个示例,c,avr,atmega16,tuner,codevisionavr,C,Avr,Atmega16,Tuner,Codevisionavr,我正在通过CodeVisionAVR设计吉他调谐器,并在我的大学项目中使用ATmega164微芯片。如果我将样本数设置为大于4,芯片LED将持续闪烁,代码将无法通过测试过程的引脚读取阶段,在每行代码后点亮LED以查看其停止位置 大学强迫我通过CVAVR设计代码,使用DFT。在最近一个问题的答案的帮助下,我制作了比原来小18倍的代码。我不知道如何使它更容易运行,以便它可以容纳4个以上的样本 由于奈奎斯特-香农采样定理,调谐器一般应能使用至少800个样本,而380 Hz左右的高E吉他弦无法准确记忆

我正在通过CodeVisionAVR设计吉他调谐器,并在我的大学项目中使用ATmega164微芯片。如果我将样本数设置为大于4,芯片LED将持续闪烁,代码将无法通过测试过程的引脚读取阶段,在每行代码后点亮LED以查看其停止位置

大学强迫我通过CVAVR设计代码,使用DFT。在最近一个问题的答案的帮助下,我制作了比原来小18倍的代码。我不知道如何使它更容易运行,以便它可以容纳4个以上的样本

由于奈奎斯特-香农采样定理,调谐器一般应能使用至少800个样本,而380 Hz左右的高E吉他弦无法准确记忆

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

}

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

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

static unsigned char x[N] = {0};
即便如此,ATmega164总共也只有1K内存。您可以创建800个样本缓冲区,但在这种情况下,堆栈必须不超过200个字节。但是,您不需要这样大小的缓冲区;您将采样数与每秒采样数混淆。DFT只需要合理的循环次数即可达到所需的精度。以Hz为单位的分辨率将等于Fs/N,因此256个样本缓冲区将产生大约3Hz的精度,这可能足够精确。

1

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

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

三,。 什么是Init_initController?您的代码中没有这样的函数。它在做什么?为什么它必须是第一个初始化操作/调用!? 可能有一个问题。查看wdogtrig;我可以假设某个地方看门狗定时器已初始化。由于浮点运算花费的时间太长,所以看门狗在循环完成之前过期

要么禁用看门狗,要么放入wdogtrig;在computeDft中的循环内;,对于看门狗定时器重置更频繁

四,。 你可以申报

unsigned char x[N] = {0};
全局,将其移到函数外部,内存将分配一次,并且不会在每次函数调用时重新填充堆栈

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

虽然采样定理规定每秒采样数>760个,然而,DFT不需要大于760个样本,也就是说,您可以使用一个不到1秒数据量的窗口。你只需要几个周期。128个样本就足够了。好的,我理解,但我仍然无法在芯片崩溃和循环不连续的情况下获得4个样本。顺便说一句:你是否打算重置re=0;im=0;在嵌套循环中,在内部循环积累它们的值之前?我的观点是注释,而不是答案。我已经发布了一个答案。高E字符串是329.63赫兹BTW.Init_initController;只是微处理器初始化。端口、中断等的声明,包括问题中的另外1000行初始化AVR代码,将过于混乱。它们都是大学作为测试程序提供给我们的预制函数,使用代码向导AVR进行初始化,ADC读取,等等。主要是不起作用的部分;函数,只要我的定义N大于4。在完成computeDft函数之前,处理器一直在重置;我只能建议。你仍然没有确认,也没有反驳我的建议,有一个看门狗定时器被使用;在岗位上。我尝试过使用DogTrig;更常见的是,在整个代码中,它确实完成了while循环的运行。非常感谢。现在我必须计算出ADC的数据是如何传输的,这样我就可以选择一个变量F=computeDft;这将被比作点亮调谐器的LED。
float re = 0;
float im = 0;  
unsigned char x[N] = {0};