任务描述
一、任务
在给定±15V 电源电压条件下,设计并制作一个正弦波和脉冲波信号源。
二、要求
1.基本要求
(1)正弦波信号源
① 信号频率: 20Hz~20kHz 步进调整,步长为20Hz
② 频率稳定度:优于 10-3
③ 波形无明显失真
(2)脉冲波信号源
① 信号频率: 20Hz~20kHz 步进调整,步长为20Hz
② 上升时间和下降时间: ≤2μs
③ 平顶斜降: ≤5%
④ 脉冲占空比: 2%~98%步进可调,步长为 2%
(3)上述两个信号源公共要求
① 频率可预置。
② 在负载为 600Ω 时,输出幅度为 3V。
③ 完成 5 位频率的数字显示。
2.发挥部分
(1)正弦波和脉冲波频率步长改为 5Hz。
(2)正弦波和脉冲波幅度可步进调整,调整范围为 100mV~5V,步长为 50mV。
(3)正弦波和脉冲波频率可自动步进,步长为 5Hz。
(4)降低正弦波非线性失真系数及其他。
三、说明
搭建单片机小系统,至少包含显示模块(至少为 128x64 以上像素)、人机交互模块(至少
为 4x4 按键或触摸屏)。
软件方案
使用AD9910模块的RAM模式实现PWM波和正弦波的输出,为了使AD9910输出信号的频率更加精确,采用了Si5351A时钟信号发生器模块来作为AD9910的外部时钟源。
配置CubeMX
主要是AD9910模块和Si5351A模块通信引脚的配置。此外,使用串口通信。
串口通信要实现串口+DMA+中断接收,串口的配置如下
串口中断优先级的设置可以在System Core的NVIC中进行设置
一般默认把system tick timer的优先级设置为0
在CubeMX中把堆栈的最小值设置为0x2000,因为在工程中有一个循环生成波表,如果堆栈区小的话,会进入HardFault_Handler这个硬件异常状态
CubeMX配置完毕生成代码即可。
CubeMX的配置文件,可以在用CubeMX新建一个工程后使用Import Project导入,之后只需要把时钟修改即可。
CubeMX配置完毕
代码编写
1.串口重定向,看之前的文章进行串口重定向,记得勾选Micro LIB,不然就下载进单片机后没法正常运行,而在Keil的调试中确实正常的。
AD9910.c
以下是我根据资料自己写的函数
// 自己写的函数
/************************************************************
** 函数名称 :void Init_AD9910_Fre(uint32_t Frequency)
** 函数功能 :根据Frequency来选择AD9910合适的VOC进行初始化,即改变cfr3[0]的值
**************************************************************/
void Init_AD9910_Fre(uint32_t Frequency)
{
int32_t CLK_Frequency = Frequency;
if (CLK_Frequency >= 400000000 && CLK_Frequency <= 460000000)
{
cfr3[0] = 0x00;
}
else if (CLK_Frequency >= 455000000 && CLK_Frequency <= 530000000)
{
cfr3[0] = 0x01;
}
else if (CLK_Frequency >= 530000000 && CLK_Frequency <= 615000000)
{
cfr3[0] = 0x02;
}
else if (CLK_Frequency >= 650000000 && CLK_Frequency <= 790000000)
{
cfr3[0] = 0x03;
}
else if (CLK_Frequency >= 760000000 && CLK_Frequency <= 875000000)
{
cfr3[0] = 0x04;
}
else if (CLK_Frequency >= 920000000 && CLK_Frequency <= 1030000000)
{
cfr3[0] = 0x05;
}
uchar k, m;
// AD9110_IOInit(); // IO初始化
// AD9910_PWR = 0; // 软件拉低
HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);
// PROFILE2 = 0;
HAL_GPIO_WritePin(PF2_GPIO_Port, PF2_Pin, GPIO_PIN_RESET);
// PROFILE1 = 0;
HAL_GPIO_WritePin(PF1_GPIO_Port, PF1_Pin, GPIO_PIN_RESET);
// PROFILE0 = 0;
HAL_GPIO_WritePin(PF0_GPIO_Port, PF0_Pin, GPIO_PIN_RESET);
// DRCTL = 0;
HAL_GPIO_WritePin(DRC_GPIO_Port, DRC_Pin, GPIO_PIN_RESET);
// DRHOLD = 0;
HAL_GPIO_WritePin(DRO_GPIO_Port, DRO_Pin, GPIO_PIN_RESET);
// MAS_REST = 1;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET);
HAL_Delay(5);
// MAS_REST = 0;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 发送CFR1控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr1[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x01); // 发送CFR2控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr2[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x02); // 发送CFR3控制字地址
if (Frequency * 2000)
for (m = 0; m < 4; m++)
txd_8bit(cfr3[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
HAL_Delay(1);
}
/************************************************************
** 函数名称 :Reset_AD9910()
** 函数功能 :复位AD9910
**************************************************************/
void Reset_AD9910()
{
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET);
}
/************************************************************
** 函数名称 :PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty)
** 函数功能 :根据地址步进率,电压,占空比来产生合适的PWM
更改地址步进率是更改RAM_Profile0[1]和RAM_Profile0[2]
**************************************************************/
void PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty)
{
int i;
const uint16_t LENGTH = 100;
uint32_t PWM_Wave[LENGTH];
uint8_t CFR1[] = {0x40, 0x40, 0x00, 0x00}; // RAM回放目的:幅度;;开启AD9910反Sinc滤波
// RAM_Profile0[1](高8位) 与 RAM_Profile0[2](低8位)共16位控制字M,决定了输出波形频率, 频率 = Fsysclk / (4*M) / 输出点数 = 1000000000 / (4*M) / 1024
uint8_t RAM_Profile0[] = {0x00, 0x00, 0x7A, 0xff, 0xc0, 0x00, 0x00, 0x04}; // 地址步进率0XFFFF=65535,,从地址0回放到1023,共1024点,输出频率 = 1G / (4*122) /1024 =2000Hz // 连续循环模式RAM_PROx[7]=0x04
// 将 step_rates 的高位字节存储到 RAM_Profile0[1]
// 使用右移 8 位操作获取高位字节,然后使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[1] = (uint8_t)(step_rates >> 8) & 0xFF;
// 将 step_rates 的低位字节存储到 RAM_Profile0[2]
// 使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[2] = (uint8_t)step_rates & 0xFF;
// 将 (LENGTH - 1) 的高位 6 位存储到 RAM_Profile0[3]
// 使用右移 2 位操作获取高位 6 位
RAM_Profile0[3] = (uint8_t)((LENGTH - 1) >> 2);
// 将 (LENGTH - 1) 的低位 2 位存储到 RAM_Profile0[4]
// 使用左移 6 位操作获取低位 2 位
RAM_Profile0[4] = (uint8_t)((LENGTH - 1) << 6);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其寄存器0x00
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0X0E); // 写寄存器RAM_Profile0
for (i = 0; i < 8; i++)
{
txd_8bit(RAM_Profile0[i]); // 将RAM的起始和终止地址、地址步进率写入相应的寄存器 0x0e
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x16);
uint16_t Zero_Num = LENGTH * Duty / 100;
for (i = 0; i < Zero_Num; i++)
{
PWM_Wave[i] = 0;
}
for (i = Zero_Num; i < LENGTH; i++)
{
PWM_Wave[i] = voltage;
}
for (i = 0; i < LENGTH; i++)
{
Write_32bit(PWM_Wave[i] << 18); // 将三角波(或其他任意波形)的数据数组写入ram,32位寄存器,14位DAC值,数据左对齐,故左移18位
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其地址0x00
CFR1[0] |= 0X80; // 使能RAM
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
}
/************************************************************
** 函数名称 :Sin_Generate(uint16_t step_rates, uint16_t voltage)
** 函数功能 :根据地址步进率,电压,来产生合适的正弦波
更改地址步进率是更改RAM_Profile0[1]和RAM_Profile0[2]
**************************************************************/
void Sin_Generate(uint16_t step_rates, uint16_t voltage)
{
int i;
const uint16_t LENGTH = 100;
uint32_t Sin_Wave[LENGTH];
uint8_t CFR1[] = {0x40, 0x40, 0x00, 0x00}; // RAM回放目的:幅度;;开启AD9910反Sinc滤波
uint8_t RAM_Profile0[] = {0x00, 0x00, 0x7A, 0xff, 0xc0, 0x00, 0x00, 0x04}; // 地址步进率0XFFFF=65535,,从地址0回放到1023,共1024点,输出频率 = 1G / (4*122) /1024 =2000Hz // 连续循环模式RAM_PROx[7]=0x04
// 将 step_rates 的高位字节存储到 RAM_Profile0[1]
// 使用右移 8 位操作获取高位字节,然后使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[1] = (uint8_t)(step_rates >> 8) & 0xFF;
// 将 step_rates 的低位字节存储到 RAM_Profile0[2]
// 使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[2] = (uint8_t)step_rates & 0xFF;
// 将 (LENGTH - 1) 的高位 6 位存储到 RAM_Profile0[3]
// 使用右移 2 位操作获取高位 6 位
RAM_Profile0[3] = (uint8_t)((LENGTH - 1) >> 2);
// 将 (LENGTH - 1) 的低位 2 位存储到 RAM_Profile0[4]
// 使用左移 6 位操作获取低位 2 位
RAM_Profile0[4] = (uint8_t)((LENGTH - 1) << 6);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其寄存器0x00
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0X0E); // 写寄存器RAM_Profile0
for (i = 0; i < 8; i++)
{
txd_8bit(RAM_Profile0[i]); // 将RAM的起始和终止地址、地址步进率写入相应的寄存器 0x0e
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x16);
for (i = 0; i < LENGTH; i++)
{
Sin_Wave[i] = (float)voltage/2 * sin(2 * PI / 100 * i)+(float)voltage/2;
}
for (i = 0; i < LENGTH; i++)
{
Write_32bit(Sin_Wave[i] << 18); // 将三角波(或其他任意波形)的数据数组写入ram,32位寄存器,14位DAC值,数据左对齐,故左移18位
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其地址0x00
CFR1[0] |= 0X80; // 使能RAM
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
}
根据频率对AD9910进行初始化需要依据AD9910数据手册中VCO的范围
信号源输入信号给AD9910之后,会进行25倍频,VCO的范围选择依据是倍频后的频率。
产生PWM和正弦波需要修改AD9910的RAM_Profile0,通过修改数组RAM_Profile0[]来实现
RAM_Profile0[1]和RAM_Profile0[2]这两个值是控制步进率
RAM_Profile0[3]和RAM_Profile0[4]这两个值是控制信号长度,在该工程中信号长度为100
下面说明了如何更改这些值
// 将 step_rates 的高位字节存储到 RAM_Profile0[1]
// 使用右移 8 位操作获取高位字节,然后使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[1] = (uint8_t)(step_rates >> 8) & 0xFF;
// 将 step_rates 的低位字节存储到 RAM_Profile0[2]
// 使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[2] = (uint8_t)step_rates & 0xFF;
// 将 (LENGTH - 1) 的高位 6 位存储到 RAM_Profile0[3]
// 使用右移 2 位操作获取高位 6 位
RAM_Profile0[3] = (uint8_t)((LENGTH - 1) >> 2);
// 将 (LENGTH - 1) 的低位 2 位存储到 RAM_Profile0[4]
// 使用左移 6 位操作获取低位 2 位
RAM_Profile0[4] = (uint8_t)((LENGTH - 1) << 6);
完整的AD9910.c文件
#include "stm32h7xx_hal.h"
#include "AD9910.h"
#include "math.h"
#define PI 3.141592654
uchar cfr1[] = {0x00, 0x40, 0x00, 0x00}; // cfr1控制字
const uchar cfr2[] = {0x01, 0x00, 0x00, 0x00}; // cfr2控制字
uchar cfr3[] = {0x00, 0x0F, 0x41, 0x32}; // cfr3控制字 40M输入 25倍频 VC0=101 ICP=001;{0000 0101, 0000 1111, 0100 0001, 0011 0010}
uchar profile11[] = {0x3f, 0xff, 0x00, 0x00, 0x25, 0x09, 0x7b, 0x42}; // profile1控制字 0x25,0x09,0x7b,0x42
uint32_t sin_wave[] = {
8192, 8706, 9218, 9726, 10229, 10723, 11207, 11679, 12138, 12581, 13006, 13413,
13799, 14163, 14503, 14819, 15108, 15370, 15603, 15808, 15982, 16126, 16238, 16318,
16367, 16383, 16367, 16318, 16238, 16126, 15982, 15808, 15603, 15370, 15108, 14819,
14503, 14163, 13799, 13413, 13006, 12581, 12138, 11679, 11207, 10723, 10229, 9726,
9218, 8706, 8192, 7677, 7165, 6657, 6154, 5660, 5176, 4704, 4245, 3802,
3377, 2970, 2584, 2220, 1880, 1564, 1275, 1013, 780, 575, 401, 257,
145, 65, 16, 0, 16, 65, 145, 257, 401, 575, 780, 1013,
1275, 1564, 1880, 2220, 2584, 2970, 3377, 3802, 4245, 4704, 5176, 5660,
6154, 6657, 7165, 7677};
// 01振幅控制 23相位控制 4567频率调谐字
/************************************************************
** 函数名称 :void AD9110_IOInit(void)
** 函数功能 :控制AD9910需要用到的IO口在此初始化
** 入口参数 :无
** 出口参数 :无
** 函数说明 :无
**************************************************************/
// void AD9110_IOInit(void)
//{
// GPIO_InitTypeDef GPIO_InitStructure;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE); // 使能PB,PE端口时钟
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10 | GPIO_Pin_1 | GPIO_Pin_0;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3 | GPIO_Pin_2 | GPIO_Pin_1 | GPIO_Pin_0;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
// GPIO_Init(GPIOC, &GPIO_InitStructure);
//}
/************************************************************
** 函数名称 :void txd_8bit(uchar txdat)
** 函数功能 :AD9910串行口写入数据
** 入口参数 :8位寄存器数据
** 出口参数 :无
** 函数说明 :无
**************************************************************/
void txd_8bit(uchar txdat)
{
uchar i, sbt;
sbt = 0x80;
// SCLK = 0;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
for (i = 0; i < 8; i++)
{
if ((txdat & sbt) == 0)
// AD9910_SDIO = 0;
HAL_GPIO_WritePin(SDIO_GPIO_Port, SDIO_Pin, GPIO_PIN_RESET);
else
// AD9910_SDIO = 1;
HAL_GPIO_WritePin(SDIO_GPIO_Port, SDIO_Pin, GPIO_PIN_SET);
// SCLK = 1;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
sbt = sbt >> 1;
// SCLK = 0;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
}
}
/************************************************************
** 函数名称 :void Write_32bit(uint32_t dat)
** 函数功能 :AD9910串行口写入数据
** 入口参数 :32位寄存器数据
** 出口参数 :无
** 函数说明 :无
**************************************************************/
void Write_32bit(uint32_t dat)
{
uint8_t i;
uint32_t com;
com = 0x80000000;
// SCLK = 0;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
for (i = 0; i < 32; i++)
{
if ((dat & com) == 0)
// AD9910_SDIO = 0;
HAL_GPIO_WritePin(SDIO_GPIO_Port, SDIO_Pin, GPIO_PIN_RESET);
else
// AD9910_SDIO = 1;
HAL_GPIO_WritePin(SDIO_GPIO_Port, SDIO_Pin, GPIO_PIN_SET);
// SCLK = 1;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_SET);
com = com >> 1;
// SCLK = 0;
HAL_GPIO_WritePin(SCK_GPIO_Port, SCK_Pin, GPIO_PIN_RESET);
}
}
/************************************************************
** 函数名称 :void Init_ad9910(void))
** 函数功能 :初始化AD9910的管脚和最简单的内部寄存器的配置,
** 入口参数 :无
** 出口参数 :无
** 函数说明 :无
**************************************************************/
void Init_AD9910(void)
{
uchar k, m;
// AD9110_IOInit(); // IO初始化
// AD9910_PWR = 0; // 软件拉低
HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);
// PROFILE2 = 0;
HAL_GPIO_WritePin(PF2_GPIO_Port, PF2_Pin, GPIO_PIN_RESET);
// PROFILE1 = 0;
HAL_GPIO_WritePin(PF1_GPIO_Port, PF1_Pin, GPIO_PIN_RESET);
// PROFILE0 = 0;
HAL_GPIO_WritePin(PF0_GPIO_Port, PF0_Pin, GPIO_PIN_RESET);
// DRCTL = 0;
HAL_GPIO_WritePin(DRC_GPIO_Port, DRC_Pin, GPIO_PIN_RESET);
// DRHOLD = 0;
HAL_GPIO_WritePin(DRO_GPIO_Port, DRO_Pin, GPIO_PIN_RESET);
// MAS_REST = 1;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET);
HAL_Delay(5);
// MAS_REST = 0;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 发送CFR1控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr1[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x01); // 发送CFR2控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr2[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x02); // 发送CFR3控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr3[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
HAL_Delay(1);
}
/************************************************************
** 函数名称 :void Txfrc(void))
** 函数功能 :向AD9910芯片发送频率,幅度等相关控制数据
** 入口参数 :无
** 出口参数 :无
** 函数说明 :无
**************************************************************/
void Txfrc(void)
{
uchar m;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x0e); // 发送profile1控制字地址
for (m = 0; m < 8; m++)
txd_8bit(profile11[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
}
/************************************************************
** 函数名称 :void AD9910_FreWrite(void))
** 函数功能 :将需要的频率转换为对应的控制数据,保存进profile11并发送到芯片
** 入口参数 :目标频率,单位Hz,范围0~420000000
** 出口参数 :无
** 函数说明 :无
**************************************************************/
void AD9910_FreWrite(ulong Freq)
{
ulong Temp;
Temp = (ulong)Freq * 4.294967296; // 将输入频率因子分为四个字节 主频1GHz,32位相位累加器,故每Hz在的控制字增量 delta = 4.294967296 = (2^32)/1000000000
profile11[7] = (uchar)Temp;
profile11[6] = (uchar)(Temp >> 8);
profile11[5] = (uchar)(Temp >> 16);
profile11[4] = (uchar)(Temp >> 24);
Txfrc();
}
/************************************************************
** 函数名称 :void AD9910_AmpWrite(void))
** 函数功能 :将幅度控制数据保存到profile11并写入芯片
** 入口参数 :幅度控制字,范围0~16383
** 出口参数 :无
** 函数说明 :14位幅度控制字,控制数据0~16383对应输出幅度0~800mV左右
**************************************************************/
void AD9910_AmpWrite(uint16_t Amp)
{
profile11[0] = (Amp % 16384) >> 8;
profile11[1] = (Amp % 16384) & 0xff;
Txfrc();
}
// 自己写的函数
/************************************************************
** 函数名称 :void Init_AD9910_Fre(uint32_t Frequency)
** 函数功能 :根据Frequency来选择AD9910合适的VOC进行初始化,即改变cfr3[0]的值
**************************************************************/
void Init_AD9910_Fre(uint32_t Frequency)
{
int32_t CLK_Frequency = Frequency;
if (CLK_Frequency >= 400000000 && CLK_Frequency <= 460000000)
{
cfr3[0] = 0x00;
}
else if (CLK_Frequency >= 455000000 && CLK_Frequency <= 530000000)
{
cfr3[0] = 0x01;
}
else if (CLK_Frequency >= 530000000 && CLK_Frequency <= 615000000)
{
cfr3[0] = 0x02;
}
else if (CLK_Frequency >= 650000000 && CLK_Frequency <= 790000000)
{
cfr3[0] = 0x03;
}
else if (CLK_Frequency >= 760000000 && CLK_Frequency <= 875000000)
{
cfr3[0] = 0x04;
}
else if (CLK_Frequency >= 920000000 && CLK_Frequency <= 1030000000)
{
cfr3[0] = 0x05;
}
uchar k, m;
// AD9110_IOInit(); // IO初始化
// AD9910_PWR = 0; // 软件拉低
HAL_GPIO_WritePin(PWR_GPIO_Port, PWR_Pin, GPIO_PIN_RESET);
// PROFILE2 = 0;
HAL_GPIO_WritePin(PF2_GPIO_Port, PF2_Pin, GPIO_PIN_RESET);
// PROFILE1 = 0;
HAL_GPIO_WritePin(PF1_GPIO_Port, PF1_Pin, GPIO_PIN_RESET);
// PROFILE0 = 0;
HAL_GPIO_WritePin(PF0_GPIO_Port, PF0_Pin, GPIO_PIN_RESET);
// DRCTL = 0;
HAL_GPIO_WritePin(DRC_GPIO_Port, DRC_Pin, GPIO_PIN_RESET);
// DRHOLD = 0;
HAL_GPIO_WritePin(DRO_GPIO_Port, DRO_Pin, GPIO_PIN_RESET);
// MAS_REST = 1;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET);
HAL_Delay(5);
// MAS_REST = 0;
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 发送CFR1控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr1[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x01); // 发送CFR2控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr2[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x02); // 发送CFR3控制字地址
if (Frequency * 2000)
for (m = 0; m < 4; m++)
txd_8bit(cfr3[m]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
for (k = 0; k < 10; k++)
;
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
HAL_Delay(1);
}
/************************************************************
** 函数名称 :Reset_AD9910()
** 函数功能 :复位AD9910
**************************************************************/
void Reset_AD9910()
{
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET);
}
/************************************************************
** 函数名称 :PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty)
** 函数功能 :根据地址步进率,电压,占空比来产生合适的PWM
更改地址步进率是更改RAM_Profile0[1]和RAM_Profile0[2]
**************************************************************/
void PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty)
{
int i;
const uint16_t LENGTH = 100;
uint32_t PWM_Wave[LENGTH];
uint8_t CFR1[] = {0x40, 0x40, 0x00, 0x00}; // RAM回放目的:幅度;;开启AD9910反Sinc滤波
// RAM_Profile0[1](高8位) 与 RAM_Profile0[2](低8位)共16位控制字M,决定了输出波形频率, 频率 = Fsysclk / (4*M) / 输出点数 = 1000000000 / (4*M) / 1024
uint8_t RAM_Profile0[] = {0x00, 0x00, 0x7A, 0xff, 0xc0, 0x00, 0x00, 0x04}; // 地址步进率0XFFFF=65535,,从地址0回放到1023,共1024点,输出频率 = 1G / (4*122) /1024 =2000Hz // 连续循环模式RAM_PROx[7]=0x04
// 将 step_rates 的高位字节存储到 RAM_Profile0[1]
// 使用右移 8 位操作获取高位字节,然后使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[1] = (uint8_t)(step_rates >> 8) & 0xFF;
// 将 step_rates 的低位字节存储到 RAM_Profile0[2]
// 使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[2] = (uint8_t)step_rates & 0xFF;
// 将 (LENGTH - 1) 的高位 6 位存储到 RAM_Profile0[3]
// 使用右移 2 位操作获取高位 6 位
RAM_Profile0[3] = (uint8_t)((LENGTH - 1) >> 2);
// 将 (LENGTH - 1) 的低位 2 位存储到 RAM_Profile0[4]
// 使用左移 6 位操作获取低位 2 位
RAM_Profile0[4] = (uint8_t)((LENGTH - 1) << 6);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其寄存器0x00
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0X0E); // 写寄存器RAM_Profile0
for (i = 0; i < 8; i++)
{
txd_8bit(RAM_Profile0[i]); // 将RAM的起始和终止地址、地址步进率写入相应的寄存器 0x0e
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x16);
uint16_t Zero_Num = LENGTH * Duty / 100;
for (i = 0; i < Zero_Num; i++)
{
PWM_Wave[i] = 0;
}
for (i = Zero_Num; i < LENGTH; i++)
{
PWM_Wave[i] = voltage;
}
for (i = 0; i < LENGTH; i++)
{
Write_32bit(PWM_Wave[i] << 18); // 将三角波(或其他任意波形)的数据数组写入ram,32位寄存器,14位DAC值,数据左对齐,故左移18位
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其地址0x00
CFR1[0] |= 0X80; // 使能RAM
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
}
/************************************************************
** 函数名称 :Sin_Generate(uint16_t step_rates, uint16_t voltage)
** 函数功能 :根据地址步进率,电压,来产生合适的正弦波
更改地址步进率是更改RAM_Profile0[1]和RAM_Profile0[2]
**************************************************************/
void Sin_Generate(uint16_t step_rates, uint16_t voltage)
{
int i;
const uint16_t LENGTH = 100;
uint32_t Sin_Wave[LENGTH];
uint8_t CFR1[] = {0x40, 0x40, 0x00, 0x00}; // RAM回放目的:幅度;;开启AD9910反Sinc滤波
uint8_t RAM_Profile0[] = {0x00, 0x00, 0x7A, 0xff, 0xc0, 0x00, 0x00, 0x04}; // 地址步进率0XFFFF=65535,,从地址0回放到1023,共1024点,输出频率 = 1G / (4*122) /1024 =2000Hz // 连续循环模式RAM_PROx[7]=0x04
// 将 step_rates 的高位字节存储到 RAM_Profile0[1]
// 使用右移 8 位操作获取高位字节,然后使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[1] = (uint8_t)(step_rates >> 8) & 0xFF;
// 将 step_rates 的低位字节存储到 RAM_Profile0[2]
// 使用按位与操作符与 0xFF 进行掩码操作以确保只取低 8 位
RAM_Profile0[2] = (uint8_t)step_rates & 0xFF;
// 将 (LENGTH - 1) 的高位 6 位存储到 RAM_Profile0[3]
// 使用右移 2 位操作获取高位 6 位
RAM_Profile0[3] = (uint8_t)((LENGTH - 1) >> 2);
// 将 (LENGTH - 1) 的低位 2 位存储到 RAM_Profile0[4]
// 使用左移 6 位操作获取低位 2 位
RAM_Profile0[4] = (uint8_t)((LENGTH - 1) << 6);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其寄存器0x00
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0X0E); // 写寄存器RAM_Profile0
for (i = 0; i < 8; i++)
{
txd_8bit(RAM_Profile0[i]); // 将RAM的起始和终止地址、地址步进率写入相应的寄存器 0x0e
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x16);
for (i = 0; i < LENGTH; i++)
{
Sin_Wave[i] = (float)voltage/2 * sin(2 * PI / 100 * i)+(float)voltage/2;
}
for (i = 0; i < LENGTH; i++)
{
Write_32bit(Sin_Wave[i] << 18); // 将三角波(或其他任意波形)的数据数组写入ram,32位寄存器,14位DAC值,数据左对齐,故左移18位
}
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// CS = 0;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
txd_8bit(0x00); // 将CFR1写入其地址0x00
CFR1[0] |= 0X80; // 使能RAM
for (i = 0; i < 4; i++)
txd_8bit(CFR1[i]);
// CS = 1;
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
// UP_DAT = 0; // 更新AD9910
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
// UP_DAT = 1;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_SET);
// UP_DAT = 0;
HAL_GPIO_WritePin(IOUP_GPIO_Port, IOUP_Pin, GPIO_PIN_RESET);
}
AD9910.h
#ifndef __AD9910_H__
#define __AD9910_H__
#include "main.h"
#include "gpio.h"
#include "math.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long int
typedef enum
{
TRIG_WAVE = 0,
SQUARE_WAVE,
SINC_WAVE,
} AD9910_WAVE_ENUM;
// void AD9110_IOInit(void); //资料里的引脚初始化函数,没用
void Init_AD9910(void); // 资料里的引脚初始化函数,没用
void AD9910_FreWrite(ulong Freq); // 单频调制模式写频率
void AD9910_AmpWrite(uint16_t Amp); // 单频调制模式写电压
void txd_8bit(uchar txdat);
void Write_32bit(uint32_t dat);
// 自己创建的函数在下面
void Init_AD9910_Fre(uint32_t Frequency); // 按照频率对AD9910进行初始化
void Reset_AD9910(); // 复位AD9910
void PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty); // 操作AD9910产生PWM
void Sin_Generate(uint16_t PFREQUENCY, uint16_t voltage); // 操作AD9910产生正弦波
#endif
SI5351A.c
#include "si5351a.h"
// static void I2C_GPIO_Config(void)
//{
// GPIO_InitTypeDef GPIO_InitStructure;
// RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE );
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_3; /* PC3-I2C_SCL、PC5-I2C_SDA*/
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
// GPIO_Init(GPIOC, &GPIO_InitStructure);
// }
///IIC初始化//
// void IIC_SI5351A_GPIO_Init(void)
// {
// I2C_GPIO_Config();
// }
粗略延时函数//
void Delay_1us(uint16_t n) // 约1us,1100k
{
unsigned int x = 5, i = 0;
for (i = 0; i < n; i++)
{
while (x--)
;
x = 5;
}
}
void Delay_ms(uint8_t n) // 约0.5ms,2k
{
unsigned int x = 5000, i = 0;
for (i = 0; i < n; i++)
{
while (x--)
;
x = 5000;
}
}
IIC启动函数//
void I2C_Start(void)
{
SDA_H;
SCL_H;
Delay_1us(1);
if (!SDA_read)
return; // SDA线为低电平则总线忙,退出
SDA_L;
Delay_1us(1);
if (SDA_read)
return; // SDA线为高电平则总线出错,退出
SDA_L;
Delay_1us(1);
SCL_L;
}
//**************************************
// IIC停止信号
//**************************************
void I2C_Stop(void)
{
SDA_L;
SCL_L;
Delay_1us(1);
SCL_H;
SDA_H;
Delay_1us(1); // 延时
}
//**************************************
// IIC发送应答信号
// 入口参数:ack (0:ACK 1:NAK)
//**************************************
void I2C_SendACK(uint8_t i)
{
if (1 == i)
SDA_H; // 写应答信号
else
SDA_L;
SCL_H; // 拉高时钟线
Delay_1us(1); // 延时
SCL_L; // 拉低时钟线
Delay_1us(1);
}
//**************************************
// IIC等待应答
// 返回值:ack (1:ACK 0:NAK)
//**************************************
bool I2C_WaitAck(void) // 返回为:=1有ACK,=0无ACK
{
unsigned int i;
SDA_H;
Delay_1us(1);
SCL_H;
Delay_1us(1);
while (SDA_read)
{
i++;
if (i == 5000)
break;
}
if (SDA_read)
{
SCL_L;
Delay_1us(1);
return FALSE;
}
SCL_L;
Delay_1us(1);
return TRUE;
}
//**************************************
// 向IIC总线发送一个字节数据
//**************************************
void I2C_SendByte(uint8_t dat)
{
unsigned int i;
SCL_L;
for (i = 0; i < 8; i++) // 8位计数器
{
if (dat & 0x80)
{
SDA_H;
} // 送数据口
else
SDA_L;
SCL_H; // 拉高时钟线
Delay_1us(1); // 延时
SCL_L; // 拉低时钟线
Delay_1us(1); // 延时
dat <<= 1; // 移出数据的最高位
}
}
//**************************************
// 从IIC总线接收一个字节数据
//**************************************
uint8_t I2C_RecvByte()
{
uint8_t i;
uint8_t dat = 0;
SDA_H; // 使能内部上拉,准备读取数据,
for (i = 0; i < 8; i++) // 8位计数器
{
dat <<= 1;
SCL_H; // 拉高时钟线
Delay_1us(1); // 延时
if (SDA_read) // 读数据
{
dat |= 0x01;
}
SCL_L; // 拉低时钟线
Delay_1us(1);
}
return dat;
}
//**************************************
// 向IIC设备写入一个字节数据
//**************************************
bool Single_WriteI2C(uint8_t Slave_Address, uint8_t REG_Address, uint8_t REG_data)
{
I2C_Start(); // 起始信号
I2C_SendByte(Slave_Address); // 发送设备地址+写信号
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte(REG_Address); // 内部寄存器地址,
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte(REG_data); // 内部寄存器数据,
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_Stop(); // 发送停止信号
}
uint8_t Single_ReadI2C(uint8_t Slave_Address, uint8_t REG_Address)
{
uint8_t REG_data;
I2C_Start(); // 起始信号
I2C_SendByte(Slave_Address); // 发送设备地址+写信号
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte(REG_Address); // 发送存储单元地址,从0开始
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_Start(); // 起始信号
I2C_SendByte(Slave_Address + 1); // 发送设备地址+读信号
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
REG_data = I2C_RecvByte(); // 读出寄存器数据
I2C_SendACK(1); // 发送停止传输信号
I2C_Stop(); // 停止信号
return REG_data;
}
uint8_t i2cSendRegister(uint8_t reg, uint8_t data)
{
I2C_Start(); // 起始信号
I2C_SendByte(0xC0); // 发送设备地址+写信号
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte(reg); // 内部寄存器地址,
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_SendByte(data); // 内部寄存器数据,
if (!I2C_WaitAck())
{
I2C_Stop();
return FALSE;
}
I2C_Stop();
return 0;
}
void si5351aSetFrequency(uint32_t frequency)
{
// 局部变量定义
uint32_t pllFreq; // PLL频率
uint32_t xtalFreq = XTAL_FREQ; // 晶体频率,由XTAL_FREQ宏定义指定
uint32_t l;
float f;
uint8_t mult; // PLL频率乘数
uint32_t num; // 分数乘数的分子
uint32_t denom; // 分数乘数的分母
uint32_t divider; // 分频比
// 计算分频比。900,000,000是内部PLL的最大频率:900MHz
divider = 900000000 / frequency;
// 如果divider是奇数,减一使其成为偶数,确保是整数分频比
if (divider % 2)
divider--;
// 计算PLL频率:分频比 * 目标输出频率
pllFreq = divider * frequency;
// 确定乘数以达到所需的PLL频率
mult = pllFreq / xtalFreq;
// 计算乘数的整数部分和小数部分
l = pllFreq % xtalFreq;
f = l;
// 小数部分的处理:乘以1048575,然后除以晶体频率
f *= 1048575;
f /= xtalFreq;
num = f;
denom = 1048575; // 简化处理,将分母设为最大值1048575
// 使用计算出的乘数、分子、分母设置PLL A
setupPLL(SI_SYNTH_PLL_A, mult, num, denom);
// 使用计算出的分频比设置MultiSynth除数0。最终R分频阶段可以将频率除以1到128之间的2的幂次
// 由SI_R_DIV1到SI_R_DIV128常量表示(见si5351a.h头文件)
// 如果你想输出低于1MHz的频率,必须使用最终的R分频阶段
setupMultisynth(SI_SYNTH_MS_0, divider, SI_R_DIV_1);
// 重置PLL。这会导致输出短暂的不稳定。对参数的小改动不需要重置PLL,也就不会有不稳定现象
i2cSendRegister(SI_PLL_RESET, 0xA0);
// 最后,打开CLK0输出(0x4F)并设置MultiSynth0的输入为PLL A
i2cSendRegister(SI_CLK0_CONTROL, 0x4F | SI_CLK_SRC_PLL_A);
}
void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom)
{
uint32_t P1; // PLL配置寄存器P1
uint32_t P2; // PLL配置寄存器P2
uint32_t P3; // PLL配置寄存器P3
// 计算P1值,首先将分数乘数转换为浮点数进行运算,然后将结果乘以128
P1 = (uint32_t)(128 * ((float)num / (float)denom));
// 然后加上乘数mult乘以128,最后减去512
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
// 计算P2值,过程同P1,但是计算方式略有不同
P2 = (uint32_t)(128 * ((float)num / (float)denom));
// 使用num乘以128减去denom乘以前面计算的P2值
P2 = (uint32_t)(128 * num - denom * P2);
// P3简单地等于分母denom
P3 = denom;
// 使用I2C发送寄存器值来配置PLL
// 发送P3的第二个字节
i2cSendRegister(pll + 0, (P3 & 0x0000FF00) >> 8);
// 发送P3的第一个字节
i2cSendRegister(pll + 1, (P3 & 0x000000FF));
// 发送P1的最高两位
i2cSendRegister(pll + 2, (P1 & 0x00030000) >> 16);
// 发送P1的中间八位
i2cSendRegister(pll + 3, (P1 & 0x0000FF00) >> 8);
// 发送P1的最低八位
i2cSendRegister(pll + 4, (P1 & 0x000000FF));
// 发送P3和P2的最高四位
i2cSendRegister(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
// 发送P2的中间八位
i2cSendRegister(pll + 6, (P2 & 0x0000FF00) >> 8);
// 发送P2的最低八位
i2cSendRegister(pll + 7, (P2 & 0x000000FF));
}
void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv)
{
uint32_t P1; // 多合成器配置寄存器P1
uint32_t P2; // 多合成器配置寄存器P2
uint32_t P3; // 多合成器配置寄存器P3
// 计算P1的值,这是基于分频比的配置,128是固定小数点运算的一部分,512用于调整
P1 = 128 * divider - 512;
P2 = 0; // 将P2设为0和P3设为1,强制使分频器的值为整数
P3 = 1;
// 通过I2C发送命令设置多合成器的配置寄存器
// 发送P3的高8位
i2cSendRegister(synth + 0, (P3 & 0x0000FF00) >> 8);
// 发送P3的低8位
i2cSendRegister(synth + 1, (P3 & 0x000000FF));
// 发送P1的最高两位和rDiv。rDiv用于进一步分频,控制输出频率的范围
i2cSendRegister(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
// 发送P1的中间8位
i2cSendRegister(synth + 3, (P1 & 0x0000FF00) >> 8);
// 发送P1的低8位
i2cSendRegister(synth + 4, (P1 & 0x000000FF));
// 结合P3和P2的部分高位,虽然这里P2始终为0
i2cSendRegister(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
// 发送P2的中间8位,这里始终为0
i2cSendRegister(synth + 6, (P2 & 0x0000FF00) >> 8);
// 发送P2的低8位,这里始终为0
i2cSendRegister(synth + 7, (P2 & 0x000000FF));
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
SI5351A.h
#ifndef __AD9910_H__
#define __AD9910_H__
#include "main.h"
#include "gpio.h"
#include "math.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long int
typedef enum
{
TRIG_WAVE = 0,
SQUARE_WAVE,
SINC_WAVE,
} AD9910_WAVE_ENUM;
// void AD9110_IOInit(void); //资料里的引脚初始化函数,没用
void Init_AD9910(void); // 资料里的引脚初始化函数,没用
void AD9910_FreWrite(ulong Freq); // 单频调制模式写频率
void AD9910_AmpWrite(uint16_t Amp); // 单频调制模式写电压
void txd_8bit(uchar txdat);
void Write_32bit(uint32_t dat);
// 自己创建的函数在下面
void Init_AD9910_Fre(uint32_t Frequency); // 按照频率对AD9910进行初始化
void Reset_AD9910(); // 复位AD9910
void PWM_Generate(uint16_t step_rates, uint16_t voltage, uint8_t Duty); // 操作AD9910产生PWM
void Sin_Generate(uint16_t PFREQUENCY, uint16_t voltage); // 操作AD9910产生正弦波
#endif
最后通过function.c统合文件
function.c
由于这两个数组太大了,所以下面的代码里面没有,但是用下面的生成这个数组的python代码生成即可。
#include "function.h"
#define max_length 1 // 宏定义UART接收最大长度
#define Fre_MAX 20000 // 最大频率
#define Fre_MIN 20 // 最小频率
#define PWM_Duty_MAX 98 // 最大占空比
#define PWM_Duty_MIN 2 // 最小占空比
#define Voltage_MAX 16383 // 最大电压
#define Voltage_MIN 0 // 最小电压
uint8_t uart1_rxceive[max_length] = {0}; // 串口接收数组
int32_t Frequency = 17452; // 频率
int8_t Duty = 50; // 占空比
int16_t Voltage = 16383; // 电压
uint16_t stepsize_auto = 5; // 自动步进的频率
uint8_t Flag_rx = 0; // 标志——串口接收
uint8_t FLag_PWM = 0; // 标志——PWM开启关闭
uint8_t Flag_Sin = 0; // 标志——正弦波开启关闭
uint8_t Flag_Auto = 0; // 标志——频率自动步进开启关闭
uint16_t stepsiez_Duty[4] = {2, 5, 10, 20}; // 步长——占空比
uint16_t stepsize_Frequency[5] = {1, 5, 100, 1000, 10000}; // 步长——频率
uint16_t stepsize_Voltage[5] = {1, 10, 110, 100, 1000}; // 步长——电压
int16_t index_Frequency = 1; // 索引——频率步长
int16_t index_Duty = 0; // 索引——占空比步长
int16_t index_Voltage = 0; // 索引——电压步长
uint8_t Num_Fre = 5 - 1; // 个数——频率步长
uint8_t Num_Duty = 4 - 1; // 个数——占空比步长
uint8_t Num_Voltage = 5 - 1; // 个数——电压步长
int32_t Error = 1470; // 频率误差
uint16_t stepisze_Error[] = {1, 3, 5, 10, 100, 1000, 5000}; // 步长——频率误差
int8_t index_Error = 0; // 索引——频率误差
void UART_Start()
{
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, uart1_rxceive, max_length); // 开启一次中断接收
}
void UART_Process()
{
if (Flag_rx == 1)
{
Flag_rx = 0; // 标志位置零
if (uart1_rxceive[0] == 0x0A) // 开启关闭正弦波的输出
{
if (Flag_Sin == 0) // 如果正弦波没有输出
{
if (FLag_PWM == 1) // 如果PWM正在输出,就关闭PWM波
{
PWM_Stop();
}
Sin_Start(Frequency, Voltage); // 开启正弦波,并打印相关参数
}
else if (Flag_Sin == 1)
{
Sin_Stop();
}
}
else if (uart1_rxceive[0] == 0x0B) // 开启和关闭PWM的输出
{
if (FLag_PWM == 0) // 当PWM关闭时
{
if (Flag_Sin == 1)
{
Sin_Stop();
}
PWM_Start(Frequency, Duty, Voltage);
}
else if (FLag_PWM == 1) // 当PWM打开时
{
PWM_Stop();
}
}
else if (uart1_rxceive[0] == 0x0C) // 增大频率
{
Fre_Up();
}
else if (uart1_rxceive[0] == 0x0D) // 缩小频率
{
Fre_Down();
}
else if (uart1_rxceive[0] == 0x0E) // 增大频率步进
{
Fre_Stepsize_Up();
}
else if (uart1_rxceive[0] == 0x0F)// 缩小频率步进
{
Fre_Stepsize_Down();
}
else if (uart1_rxceive[0] == 0x11) // 增大电压
{
Voltage_Up();
}
else if (uart1_rxceive[0] == 0x22) // 减小电压
{
Voltage_Down();
}
else if (uart1_rxceive[0] == 0x33) // 增大电压步进
{
Voltage_Stepsize_Up();
}
else if (uart1_rxceive[0] == 0x44) // 减小电压步进
{
Voltage_Stepsize_Down();
}
else if (uart1_rxceive[0] == 0x55) // 增大PWM的占空比
{
PWM_Duty_Up();
}
else if (uart1_rxceive[0] == 0x66) // 缩小PWM的占空比
{
PWM_Duty_Down();
}
else if (uart1_rxceive[0] == 0x77) // 增大占空比步进
{
Duty_Stepsize_Up();
}
else if (uart1_rxceive[0] == 0x88) // 缩小占空比步进
{
Duty_Stepsize_Down();
}
else if (uart1_rxceive[0] == 0x99)//频率误差增大
{
Error_Up();
}
else if(uart1_rxceive[0] == 0x00)//频率误差减小
{
Error_Down();
}
else if(uart1_rxceive[0] == 0x1A)//频率误差步进增大
{
Error_Stepsize_Up();
}
else if(uart1_rxceive[0] == 0x1B)//频率误差步进增大
{
Error_Stepsize_Down();
}
else if(uart1_rxceive[0] == 0x1C)//频率自动步进
{
if (Flag_Auto == 0)
{
Flag_Auto = 1;
}
else if (Flag_Auto == 1)
{
Flag_Auto = 0;
}
}
else if(uart1_rxceive[0] == 0x1D)//元神启动
{
printf("p0.pic=2\xff\xff\xff");
}
UART_Start();
}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) // 中断接收回调函数
{
if (huart->Instance == USART1) // 判断串口
{
Flag_rx = 1; // 标志位置1
}
}
void PWM_Start(uint16_t Frequency, uint16_t Duty, uint16_t Voltage)
{
FLag_PWM = 1; // PWM输出标志置为1
si5351aSetFrequency(step_rates_PWM[Frequency - 20] * 400 * Frequency / 25 - Error); // 信号源设置为合适的信号输出
Init_AD9910_Fre(step_rates_PWM[Frequency - 20] * 400 * Frequency); // AD9910依据信号进行初始化,更改VOC的值
PWM_Generate(step_rates_PWM[Frequency - 20], Voltage, Duty); // 依据频率,占空比来产生PWM波
printf("t1.txt=\"脉冲波\"\xff\xff\xff");
printf("t3.txt=\"%dHz\"\xff\xff\xff", Frequency);
printf("t5.txt=\"%dHz\"\xff\xff\xff", stepsize_Frequency[index_Frequency]);
printf("t7.txt=\"%dHz\"\xff\xff\xff", Voltage);
printf("t9.txt=\"%dHz\"\xff\xff\xff", stepsize_Voltage[index_Voltage]);
printf("t11.txt=\"%d%%\"\xff\xff\xff", Duty);
printf("t13.txt=\"%d%%\"\xff\xff\xff", stepsiez_Duty[index_Duty]);
printf("t15.txt=\"%d\"\xff\xff\xff", Error);
printf("t17.txt=\"%d\"\xff\xff\xff", stepisze_Error[index_Error]);
printf("p0.pic=1\xff\xff\xff");
}
void Sin_Start(uint16_t Frequency, uint16_t Voltage)
{
Flag_Sin = 1;
si5351aSetFrequency(step_rates_Sin[Frequency - 20] * 1600 * Frequency / 25 - Error); // 信号源设置为合适的信号输出
Init_AD9910_Fre(step_rates_Sin[Frequency - 20] * 1600 * Frequency); // AD9910依据信号进行初始化,更改VOC的值
Sin_Generate(step_rates_Sin[Frequency - 20], Voltage); // 依据频率,占空比来产生正弦波
printf("t1.txt=\"正弦波\"\xff\xff\xff");
printf("t3.txt=\"%dHz\"\xff\xff\xff", Frequency);
printf("t5.txt=\"%dHz\"\xff\xff\xff", stepsize_Frequency[index_Frequency]);
printf("t7.txt=\"%dHz\"\xff\xff\xff", Voltage);
printf("t9.txt=\"%dHz\"\xff\xff\xff", stepsize_Voltage[index_Voltage]);
printf("t11.txt=\"%d%%\"\xff\xff\xff", Duty);
printf("t13.txt=\"%d%%\"\xff\xff\xff", stepsiez_Duty[index_Duty]);
printf("t15.txt=\"%d\"\xff\xff\xff", Error);
printf("t17.txt=\"%d\"\xff\xff\xff", stepisze_Error[index_Error]);
printf("p0.pic=0\xff\xff\xff");
}
void PWM_Stop()
{
Reset_AD9910();
FLag_PWM = 0;
printf("t1.txt=\" \"\xff\xff\xff");
printf("t3.txt=\" \"\xff\xff\xff");
printf("t5.txt=\" \"\xff\xff\xff");
printf("t7.txt=\" \"\xff\xff\xff");
printf("t9.txt=\" \"\xff\xff\xff");
printf("t11.txt=\" \"\xff\xff\xff");
printf("t13.txt=\" \"\xff\xff\xff");
printf("t15.txt=\" \"\xff\xff\xff");
printf("t17.txt=\" \"\xff\xff\xff");
printf("p0.pic=2\xff\xff\xff");
}
void Sin_Stop()
{
Reset_AD9910();
Flag_Sin = 0;
printf("t1.txt=\" \"\xff\xff\xff");
printf("t3.txt=\" \"\xff\xff\xff");
printf("t5.txt=\" \"\xff\xff\xff");
printf("t7.txt=\" \"\xff\xff\xff");
printf("t9.txt=\" \"\xff\xff\xff");
printf("t11.txt=\" \"\xff\xff\xff");
printf("t13.txt=\" \"\xff\xff\xff");
printf("t15.txt=\" \"\xff\xff\xff");
printf("t17.txt=\" \"\xff\xff\xff");
printf("p0.pic=2\xff\xff\xff");
}
void Fre_Up()
{
Frequency += stepsize_Frequency[index_Frequency];
if (Frequency >= Fre_MAX)
{
Frequency = Fre_MAX;
}
Reset_AD9910();
if (FLag_PWM == 1)
{
PWM_Start(Frequency, Duty, Voltage);
}
else if (Flag_Sin == 1)
{
Sin_Start(Frequency, Voltage);
}
}
void Fre_Down()
{
Frequency -= stepsize_Frequency[index_Frequency];
if (Frequency <= Fre_MIN)
{
Frequency = Fre_MIN;
}
Reset_AD9910();
if (FLag_PWM == 1)
{
PWM_Start(Frequency, Duty, Voltage);
}
else if (Flag_Sin == 1)
{
Sin_Start(Frequency, Voltage);
}
}
void PWM_Duty_Up() // 增大PWM占空比
{
Duty += stepsiez_Duty[index_Duty]; // PWM的占空比增大指定步长
if (Duty >= PWM_Duty_MAX)
{
Duty = PWM_Duty_MAX; // 占空比最大98%
}
PWM_Start(Frequency, Duty, Voltage); // 修改PWM频率,占空比
}
void PWM_Duty_Down() // 减小PWM占空比
{
Duty -= stepsiez_Duty[index_Duty]; // PWM的占空比缩小指定步长
if (Duty <= PWM_Duty_MIN)
{
Duty = PWM_Duty_MIN; // 占空比最小2%
}
PWM_Start(Frequency, Duty, Voltage); // 修改PWM频率,占空比
}
void Fre_Stepsize_Up() // 频率步进增大
{
index_Frequency += 1;
if (index_Frequency >= Num_Fre)
{
index_Frequency = Num_Fre;
}
printf("t5.txt=\"%dHz\"\xff\xff\xff", stepsize_Frequency[index_Frequency]);
}
void Fre_Stepsize_Down() // 频率步进减小
{
index_Frequency -= 1;
if (index_Frequency <= 0)
{
index_Frequency = 0;
}
printf("t5.txt=\"%dHz\"\xff\xff\xff", stepsize_Frequency[index_Frequency]);
}
void Duty_Stepsize_Up() // 占空比步进增大
{
index_Duty += 1;
if (index_Duty >= Num_Duty)
{
index_Duty = Num_Duty;
}
printf("t13.txt=\"%d%%\"\xff\xff\xff", stepsiez_Duty[index_Duty]);
}
void Duty_Stepsize_Down() // 占空比步进减小
{
index_Duty -= 1;
if (index_Duty <= 0)
{
index_Duty = 0;
}
printf("t13.txt=\"%d%%\"\xff\xff\xff", stepsiez_Duty[index_Duty]);
}
void Voltage_Up()
{
Voltage += stepsize_Voltage[index_Voltage];
if (Voltage >= Voltage_MAX)
{
Voltage = Voltage_MAX;
}
if (FLag_PWM == 1)
{
PWM_Start(Frequency, Duty, Voltage);
}
else if (Flag_Sin == 1)
{
Sin_Start(Frequency, Voltage);
}
}
void Voltage_Down()
{
Voltage -= stepsize_Voltage[index_Voltage];
if (Voltage <= Voltage_MIN)
{
Voltage = Voltage_MIN;
}
if (FLag_PWM == 1)
{
PWM_Start(Frequency, Duty, Voltage);
}
else if (Flag_Sin == 1)
{
Sin_Start(Frequency, Voltage);
}
}
void Voltage_Stepsize_Up()
{
index_Voltage += 1;
if (index_Voltage >= Num_Voltage)
{
index_Voltage = Num_Voltage;
}
printf("t9.txt=\"%dHz\"\xff\xff\xff", stepsize_Voltage[index_Voltage]);
}
void Voltage_Stepsize_Down()
{
index_Voltage -= 1;
if (index_Voltage <= 0)
{
index_Voltage = 0;
}
printf("t9.txt=\"%dHz\"\xff\xff\xff", stepsize_Voltage[index_Voltage]);
}
void Auto_Stepsize()
{
if (Flag_Auto == 1)
{
Frequency += stepsize_Frequency[index_Frequency];
if (Frequency >= Fre_MAX)
{
Frequency = Fre_MAX;
}
if (FLag_PWM == 1)
{
PWM_Start(Frequency, Duty, Voltage);
}
else if (Flag_Sin == 1)
{
Sin_Start(Frequency, Voltage);
}
HAL_Delay(200);
}
}
void Error_Up()
{
Error += stepisze_Error[index_Error];
Reset_AD9910();
PWM_Start(Frequency, Duty, Voltage);
}
void Error_Down()
{
Error -= stepisze_Error[index_Error];
Reset_AD9910();
PWM_Start(Frequency, Duty, Voltage);
}
void Error_Stepsize_Up()
{
index_Error++;
if (index_Error >= 6)
{
index_Error = 6;
}
printf("t17.txt=\"%d\"\xff\xff\xff", stepisze_Error[index_Error]);
}
void Error_Stepsize_Down()
{
index_Error--;
if (index_Error >= 6)
{
index_Error = 6;
}
printf("t17.txt=\"%d\"\xff\xff\xff", stepisze_Error[index_Error]);
}
function.h
#ifndef _Function_H
#define _Function_H
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include "AD9910.h"
#include "si5351a.h"
void UART_Start(); // 打开串口中断接收
void UART_Process(); // 对串口接收到的信息进行处理,最主要的处理函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size); // 串口中断接收回调函数
void PWM_Start(uint16_t Frequency, uint16_t Duty, uint16_t Voltage); // PWM开始输出
void Sin_Start(uint16_t Frequency, uint16_t Voltage); // 正弦波开始输出
void PWM_Stop(); // 停止PWM输出
void Sin_Stop(); // 停止正弦波输出
void Fre_Up(); // 频率增大
void Fre_Down(); // 频率减小
void PWM_Duty_Up(); // 占空比增大
void PWM_Duty_Down(); // 占空比减小
void Fre_Stepsize_Up(); // 频率步进增大
void Fre_Stepsize_Down(); // 频率步进减小
void Duty_Stepsize_Up(); // 占空比步进增大
void Duty_Stepsize_Down(); // 占空比步进减小
void Voltage_Up(); // 电压增大
void Voltage_Down(); // 电压减小
void Voltage_Stepsize_Up(); // 电压步进增大
void Voltage_Stepsize_Down(); // 电压步进减小
void Auto_Stepsize(); // 频率自动增大
void Error_Up(); // 误差修正值增大
void Error_Down(); // 误差修正值减小
void Error_Stepsize_Up(); // 误差修正值步进增大
void Error_Stepsize_Down(); // 误差修正值步进减小
#endif
生成PWM波的步进率的python代码
def calculate_step_rate(frequency):
min_clock_frequency = 400000000
max_clock_frequency = 460000000
for step_rate in range(1, 65536):
clock_frequency = frequency * 100 * 4 * step_rate
if min_clock_frequency <= clock_frequency <= max_clock_frequency:
return step_rate
return None
# 自动计算频率从20到20000赫兹
unfit_frequencies = []
with open("step_rates3.txt", "w") as file:
file.write("unsigned int step_rates[] = {\n")
count = 0
for frequency in range(20, 20001):
step_rate = calculate_step_rate(frequency)
if step_rate is not None:
file.write(f" /* {frequency} Hz */ {step_rate}, ")
count += 1
if count % 200 == 0: # 如果达到200个数据,换行
file.write("\n")
else:
unfit_frequencies.append(frequency)
file.write("\n};")
# 输出找不到合适步进率的频率
if unfit_frequencies:
with open("step_rates3.txt", "a") as file:
file.write("\n\n找不到合适步进率的频率:\n")
for frequency in unfit_frequencies:
file.write(f"{frequency}\n")
print("结果已保存到 step_rates3.txt 文件中。")
生成正弦波的步进率的python代码
def calculate_step_rate(frequency):
min_clock_frequency = 400000000
max_clock_frequency = 460000000
for step_rate in range(1, 65536):
clock_frequency = frequency * 400 * 4 * step_rate
if min_clock_frequency <= clock_frequency <= max_clock_frequency:
return step_rate
return None
# 自动计算频率从20到20000赫兹
unfit_frequencies = []
with open("sin_step_rates.txt", "w") as file:
file.write("unsigned int step_rates[] = {\n")
count = 0
for frequency in range(20, 20001):
step_rate = calculate_step_rate(frequency)
if step_rate is not None:
file.write(f" /* {frequency} Hz */ {step_rate}, ")
count += 1
if count % 200 == 0: # 如果达到200个数据,换行
file.write("\n")
else:
unfit_frequencies.append(frequency)
file.write("\n};")
# 输出找不到合适步进率的频率
if unfit_frequencies:
with open("sin_step_rates.txt", "a") as file:
file.write("\n\n找不到合适步进率的频率:\n")
for frequency in unfit_frequencies:
file.write(f"{frequency}\n")
print("结果已保存到 sin_step_rates.txt 文件中。")
两个python函数的区别就是PWM的波表长度为100,正弦波的波表长度为400,改一下计算公式即可。
python代码的生成原理如下:
main.c在包含头文件后这样写就行了
main.c
HAL_Delay(100); // 为了使UART和DMA上电稳定后再打开UART的DMA接收,否则单片机上电后串口屏不能正常工作
UART_Start();
UART_Process();//串口处理函数
Auto_Stepsize();//频率自动步进
在此过程中出现的问题以及解决方法
1.单片机的堆栈区设置小了,CubeMX默认是0x200,当进行一个1024数组的循环生成时会跳到HardFault_Handler这个硬件异常状态。并且不会运行下面的代码。
2.当变量定义为uint时,变量小于0时会变成65535,对于哪些一般都是正数,但是会减一个数有变得小于0的风险的数要设置为int,比如该项目中的频率,占空比等,它们减去频率步进,占空比步进时会有小于0的风险,所以要设置为int。
3.32位定时器产生可调频率PWM,在调节频率时会突然罢工,H723ZGT6和F407ZGT6都是这样,当把定时器的auto reload enable打开时就不会了,但是第一次打开PWM会卡一会。
4.单片机上电后会正常的工作,但是打开串口的DMA接收之前要延时一段时间(100ms),等单片机上电稳定后再打开串口的DMA接收,这样的话单片机上电就能正常工作了。
5.代码中Sin_stop()等函数会把AD9910复位,AD9910复位之后要再次重新初始化一次,不然不能正常工作,所有的模块应该都是这样,模块不能正常工作时记得想一想是不是没有初始化。
6.keil5开版本6可以加快编译速度,但是不会go to definition 并且keil5的版本6有Bug,不会正确编译,不会正确调试程序,有可能下载到单片机里是错误的,所以把版本6当作一个找错误的工具还行,下载和调试还是得用版本5.
7.莫名其妙的错误,SI5351接到G2 G4 G7 C9 这4个引脚不管用,接到D12 F9 F8 F10这四个引脚就管用了,有时候穷途末路的时候可以改一下引脚。