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

【经验分享】STM32 F1 系列 DAC 的示例详解

[复制链接]
STMCU小助手 发布时间:2022-2-23 18:36
前言
基于学习的目的,详细讲解关于 Cube 库中的 DAC 的功能。本次介绍 DAC。


一、示例详解
基于硬件平台:STM32F10C-EVAL,MCU 的型号是 STM32F107VCT6。
软件则是其 Cube 库,路径:
STM32Cube\Repository\STM32Cube_FW_F1_V1.3.0\Projects\STM3210C_EVAL\Examples\DAC\DAC_SignalsGeneration 。
1、主程序
软件配置,运行程序可以发现,系统时钟设置为 72MHz,定时器使用到的是 TIM6;
  1. int main(void)
  2. {
  3. HAL_Init();
  4. /* Configure the system clock to 72 MHz */
  5. SystemClock_Config();

  6. /* Configure LED3 */
  7. BSP_LED_Init(LED3);
  8. /* Configures Key push-button */
  9. BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);
  10. /*##-1- Configure the DAC peripheral #######################################*/
  11. DacHandle.Instance = DACx;
  12. /*##-2- Configure the TIM peripheral #######################################*/
  13. TIM6_Config();
  14. /* Infinite loop */
  15. while (1)
  16. {
  17. /* If the Key is pressed */
  18. if (ubKeyPressed != RESET)
  19. {
  20. HAL_DAC_DeInit(&DacHandle);
  21. /* select waves forms according to the Key push-button status */
  22. if (ubSelectedWavesForm == 1)
  23. {
  24. /* The triangle wave has been selected */
  25. /* Triangle Wave generator -------------------------------------------*/
  26. DAC_Ch1_TriangleConfig();
  27. }
  28. else
  29. {
  30. /* The escalator wave has been selected */
  31. /* Escalator Wave generator -------------------------------------------*/
  32. DAC_Ch1_EscalatorConfig();
  33. }
  34. ubKeyPressed = RESET;
  35. }
  36. }
  37. }
复制代码

根据时钟树的图谱及其程序, 该示例选择的是内部时钟源作为定时器的时钟源;TIM6 的时钟源来自 APB1 的分频。

BOJGIK$J9Y1T)GWEOLDORNY.png

