极客秀
搜索

STM32上的DAC输出(三角波/正弦波/FM调制信号)并且利用ADC+DMA采样显示

DAC,即Digital to Analog
Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。

DAC的工作原理主要包括数字信号采样、量化、编码和模拟信号输出几个步骤。首先,将连续变化的模拟信号在一定的时间间隔内进行离散取样,即数字信号采样。接着,对采样后的数字信号进行量化,将其转换为离散的数值。然后,通过编码将量化后的数值进行转换,以便DAC能够识别和处理。最后,DAC将这些数字信号转换为模拟信号输出。

DAC是数字系统和模拟系统之间的桥梁,具有广泛的应用领域。在音频处理中,DAC被用来将数字音频信号转换为模拟音频信号,以驱动扬声器和耳机,其性能对音频质量有着决定性的影响。在通信系统中,DAC用于将数字信号转换为模拟信号,以实现信号调制和解调。此外,在仪器仪表领域,DAC也被广泛应用于各种测量和控制设备中。

STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。
本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。
CubeMX配置

在DAC通道中开启DAC,在F407ZGT6中DAC1对应PA4,DAC2对应PA5。

OutputBuffer这里设置DAC的输出缓存使能,Trigger是DAC是触发方式,这里我们选择不触发(手动写入)。
如果选择触发的话是从缓存区写入数据。

这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。 这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。

但是相比于之前的,需要更改一些设置,首先是DMA的设置

这里设置单词请求,而不是循环模式防止数据跑飞掉。


  MX_GPIO_Init();  MX_DMA_Init();  MX_ADC1_Init();  MX_DAC_Init();  MX_USART1_UART_Init();  MX_TIM1_Init();  MX_TIM2_Init();  /* USER CODE BEGIN 2 */  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);        //用来触发adc采样   HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC  HAL_DAC_Start(&hdac,DAC_CHANNEL_1);  /* USER CODE END 2 */  
  /* Infinite loop */  /* USER CODE BEGIN WHILE */  while (1)  {    /* USER CODE END WHILE */  
    /* USER CODE BEGIN 3 */    if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))    {      HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC  
      HAL_Delay(20);            while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));      HAL_Delay(1000);      for(int i = 0;i<ADLenth;i++)      {        printf("A:%drn",AD_Value[i]);      }                }  }  /* USER CODE END 3 */}

我们编写一段代码。
按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。

可以看到,我们按下按键之后,ADC的值会呈阶梯状上升。

  • 三角波发生器

在DAC配置中打开波形发生器,触发方式选择定时器2触发,三角波最大振幅511。

之后开启定时器2,由于ADC的采样率是1000HZ,因此根据奈奎斯特采样定律,信号的最大频率不能超过500HZ,因此我们使用100HZ的三角波。

定时器设置好时间之后,设置触发事件。

芯片手册中简单的介绍了一下如何计算三角波的频率。当触发信号发生后,内部计数器的值就会+1,所以频率可以用如下公式计算:
定时器频率/分频系数+1/Period/三角波最大值/2


  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);        //用来触发adc采样   HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);        //用来触发DAC输出  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC  HAL_DAC_Start(&hdac,DAC_CHANNEL_1);  HAL_DAC_SetValue(&hdac,DAC_CHANNEL_1,DAC_ALIGN_12B_L,0);//设置直流信号

  • ** 正弦波发生器 **

首先是定时器触发(方便控制频率)。但是关闭波形发生器。

添加DMA,模式选择循环模式。 还有改变一下定时器的频率!
其他几乎不做改变。


  #define POINTS 256                           #define MIN_VALUE 50                           #define MAX_VALUE 650                           #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)    #define OFFSET 50    #define M_PI  3.14159265    uint16_t SinWaveInt[POINTS];  int SinWave[POINTS];   void SinInit(void) {       for (int i = 0; i < POINTS; i++)       {        double x = ((double)i / (POINTS - 1)) * 2 * M_PI;       double sin_value = sin(x);  // 计算正弦值        SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);       SinWaveInt[i] = (uint16_t)SinWave[i];      }  }

计算一个正弦表。
这里的Points决定了分辨率,结合定时器触发频率决定了正弦波的信号。

测试一下正弦表,输出的是正弦信号。 我们之后将正弦信号表导入DMA中。


  SinInit();  HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);  

正弦表初始化,之后启动DMA传输,导入正弦信号。

测试正弦信号成功。

  • FM调制

  #define POINTS 1024                           #define MIN_VALUE 50                           #define MAX_VALUE 650                           #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)    #define OFFSET 50    #define M_PI  3.14159265    uint16_t SinWaveInt[POINTS];  int SinWave[POINTS];   void SinInit(void) {       for (int i = 0; i < POINTS; i++)       {        double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;       double sin_val = sin(x)*sin(x/4);  // 计算正弦值        SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);       SinWaveInt[i] = (uint16_t)SinWave[i];      }  }

拓宽点数,加上载波,即可构成FM调制信号。

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容