电赛知识点总结17:DDS

2023-11-22 07:38
文章标签 知识点 总结 17 dds 电赛

本文主要是介绍电赛知识点总结17:DDS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

电赛知识点总结17:DDS

  • DDS
    • 1 DDS
      • 1.1 DDS核心思想
        • 1.1.1 正弦波的相位-幅度表:
        • 1.1.2 内核
        • 1.1.3 优缺点
      • 1.2 常用芯片
        • 1.2.1 AD9833
      • 1.3 DDS的外围电路
      • 1.4 Vivado(FPGA)仿真
      • 1.5 实战
        • 1.5.1 AD9850
        • 1.5.2 原理图
        • 1.5.3 PCB及注意事项
        • 1.5.4 单片机程序
    • 2 椭圆滤波器

DDS

1 DDS

1.1 DDS核心思想

1.1.1 正弦波的相位-幅度表:

具有足够细密的相位步长。N为数据序号,phase为相位,Am为正弦波计算值,Data_10为10位数字量的10进制表示,用一个10位DAC描述,其中512对应的实际值为0。
在这里插入图片描述
从0开始正弦波幅度一直增加,但是直到第12个点才会被DAC的输出表示出来。

固定时钟MCLK为36MHz,DAC以MCLK为节拍在表上遍历,如果步长为1,则:

f O U T = 1 T M C L K × N max ⁡ m = f M C L K × m N max ⁡ = 36 × 1 0 6 × 1 36000 = 1000 H z f_{O U T}=\frac{1}{T_{M C L K} \times \frac{N_{\max }}{m}}=\frac{f_{M C L K} \times m}{N_{\max }}=\frac{36 \times 10^{6} \times 1}{36000}=1000 \mathrm{~Hz} fOUT=TMCLK×mNmax1=NmaxfMCLK×m=3600036×106×1=1000 Hz
这个公式可以这么理解:输出的正弦波遍历完一整个表的话就算是一个周期,遍历1步需要 T M C L K T_{M C L K} TMCLK秒,一共需要走 N max ⁡ m \frac{N_{\max }}{m} mNmax步(表中一共 N max ⁡ N_{\max } Nmax个点),这样就可以计算出周期以及频率。

DDS的最小分辨率为:
Δ f O U T = f M C L K × Δ m N max ⁡ = 36 × 1 0 6 × 1 36000 = 1000 H z \Delta f_{O U T}=\frac{f_{M C L K} \times \Delta m}{N_{\max }}=\frac{36 \times 10^{6} \times 1}{36000}=1000 \mathrm{~Hz} ΔfOUT=NmaxfMCLK×Δm=3600036×106×1=1000 Hz
此外,样点总数除以m可以不为整数。虽然不能完整的扫描整个表,但是差别其实是很小的,可以忽略。

1.1.2 内核

由相位累加器PA、相位幅度表和数模转换器DAC组成。以28位的DAC为例,它可以计数0- 2 28 2^{28} 228。步长为m,则正弦波频率为:
f out  = m 2 28 × f M C L K f_{\text {out }}=\frac{m}{2^{28}} \times f_{M C L K} fout =228m×fMCLK
其原理与前文是一致的。
总体结构如图:
在这里插入图片描述
相位累加器外部一般不需要很高的位数。

1.1.3 优缺点

优点:

  • 极低频率到极高频率,频率增量极低
  • 快速跳频
  • 正交输出,相位设置
  • 正弦波、三角波、方波输出

缺点:

  • 失真度低

1.2 常用芯片

1.2.1 AD9833

在这里插入图片描述
FREQ0与FREQ1是两个频率寄存器,通过SPI写入,代表的是相位步长m。两个寄存器是为了方便切换。然后是28位相位累加器,完成递增的操作。之后的加法器完成相位失调的接入,代表的是初相角,存在PHASE0和PHASE1中。加法器的结果(代表相位)高12位提供给查找表,作为地址读取内容,并通过DAC输出。

1.3 DDS的外围电路