77WD7)KJ43(PDZ(H~BOM[O7.png

AHB 时钟 (HCLK)在 RCC_CFGR 寄存器中的分频系数 HPRE 的值为 0,即 SYSCLK not divided,即/1,所以 HCLK 就是72MHz;
APB1 的 prescaler 的系数是 PPRE1:0x4,HCLK divided 2,即/2,APB1CLK 为 36MHz;由于 APB1 的 prescaler 系数部分频,即/4,所以倍频器起作用,即为上图中的 TIMxCLK = 72Mhz。
2、 定时器 Tim6
  1. void TIM6_Config(void)
  2. {
  3. static TIM_HandleTypeDef htim;
  4. TIM_MasterConfigTypeDef sMasterConfig;
  5. /*##-1- Configure the TIM peripheral #######################################*/
  6. /* Time base configuration */
  7. htim.Instance = TIM6;
  8. htim.Init.Period = 0x7FF;
  9. htim.Init.Prescaler = 0;
  10. htim.Init.ClockDivision = 0;
  11. htim.Init.CounterMode = TIM_COUNTERMODE_UP;
  12. htim.Init.RepetitionCounter = 0;
  13. HAL_TIM_Base_Init(&htim);
  14. /* TIM6 TRGO selection */
  15. sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  16. sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  17. HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);
  18. /*##-2- Enable TIM peripheral counter ######################################*/
  19. HAL_TIM_Base_Start(&htim);
  20. }
复制代码

设置的是向上计数,周期是 0x7FF(2047),从 0 开始计数到 2047,所以该定时器的更新周期:(2047+1)/72 = 28us,

UD%CQTP%_3DB8V(4{EY%4.png

所以传输的 6 个数值:

P_({2T$L6~XQN4K@H4]NMGD.png

对于 8 位的 DAC,程序中设定的是右对齐,

5C[%R)IG%8H@80JPTHDWIZ2.png

所以,对应的 DOR 分别为
0x000(0), 0x330(816), 0x660(1632), 0x990(2448), 0xCC0(3264), 0xFF0(4080) ;
而 Vref = 3.3V, 所以:
Vdac 分别等于:也是约在 0V; 0.66V; 1.32V; 1.98V; 2.64V; 3.3V 之间;
3、阶梯波形
  1. static void DAC_Ch1_EscalatorConfig(void)
  2. {
  3. /*##-1- Initialize the DAC peripheral ######################################*/
  4. if (HAL_DAC_Init(&DacHandle) != HAL_OK)
  5. {
  6. /* Initialization Error */
  7. Error_Handler();
  8. }
  9. /*##-1- DAC channel1 Configuration #########################################*/
  10. sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
  11. sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  12. if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL) != HAL_OK)
  13. {
  14. /* Channel configuration Error */
  15. Error_Handler();
  16. }
  17. /*##-2- Enable DAC selected channel and associated DMA #############################*/
  18. if (HAL_DAC_Start_DMA(&DacHandle, DACx_CHANNEL, (uint32_t *)aEscalator8bit, 6,
  19. DAC_ALIGN_8B_R) != HAL_OK)
  20. {
  21. /* Start DMA Error */
  22. Error_Handler();
  23. }
  24. }
复制代码

对于阶梯波形比较简单:
就是上述的 6 个数值每个 28us 触发 DMA 传输一次到 DOR 的寄存器;
所以测得的实际波形(6 个梯阶,电压分别 0V; 0.66V; 1.32V; 1.98V; 2.64V; 3.3V; 周期 28*6 = 168us);
验证的波形如下:

KZ{B_~0$B{QM6{738FWZDVS.png

`78VU$NQP$H`4QXGF40~7[6.png

对于阶梯波形的产生,WAVE 设置的是 0x00;即:wave generation disable;


)_`}[[`@_O~0WBY[)K~(AOG.png

4、三角波
  1. HAL_StatusTypeDef HAL_DACEx_TriangleWaveGenerate(DAC_HandleTypeDef* hdac, uint32_t
  2. Channel, uint32_t Amplitude)
  3. {
  4. /* Check the parameters */
  5. assert_param(IS_DAC_CHANNEL(Channel));
  6. assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));

  7. /* Process locked */
  8. __HAL_LOCK(hdac);

  9. /* Change DAC state */
  10. hdac->State = HAL_DAC_STATE_BUSY;

  11. /* Enable the selected wave generation for the selected DAC channel */
  12. MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1)|(DAC_CR_MAMP1))<<Channel,
  13. (DAC_CR_WAVE1_1 | Amplitude) << Channel);

  14. /* Change DAC state */
  15. hdac->State = HAL_DAC_STATE_READY;

  16. /* Process unlocked */
  17. __HAL_UNLOCK(hdac);

  18. /* Return function status */
  19. return HAL_OK;
  20. }
复制代码


产生三角波的主要代码如上,其实也就是下面的这一段代码:
  1. /* Enable the selected wave generation for the selected DAC channel */
  2. MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1)|(DAC_CR_MAMP1))<<Channel,
  3. (DAC_CR_WAVE1_1 | Amplitude) << Channel);
复制代码
其实也就是设置下面的寄存器的比特位;

E}H]QH04B{%%~7AFM}7WR3X.png

最大的振幅是 3.3V,即对应的是 4095,
软件里面设置的 2047,所以振幅是大约 1.65V



该三角波的产生是由单片机的硬件产生的,软件控制的是:振幅和周期;
振幅通过上述寄存器中的 MAMP1 来控制;
周期则是定时器 Tim6 的触发事件?
但是这里的周期并不是 128us 啊?
改变幅值也会改变三角波的周期的,
那么这幅值和周期以及定时器之间三者的关系如何呢?
答案:

  1. 因为每个时钟节拍才步进 1 格,如果是满幅值输出时,要步进 4095*2 个定时器时钟节拍。
  2. 我的程序中,设定的幅值是 2047,所以输出一个三角波需要 2047*2 个时钟节拍;
  3. 一个时钟节拍在上面计算的 TIM6 的更新是大约 28us;所以周期 28*2047*2us;即大约是 115ms;
复制代码


