STM32-正弦波可调(50HZ~20KHZ可调、峰峰值0~3.3V可调)

2023-05-16

1.原理:

通过定时器每隔一段时间触发一次DAC转换,然后通过DMA发送正玄波码表值给DAC.

  • 当需要改变频率HZ时,只需要修改定时器频率即可(最高只能达到20KHz)
  • 当需要改变正玄波的正峰峰值/负峰峰值时,只需要修改正玄波码表即可

 

2.实现

代码如下所示(采用的是定时器2,DAC引脚是PA4)


#define HZ(x) (u16)(72000000/sizeof(Sine12bit)*2/x)     //计算Hz

#define DAC_DHR12R1 0x40007408 //外设DAC通道1的基地址


u16 Sine12bit[256] = { //正弦波描点
 2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496,
 2545, 2594, 2642, 2690, 2737, 2785, 2831, 2877, 2923, 2968,
 3013, 3057, 3100, 3143, 3185, 3227, 3267, 3307, 3347, 3385,
 3423, 3460, 3496, 3531, 3565, 3598, 3631, 3662, 3692, 3722,
 3750, 3778, 3804, 3829, 3854, 3877, 3899, 3920, 3940, 3958,
 3976, 3992, 4007, 4021, 4034, 4046, 4056, 4065, 4073, 4080,
 4086, 4090, 4093, 4095, 4095, 4095, 4093, 4090, 4086, 4080,
 4073, 4065, 4056, 4046, 4034, 4021, 4007, 3992, 3976, 3958,
 3940, 3920, 3899, 3877, 3854, 3829, 3804, 3778, 3750, 3722,
 3692, 3662, 3631, 3598, 3565, 3531, 3496, 3460, 3423, 3385,
 3347, 3307, 3267, 3227, 3185, 3143, 3100, 3057, 3013, 2968,
 2923, 2877, 2831, 2785, 2737, 2690, 2642, 2594, 2545, 2496,
 2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098, 2047, 1997,
 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1501,
 1453, 1405, 1358, 1310, 1264, 1218, 1172, 1127, 1082, 1038,
 995, 952, 910, 868, 828, 788, 748, 710, 672, 635,
 599, 564, 530, 497, 464, 433, 403, 373, 345, 317,
 291, 266, 241, 218, 196, 175, 155, 137, 119, 103,
 88, 74, 61, 49, 39, 30, 22, 15, 9, 5,
 2, 0, 0, 0, 2, 5, 9, 15, 22, 30,
 39, 49, 61, 74, 88, 103, 119, 137, 155, 175,
 196, 218, 241, 266, 291, 317, 345, 373, 403, 433,
 464, 497, 530, 564, 599, 635, 672, 710, 748, 788,
 828, 868, 910, 952, 995, 1038, 1082, 1127, 1172, 1218,
 1264, 1310, 1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697,
 1747, 1797, 1847, 1897, 1947, 1997 };


 /*************************************************************
Function  :  set_Sine12bit
Description : 设置正玄波码表
Input  :   MAX(正峰峰值) MIN(负峰峰值)
return  :  none
*************************************************************/ 
 void Set_Sine12bit(float MAX,float MIN)
{
         int i;
         float  jiaodu=0;

float MID=(MAX+MIN)/2.0;                        //中间峰值

if(MAX>3.3) MAX=3.3;

else if(MAX<=MIN) MIN=0;
for(i=0;i<256;i++)
         {
             jiaodu=i*0.0247369;      //当i =127时,表示为180度,由于sin()是弧度制,所以需要转换
             Sine12bit[i]=  ((float)sin(jiaodu)*(MAX-MID)+MID)*1241.212;     //1241.212是比例,等于4096/3.3            
         }  
}

/*************************************************************
Function  :   Set_Period
Description : 设置频率hz
Input  :   value(需要设置的频率hz值)
return :  none
*************************************************************/ 
void  Set_Period(u32 value)
{
     TIM_ARRPreloadConfig(TIM2,DISABLE);
     TIM2->ARR=HZ(value);                //更新预装载值 
     TIM_ARRPreloadConfig(TIM2,ENABLE);

}

/*************************************************************
Function : TIM2_Int_Init
Description: 初始化定时器2
Input :  Hz (需要初始化的频率hz值)
return :  none
*************************************************************/ 
void TIM2_Int_Init(u32 Hz)
{

      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//初始化定时器2与6的时钟

      TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
      TIM_TimeBaseStructure.TIM_Period = HZ(Hz);                        //正弦波频率设置
      TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                   //没有预分频
      TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;  //时钟不分频  72M
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //增计数
      TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

      TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//更新TIM2输出触发    
}

