前言
基于学习的目的,详细讲解关于 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;
- int main(void)
- {
- HAL_Init();
- /* Configure the system clock to 72 MHz */
- SystemClock_Config();
- /* Configure LED3 */
- BSP_LED_Init(LED3);
- /* Configures Key push-button */
- BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);
- /*##-1- Configure the DAC peripheral #######################################*/
- DacHandle.Instance = DACx;
- /*##-2- Configure the TIM peripheral #######################################*/
- TIM6_Config();
- /* Infinite loop */
- while (1)
- {
- /* If the Key is pressed */
- if (ubKeyPressed != RESET)
- {
- HAL_DAC_DeInit(&DacHandle);
- /* select waves forms according to the Key push-button status */
- if (ubSelectedWavesForm == 1)
- {
- /* The triangle wave has been selected */
- /* Triangle Wave generator -------------------------------------------*/
- DAC_Ch1_TriangleConfig();
- }
- else
- {
- /* The escalator wave has been selected */
- /* Escalator Wave generator -------------------------------------------*/
- DAC_Ch1_EscalatorConfig();
- }
- ubKeyPressed = RESET;
- }
- }
- }
复制代码
根据时钟树的图谱及其程序, 该示例选择的是内部时钟源作为定时器的时钟源;TIM6 的时钟源来自 APB1 的分频。
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
- void TIM6_Config(void)
- {
- static TIM_HandleTypeDef htim;
- TIM_MasterConfigTypeDef sMasterConfig;
- /*##-1- Configure the TIM peripheral #######################################*/
- /* Time base configuration */
- htim.Instance = TIM6;
- htim.Init.Period = 0x7FF;
- htim.Init.Prescaler = 0;
- htim.Init.ClockDivision = 0;
- htim.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim.Init.RepetitionCounter = 0;
- HAL_TIM_Base_Init(&htim);
- /* TIM6 TRGO selection */
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);
- /*##-2- Enable TIM peripheral counter ######################################*/
- HAL_TIM_Base_Start(&htim);
- }
复制代码
设置的是向上计数,周期是 0x7FF(2047),从 0 开始计数到 2047,所以该定时器的更新周期:(2047+1)/72 = 28us,
所以传输的 6 个数值:
对于 8 位的 DAC,程序中设定的是右对齐,
所以,对应的 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、阶梯波形
- static void DAC_Ch1_EscalatorConfig(void)
- {
- /*##-1- Initialize the DAC peripheral ######################################*/
- if (HAL_DAC_Init(&DacHandle) != HAL_OK)
- {
- /* Initialization Error */
- Error_Handler();
- }
- /*##-1- DAC channel1 Configuration #########################################*/
- sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
- sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
- if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL) != HAL_OK)
- {
- /* Channel configuration Error */
- Error_Handler();
- }
- /*##-2- Enable DAC selected channel and associated DMA #############################*/
- if (HAL_DAC_Start_DMA(&DacHandle, DACx_CHANNEL, (uint32_t *)aEscalator8bit, 6,
- DAC_ALIGN_8B_R) != HAL_OK)
- {
- /* Start DMA Error */
- Error_Handler();
- }
- }
复制代码
对于阶梯波形比较简单:
就是上述的 6 个数值每个 28us 触发 DMA 传输一次到 DOR 的寄存器;
所以测得的实际波形(6 个梯阶,电压分别 0V; 0.66V; 1.32V; 1.98V; 2.64V; 3.3V; 周期 28*6 = 168us);
验证的波形如下:
对于阶梯波形的产生,WAVE 设置的是 0x00;即:wave generation disable;
4、三角波
- HAL_StatusTypeDef HAL_DACEx_TriangleWaveGenerate(DAC_HandleTypeDef* hdac, uint32_t
- Channel, uint32_t Amplitude)
- {
- /* Check the parameters */
- assert_param(IS_DAC_CHANNEL(Channel));
- assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
- /* Process locked */
- __HAL_LOCK(hdac);
- /* Change DAC state */
- hdac->State = HAL_DAC_STATE_BUSY;
- /* Enable the selected wave generation for the selected DAC channel */
- MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1)|(DAC_CR_MAMP1))<<Channel,
- (DAC_CR_WAVE1_1 | Amplitude) << Channel);
- /* Change DAC state */
- hdac->State = HAL_DAC_STATE_READY;
- /* Process unlocked */
- __HAL_UNLOCK(hdac);
- /* Return function status */
- return HAL_OK;
- }
复制代码
产生三角波的主要代码如上,其实也就是下面的这一段代码:
- /* Enable the selected wave generation for the selected DAC channel */
- MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1)|(DAC_CR_MAMP1))<<Channel,
- (DAC_CR_WAVE1_1 | Amplitude) << Channel);
复制代码 其实也就是设置下面的寄存器的比特位;
最大的振幅是 3.3V,即对应的是 4095,
软件里面设置的 2047,所以振幅是大约 1.65V
该三角波的产生是由单片机的硬件产生的,软件控制的是:振幅和周期;
振幅通过上述寄存器中的 MAMP1 来控制;
周期则是定时器 Tim6 的触发事件?
但是这里的周期并不是 128us 啊?
改变幅值也会改变三角波的周期的,
那么这幅值和周期以及定时器之间三者的关系如何呢?
答案:
- 因为每个时钟节拍才步进 1 格,如果是满幅值输出时,要步进 4095*2 个定时器时钟节拍。
- 我的程序中,设定的幅值是 2047,所以输出一个三角波需要 2047*2 个时钟节拍;
- 一个时钟节拍在上面计算的 TIM6 的更新是大约 28us;所以周期 28*2047*2us;即大约是 115ms;
复制代码
符合推论。
设置的波形控制模式:WAVE1 = 0x02,即产生三角波;
对于三角波的产生器,还有一段函数代码的作用是什么意思呢?
- /*##-3- DAC channel2 Triangle Wave generation configuration ################*/
- if (HAL_DACEx_TriangleWaveGenerate(&DacHandle, DACx_CHANNEL,
- DAC_TRIANGLEAMPLITUDE_2047) != HAL_OK)
- {
- /* Triangle wave generation Error */
- Error_Handler();
- }
- #if 1
- /*##-4- Enable DAC Channel1 ################################################*/
- if (HAL_DAC_Start(&DacHandle, DACx_CHANNEL) != HAL_OK)
- {
- /* Start Error */
- Error_Handler();
- }
- #endif
- #if 0
- /*##-5- Set DAC channel1 DHR12RD register
- ################################################*/
- if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
- {
- /* Setting value Error */
- Error_Handler();
- }
- #endif
复制代码
即其中的代码:
- if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
- {
- /* Setting value Error */
- Error_Handler();
- }
复制代码
是什么作用呢?
产生的波形:
- /*##-5- Set DAC channel1 DHR12RD register
- ################################################*/
- if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0) != HAL_OK)
- {
- /* Setting value Error */
- Error_Handler();
- }
复制代码
在加了函数之后:
- /*##-5- Set DAC channel1 DHR12RD register
- ################################################*/
- if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 10000) != HAL_OK)
- {
- /* Setting value Error */
- Error_Handler();
- }
复制代码
从波形上来看,当参数数值不为 0 时,波形更像三角波,那这个参数影响的是什么呢?
参数的 tmp 的值,位于 0x200004A4 处,初始值为 0,运行到:
- tmp = (uint32_t)hdac->Instance;
复制代码
后 tmp 的值为 0x40007400,该值是解释得通的:DAC 外设的基地址(0x40007400)
执行完语句之后:由于传递的参数是#define DAC_ALIGN_12B_R ((uint32_t)0x00000000)
- DAC_DHR12R2_ALIGNMENT(Alignment);
复制代码
得到的结果是(注意上图中虽然断点停在了 DAC_DHR12R2_ALIGNMENT 处,但是程序是 DAC_CHANNEL_1,所以最终执行的还是下面的语句)
- #define DAC_DHR12R1_ALIGNMENT(__ALIGNMENT__) (((uint32_t)0x00000008) + (__ALIGNMENT__))
复制代码
所以最终产生的效果就是:
- *(__IO uint32_t *) tmp = Data;
复制代码
地址为 0x40007408 的寄存器赋值,即下面寄存器赋值:
但是这寄存器的作用是什么呢?holding data?
Holding data 寄存器,可以简单的理解为:
设置影响 DAC 的直流分量(直流分量还是根据下面的公式计算出来的):
当传递的参数设置为 0 是,DACoutput 即三角波的最低电平为 0:
当传递的参数设置为 2047,DACoutput 即三角波的最低电平为 1.65V
如果传递的参数设置为 1024,DACoutput 即三角波的最低电平为 0.82V;
如果传递的参数设置为 3000,DACoutput 即三角波的最低电平为 2.42V;
5、噪声产生器
主要函数的代码如下:
- if (HAL_DACEx_NoiseWaveGenerate(&DacHandle, DACx_CHANNEL,
- DAC_TRIANGLEAMPLITUDE_2047) != HAL_OK)
- {
- /* Triangle wave generation Error */
- Error_Handler();
- }
- /*##-4- Enable DAC Channel1 ################################################*/
- if (HAL_DAC_Start(&DacHandle, DACx_CHANNEL) != HAL_OK)
- {
- /* Start Error */
- Error_Handler();
- }
复制代码
由于一般的认为噪声是随机性的,所以可以认为只是修改幅值,对于其周期不可控;
|