DAC输出正弦波实验
实验简要
1,功能描述
通过DAC1通道1(PA4)输出正弦波,然后通过DS100示波器查看波形
2,使用定时器7 TRGO事件触发转换
TEN1位置1、TSEL1[2:0]=010
3,关闭输出缓冲
BOFF1位置1
4,使用DMA模式
DMAEN1位置1
5,使用12位右对齐模式
将数字量写入DAC_DHR12R1寄存器
配置步骤
1,初始化DMA
HAL_DMA_Init()
2,将DMA和ADC句柄联系起来
__HAL_LINKDMA()
3,初始化DAC
HAL_DAC_Init()
4,DAC MSP初始化
HAL_DAC_MspInit() 配置NVIC、CLOCK、GPIO等
5,配置DAC相应通道相关参数
HAL_DAC_ConfigChannel()
6,启动DAM传输
HAL_DMA_Start()
7,配置定时器溢出频率并启动
HAL_TIM_Base_Init()、 HAL_TIM_Base_Start()
8,配置定时器触发DAC转换
HAL_TIMEx_MasterConfigSynchronization()
9,停止/启动DAC转换、DMA传输
HAL_DAC_Stop_DMA()、 HAL_DAC_Start_DMA()
正弦波序列
源码
dac.c
#include "./BSP/DAC/dac.h"DMA_HandleTypeDef g_dma_dac_handle;
DAC_HandleTypeDef g_dac_dma_handle;extern uint16_t g_dac_sin_buf[4096]; /* 发送数据缓冲区 *//* DAC DMA输出波形初始化函数 */
void dac_dma_wave_init(void)
{DAC_ChannelConfTypeDef dac_ch_conf;__HAL_RCC_DMA2_CLK_ENABLE();g_dma_dac_handle.Instance = DMA2_Channel3;g_dma_dac_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;g_dma_dac_handle.Init.PeriphInc = DMA_PINC_DISABLE;g_dma_dac_handle.Init.MemInc = DMA_MINC_ENABLE;g_dma_dac_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;g_dma_dac_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;g_dma_dac_handle.Init.Mode = DMA_CIRCULAR;g_dma_dac_handle.Init.Priority = DMA_PRIORITY_MEDIUM;HAL_DMA_Init(&g_dma_dac_handle);__HAL_LINKDMA(&g_dac_dma_handle, DMA_Handle1, g_dma_dac_handle);g_dac_dma_handle.Instance = DAC;HAL_DAC_Init(&g_dac_dma_handle);dac_ch_conf.DAC_Trigger = DAC_TRIGGER_T7_TRGO;dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;HAL_DAC_ConfigChannel(&g_dac_dma_handle, &dac_ch_conf, DAC_CHANNEL_1);HAL_DMA_Start(&g_dma_dac_handle, (uint32_t)g_dac_sin_buf, (uint32_t)&DAC1->DHR12R1, 0);
}/* DAC MSP初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{if (hdac->Instance == DAC){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_DAC_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_4;gpio_init_struct.Mode = GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA, &gpio_init_struct);}
}/*** @brief DAC DMA使能波形输出* @note TIM7的输入时钟频率(f)来自APB1, f = 36M * 2 = 72Mhz.* DAC触发频率 ftrgo = f / ((psc + 1) * (arr + 1))* 波形频率 = ftrgo / ndtr; ** @param ndtr : DMA通道单次传输数据量* @param arr : TIM7的自动重装载值* @param psc : TIM7的分频系数* @retval 无*/
void dac_dma_wave_enable(uint16_t cndtr, uint16_t arr, uint16_t psc)
{TIM_HandleTypeDef tim7_handle = {0};TIM_MasterConfigTypeDef tim_mater_config = {0};__HAL_RCC_TIM7_CLK_ENABLE();tim7_handle.Instance = TIM7;tim7_handle.Init.Prescaler = psc;tim7_handle.Init.Period = arr;HAL_TIM_Base_Init(&tim7_handle);tim_mater_config.MasterOutputTrigger = TIM_TRGO_UPDATE;tim_mater_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(&tim7_handle, &tim_mater_config);HAL_TIM_Base_Start(&tim7_handle);HAL_DAC_Stop_DMA(&g_dac_dma_handle, DAC_CHANNEL_1);HAL_DAC_Start_DMA(&g_dac_dma_handle, DAC_CHANNEL_1, (uint32_t *)g_dac_sin_buf, cndtr, DAC_ALIGN_12B_R);
}
dac.h
#ifndef __DAC_H
#define __DAC_H#include "./SYSTEM/sys/sys.h"void dac_dma_wave_init(void);
void dac_dma_wave_enable(uint16_t cndtr, uint16_t arr, uint16_t psc);#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"
#include "./BSP/DAC/dac.h"
#include "./BSP/KEY/key.h"
#include "math.h"uint16_t g_dac_sin_buf[4096]; /* 发送数据缓冲区 *//*** @brief 产生正弦波序列函数* @note 需保证: maxval > samples/2* @param maxval : 最大值(0 < maxval < 2048)* @param samples: 采样点的个数* @retval 无*/
void dac_creat_sin_buf(uint16_t maxval, uint16_t samples)
{uint8_t i;float outdata = 0; /* 存放计算后的数字量 */float inc = (2 * 3.1415962) / samples; /* 计算相邻两个点的x轴间隔 */if(maxval <= (samples / 2))return ; /* 数据不合法 */for (i = 0; i < samples; i++){/* * 正弦波函数解析式:y = Asin(ωx + φ)+ b* 计算每个点的y值,将峰值放大maxval倍,并将曲线向上偏移maxval到正数区域* 注意:DAC无法输出负电压,所以需要将曲线向上偏移一个峰值的量,让整个曲线都落在正数区域*/outdata = maxval * sin(inc * i) + maxval;if (outdata > 4095)outdata = 4095; /* 上限限定 *///printf("%f\r\n",outdata);g_dac_sin_buf[i] = outdata;}
}int main(void)
{uint8_t t = 0;uint8_t key;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */dac_dma_wave_init();lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "DAC DMA Sine WAVE TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "KEY0:3Khz KEY1:30Khz", RED);dac_creat_sin_buf(2048, 100);dac_dma_wave_enable(100, 10 - 1, 72 - 1); /* 100Khz触发频率, 100个点, 得到1Khz的正弦波 */while (1){t++;key = key_scan(0); /* 按键扫描 */if (key == KEY0_PRES) /* 高采样率 */{dac_creat_sin_buf(2048, 100);dac_dma_wave_enable(100, 10 - 1, 24 - 1); /* 300Khz触发频率, 100个点, 得到最高3KHz的正弦波. */}else if (key == KEY1_PRES) /* 低采样率 */{dac_creat_sin_buf(2048, 10);dac_dma_wave_enable(10, 10 - 1, 24 - 1); /* 300Khz触发频率, 10个点, 可以得到最高30KHz的正弦波. */}if (t == 40) /* 定时时间到了 */{LED0_TOGGLE(); /* LED0闪烁 */t = 0;}delay_ms(5);}
}
PWM DAC实验
定时器输出PWM原理
PWM DAC 分辨率
实验功能
通过定时器1通道1(PA8)输出PWM,经过二阶RC滤波器,输出预设电压,
然后由ADC1通道1 (PA1) 采集,最后显示ADC转换的数字量及换算后的电压值。
源码
pwmdac.c
#include "./BSP/PWMDAC/pwmdac.h"TIM_HandleTypeDef g_timx_pwm_chy_handle;/* PWM DAC初始化 */
void pwmdac_init(uint16_t arr, uint16_t psc)
{TIM_OC_InitTypeDef timx_oc_pwm_chy = {0};g_timx_pwm_chy_handle.Instance = TIM1;g_timx_pwm_chy_handle.Init.Prescaler = psc;g_timx_pwm_chy_handle.Init.Period = arr;g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;g_timx_pwm_chy_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;timx_oc_pwm_chy.Pulse = 0;timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH;HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_1);
}/* TIM MSP初始化函数 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM1){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_TIM1_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_8;gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽复用 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */HAL_GPIO_Init(GPIOA, &gpio_init_struct);}
}/* 设置PWM DAC输出电压 */
void pwmdac_set_voltage(uint16_t vol)
{//输出电压为0-3.3v 用0-3300表示0-3.3float temp = vol;temp /= 1000; //temp 表达的是f(t)的值(也就是电压)temp = temp * 256 / 3.3; //temp 计算得到的结果是n(CCRx的值)__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, TIM_CHANNEL_1, temp);
}
pwmdac.h
#ifndef __PWMDAC_H
#define __PWMDAC_H#include "./SYSTEM/sys/sys.h"void pwmdac_init(uint16_t arr, uint16_t psc);
void pwmdac_set_voltage(uint16_t vol);#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"
#include "./BSP/PWMDAC/pwmdac.h"int main(void)
{uint16_t adcx;float temp;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */adc_init(); /* 初始化ADC */pwmdac_init(256 - 1, 0);pwmdac_set_voltage(2800);lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);lcd_show_string(30, 70, 200, 16, 16, "ADC TEST", RED);lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "ADC1_CH1_VOL:0.000V", BLUE); /* 先在固定位置显示小数点 */while (1){adcx = adc_get_result();temp = (float)adcx * (3.3 / 4096); /* 获取计算后的带小数的实际电压值,比如3.1111 */adcx = temp; /* 赋值整数部分给adcx变量,因为adcx为u16整形 */lcd_show_xnum(134, 110, adcx, 1, 16, 0, BLUE); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */temp -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */temp *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */lcd_show_xnum(150, 110, temp, 3, 16, 0X80, BLUE);/* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */LED0_TOGGLE();delay_ms(100);}
}