DAC有两种输出模式,电压输出和互补电流输出。电压输出无需过多处理,比如AD9833的DAC为单端电流输出型,通过内部200 Ω \Omega Ω的电阻转变为电压输出。

电流输出形式的一般为互补型,具有两个管脚,以AD9850为例:
在这里插入图片描述
两个管脚输出的电流满足:
I O U T + I O U T B = I F S I_{O U T}+I_{O U T B}=I_{F S} IOUT+IOUTB=IFS
I F S I_{F S} IFS为满幅度输出电流,由 R s e t R_set Rset决定。两个管脚的输出可以产生相差180°的差分信号。输出再经过电阻转化电压,注意输出脚顺从电压的限制。外部电路可能并联电容起到低通滤波的作用:
在这里插入图片描述
f H = 1 2 π R 5 C 12 = 7.96 k H z f_{H}=\frac{1}{2 \pi R_{5} C_{12}}=7.96 \mathrm{kHz} fH=2πR5C121=7.96kHz
正弦信号不应超过此频率。若要更有效的低通滤波,可以采用椭圆滤波器。

1.4 Vivado(FPGA)仿真

1.5 实战

1.5.1 AD9850

结构:
AD9850采用32位的相位累加器将信号截断成14位输入到正弦查询表,查询表的输出再被截断成10位后输入到DAC,DAC再输出两个互补的电流。DAC满量程输出电流通过一个外接电阻RSET调节,调节关系为ISET=32(1.148V/RSET),RSET的典型值是3.9kΩ。

AD9850在接上精密时钟源和写入频率相位控制字之间后就可产生一个频率和相位都可编程控制的模拟正弦波输出,此正弦波可直 接用作频率信号源或经内部的高速比较器转换为方波输出。在125MHz的时钟下,32位的频率控制字可使AD9850的输出频率分辨率 达0.0291Hz;并具有5位相位控制位,而且允许相位按增量180°、90°、45°、22.5°、11.25°或这些值的组合进行调整。

控制:

AD9850有40位控制字,32位用于频率控制,5位用于相位控制。1位用于电源休眠(Power down)控制,2位用于选择工作方式。这40位控制字可通过并行方式或串行方式输入到AD9850,控制时序图如下:
在这里插入图片描述

在并行装入方式中,通过8位总线将可数据输入到寄存器,在重复5次之后再在FQ-UD上升沿把40位数据从输 入寄存器装入到频率/相位数据寄存器(更新DDS输出频率和相位),同时把地址指针复位到第一个输入寄存器。

在W-CLK的上升沿装入8位数据,并把指针指向下一个输入寄存器,连续5个W-CLK上升沿后,W-CLK的边沿就不再起作用,直到复位信号或FQ-UD上升沿把地址指针复位到第一个寄存器。

下图展示了各位数据的含义

在这里插入图片描述

在串行输入方式,W-CLK上升沿把25引脚的一位数据串行移入,当移动40位后,用一个FQ-UD脉冲即可更新输出频率和相位。下图是相应的控制字串行输入的控制时序图:
在这里插入图片描述
AD9850的复位(RESET)信号为高电平有效,且脉冲宽度不小于5个参考时钟周期。AD9850的参考时钟频率一般远高于单片机的时钟频率,因此AD9850的复位(RESET)端可与单片机的复位端直接相连。串行的3脚、4脚需要连接在一起:
在这里插入图片描述
各位数据代表含义如下:
在这里插入图片描述

用于选择工作方式的两个控制位,无论并行还是串行最好都写成00.

单片机:

I/O方式的并行接口电路比较简单,但占用单片机资源相对较多,下图是I/O方式并行接口的电路图,AD9850的数据线D0~D7与P1口相连,FQ-UD和W-CLK分别与P3.0(10引脚)和P3.1(11引 脚)相连,所有的时序关系均可通过软件控制实现。
在这里插入图片描述
将DDS控制字从高至低存放于30H至34H中,汇编语言如下:

MOV R0,#05H		;数据05输入R0
MOV R1,#30H 		;数据30输入R1
DD:MOV P1,@R1 		;(30H)地址上的数据传入P1,且程序位置为DD
SETB P3.1 			;P3.11
CLR P3.1 			;P3.10
INC R1 				;R1数据加1,指向下一个地址
DJNZ R0,DD 		;R0先减1,若不为0,则转移到DD,循环一共执行5
SETB P3.0 			;P3.01
CLR P3.0 			;P3.00
END					;结束

在程序中,每将一字节的数据送到P1口后,必须将P3.1(W-CLK)置高。在其上升沿,AD9850接收到P1口相连的 数据线上的数据,然后将P3.1置低,并准备下一字节的发送,连续发送5个字节后,须将P3.0(FQ-UD)置高,以使AD9850根据则输入的控制字更改频率和相位输出,随后再置P3.0为低,准备下一组发送。单片机的P3.0、P3.1引脚为串行口,当被占用时,W-CLK和FQ-UD引脚也可与其它I/O脚相连,这时需要修改相应的发送程序。

总线方式并行接口占用的单片机资源较少,在这种方式下,AD9850仅作为一扩展芯片而占用RAM的一段地址,必须时也可以只占用一个地址。 下图是总线方式并行接口的电路原理图。
在这里插入图片描述
同样将DDS控制字从高至低存放于30H至34H中,发送控制字的程序清单如下:

MOV R0,#05H 		;数据05输入R0
MOV R1,#30H 		;数据30输入R1
MOV DPTR,#0700H 	;DRTR为数据指针寄存器,指向0700H
DD:MOV A,@R1 		;(30H)地址上的数据传入A,且程序位置为DD
MOVX @DPTR,A		;A的数据传入DPTR指向的地址
INC R1 				;R1数据加1,指向下一个地址
DJNZ R0,DD 		;R0先减1,若不为0,则转移到DD,循环一共执行5
MOVX A,@DPTR 		;DPTR指向的地址中的数据
END					;结束

AD9850的W-CLK和FQ-UD信号都是上升沿有效,用MOVX @DPTR,A指令向AD9850传送控制字时,由74F138将高八位地址的低三位译码(0700H正好是高八位地址低三位是高电平,其余低电平),其输出经反相(38译码器输出低有效)并与反相后的信号相与得到一上升沿送至AD9850的W-CLK脚。这一步其实是关键也是不同之处,MOVX @DPTR,A指令执行时WR脚变为低电平反相后为高电平,p0输出数据,p2输出地址高8位,0700H对应的输出在经过38译码器再反相之后输出的也是高电平,相与之后WCLK接收到高电平,控制AD9850接收信号。一旦程序结束,WCLK接收到的是低电平。此时已送到总线上的数据将被AD9850接收完毕。

连续五次将40位的控制字全部发送以后,用MOVA A,@DPTR指令产生FQ-UD信号,使AD9850更改输出频率和相位,此时读入到单片机内的数据实际上无任何意义。这一步与前面是类似的,该指令使单片机读信号,信号地址为0700H,P2口产生信号地址的高8位,RD变为低电平,两者反相相与之后变为高电平,被FQ_UD接受;P0接受信号,但是接收到的信号无意义。一旦程序结束,FQ_UD接收到的是低电平。图中AD9850的地址为0700H。

上述接口电路和程序也适用于与AD9850脚对脚兼容的AD9851,值得注意的是:AD9851的控制字与AD9850控制辽中别位的定义稍有区别,编程时应予以注意。

1.5.2 原理图

