STM32
直播中

英雄孤寂

11年用户 1184经验值
私信 关注
[问答]

如何去设计并制作一个基于STM32F103ZET6和AD9850的任意波形发生器呢

如何去设计并制作一个基于STM32F103ZET6和AD9850的任意波形发生器呢?

任意波形发生器怎样才能产生正弦波、方波、三角波呢?

回帖(1)

李泓翔

2021-11-15 14:19:26
  基于STM32F103ZET6和AD9850的任意波形发生器
  一、任务
  设计制作一个任意波形发生器,该波形发生器能产生正弦波、方波、三角波,
  波形发生器能够在一定范围内保证恒压输出。
  二、要求
  1、基本要求
  (1)波形发生器能产生正弦波、方波、三角波三种周期性信号;
  (2)输出波形的频率范围为 100Hz~100kHz;频率可调,频率步进间隔≤
  100Hz;
  (3)在 50Ω负载条件下,输出电压峰-峰值最大值≥2V;
  (4)显示输出波形的类型、重复频率(周期)和幅度的功能;
  (5)用示波器观察时无明显失真。
  2.发挥部分
  (1)正弦信号频率范围扩展至 1Hz~10MHz,进一步提高方波和三角波输
  出频率。
  (2)具有输出频率和频率步进设置功能;
  (3)在 50Ω负载条件下,输出电压峰-峰值最大值≥5V;
  (4)具有波形类型和频率和幅度显示功能;
  (5)可以输出至少一种任意波形。
  三、说明
  1、基本部分频率调节方式可以采用模拟式或数字式,发挥部分的频率调节
  只能为数字式。
  2、发挥部分输出频率和频率步进需要利用键盘进行设置。
  3、任意波波形的种类可以任选,可以改变频率。
  *************分割线-----------------------/
  这是我们学校电赛校级选拔赛的一道题目,我和我的队友梁某人从7/19-7/25早上八点前完成的,大概共花了6天左右的时间。验收时所有功能都能实现,成绩是满分(2333hhhh),所以用博客记录下我们的第一次合作完成一个小比赛的历程~
  *************分割线-----------------------/
  开始准备做的时候 第一件事当然是查找资料和确定方案。一开始选择这个题目的原因完全是因为觉得 “任意波形发生器,是真的可以产生波形吗?感觉好像很好看 又好玩的亚子”…然后就选了,但是其实那时候连DDS是啥我都不知道。。老师说了一堆方案,可惜我好像啥也听不懂(水过鸭背233)?!果然还是得自己慢慢查找资料,最终我们确定了两种主要的方案。
  1、用STM32内部自带的AD产生所有的波形
  2、用STM32内部自带AD产生三角波,再用AD9850产生正弦波和方波
  由于考虑到32产生的波形最高只能达到14MHz,达不到题目要求。故我们选择了方案2。
  我们最终的成品:
  1、能产生最高频率为14MHz的三角波、锯齿波,
  2、正弦波和方波的频率能保证100MHz内不失真,
  3、输出幅值能达到6~7V(但其实也可以更高,改变后级放大电路的阻值即可)
  4、产生的波形名称在OLED屏上显示
  5、通过按键实现任意波形的切换和频率值的改变
  程序如下:
  1、主函数
  主要包括一些硬件的初始化、及显示
  int main(void)
  {
  // u32 freq;
  float Um;
  Um= 6.6;
  // freq=100;
  SineWave_Init1(freq,Um); ///******///
  delay_init();
  OLED_Init();
  HardwareInit();
  AD9850_Init();
  OLED_ShowString(0,0, “xiuer”);
  OLED_Refresh_Gram(); //调用显示函数之后必须更新缓存
  OLED_Clear();
  Delay_ms(100);
  while(1)
  {
  GetKeyVal();
  if(flange==1)
  {
  SineWave_Init2(freq,Um);
  display();
  }
  else
  {
  SineWave_Init1(freq,Um);
  display();
  }
  }
  }
  2、产生三角波和锯齿波
  注释有的不太对,主要得看代码内容
  其中包括一些DAC的初始化、DMA的配置以及波形输出表
  #include “sign.h”
  u16 SineWave_Value[256];
  /********正弦波输出表***********/
  //cycle :波形表的位数 (0~256)
  //Um :输出电压的峰值(0~1.5)
  /*******************************/
  void SineWave_Data( u16 cycle ,u16 *D,float Um)
  {
  u16 i;
  int n=1;
  for( i=0;i《cycle;i++)
  {
  if(i《cycle/2)
  {
  D[i]= (u16)(1.0*i/255*4095);
  }
  else
  {
  D[i]= (u16)(1.0*(i-2*n)/255*4095);
  n++;
  }
  }
  }
  /********生成锯齿波形输出表***********/
  void SawTooth_Data( u16 cycle ,u16 *D,float Um)
  {
  u16 i;
  // int n=1;
  for( i=0;i《cycle;i++)
  {
  D[i]= (u16)(1.0*i/255*4095);
  }
  }
  /****************初始化引脚******************/
  void SineWave_GPIO_Config(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开时钟
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速率
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ; //选择引脚
  GPIO_SetBits(GPIOA,GPIO_Pin_4) ; //拉高输出
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
  }
  /******************DAC初始化ˉ*************************/
  void SineWave_DAC_Config( void)
  {
  DAC_InitTypeDef DAC_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//开DAC时钟
  /**************DAC结构初始化*******************/
  DAC_StructInit(&DAC_InitStructure);
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//不产生波形
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //不使能输出缓存
  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//DAC触发为定时器2触发
  DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化
  DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC的通道1
  DAC_DMACmd(DAC_Channel_1, ENABLE); //使能DAC通道1的DMA
  }
  /*********定时器初始化************/
  void SineWave_TIM_Config(u32 Wave1_Fre)
  {
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//开时钟
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //不预分频
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //不分频《br》  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
  TIM_TimeBaseStructure.TIM_Period = Wave1_Fre;//设置输出频率
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//设置TIME输出触发为更新模式
  }
  /*********DMA配置***********/
  void SineWave_DMA_Config(void)
  {
  DMA_InitTypeDef DMA_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//开启DMA2时钟
  DMA_StructInit( &DMA_InitStructure); //DMA结构体初始化
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//从寄存器读数据
  DMA_InitStructure.DMA_BufferSize = 256;//寄存器大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不递增
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址递增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//宽度为半字
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//宽度为半字
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//优先级非常高
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//关闭内存到内存模式
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环发送模式
  DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//外设地址为DAC通道1的地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SineWave_Value;//波形数据表内存地址
  DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化
  DMA_Cmd(DMA2_Channel3, ENABLE); //使能DMA通道3
  }
  /**********正弦波初始化**********************/
  //Wave1_Fre: 频率值(0~60 000)Hz
  //Um : 电压峰值(0.0~1.5)V
  /*******************************************/
  void SineWave_Init1(u16 Wave1_Fre,float Um)
  {
  u32 f1;
  f1=(u32)(72000000/sizeof(SineWave_Value)*2/Wave1_Fre);//计算频率
  SineWave_Data(256,SineWave_Value,Um); //生成输出正弦波的波形表
  SineWave_GPIO_Config(); //初始化io
  SineWave_TIM_Config(f1); //初始化定时器
  SineWave_DAC_Config(); //配置DAC
  SineWave_DMA_Config(); //配置DMA
  TIM_Cmd(TIM2, ENABLE); //开启定时器
  }
  void SineWave_Init2(u16 Wave1_Fre,float Um)
  {
  u32 f1;
  f1=(u32)(72000000/sizeof(SineWave_Value)*2/Wave1_Fre);//计算频率
  SawTooth_Data(256,SineWave_Value,Um); //生成输出正弦波的波形表
  SineWave_GPIO_Config(); //初始化io
  SineWave_TIM_Config(f1); //初始化定时器
  SineWave_DAC_Config(); //配置DAC
  SineWave_DMA_Config(); //配置DMA
  TIM_Cmd(TIM2, ENABLE); //开启定时器
  }
  3、按键部分
  我们用的是4*4矩阵按键,因为当时时间不太多,再加上前期也没怎么准备。老师说我们的按键程序不太成熟,把16个键都用完了。。不过能功能都能实现。等把按键程序完善了再贴出,想实现用三个按键实现所有功能,在菜单里实现返回、确认和复位。
  
  程序部分再加上一个显示和AD9850的驱动即可。
  4、后级放大部分
  我们采用的是差动放大电路,大致电路如下,但电阻阻值需要根据你的输出幅值和想放大的倍数进行重新计算和配置
  
  最后放几张当时拍的照片~
  刚开始入手的时候,代码一堆错误…找了一两天 解决了一个问题又出现一大堆的子问题,因为这个是用hal库写的,为此我还专门下载了和学了STM32Cube MX,不过最终还是救不了这个代码,时间又没有多少了 那还是决定自己弄吧…用熟悉的库函数
  研究了好久,终于出了三角波,当时波形出来的时候我们三超激动,啊哈哈~
  验收前两天,不知道我干了啥。。出了个“蝴蝶波”,觉得很好看就拍下来了
  验收前一天晚上,还有几个功能没调出来,那时候打算在实验室通宵 但综合考虑还是决定回宿舍,不过果然deadline是最大生产力。。大概凌晨三点的时候突然有了思路,此时电脑已关机,好在我有笔23333,第二天六点起床就拉上队友去调,果然 九点钟验收的时候都实现了,而且居然丝毫没有困意…
举报

更多回帖

发帖
×
20
完善资料,
赚取积分