PPH2K@RB]M6`O~W08AX3R~V.png

符合推论。
设置的波形控制模式:WAVE1 = 0x02,即产生三角波;

G5Q5A8[6VBWMIUJA6UNG28E.png

对于三角波的产生器,还有一段函数代码的作用是什么意思呢?


  1. /*##-3- DAC channel2 Triangle Wave generation configuration ################*/
  2. if (HAL_DACEx_TriangleWaveGenerate(&DacHandle, DACx_CHANNEL,
  3. DAC_TRIANGLEAMPLITUDE_2047) != HAL_OK)
  4. {
  5. /* Triangle wave generation Error */
  6. Error_Handler();
  7. }
  8. #if 1
  9. /*##-4- Enable DAC Channel1 ################################################*/
  10. if (HAL_DAC_Start(&DacHandle, DACx_CHANNEL) != HAL_OK)
  11. {
  12. /* Start Error */
  13. Error_Handler();
  14. }
  15. #endif
  16. #if 0
  17. /*##-5- Set DAC channel1 DHR12RD register
  18. ################################################*/
  19. if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
  20. {
  21. /* Setting value Error */
  22. Error_Handler();
  23. }
  24. #endif
复制代码


即其中的代码:
  1. if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
  2. {
  3. /* Setting value Error */
  4. Error_Handler();
  5. }
复制代码


是什么作用呢?
产生的波形:

  1. /*##-5- Set DAC channel1 DHR12RD register
  2. ################################################*/
  3. if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
  4. {
  5. /* Setting value Error */
  6. Error_Handler();
  7. }
复制代码


PF95M`$(5D[@%V5]AW_1ZNJ.png

在加了函数之后:
  1. /*##-5- Set DAC channel1 DHR12RD register
  2. ################################################*/
  3. if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 10000) != HAL_OK)
  4. {
  5. /* Setting value Error */
  6. Error_Handler();
  7. }
复制代码

6KAJS6$~[D2BJK`TWFS~K(A.png

从波形上来看,当参数数值不为 0 时,波形更像三角波,那这个参数影响的是什么呢?

HY$E2N_T)KB0(A9$)5RB$SN.png
参数的 tmp 的值,位于 0x200004A4 处,初始值为 0,运行到:
  1. tmp = (uint32_t)hdac->Instance;
复制代码


后 tmp 的值为 0x40007400,该值是解释得通的:DAC 外设的基地址(0x40007400)

0VFS)9`NB1@(H90VCS6HE{L.png

执行完语句之后:由于传递的参数是#define DAC_ALIGN_12B_R                  ((uint32_t)0x00000000)
  1. DAC_DHR12R2_ALIGNMENT(Alignment);
复制代码

得到的结果是(注意上图中虽然断点停在了 DAC_DHR12R2_ALIGNMENT 处,但是程序是 DAC_CHANNEL_1,所以最终执行的还是下面的语句)
  1. #define DAC_DHR12R1_ALIGNMENT(__ALIGNMENT__) (((uint32_t)0x00000008) + (__ALIGNMENT__))
复制代码

所以最终产生的效果就是:
  1. *(__IO uint32_t *) tmp = Data;
复制代码

地址为 0x40007408 的寄存器赋值,即下面寄存器赋值:

$VY8TU)HK7YNVS7381$J1)9.png

但是这寄存器的作用是什么呢?holding data?
Holding data 寄存器,可以简单的理解为:
设置影响 DAC 的直流分量(直流分量还是根据下面的公式计算出来的):



当传递的参数设置为 0 是,DACoutput 即三角波的最低电平为 0:
当传递的参数设置为 2047,DACoutput 即三角波的最低电平为 1.65V

((~IQBBQ`%8]8OY$)C~ZSMG.png

如果传递的参数设置为 1024,DACoutput 即三角波的最低电平为 0.82V;

YKU_`@}WQ1HO[_64VHLHR~D.png

如果传递的参数设置为 3000,DACoutput 即三角波的最低电平为 2.42V;

QO]W{{MY9ISBI`VH9NZ[25Q.png

50}5O~JR4M]C~)J04DY)~13.png

5、噪声产生器
主要函数的代码如下:
  1. if (HAL_DACEx_NoiseWaveGenerate(&DacHandle, DACx_CHANNEL,
  2. DAC_TRIANGLEAMPLITUDE_2047) != HAL_OK)
  3. {
  4. /* Triangle wave generation Error */
  5. Error_Handler();
  6. }
  7. /*##-4- Enable DAC Channel1 ################################################*/
  8. if (HAL_DAC_Start(&DacHandle, DACx_CHANNEL) != HAL_OK)
  9. {
  10. /* Start Error */
  11. Error_Handler();
  12. }
复制代码



由于一般的认为噪声是随机性的,所以可以认为只是修改幅值,对于其周期不可控;







PDZKNYI_I07HJNH`(NQ2ANG.png
收藏 评论0 发布时间:2022-2-23 18:36

举报

0个回答

所属标签

相似技术帖

官网相关资源

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