原理图如下:
在这里插入图片描述
下面以AD9850为核心,一部分一部分的来分析。AD9850的引脚含义在数据手册中已经给出:
在这里插入图片描述
D0-D7为AD9850的8位数据接收口,连接在单片机的一组IO口上:
在这里插入图片描述
按照要求连接AD9850的数字电源、数字地,模拟电源、模拟地,电源为5V即可:
在这里插入图片描述
RESET、WCLK、FQ_UD 3个引脚引出到排针上,可以选择之前提到的第一钟方式连接在单片机上,通过单片机来控制:
在这里插入图片描述
CLK_IN引脚也引出到排针上,它需要接一个参考的时钟信号,可以外接上一个50MHz的晶振(超过的话就会关断):
在这里插入图片描述
2个QOUT是比较器的输出,输出的是方波,两者是互补的(AD9850是互补电流输出)
在这里插入图片描述
IOUT与IOUTB为互补电流输出,IOUT通过200 Ω \Omega Ω的电阻转化为电压信号,然后通过椭圆滤波器得到正弦信号输出。VINP与VINN为比较器的正端、负端输入信号,前者直接接正弦输出,后者接在R4、R5间,得到输出电压的均值
在这里插入图片描述
这一部分有一个问题:就是无论是上面的原理图中,还是数据手册中给出的压流转换的电阻都是200 Ω \Omega Ω,在Rset为3.9k Ω \Omega Ω的情况下,最大输出电流为10mA,而AD9850的顺从电压为1.5V:
在这里插入图片描述

按理说,根据:
在这里插入图片描述
电阻不应该超过150?

其余部分不做具体介绍。

1.5.3 PCB及注意事项
  • 包含AD9850的印刷电路板应该是允许专用电源和地面平面的多层板
  • 避免在设备下运行数字线路
  • 到AD9850的电源线路应使用尽可能大的轨道
  • 时钟这样的快速开关信号应被地面保护
  • 避免数字和模拟信号路径的交叉
  • 提供给AD9850的模拟(AVDD)和数字(DVDD)电源是独立的,并具有高质量的陶瓷电容器
1.5.4 单片机程序

变量定义:

/*
1 、可通过按键实现频率输出步进加减;步进频率范围0~10MHz;2、步进值有六种选择:10Hz、100Hz、1000Hz、10KHz、100KHz、1000KHz3、采用1602液晶显示屏,可以实时显示输出频率值,显示当前步进值,显示频率的单位都为Hz。
*///基本功能全部实现;2009041407
#include  <reg52.h>     //调用头文件(单片机内部的寄存器定义)
#define  uchar unsigned char
#define  uint unsigned int/******本段为硬件I/O口定义********/sbit  LCD_E  = P1^1;//定义1602液晶的使能管脚;
sbit  LCD_RW = P1^2;//定义1602液晶的读写管脚;  
sbit  LCD_RS = P1^3;//定义1602液晶的选通管脚; sbit reset  = P1^4;  //ad9850的复位引脚;
sbit w_clk =  P1^7;  //ad9850的时钟引脚;
sbit fqud  =  P1^6;  //ad9850的输出更新引脚;#define  LCD_DATA   P2   //向1602液晶传送数据的端口,这里用的是P2口;
#define  LCD_BUSY   0x80  // 用于检测LCD的忙标识(本程序中用的是延时,未检测)//LCD显示内容,定义到代码段;
unsigned  char code LcdBuf1[]= {"FRQ:        Hz"};
unsigned  char code LcdBuf2[]= {"Step:"};double Con_Word_1 = 0x00;//定义了一个浮点变量,用于计算控制字;
double Con_Word_2 = 0x00;//定义了一个浮点变量,用于计算控制字;
long uint ConTrol_Word = 0x00;//用来存储控制字的数值;
long uint Frequency_Out;//设置的频率值;
uchar a,b,c,d,e,f,g,h; //为了向1602写入频率值,首先将频率值拆分存于这8个变量中;
sbit Light = P1^0; //程序状态指示灯,它与单片机对9850控制无关,只是调试程序的时候使用!
//定义按键;2X3矩阵键盘;
sbit  P3_4 = P3^4;
sbit  P3_6 = P3^6;
sbit  P3_7 = P3^7;
sbit  P3_3 = P3^3;
sbit  P3_5 = P3^5;	 uchar dat = 0;//键盘子程序处理过程中使用的中间变量;
uchar keyzhi = 0x00;//键值;键盘扫描子程序的返回值存于该变量中;

