文章目录[隐藏]
基于STM32F103RCT6的AD9833驱动开发(代码可以免费发邮箱)
AD9833手册分析
管脚定义:
手册就先讲到这里,不明白的欢迎评论区留言,另外我会把代码还有手册一并发送给感兴趣的朋友。
AD9833典型应用电路(亲测有效,可以直接拿走)
注意晶振是有源晶振。
软件部分
SPI驱动部分(建议用库函数版本调用STM32SPI功能,尽量不要IO模拟,测过时序之后你可能会明白,IO时序乱的yipi)
spi时序图:
SPI初始化
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*******************/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*******这里很关键*************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //SPI_NSS
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
GPIO_SetBits(GPIOB,GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //选择了串行时钟的稳态:时钟悬空高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第二个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft/*Hard Soft*/; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
//SPI2_ReadWriteByte(0xff);//启动传输
}
我用的是SPI2,假如你打算用SPI1的话,只需要配置一下IO,然后最重要的是SPI时钟千万别挂载错了,RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );改为RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI2, ENABLE );
而且一定要明白NSS管脚含义,AD9833要求写之前有一个拉低的过程,弄明白NSS信号软硬件管理到底什么含义,这里我推荐用软件管理模式,有内部信号接管,(这时候你就不用管主机的NSS了),这时候STM32的NSS管脚可以当普通IO使用,不过要手动拉高拉低NSS管脚(可以参考AD9833写操作时序)小遍在这里给大家安利一篇博客,这一部分说的比较详细。
https://blog.csdn.net/otto1230/article/details/100122559
SPI读写功能
u8 SPI2_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
{
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
一定一定要用这个函数,小遍在这吃过亏,一定要一读一写,否则可能出现写不进去的情况。反正强调一点,不管用SPI做什么,相信我老铁,没毛病。用这个读写函数一点问题都没有。
AD9833驱动代码(重点来了)
下面是头文件标注
ad9833.h
#ifndef _AD9833_H_
#define _AD9833_H_
/******************************************************************************/
/* Include Files */
/******************************************************************************/
#include "sys.h"
#define AD9833_FSYNC PBout(12)//这个是NSS管脚
/******************************************************************************/
/* AD9833 */
/******************************************************************************/
/* Registers */
#define AD9833_REG_CMD (0 << 14)
#define AD9833_REG_FREQ0 (1 << 14)
#define AD9833_REG_FREQ1 (2 << 14)
#define AD9833_REG_PHASE0 (6 << 13)
#define AD9833_REG_PHASE1 (7 << 13)
/* Command Control Bits */
#define AD9833_B28 (1 << 13)
#define AD9833_HLB (1 << 12)
#define AD9833_FSEL0 (0 << 11)
#define AD9833_FSEL1 (1 << 11)
#define AD9833_PSEL0 (0 << 10)
#define AD9833_PSEL1 (1 << 10)
#define AD9833_PIN_SW (1 << 9)
#define AD9833_RESET (1 << 8)
#define AD9833_SLEEP1 (1 << 7)
#define AD9833_SLEEP12 (1 << 6)
#define AD9833_OPBITEN (1 << 5)
#define AD9833_SIGN_PIB (1 << 4)
#define AD9833_DIV2 (1 << 3)
#define AD9833_MODE (1 << 1)
#define AD9833_OUT_SINUS ((0 << 5) | (0 << 1) | (0 << 3))
#define AD9833_OUT_TRIANGLE ((0 << 5) | (1 << 1) | (0 << 3))
#define AD9833_OUT_MSB ((1 << 5) | (0 << 1) | (1 << 3))
#define AD9833_OUT_MSB2 ((1 << 5) | (0 << 1) | (0 << 3))
/******************************************************************************/
/* Functions Prototypes */
/******************************************************************************/
/* Initializes the SPI communication peripheral and resets the part. */
unsigned char AD9833_Init(void);
/* Sets the Reset bit of the AD9833. */
void AD9833_Reset(void);
/* Clears the Reset bit of the AD9833. */
void AD9833_ClearReset(void);
/* Writes the value to a register. */
void AD9833_SetRegisterValue(unsigned short regValue);
/* Writes to the frequency registers. */
void AD9833_SetFrequency(unsigned short reg, float fout);
/* Writes to the phase registers. */
void AD9833_SetPhase(unsigned short reg, unsigned short val);
/* Selects the Frequency,Phase and Waveform type. */
void AD9833_Setup(unsigned short freq,
unsigned short phase,
unsigned short type);
void AD9833_SetFrequencyQuick(float fout,unsigned short type);
unsigned char AD9833_SPI_Write(unsigned char* data,
unsigned char bytesNumber);
#endif // _AD9833_H
ad9833.c
#define FCLK 30000000 //设置晶振频率
//#define RealFreDat 268435456.0/FCLK//总的公式为 Fout=(Fclk/2的28次方)*28位寄存器的值
double RealFreDat = 268435456.0/FCLK;
/********往ad9833写******************************/
unsigned char AD9833_SPI_Write(unsigned char* data,
unsigned char bytesNumber)
{
unsigned char i =0,j = 0;
unsigned char writeData[5] = {0,0, 0, 0, 0};
AD9833_FSYNC =0;
for(i = 0;i < bytesNumber;i ++)
{
writeData[i] = data[i + 1];
}
for(i=0 ;i<bytesNumber ;i++)
{
//while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //检查指定的SPI标志位设置与否:发送缓存空标志位
SPI2_ReadWriteByte(writeData[i]);
}
AD9833_FSYNC = 1;
delay_us(5);
return i;
}
void AD9833_SetRegisterValue(unsigned short regValue)
{
unsigned char data[5] = {0x03, 0x00, 0x00};
data[1] = (unsigned char)((regValue & 0xFF00) >> 8);
data[2] = (unsigned char)((regValue & 0x00FF) >> 0);
AD9833_SPI_Write(data,2);
}
void AD9833_SetFrequency(unsigned short reg, float fout)
{
unsigned short freqHi = reg;
unsigned short freqLo = reg;
unsigned long val=RealFreDat*fout;//F寄存器的值
freqHi |= (val & 0xFFFC000) >> 14 ;
freqLo |= (val & 0x3FFF);
AD9833_SetRegisterValue(AD9833_B28);
AD9833_SetRegisterValue(freqLo);
AD9833_SetRegisterValue(freqHi);
}
void AD9833_SetFrequencyQuick(float fout,unsigned short type)
{
AD9833_SetFrequency(AD9833_REG_FREQ0, fout*1000);// 400 kHz
AD9833_Setup(AD9833_FSEL0, AD9833_PSEL0, type);
}
unsigned char AD9833_Init(void)
{
SPI2_Init();
AD9833_SetRegisterValue(AD9833_REG_CMD | AD9833_RESET);
return (1);
}
void AD9833_Setup(unsigned short freq,
unsigned short phase,
unsigned short type)
{
unsigned short val = 0;
val = freq | phase | type;
AD9833_SetRegisterValue(val);
}
main.c
AD9833_Init();
AD9833_SetFrequencyQuick(0,AD9833_OUT_SINUS );//输出频率 HZ 波形类型 /* SINUS TRIANGLE*/
大体就介绍到这,有问题的朋友可以评论区留言,或者微信都可以,欢迎交流。
版权声明:本文为CSDN博主「你K哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43141547/article/details/106452650
暂无评论