
用GPIO模拟SPI接口驱动AD9837 DDS合成芯片输出正弦波主函数#include stm32f4xx_gpio.h #include ad9837.h // 宏定义用于快速操作GPIO提高模拟SPI速度 #define FSYNC_HIGH() GPIO_SetBits(AD9837_FSYNC_PORT, AD9837_FSYNC_PIN) #define FSYNC_LOW() GPIO_ResetBits(AD9837_FSYNC_PORT, AD9837_FSYNC_PIN) #define SCLK_HIGH() GPIO_SetBits(AD9837_SCLK_PORT, AD9837_SCLK_PIN) #define SCLK_LOW() GPIO_ResetBits(AD9837_SCLK_PORT, AD9837_SCLK_PIN) #define SDATA_HIGH() GPIO_SetBits(AD9837_SDATA_PORT, AD9837_SDATA_PIN) #define SDATA_LOW() GPIO_ResetBits(AD9837_SDATA_PORT, AD9837_SDATA_PIN) // 简单的延时函数用于满足SPI时序要求 static void Delay_us(__IO uint32_t nCount) { volatile int i; for(i0; i100; i){ for(; nCount ! 0; nCount--); } } /** * brief 初始化AD9837所需的GPIO引脚 */ void AD9837_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_AHB1PeriphClockCmd(AD9837_FSYNC_CLK | AD9837_SCLK_CLK | AD9837_SDATA_CLK, ENABLE); // 配置FSYNC (PC13) GPIO_InitStructure.GPIO_Pin AD9837_FSYNC_PIN; GPIO_InitStructure.GPIO_Mode GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; GPIO_Init(AD9837_FSYNC_PORT, GPIO_InitStructure); FSYNC_HIGH(); // 初始状态为高 // 配置SCLK (PB2) GPIO_InitStructure.GPIO_Pin AD9837_SCLK_PIN; GPIO_Init(AD9837_SCLK_PORT, GPIO_InitStructure); SCLK_LOW(); // 初始状态为低 (CPOL0) // 配置SDATA (PB5) GPIO_InitStructure.GPIO_Pin AD9837_SDATA_PIN; GPIO_Init(AD9837_SDATA_PORT, GPIO_InitStructure); SDATA_LOW(); } /** * brief 通过GPIO模拟SPI写入16位数据到AD9837 * param data: 要写入的16位数据 * note AD9837在SCLK下降沿锁存数据 (CPOL0, CPHA1 或类似时序通常DDS芯片在下降沿采样) * 模拟时序先准备数据然后产生一个脉冲低-高-低 或 高-低-高。 * 根据AD9837 datasheet: Data is valid on the falling edge of SCLK. * 这意味着我们需要在SCLK为高时改变数据然后在SCLK下降沿时数据必须稳定。 * 或者更常见的模拟方式 * 1. SCLK Low * 2. Set Data Bit * 3. SCLK High (Data sampled on rising edge? No, AD9837 samples on Falling) * * 修正AD9837 Datasheet Figure 1. * SCLK idle low. Data changes on SCLK rising edge? No. * Data is clocked into the device on the falling edge of SCLK. * 所以 * 1. SCLK High * 2. Set Data Bit (MSB first) * 3. SCLK Low (Falling edge - Device samples data) */ void AD9837_WriteReg(uint16_t data) { uint8_t i; FSYNC_LOW(); // 拉低片选开始通信 // 等待一小段时间确保FSYNC稳定 Delay_us(20); // 发送16位数据高位在前 (MSB First) for (i 0; i 16; i) { // 2. 设置数据位 if (data 0x8000) { SDATA_HIGH(); } else { SDATA_LOW(); } // 数据建立时间 Delay_us(10); // 3. SCLK 置低 (下降沿AD9837在此刻锁存数据) SCLK_LOW(); // 数据保持时间 Delay_us(10); SCLK_HIGH(); Delay_us(10); // 左移一位准备下一位 data 1; } Delay_us(10); // 通信结束拉高FSYNC FSYNC_HIGH(); Delay_us(10); } /** * brief 复位AD9837 */ void AD9837_Reset(void) { // 写复位命令 AD9837_WriteReg(AD9837_REG_CMD | AD9837_RESET); Delay_us(10); // 清除复位位正常工作 AD9837_WriteReg(AD9837_REG_CMD); } /** * brief 设置输出频率 * param freq: 目标频率 (Hz) * note 假设MCLK 16MHz */ void AD9837_SetFrequency(unsigned short reg, uint32_t val) { unsigned short freqHi reg; unsigned short freqLo reg; unsigned int value0; double tempval/((AD9837_Frequency)/(268435456.0)); value(int)temp; freqHi | (value 0xFFFC000) 14 ; freqLo | (value 0x3FFF); /*写控制字Control word write(D15, D14 00), B28 (D13) 1*/ AD9837_WriteReg(AD9837_B28); AD9837_WriteReg(freqLo); AD9837_WriteReg(freqHi); } /** * brief 设置波形类型 * param mode: 波形模式 (MODE_SINE, MODE_TRIANGLE, MODE_SQUARE) */ void AD9837_SetWaveform(uint16_t mode) { AD9837_WriteReg(mode); } /** * brief AD9837 完整初始化 */ void AD9837_Init(void) { AD9837_GPIO_Init(); // 复位设备 AD9837_Reset(); // 设置频率为 40Hz AD9837_SetFrequency(AD9837_REG_FREQ0, 40); AD9837_SetFrequency(AD9837_REG_FREQ1, 00); // 设置为正弦波 AD9837_SetWaveform(AD9837_OUT_SINUS); }头文件