LCD相关函数:

//函数声明
void  lcd_init(void);//1602液晶初始化子程序;
void  display_string(unsigned  char x,unsigned  char y,unsigned  char *s);
//显示字符子程序;x、y是坐标;x:从左边数起第几个字符:y:是第一行还是第二行;/**************************************************
** 函数名称: delay
** 入口参数:h(unsigned int型)
** 出口参数:无
** 功能描述: 短暂延时,使用11.0592晶体,约0.01MS
****************************************************/
void delay(long unsigned int h)
{while(h--);    //延时子程序
}/**************************************************
** 函数名称: WriteDataLcd
** 入口参数:wdata(unsigned  char型)
** 出口参数:无
** 功能描述: 写数据到LCD
****************************************************/
void  WriteDataLcd(unsigned  char wdata)//向1602液晶写入数据;
{LCD_RS=1;LCD_RW=0;LCD_E=0;LCD_E=1;LCD_DATA=wdata;delay(100);     //短暂延时,代替检测忙状态LCD_E=0;
}
/**************************************************
** 函数名称: WriteCommandLcd
** 入口参数:wdata(unsigned  char型)
** 出口参数:无
** 功能描述: 写命令到LCD
****************************************************/
void  WriteCommandLcd(unsigned char wdata)//向1602液晶写入命令;
{LCD_RS=0;LCD_RW=0;LCD_E=0;LCD_E=1;LCD_DATA=wdata;delay(100);     //短暂延时,代替检测忙状态LCD_E=0;}//LCD初始化
void  lcd_init(void)
{LCD_DATA = 0;delay(1000);WriteCommandLcd(0x38);delay(500);WriteCommandLcd(0x38); //显示模式设置delay(500);WriteCommandLcd(0x38); //显示模式设置delay(500);WriteCommandLcd(0x01); //关闭显示WriteCommandLcd(0x38); //显示清屏WriteCommandLcd(0x0c); //显示光标移动设置WriteCommandLcd(0x06); //显示开及光标移动设置
}
/**************************************************
** 函数名称: display_xy
** 入口参数:x(unsigned  char型),y(unsigned  char型)
** 出口参数:无
** 功能描述: 设置光标位置, x是行号,y是列号
****************************************************/
void  display_xy(unsigned  char x,unsigned  char y)
{ if(y==0x01){x = x + 0x40 + 0x80;     }else{x = x+0x80; }WriteCommandLcd(x);
}
/*********************************************************************
** 函数名称: display_string
** 入口参数:x(unsigned  char型),y(unsigned  char型),s(指针型)
** 出口参数:无
** 功能描述: 在具体位置显示字符串,以/0结束,x是列号,y是行号
**********************************************************************/
void  display_string(unsigned  char x,unsigned  char y,unsigned  char *s)
{display_xy(x,y);while(*s){WriteDataLcd(*s);s++;}
}Qu_Chu_Shu_Ma_Ge_Wei() //取出要显示的每一位数据;{a = Frequency_Out % 10;b = (Frequency_Out % 100)/10;c = (Frequency_Out % 1000)/100;d = (Frequency_Out % 10000)/1000;e = (Frequency_Out % 100000)/10000;f = (Frequency_Out % 1000000)/100000;g = (Frequency_Out % 10000000)/1000000;h = (Frequency_Out % 100000000)/10000000;}display_data()	 //显示数据子程序
{Qu_Chu_Shu_Ma_Ge_Wei();//取出要显示的每一位数据;display_string(1,0,LcdBuf1);//显示第一行,从第2个位置开始WriteCommandLcd(0x85);//显示数值的话,用其真实的地址,如0x83等,WriteDataLcd(0x30+h); //如果要显示字符的话,暂时用x、y坐标的方式	WriteDataLcd(0x30+g);//以下都是送显示数据;WriteDataLcd(0x30+f);WriteDataLcd(0x30+e);WriteDataLcd(0x30+d);WriteDataLcd(0x30+c);WriteDataLcd(0x30+b);WriteDataLcd(0x30+a);
}

按键处理函数:

scan_KEY(void)     //键值处理子程序
{
uchar key = 0;
key = P3;         
key = key & 0xf8;switch(key){case 0xb0:keyzhi = 3 ;break;case 0xa8:keyzhi = 2 ;break;case 0x98:keyzhi = 1 ;break;case 0x70:keyzhi = 6 ;break;case 0x68:keyzhi = 5 ;break;case 0x58:keyzhi = 4 ;break;default:   keyzhi=0;}return(keyzhi);
}keychuli()//键盘扫描子程序{P3_3 = 0x01;P3_5 = 0x01;P3_4 = 0x01;P3_6 = 0x00;P3_7 = 0x00;delay(100);if((P3_3&P3_4&P3_5) == 0x00){if((P3_3&P3_4&P3_5) == 0x00){P3_6 = 0x00;P3_7 = 0x01;dat = scan_KEY();if(dat == 0x00)	 {P3_6 = 0x01;P3_7 = 0x00;dat = scan_KEY();		  }}else{dat = 0x00;	 goto down;//无键按下}}down:return(dat);}

下面这块才是主要的程序,用来控制、使用AD9850:这一部分也是最核心的地方


Calculate_Control_Word(long uint Frequency_Out){Con_Word_1 = Frequency_Out * 85;Con_Word_2 = Frequency_Out *0.88423027547;//50MHz计算方法//首先有源晶体是50MHz的,然后用2的32次方减1,再除以50MHz得到的;Con_Word_2 = Con_Word_2 + 0.5;//小数部分四舍五入;Con_Word_1 = Con_Word_1 + Con_Word_2;//根据设定的频率以浮点形式计算控制字ConTrol_Word = Con_Word_1 / 1;//将控制字换算成整数形式  }Send_Control_Word(long uint ConTrol_Word)//向AD9850送入频率控制字;{ long uint ConTrol_Word_Temporary ;uchar data_word ;w_clk = 0x00;	//根据时序图fqud = 0x00;  //根据时序图//data_word = 0x00;	 //设置AD9851相位、掉电等相关控制字data_word = 0x00;	 //设置AD9850相位、掉电等相关控制字P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word_Temporary = ConTrol_Word;  ConTrol_Word = ConTrol_Word >> 24;data_word = ConTrol_Word % 256;//取出W1,频率控制字中的最高字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;ConTrol_Word = ConTrol_Word >> 16;data_word = ConTrol_Word % 256;//取出W2,频率控制字中的次高字节;P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;ConTrol_Word = ConTrol_Word >> 8;data_word = ConTrol_Word % 256;//取出W3,频率控制字中的第三字节;  P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;ConTrol_Word = ConTrol_Word_Temporary;data_word = ConTrol_Word % 256;//取出W4,频率控制字中的最后一个字节;  P2 = data_word;delay(200);w_clk=1;delay(200);w_clk=0;	   //根据时序图fqud=1;	   //根据时序图
}

主程序:

main()
{unsigned char i = 0x00; uint Step_Bian_Liang = 0x00;//步进变量;long uint Step_Data = 10;//默认为10Hz;long unsigned int Step_Data_Xian_Shi = 0x00;reset  =  1;	   //复位AD9850;delay(1000);  reset  =  0;	   //使AD9850进入正常的工作状态;  lcd_init();	   //初始化子程序;Frequency_Out = 0;//开机默认的频率输出值为0;Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word);      //向AD9850送出频率控制字;  display_data();		//显示数据;display_string(0,1,LcdBuf2);  //显示第二行,从第0个位置开始;WriteCommandLcd(0xc5);//从第二行第六个开始显示数据;WriteDataLcd(0x30+(Step_Data/1000));//送出显示数据;WriteDataLcd(0x30+(Step_Data/100)%10);//送出显示数据;WriteDataLcd(0x30+(Step_Data/10)%10);//送出显示数据;WriteDataLcd(0x30+(Step_Data%10));//送出显示数据;display_string(9,1,"Hz");//显示Hz;while(1){keychuli();//键处理子程序if(dat == 0x01)//键值为1;步进加{dat = 0x00;delay(5000);Frequency_Out = Frequency_Out + Step_Data;if(Frequency_Out > 10000000){Frequency_Out = Frequency_Out - Step_Data;}Light =~Light;display_data();reset  =  1;	   //复位AD9850;delay(100);  reset  =  0;	   //使AD9850进入正常的工作状态;  Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word);      //向AD9850送出频率控制字;  }if(dat == 0x04)//键值为4;步进减{dat = 0x00;delay(5000);if(Frequency_Out >= Step_Data){Frequency_Out = Frequency_Out - Step_Data;}Light =~Light;display_data();reset  =  1;	   //复位AD9850;delay(1000);  reset  =  0;	   //使AD9850进入正常的工作状态;  Calculate_Control_Word(Frequency_Out);//根据设置的频率换算成将要送入AD9850中的整数值;Send_Control_Word(ConTrol_Word);      //向AD9850送出频率控制字;  }if(dat == 0x06)//步进选择;这里有三种选择{dat = 0x00;delay(5000);Light =~Light;Step_Bian_Liang++; Step_Bian_Liang = Step_Bian_Liang%6;if(Step_Bian_Liang == 0x00){Step_Data = 10;//步进10;改成1}if(Step_Bian_Liang == 0x01){Step_Data = 100;}if(Step_Bian_Liang == 0x02){Step_Data = 1000;}if(Step_Bian_Liang == 0x03){Step_Data = 10000;}if(Step_Bian_Liang == 0x04){Step_Data = 100000;}if(Step_Bian_Liang == 0x05){Step_Data = 1000000;}if(Step_Data<=1000){WriteCommandLcd(0xc5);//参考上面类似的部分WriteDataLcd(0x30+(Step_Data/1000));WriteDataLcd(0x30+(Step_Data/100)%10);WriteDataLcd(0x30+(Step_Data/10)%10);WriteDataLcd(0x30+(Step_Data%10));display_string(9,1,"Hz ");}else{Step_Data_Xian_Shi = Step_Data/1000;WriteCommandLcd(0xc5);//参考上面类似的部分WriteDataLcd(0x30+(Step_Data_Xian_Shi/1000));WriteDataLcd(0x30+(Step_Data_Xian_Shi/100)%10);WriteDataLcd(0x30+(Step_Data_Xian_Shi/10)%10);WriteDataLcd(0x30+(Step_Data_Xian_Shi%10));display_string(9,1,"kHz");}}}
} 

2 椭圆滤波器

这篇关于电赛知识点总结17:DDS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/408556

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter

整数Hash散列总结

方法:    step1  :线性探测  step2 散列   当 h(k)位置已经存储有元素的时候,依次探查(h(k)+i) mod S, i=1,2,3…,直到找到空的存储单元为止。其中,S为 数组长度。 HDU 1496   a*x1^2+b*x2^2+c*x3^2+d*x4^2=0 。 x在 [-100,100] 解的个数  const int MaxN = 3000

状态dp总结

zoj 3631  N 个数中选若干数和(只能选一次)<=M 的最大值 const int Max_N = 38 ;int a[1<<16] , b[1<<16] , x[Max_N] , e[Max_N] ;void GetNum(int g[] , int n , int s[] , int &m){ int i , j , t ;m = 0 ;for(i = 0 ;

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel

9.8javaweb项目总结

1.主界面用户信息显示 登录成功后,将用户信息存储在记录在 localStorage中,然后进入界面之前通过js来渲染主界面 存储用户信息 将用户信息渲染在主界面上,并且头像设置跳转,到个人资料界面 这里数据库中还没有设置相关信息 2.模糊查找 检测输入框是否有变更,有的话调用方法,进行查找 发送检测请求,然后接收的时候设置最多显示四个类似的搜索结果