我正在尝试使用带有ATmega32-A微控制器的可编程波形发生器AD9833生成正弦波(MCLK = 8MHz时钟频率)。我正在使用USART通信,所以如果我改变超级终端的频率,那么波形频率必须改变。 我为此编写了一些小代码,如下所示。
但是从上面的代码我生成正弦波,但如果我想将信号频率改为125KHz,那么我必须在超高频输入499.9KHz。如果输入125KHz则显示31.2KHz。我不知道为什么会产生这样的错误,我做了什么错误?并且它正在改变波形,直到500KHz频率假设我输入大约1000KHz的波形频率但信号频率没有变化它只显示125KHz。
最后我想生成不同频率的波形。如果我在超级终端或腻子处改变频率,那么我输入的频率必须生成具有该频率的波形。
这是我的第一篇文章,如果有任何语法错误,那么请原谅。
提前致谢。
void unicom(void){
switch(Command){
case(WGF):
if(Param < 500)
SetWGFreq(Param);
Command = 0;
break;
case....
case....
default:
}
void main(void){
SetWGFreq(125);
-----------
--------
}
再一次,
这次我尝试通过SPI用SM470R1B1M-HT微控制器编程AD9833。我正在遵循下面“罗斯”所解释的相同原则。 看来我无法改变正弦波频率。 下面是我正在尝试的代码,我使用时钟设置相同的配置。
void SetupSPI(void);
unsigned char spi(unsigned char data);
void SetWGFreq(unsigned int);
void setFrequencyA(unsigned long fdata);
void WG_CS_Status(int status);
int main(void)
{
GCR &= ~ZPLL_MULT4;
GCR &= ~ZPLL_CLK_DIV_PRE1;
GCR &= ~ZPLL_CLK_DIV_PRE2;
GCR &= ~ZPLL_CLK_DIV_PRE3;
PCR = CLKDIV_1; // ICLK = SYSCLK
PCR |= PENABLE; // Enable peripherals
GIODIRA |= X7;
CLKCNTL |= CLKDIR | CLKSR_ICLK;
SetupSPI();
for(;;)
{
//SetWGFreq(25);
setFrequencyA(1045200);
} // Wait in endless loop
}
void SetupSPI(void)
{
int data = 0;
SPI2CTRL1 = CHARLEN_8 + PRESCALE_4; // 8 bits per xfer
SPI2CTRL2 |= CLKMOD + MASTER + POLARITY; // We are the master
SPI2PC6 |= SOMI_FUN | SIMO_FUN | CLK_FUN;
// SPI2PC6 |= 0x0E;
// enable
SPI2CTRL2 |= SPIEN;
data = SPI2BUF;
}
unsigned char spi(unsigned char data)
{
SPI2DAT1 = data;
while(!(SPI2CTRL3 & 0x01)){} // Wait for RxFlag to get set
return (SPI2BUF & 0x000000FF); // Read SPIBUF
}
void setFrequencyA(unsigned long fdata)
{
WG_CS_Status(0);
while(GIODOUTA&X7); // Delay
spi(0x20); // Initiate loading of frequence register 0 by 28 bits.
spi(0x00);
spi(( 0x40 | (0x3F & (fdata >> 8)))); // load bit 8-13 + 0x40.
spi(fdata); // load bit 0-7
spi(( 0x40 | (0x3F & (fdata >> 22)))); // load bit 22-27 + 0x40.
spi(fdata >> 14); // load bit 14-21
spi(0); // dummy write
WG_CS_Status(1);
}
void WG_CS_Status(int status)
{
if(status == 0)
{
// Make Chip Select low
GIODOUTA &= ~X7;
}
else
{
// Make Chip select high
GIODOUTA |= X7;
}
}
答案 0 :(得分:2)
当您将频率转换为AD9833需要的两个14位数字块时,您在频率寄存器的D14和D15中进行“或”操作。那里有两个问题。
第一个问题是你的freg值丢失了4位(2位)。
76543210 76543210 76543210 76543210
LL000000 00000000 LL000000 00000000 //The L's are lost because they're overwritten by the addressing.
第二个问题是你需要第15位和第14位正好是0x40。现在,如果根据您的频率数据已经存在,那么在数据中进行“或”运算可能会得到0xC0。
作为次要注释,我认为在分配给fByte0-3
时没有理由使用蒙版,因为您正在使用作为作业。
因此,结合两个修正并简化蒙版可以得到:
fByte0 = (char)freg;
fByte1 = (char)(freg>>8);
fByte1 = (fByte1 & 0x3F) | 0x40; //clears bits 15 and 14, then sets for FREQ0
fByte2 = (char)(freg>>14); //byte1 only has 6 bits, so move over by 8+6
fByte3 = (char)(freg>>22); //byte1 only has 6 bits, so move over by 8+8+6
fByte3 = (fByte3 & 0x3F) | 0x40; //clears bits 15 and 14, then sets for FREQ0
我认为这会让你到达目的地。
答案 1 :(得分:0)
我在您的代码中看到的基本问题是它不是分层。您试图在一个例程中进行过多的数据操作。您在另一篇文章中读取ADC值的代码是分层的,这就是您应该为此设备做的事情。
AD9833波形发生器基本上是一个16位器件。它需要编程的三种类型的寄存器都是16位。它只是8位的数据传输(使用SPI)。因此,只有实际的输出语句(使用 spi())需要处理字节(就像您的ADC输入例程立即将读取的字节转换为短整数一样)。为发生器计算的值应为16位值。然后,您应该能够看到代码如何在生成器的数据表中实现数据要求。
void WG_out(unsigned short rval)
{
/* assume little-endian CPU but AD9833 wants high byte first */
spi(*((unsigned char *)&rval + 1));
spi(*(unsigned char *)&rval);
}
void SetWGFreq(int fsel, unsigned int freq)
{
unsigned short freg_addr;
unsigned short freq_reghi;
unsigned short freq_reglo;
unsigned short cntl_reg;
SPCR = 0x5A; /* set SPI to mode 2 and Fosc/64 */
WG_CS = 0;
freg_addr = (fsel > 0) ? 0x8000 : 0x4000;
/* split the f value into two 14-bit values */
freq *= 33554.432; /* number based on a MCLK of 8 MHz */
freq_reghi = freg_addr | ((freq >> 14) & 0x00003fff);
freq_reglo = freg_addr | (freq & 0x00003fff);
cntl_reg = (1 << 13) | (fsel > 0) ? (1 << 11) : 0;
while (WG_CS_PIN) /* wait for chip select to go low */
/* DELAY */ ;
WG_out(cntl_reg); /* set B28 in Control */
WG_out(freq_reglo); /* 14 LSB goes first */
WG_out(freq_reghi); /* 14 MSB goes next */
WG_CS = 1;
}
void SetWGPhase(int fsel, int psel, unsigned int phase)
{
unsigned short cntl_reg;
unsigned short phase_reg;
SPCR = 0x5A;
WG_CS = 0;
cntl_reg = (1 << 13) | (fsel > 0) ? (1 << 11) : 0 | (psel > 0) ? (1 << 10) : 0;
phase *= 1303; /* 4096 / 2pi radians */
phase_reg = 0xc000 | (psel > 0) ? (1 << 13) : 0 | (phase & 0x0fff);
while (WG_CS_PIN) /* wait for chip select to go low */
/* DELAY */ ;
WG_out(cntl_reg); /* set B28 in Control */
WG_out(phase_reg);
WG_CS = 1;
}
此代码允许指定 FREQ0 或 FREQ1 以及 PHASE0 或 PHASE1 寄存器。 * WG_out()*的源代码看起来很复杂,但它实际上编译为非常简单的机器代码。
仍然需要代码改进
幻数需要替换为#define
s。
不需要重写完整的控制寄存器,而是需要维护状态变量,以便只根据需要修改控制位。然后可以消除 SetWGPhase()中的 fsel 参数。