stm32通过hal库实现dac输出正弦波
在 STM32 微控制器中,通过 HAL 库可以使用 DAC 输出正弦波信号。实现的步骤包括以下几个部分:
- DAC 初始化:配置 DAC 外设。
- DMA 初始化:将正弦波数据通过 DMA 传输给 DAC,实现连续的输出。
- 定时器初始化:配置定时器触发 DAC,以设定输出信号的频率。
- 正弦波表生成:生成一个正弦波查找表,用于输出模拟信号。
以下是通过 HAL 库实现 DAC 输出正弦波的详细步骤:
1. 正弦波数据生成
首先,我们需要生成一个正弦波查找表。假设使用 12 位分辨率 DAC,DAC 的输出范围是 0 到 4095。
#define SINE_RES 128 // 正弦波数据点数
uint32_t sine_wave[SINE_RES];
void generate_sine_wave(void)
{
for (int i = 0; i < SINE_RES; i++) {
// 生成从 0 到 4095 的正弦波
sine_wave[i] = (uint32_t)((sin(i * 2 * M_PI / SINE_RES) + 1) * 2047.5);
}
}
2. DAC 配置与初始化
使用 DAC1 的通道 1 (PA4),配置 DAC 和 DMA 以便通过 DMA 传输正弦波数据给 DAC。
DAC_HandleTypeDef hdac;
DMA_HandleTypeDef hdma_dac1;
void dac_init(void)
{
// 启用 DAC 和 GPIOA 时钟
__HAL_RCC_DAC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置 DAC GPIO:PA4 = DAC_OUT1
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置 DAC
hdac.Instance = DAC1;
HAL_DAC_Init(&hdac);
// 配置 DAC 通道1
DAC_ChannelConfTypeDef sConfig = {0};
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO; // 使用定时器触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; // 输出缓冲使能
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
// 启用 DAC1 通道1
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
}
3. DMA 配置与初始化
配置 DMA,用于将正弦波表的数据传输到 DAC 外设。
void dma_init(void)
{
__HAL_RCC_DMA1_CLK_ENABLE(); // 启用 DMA1 时钟
// 配置 DMA
hdma_dac1.Instance = DMA1_Channel1;
hdma_dac1.Init.Direction = DMA_MEMORY_TO_PERIPH; // 内存到外设传输
hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不增量
hdma_dac1.Init.MemInc = DMA_MINC_ENABLE; // 内存地址增量
hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // 外设数据对齐为16位
hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // 内存数据对齐为16位
hdma_dac1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_dac1.Init.Priority = DMA_PRIORITY_LOW;
// 初始化 DMA 并链接到 DAC
HAL_DMA_Init(&hdma_dac1);
__HAL_LINKDMA(&hdac, DMA_Handle1, hdma_dac1);
// 启动 DAC 通道1 的 DMA
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sine_wave, SINE_RES, DAC_ALIGN_12B_R);
}
4. 定时器配置
定时器用于设定 DAC 的更新速率,控制 DAC 的输出频率。
TIM_HandleTypeDef htim6;
void tim6_init(void)
{
__HAL_RCC_TIM6_CLK_ENABLE(); // 启用 TIM6 时钟
// 配置 TIM6 以产生触发输出
htim6.Instance = TIM6;
htim6.Init.Prescaler = 80 - 1; // 根据系统时钟,假设系统时钟为 80MHz
htim6.Init.Period = 1000 - 1; // 定时器周期设定,控制 DAC 更新频率
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_Base_Init(&htim6);
// 配置 TIM6 的触发输出 TRGO
HAL_TIM_Base_Start(&htim6);
TIM_MasterConfigTypeDef sMasterConfig = {0};
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // 定时器更新事件触发
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig);
}
5. 主函数
初始化 DAC、DMA、定时器,并输出正弦波信号。
int main(void)
{
HAL_Init(); // 初始化 HAL 库
SystemClock_Config(); // 配置系统时钟
generate_sine_wave(); // 生成正弦波查找表
dac_init(); // 初始化 DAC
dma_init(); // 初始化 DMA
tim6_init(); // 初始化 TIM6,定时触发 DAC
while (1) {
// 主循环
}
}
6. 结果
通过定时器触发 DAC 更新,DAC 会输出通过 DMA 传输的正弦波数据,从而在 DAC 通道上输出连续的正弦波信号。
调整正弦波频率
正弦波的输出频率由定时器的频率控制,通过调整 TIM6
的 Prescaler
和 Period
,你可以改变 DAC 的更新频率,从而控制正弦波的输出频率。
例如,频率计算公式为:
作者:wys99999