dw做网站背景图片设置,汕头seo管理,响应式官方网站,企业官网营销推广DAC 输出三角波实验
本实验我们来学习使用如何让 DAC 输出三角波#xff0c;DAC 初始化部分还是用 DAC 输出实验 的#xff0c;所以做本实验的前提是先学习 DAC 输出实验。
使用 DAC 输出三角波#xff0c;通过 KEY0/KEY1 两个按键#xff0c;控制 DAC1 的通道 1 输出两种…DAC 输出三角波实验
本实验我们来学习使用如何让 DAC 输出三角波DAC 初始化部分还是用 DAC 输出实验 的所以做本实验的前提是先学习 DAC 输出实验。
使用 DAC 输出三角波通过 KEY0/KEY1 两个按键控制 DAC1 的通道 1 输出两种三角 波需要通过示波器接 PA4 进行观察。LED0 闪烁提示程序运行。
我们只需要把示波器的探头接到 DAC1 通道 1PA4引脚就可以在示波器上显示 DAC 输出的波形。 #include ./BSP/DAC/dac.h
#include ./SYSTEM/delay/delay.hDAC_HandleTypeDef g_dac_handle;/* DAC初始化函数 */
void dac_init(void)
{DAC_ChannelConfTypeDef dac_ch_conf {0};g_dac_handle.Instance DAC;HAL_DAC_Init(g_dac_handle);/* 初始化 DAC */dac_ch_conf.DAC_Trigger DAC_TRIGGER_NONE;/* 不使用触发功能,(自动模式) */dac_ch_conf.DAC_OutputBuffer DAC_OUTPUTBUFFER_DISABLE;/* DAC1 输出缓冲关闭 */HAL_DAC_ConfigChannel(g_dac_handle, dac_ch_conf, DAC_CHANNEL_1);HAL_DAC_Start(g_dac_handle, DAC_CHANNEL_1);/* 开启 DAC 通道 1 */
}/* DAC MSP底层初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{if(hdac-Instance DAC){GPIO_InitTypeDef gpio_init_struct {0};__HAL_RCC_DAC_CLK_ENABLE();/* 使能 DAC1 的时钟 */__HAL_RCC_GPIOA_CLK_ENABLE();;/* 使能 DAC OUT1/2 的 IO 口时钟(都在 PA 口,PA4/PA5) */gpio_init_struct.Pin GPIO_PIN_4;gpio_init_struct.Mode GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOA, gpio_init_struct);}
}/*** brief 设置DAC_OUT1输出三角波* note 输出频率 ≈ 1000 / (dt * samples) Khz, 不过在dt较小的时候,比如小于5us时, 由于delay_us* 本身就不准了(调用函数,计算等都需要时间,延时很小的时候,这些时间会影响到延时), 频率会偏小.* * param maxval : 最大值(0 maxval 4096), (maxval 1)必须大于等于samples/2* param dt : 每个采样点的延时时间(单位: us)* param samples: 采样点的个数, samples必须小于等于(maxval 1) * 2 , 且maxval不能等于0* param n : 输出波形个数,0~65535** retval 无*/
void dac_triangular_wave(uint16_t maxval, uint16_t dt, uint16_t samples, uint16_t n)
{uint16_t i, j;float incval; /* 递增量 */float Curval; /* 当前值 */if((maxval 1) samples)return ; /* 数据不合法 */incval (maxval 1) / (samples / 2); /* 计算递增量 */for(j 0; j n; j){Curval 0;HAL_DAC_SetValue(g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval); /* 先输出0 */for(i 0; i (samples / 2); i) /* 输出上升沿 */{Curval incval; /* 新的输出值 */HAL_DAC_SetValue(g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval);delay_us(dt);}for(i 0; i (samples / 2); i) /* 输出下降沿 */{Curval - incval; /* 新的输出值 */HAL_DAC_SetValue(g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, Curval);delay_us(dt);}}
}
该函数用于设置 DAC 通道 1 输出三角波输出频率 ≈ 1000 / (dt * samples) Khz形参含 义在源码已经有详细注释。该函数中我们使用 HAL_DAC_SetValue 函数来设置 DAC 的输出 值这样得到的三角波在示波器上可以看到。如果有跳动现象不平稳是正常的因为调用 函数计算等都需要时间这样就会导致输出的波形是不太稳定的。越高性能的 MCU得到的 波形会越稳定。而且用 HAL 库函数操作效率没有直接操作寄存器高所以可以像寄存器版本实 验一样直接操作 DHR12R1 寄存器得到的波形会相对稳定些。
由于使用 HAL 库的函数CPU 花费的时间会更长因为指令变多了在时间精度要求比 较高的应用就不适合用 HAL 库函数来操作了这一点希望大家明白。所以学 STM32 不是说 只要会 HAL 库就可以了对寄存器也是需要有一定的理解最好是熟悉。这里用 HAL 库操作 只是为了演示怎么使用 HAL 库的相关函数。
#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.hint 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); /* 传口初始化 */led_init(); /* LED初始化 */lcd_init(); /* LCD初始化 */adc_init(); /* ADC初始化 */dac_init(); /* DAC初始化 */key_init(); /* KEY初始化 */lcd_show_string(30, 50, 200, 16, 16, STM32, RED);lcd_show_string(30, 70, 200, 16, 16, DAC Triangular WAVE TEST, RED);lcd_show_string(30, 90, 200, 16, 16, ATOMALIENTEK, RED);lcd_show_string(30, 110, 200, 16, 16, KEY0:Wave1 KEY1:Wave2, RED);lcd_show_string(30, 130, 200, 16, 16, DAC None, BLUE); /* 提示无输出 */while(1){t;key key_scan(0); /* 按键扫描 */if (key KEY0_PRES) /* 高采样率 , 约1Khz波形 */{lcd_show_string(30, 130, 200, 16, 16, DAC Wave1 , BLUE);dac_triangular_wave(4095, 5, 2000, 100); /* 幅值4095, 采样点间隔5us, 2000个采样点, 100个波形 */lcd_show_string(30, 130, 200, 16, 16, DAC None , BLUE);}else if (key KEY1_PRES) /* 低采样率 , 约1Khz波形 */{lcd_show_string(30, 130, 200, 16, 16, DAC Wave2 , BLUE);dac_triangular_wave(4095, 500, 20, 100); /* 幅值4095, 采样点间隔500us, 20个采样点, 100个波形 */lcd_show_string(30, 130, 200, 16, 16, DAC None , BLUE);}if (t 10) /* 定时时间到了 */{LED0_TOGGLE(); /* LED0闪烁 */t 0;}delay_ms(10);}
}
该部分代码功能是按下 KEY0 后DAC 输出三角波 1按下 KEY1 后DAC 输出三角波 2将 dac_triangular_wave 的形参代入公式输出频率 ≈ 1000 / (dt * samples) KHz得到三角 波 1 和三角波 2 的频率都是 0.1KHz。
下载代码后可以看到 LED0 不停的闪烁提示程序已经在运行了。LCD 显示如图 33.3.4.1 所示
没有按下任何按键之前LCD 屏显示 DAC None当按下 KEY0 后DAC 输出三角波 1 LCD 屏显示 DAC Wave1 三角波 1 输出完成后 LCD 屏继续显示 DAC None当按下 KEY1后DAC 输出三角波 2LCD 屏显示 DAC Wave2三角波 2 输出完成后 LCD 屏继续显示 DAC None。
其中三角波 1 和三角波 2 在示波器的显示情况如下图所示
由上面两副测试图可以知道三角波 1 的频率是 64.5Hz三角波 2 的频率是 99.5Hz。三角 波 2 基本接近我们算出来的结果 0.1KHz三角波 1 有较大误差在介绍 dac_triangular_wave 函 数时也说了原因加上三角波 1 的采样率比较高所以误差就会比较大。
DAC 输出正弦波实验
本实验我们来学习使用如何让 DAC 输出正弦波。实验将用定时器 7 来触发 DAC 进行转换 输出正弦波以 DMA 传输数据的方式。
使用 DAC 输出正弦波通过 KEY0/KEY1 两个按键控制 DAC1 的通道 1 输出两种正弦 波需要通过示波器接 PA4 进行观察。LED0 闪烁提示程序运行。
我们只需要把示波器的探头接到 DAC1 通道 1PA4引脚就可以在示波器上显示 DAC 输出的波形。PA4 在 P7 已经引出硬件连接如图 33.4.2.1 所示 HAL库函数 代码
#include ./BSP/DAC/dac.hDMA_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 {0};__HAL_RCC_DMA2_CLK_ENABLE();/* DMA2 时钟使能 */g_dma_dac_handle.Instance DMA2_Channel3;/* 设置 DMA 通道 */g_dma_dac_handle.Init.Direction DMA_MEMORY_TO_PERIPH;/* 从存储器到外设模式 */g_dma_dac_handle.Init.MemDataAlignment DMA_MDATAALIGN_HALFWORD;/* 存储器数据长度:16 位 */g_dma_dac_handle.Init.MemInc DMA_MINC_ENABLE;/* 存储器增量模式 */g_dma_dac_handle.Init.Mode DMA_CIRCULAR;/* 循环模式 */g_dma_dac_handle.Init.PeriphDataAlignment DMA_PDATAALIGN_HALFWORD;/* 外设数据长度:16 位 */g_dma_dac_handle.Init.PeriphInc DMA_PINC_DISABLE;/* 外设非增量模式 */g_dma_dac_handle.Init.Priority DMA_PRIORITY_HIGH;/* 优先级 */HAL_DMA_Init(g_dma_dac_handle);/* 初始化 DMA */__HAL_LINKDMA(g_dac_dma_handle, DMA_Handle1, g_dma_dac_handle);/* DMA 句柄与 DAC 句柄关联 */g_dac_dma_handle.Instance DAC;HAL_DAC_Init(g_dac_dma_handle);dac_ch_conf.DAC_Trigger DAC_TRIGGER_T7_TRGO;/* 使用 TIM7 TRGO 事件触发 */dac_ch_conf.DAC_OutputBuffer DAC_OUTPUTBUFFER_DISABLE;/* DAC1 输出缓冲关闭 */HAL_DAC_ConfigChannel(g_dac_dma_handle, dac_ch_conf, DAC_CHANNEL_1);/* DAC 通道 1 配置 *//* 配置 DMA 传输参数 */HAL_DMA_Start(g_dma_dac_handle, (uint32_t)g_dac_sin_buf, (uint32_t)DAC-DHR12R1, 0);
}/* DAC MSP底层初始化函数 */
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{if(hdac-Instance DAC){GPIO_InitTypeDef gpio_init_struct {0};__HAL_RCC_DAC_CLK_ENABLE();/* 使能 DAC1 的时钟 */__HAL_RCC_GPIOA_CLK_ENABLE();/* DAC 通道引脚端口时钟使能 *//* STM32 单片机, 总是 PA4DAC1_OUT1, PA5DAC1_OUT2 */gpio_init_struct.Pin GPIO_PIN_4;gpio_init_struct.Mode GPIO_MODE_ANALOG;/* 模拟 */HAL_GPIO_Init(GPIOA, gpio_init_struct);}
}void dac_dma_wave_enable(uint16_t cndtr, uint16_t arr, uint16_t psc)
{TIM_HandleTypeDef tim7_handle {0};TIM_MasterConfigTypeDef tim7_master_config {0};__HAL_RCC_TIM7_CLK_ENABLE();/* TIM7 时钟使能 */tim7_handle.Instance TIM7;/* 选择定时器 7 */tim7_handle.Init.Prescaler psc;/* 预分频 */tim7_handle.Init.Period arr;/* 自动装载值 */tim7_handle.Init.CounterMode TIM_COUNTERMODE_UP; /* 递增计数器 */HAL_TIM_Base_Init(tim7_handle);tim7_master_config.MasterOutputTrigger TIM_TRGO_UPDATE;/* 定时器更新事件用于触发 */tim7_master_config.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE;HAL_TIMEx_MasterConfigSynchronization(tim7_handle, tim7_master_config);/* 配置定时器 7 的更新事件触发 DAC 转换 */HAL_TIM_Base_Start(tim7_handle);/* 启动定时器 7 */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 用 DMA 的方式输出正弦波。本函数用到的 API 函数起前面都介 绍过请结合前面介绍过的相关内容来理解源码。这里值得注意的是我们是采用定时器 7 触发 DAC 进行转换输出的。
该函数用于使能波形输出利用定时器 7 的更新事件来触发 DAC 转换输出。使能定时器 7 的时钟后调用 HAL_TIMEx_MasterConfigSynchronization 函数配置 TIM7 选择更新事件作为触 发输出 TRGO然后调用 HAL_DAC_Stop_DMA 函数停止 DAC 转换以及 DMA 传输最后 再调用 HAL_DAC_Start_DMA 函数重新配置并启动 DAC 和 DMA。
#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.huint16_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 inc (2 * 3.1415962) / samples; /* 计算增量一个周期DAC_SIN_BUF个点*/float outdata 0;for (i 0; i samples; i){outdata maxval * (1 sin(inc * i)); /* 计算以dots个点为周期的每个点的值放大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); /* 传口初始化 */led_init(); /* LED初始化 */lcd_init(); /* LCD初始化 */key_init(); /* KEY初始化 *//* 初始化DAC通道1 DMA波形输出 */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, ATOMALIENTEK, 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) /* 高采样率 , 约1Khz波形 */{dac_creat_sin_buf(2048, 100);dac_dma_wave_enable(100, 10 - 1, 24 - 1); /* 300Khz触发频率, 100个点, 得到最高3KHz的正弦波. */}else if (key KEY1_PRES) /* 低采样率 , 约1Khz波形 */{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);}
}
dac_dma_wave_init 函数初始化 DAC 通道 1并指定 DMA 搬运的数据的开始地址和目标 地址。dac_creat_sin_buf 函数用于产生正弦波序列并保存在 g_dac_sin_buf 数组中供给 DAC 转换。在进入wilhe(1)循环之前dac_dma_wave_enable函数默认配置DAC的采样点个数时100 并配置定时器 7 的溢出频率为 100KHz。这样就可以输出 1KHz 的正弦波。下面给大家解释一下 为什么是输出 1KHz 的正弦波
定时器 7 的溢出频率为 100KHz不记得怎么计算的朋友请回顾基本定时器的相关内容 这里直接把公式列出Tout ((arr1)*(psc1))/Tclk
看到 dac_dma_wave_enable(100, 10 - 1, 72 - 1);这个语句第二个形参是自动重装载值第 三个形参是分频系数那么代入公式可得Tout ((arr1)*(psc1))/Tclk ((91)*(711))/ 72000000 0.00001s得到定时器的更新事件周期是 0.00001 秒即更新事件频率为 100KHz也就得到 DAC 输 出触发频率为 100KHz。再结合总一个正弦波共有 100 个采样点就可以得到正弦波的频率为 100KHz/100 1KHz。
知道了正弦波的频率怎么来的下面代码中按下按键 KEY0得到 3KHz 的正弦波按下 按键 KEY1得到 30KHz 的正弦波计算方法都一样的。
实验现象
没有按下任何按键之前默认输出 1KHz100 个采样点的正弦波如下图所示
当按下 KEY0 后DAC 输出 3KHz100 个采样点的正弦波如下图所示 当按下 KEY1 后DAC 输出 30KHz10 个采样点的正弦波如下图所示