/*************************************************************
Function : DAC_DMA_Config
Description: 初始化DAC和DMA
Input :   none
return :  none
*************************************************************/ 
void DAC_DMA_Config(void)
{  
     DAC_InitTypeDef DAC_InitStructure;
     DMA_InitTypeDef DMA_InitStructure;
     GPIO_InitTypeDef GPIO_InitStructure;

     RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

     RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//初始化DAC的时钟

     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//初始化DMA2的时钟

     /*初始化GPIO*/
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;//DAC channel1和channel2对应的引脚
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOA, &GPIO_InitStructure);

    /*初始化DAC寄存器*/
     DAC_StructInit(&DAC_InitStructure);
     DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//指定DAC1的触发定时器TIM2
     DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//无波形产生
     DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //不是能DAC输出缓冲
     DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化DAC channel1
     DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC channel1
     DAC_DMACmd(DAC_Channel_1, ENABLE); //使能DAC Channel1的DMA
/*初始化DMA寄存器*/ DMA_DeInit(DMA2_Channel3); //将DMA配置成默认值 DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//指定DMA2通道3的目标地址为DAC1_DHR12R1 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;//指定DMA的源地址为数组Sine12bit DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为数据传输的目的地 DMA_InitStructure.DMA_BufferSize = sizeof(Sine12bit)/2;//DMA缓冲区大小 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_Mode = DMA_Mode_Circular;//工作在循环缓存模式,数据传输数为0时,自动恢复配置初值 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//非常高优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被设置成内存到内存模式,与循环模式相对 DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化DMA DMA_Cmd(DMA2_Channel3, ENABLE); //使能DMA的channel3 TIM_Cmd(TIM2, ENABLE); //最后开启TIM2转换 }

 

然后在main()函数里,调用USART_handler()

其中USART_handler()函数实现如下:


void USART_handler()
{  
       u8 len;
       u32 hz;                //获取HZ频率
       float dac_max,dac_min; //获取DAC峰值     

       if(USART_RX_STA&0x8000)
       { 
              len=USART_RX_STA&0x2F;
              USART_RX_BUF[len]=0;
              sscanf((char *)USART_RX_BUF,"%d,%f,%f",&hz,&dac_max,&dac_min);
              printf("SET  HZ = %d, MAX = %f,MIN = %f\r\n", hz,dac_max,dac_min);

              Set_Sine12bit(dac_max,dac_min);        //更改峰值
              Set_Period( hz);                       //更改频率

              USART_RX_STA=0;
       }
}  

 

3.进入串口试验

1)设置频率=50hz,正峰值=3.3V,负峰值=0V,串口则发送50,3.3,0.0,如下图所示:

 

示波器测量:

 

 

2)设置频率=100hz,正峰值=3V,负峰值=0V, 串口则发送100,3,0.0:

 

 

3)设置频率=100hz,正峰值=2V,负峰值=1V, 串口则发送100,2,1:

 

 

4)设置频率=1khz,正峰值=3.3V,负峰值=0V, 串口则发送1000,3.3,0

 

 

5)设置频率=20khz,正峰值=3.3V,负峰值=0V,串口则发送20000,3.3,0:    

 

 

 是不是很简单~

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32-正弦波可调(50HZ~20KHZ可调、峰峰值0~3.3V可调) 的相关文章

