你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32利用ADC+DMA采样显示经验分享

[复制链接]
攻城狮Melo 发布时间:2024-5-29 17:24
DAC,即Digital to Analog Convertor,是数字到模拟转换器,也称为D/A转换器。其核心部分由R-2R电阻网络(也称倒T型电阻网络)、模拟开关和运算放大器组成。它可以将二进制码或BCD码表示的数字量转换为与其成正比的模拟量输出。

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

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

微信图片_20240529172405.png

STM32中的DAC(视芯片而定例如F407ZGT6是2个DAC通道,有些芯片不支持DAC功能)支持12模式的数据输入,可以双通道同时转换。

本期我们将介绍如何使用STM32F407和CubeMX利用HAL库实现DAC的输出。(本来是想使用C8T6的,结果突然想起来C8T6)没有DAC。

CubeMX配置

微信图片_20240529172401.png

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

微信图片_20240529172356.png

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

如果选择触发的话是从缓存区写入数据。

微信图片_20240529172353.png

这里顺带加一路ADC采样,因为手上没有示波器,所以使用ADC来进行查看。

这里使用DMA进行采样,具体可以参考公众号之前的关于DMA+ADC采样的内容。

STM32的DMA采样+FFT时域分析(STM32F407)

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

微信图片_20240529172349.png

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


  1.   MX_GPIO_Init();
  2.   MX_DMA_Init();
  3.   MX_ADC1_Init();
  4.   MX_DAC_Init();
  5.   MX_USART1_UART_Init();
  6.   MX_TIM1_Init();
  7.   MX_TIM2_Init();
  8.   /* USER CODE BEGIN 2 */
  9.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);        //用来触发adc采样
  10.   HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC
  11.   HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
  12.   /* USER CODE END 2 */

  13.   /* Infinite loop */
  14.   /* USER CODE BEGIN WHILE */
  15.   while (1)
  16.   {
  17.     /* USER CODE END WHILE */

  18.     /* USER CODE BEGIN 3 */
  19.     if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
  20.     {
  21.       HAL_ADC_Start_DMA(&hadc1, (uint32_t *)AD_Value, ADLenth);//开启ADC

  22.       HAL_Delay(20);
  23.       
  24.       while(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0));
  25.       HAL_Delay(1000);
  26.       for(int i = 0;i<ADLenth;i++)
  27.       {
  28.         printf("A:%d\r\n",AD_Value[i]);
  29.       }
  30.       
  31.       
  32.     }
  33.   }
  34.   /* USER CODE END 3 */
  35. }
复制代码


我们编写一段代码。

按下按键的时候设置DAC的值,开启DMA传输,再加上ADC采样,之后输出结果。

微信图片_20240529172345.png

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

三角波发生器

微信图片_20240529172342.png

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

微信图片_20240529172337.png

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

微信图片_20240529172334.png

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

微信图片_20240529172331.png

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

定时器频率/分频系数+1/Period/三角波最大值/2

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

微信图片_20240529172327.png

正弦波发生器

微信图片_20240529172323.png

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

微信图片_20240529172320.png

添加DMA,模式选择循环模式。

还有改变一下定时器的频率!

其他几乎不做改变。


  1.   #define POINTS 256                        
  2.   #define MIN_VALUE 50                        
  3.   #define MAX_VALUE 650                        
  4.   #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)  
  5.   #define OFFSET 50  
  6.   #define M_PI  3.14159265
  7.   
  8.   uint16_t SinWaveInt[POINTS];
  9.   int SinWave[POINTS];
  10.   void SinInit(void)
  11. {  
  12.      for (int i = 0; i < POINTS; i++)
  13.       {  
  14.       double x = ((double)i / (POINTS - 1)) * 2 * M_PI;
  15.       double sin_value = sin(x);  // 计算正弦值  
  16.       SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
  17.       SinWaveInt[i] = (uint16_t)SinWave[i];  
  18.     }
  19.   }
复制代码

计算一个正弦表。

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

微信图片_20240529172317.png

测试一下正弦表,输出的是正弦信号。

我们之后将正弦信号表导入DMA中。

  1.   SinInit();
  2.   HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)SinWave, POINTS, DAC_ALIGN_12B_R);
复制代码

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

微信图片_20240529172311.png

测试正弦信号成功。

FM调制
  1.   #define POINTS 1024                        
  2.   #define MIN_VALUE 50                        
  3.   #define MAX_VALUE 650                        
  4.   #define SCALE ((MAX_VALUE - MIN_VALUE) / 2.0)  
  5.   #define OFFSET 50  
  6.   #define M_PI  3.14159265
  7.   
  8.   uint16_t SinWaveInt[POINTS];
  9.   int SinWave[POINTS];
  10.   void SinInit(void)
  11. {  
  12.      for (int i = 0; i < POINTS; i++)
  13.       {  
  14.       double x = ((double)i / (POINTS/4 - 1)) * 2 * M_PI;
  15.       double sin_val = sin(x)*sin(x/4);  // 计算正弦值  
  16.       SinWave[i] = (int)((sin_value + 1) * SCALE + OFFSET);
  17.       SinWaveInt[i] = (uint16_t)SinWave[i];  
  18.     }
  19.   }
复制代码


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

微信图片_20240529172305.png


转载自:电路小白
如有侵权请联系删除



1 收藏 1 评论2 发布时间:2024-5-29 17:24

举报

2个回答
STMWoodData 回答时间:2024-5-29 22:06:30

资料不错,值得参考学习。

喻皓文 回答时间:2024-7-12 14:10:53

dac+dma?

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版