随机推荐

  • 性能专题

    if与switch 当多个条件语句判断时 xff0c switch比多个if语句的性能高 转载于 https www cnblogs com lanchong archive 2011 11 03 2234180 html
  • 自制户外登山地图傻瓜书(转载)

    自制户外登山地图傻瓜书 2009 02 19 灰羊羊 转载请注明出处 第一章 前言 大概4年前喜欢上了户外运动 xff0c 从此一发不可收拾 xff0c 07年初买了一个GPS xff0c 最初只是为了避免在山中迷路 xff0c 随着使用的
  • 文件加密和解密 - 密钥存储

    当我们想要做一次加密系统 xff0c 或者只是有一个关于这个问题 xff0c 它是如何保存的加密和解密密钥 一般认为想要的文件加密和解密 xff0c 对称算法用于 一般是AES要么DES 这就存在密钥管理的问题 xff0c 它是如何 xff
  • spring mvc绑定复杂对象报错“Could not instantiate property type [com.ld.net.spider.pojo.WorkNode] to auto-gro...

    解决方法之一 xff1a 1 确保所有的Pojo都包含了默认的构造器 xff1b
  • Docker容器 暴露多个端口

    1 创建容器是指定 docker run p lt host port1 gt lt container port1 gt p lt host port2 gt lt container port2 gt 2 修改dockerfile ex
  • 巴特沃斯(Butterworth)滤波器 (1)

    下面深入浅出讲一下Butterworth原理及其代码编写 1 首先考虑一个归一化的低通滤波器 xff08 截止频率是1 xff09 xff0c 其幅度公式如下 xff1a 当n gt 时 xff0c 得到一个理想的低通滤波反馈 xff1c
  • 用预训练的densenet121模型训练cifar10数据集

    densenet121采用pytorch预训练模型 xff0c 这里用cifar10作为数据集 import torchvision models as models import ssl ssl create default https
  • Ubuntu环境下安装DBoW2

    简介 DBoW2 is an improved version of the DBow library an open source C 43 43 library for indexing and converting images in
  • java如何将二进制转换为十进制

    1 使用java内部提供的方法 xff0c 直接进行api的调用 public static void binaryTodecimal2 int n String res 61 Integer toBinaryString n System
  • Spring Cloud Feign 请求动态URL

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 FeignClient 中不要写url 使用 64 RequestLine 修饰方法 2 调用地方必须引入 FeignClientConfiguration 必须有De
  • 折半查找:查找成功的最少/多次数、平均次数,查找不成功的最少/多次数、平均次数...

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 最方面的方法是建立一个判定树 现在有11个数 xff1a xff08 第1行是索引 xff0c 第2行是数 xff09 0 1 2 3 4 5 6 7 8 9 10 7 1
  • 关于maven打包 “程序包com.sun.deploy.net不存在” 的问题

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 关于maven打包 程序包com sun deploy net不存在 的问题 遇到问题如下 xff1a INFO payGateway 1 0 SNAPSHOT SUCCE
  • 印度理工学院有多难考?

    http app myzaker com news article php pk 61 599546401bc8e08604000085 印度理工学院有多难考 xff1f 何赟08 17 原文是六月高考季时给公众号 34 中印对话 34 x
  • iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结

    今天 我对iOS系统下 的手机屏幕尺寸 分辨率 及系统版本做了一次系统总结 供大家参考 首先 是系统 xff1a 随着iOS 系统不断升级 xff0c 现在已经到iOS7 0了 xff0c 并且TA有了很多新变化 xff0c 最震撼的就是
  • android ViewFlipper的使用

    屏幕切换指的是在同一个Activity内屏幕见的切换 xff0c 最长见的情况就是在一个FrameLayout内有多个页面 xff0c 比如一个系统设置页面 xff1b 一个个性化设置页面 通过查看 OPhone API文档可以发现 xff
  • Linux下路由配置梳理

    在日常运维作业中 xff0c 经常会碰到路由表的操作 下面就linux运维中的路由操作做一梳理 xff1a 先说一些关于路由的基础知识 xff1a 1 xff09 路由概念 路由 xff1a 跨越从源主机到目标主机的一个互联网络来转发数据包
  • ASP.NET成员角色系列(一)--验证与授权入门

    在当今的信息世界里 无论是门户网站 电子商务 社区论坛 都有一个共性 它们通常都需要验证当前用户的身份并根据验证结果判断用户所具有的权限 例如博客园 它允许未注册的匿名用户可能查看帖子 但是不允许他们发表帖子 为了能够发表帖子 匿名用户必须
  • 老赵谈IL(4):什么时候应该学IL,该怎么学IL

    又是一个拖了半年的系列 xff0c 可能是前几篇主要以事实为准 xff0c 举例子的文章总是比较容易写的 xff0c 因此十分顺畅 而最后一篇打算做一个总结 xff0c 以讲道理为主 却发现该将的似乎都已经讲完了 不过做事要有始有终 xff
  • FreeRTOS的第一个任务是怎么跑起来的

    一 一般在程序末尾会有一个vTaskStartSheduler 函数 span class hljs keyword int span main span class hljs keyword void span BSP INIT Bina
  • STM32-正弦波可调(50HZ~20KHZ可调、峰峰值0~3.3V可调)

    1 原理 通过定时器每隔一段时间触发一次DAC转换 然后通过DMA发送正玄波码表值给DAC 当需要改变频率HZ 时 只需要修改定时器频率 即可 最高只能达到20KHz 当需要改变 正玄波的正峰峰值 负峰峰值 时 只需要修改正玄波码表 即可