STM32实验-输出DAC正弦波

首先我们知道正弦波的解析式为y=Asin(omiga*x+fei)+b,拓展到STM32中则会得到如下的式子:

y=2048*sin((2*pi/samples)*x)+2048.

其中形参的取值范围是(samples/2)<maxval,采样的间隔是2*pi/samples。

接下来编写我们的函数代码dac_sin.c:

#include "./BSP/DAC/dac_sin.h"
#include "math.c"
 
DAC_HandleTypeDef g_dac_handle;
DMA_HandleTypeDef g_dma_handle;
uint16_t g_dac_sin_buf[4096];

void dac_dma_init(void){

    g_dma_handle.Instance = DMA2_Channel3;
    g_dma_handle.Init.Direction = DMA_MEMORY_TO_PERIPH;  //外设到内存
    g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;  //因为选取的是DMA2的数据寄存器,选择不增量
    g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;  //对于存储器需要存储多个数据,所以选择增量模式
    g_dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据位宽,我们选择16位半字(全字可以理解为全角中文字符)
    g_dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;  //存储器数据位宽,我们也选择16位半字
    g_dma_handle.Init.Mode = DMA_CIRCULAR;   //选择循环模式
    g_dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;   //只有1个DMA随便选
    HAL_DMA_Init(&g_dma_handle);
 
    DAC_ChannelConfTypeDef dac_ch_conf;
 
    g_dac_handle.Instance = DAC1; //寄存器基地址
    HAL_DAC_Init(&g_dac_handle);
    _HAL_LINKDMA(&g_dac_handle, DMA_Handle1, &g_dma_handle); //DMA_Handle1是因为选用的是DAC通道1
 
    dac_ch_conf.Trigger = DAC_TRIGGER_T7_TRGO; //触发源选择,选择外部定时器7
    dac_ch_conf.OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
    HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);
 
    HAL_DAC_Start(&g_dac_handle, (uint32_t*)g_dac_sin_buf, (uint32_t)&DAC->DHR12R1, 0); //第三个参数,12位右对齐
}
 
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac){
 
    if(hdac->Instance == DAC1){
        GPIO_InitTypeDef gpio_init_struct;
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_DAC_CLK_ENABLE();
 
        gpio_init_struct.Pin = GPIO_PIN_4;
        gpio_init_strcut.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 g_tim7_handle = {0};
    TIM_MasterConfigTypeDef tim_master_config = {0};
    __HAL_RCC_TIM7_CLK_ENABLE();

    g_tim7_handle.Instance = TIM7;
    g_tim7_Handle.Init.Prescalar = psc;
    g_tim7_handle.init.Period = arr;
    HAL_TIM_Base_Init(&g_tim7_handle);
    
    tim_master_config.MasterOutputTrigger = TIM_TRGO_UPDATE; //选择更新,更新事件作为触发源
    tim_master_config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; //可选同步或无,我们选择无
    HAL_TIMEx_MasterConifgSynchronization(&g_tim7_handle, &);
    //配置定时器触发DAC变换
    HAL_TIM_Base_Start(&g_tim7_handle);

    HAL_DAC_Stop_DMA(&g_dac_handle, &DAC_CHANNEL_1);
    HAL_DAC_Start_DMA(&g_dac_handle, &DAC_CHANNEL_1, (uint32_t*)g_dac_sin_buf, cndtr); //第三个参数为数据来源,第四个参数为数据长度
}

void dac_creat_sin_buf(uint16_t maxval, uint_16 samples){
    uint8_t i;
    float outdata = 0;
    float inc = (2 * 3.1415926) / samples;

    if(maxval <= (samples / 2))return;

    for(i=0; i<samples; i++){
        outdata = maxval * sin(inc * i) + maxval;
        if(outdata > 4095){
            outdata = 4095;
        }
        g_dac_sin_buf[i] = outdata;
    }
}

接下来编写函数头文件dac_sin.h:

#ifndef __DAC_SIN_H
#define __DAC_SIN_H

extern g_dac_sin_buf[4096];
 
void dac_dma_init(void);
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac);
void dac_creat_sin_buf(uint16_t vol);
 
#endif

最后编写主函数main.c:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/DAC/dac_sin.h"
#include "./BSP/ADC/adc.h"
 
int main(void)
{
    uint16_t adcx;
    float temp;
    uint8_t t = 0;
    uint16_t dacval = 0;
    uint8_t key;
 
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
    delay_init(72);                             /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    usmart_dev.init(72);                        /* 初始化USMART */
    led_init();                                 /* 初始化LED */
    lcd_init();                                 /* 初始化LCD */
    key_init();                                 /* 初始化按键 */
    adc3_init();                                /* 初始化ADC3 */
    dac_dma_init(1);                                /* 初始化DAC1_OUT1通道 */
    
    lcd_show_string(30,  50, 200, 16, 16, "STM32F103", RED);
    lcd_show_string(30,  70, 200, 16, 16, "DAC TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+  KEY1:-", 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 == WKUP_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, 100);
            dac_dma_wave_enable(10, 10 - 1, 24 - 1);  //300kHz, 10个点,得到30kHz的正弦波
        }
 
        if(t == 40){
            LED0_TOGGLE();
            t = 0;
        }
 
        delay_ms(10);
    }
}

到这里我们的实验代码就写完了。

  • 4
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现stm32f4dacdma正弦波输出,需要以下步骤: 1. 配置DAC通道和DMA通道,使能时钟 在使用DAC和DMA前,需要先使能相应的时钟。对于DAC来说,需要使能DAC时钟和GPIO时钟。对于DMA来说,需要使能DMA时钟。同时也需要配置好DAC通道和DMA通道。 2. 构建正弦波表并放入内存 正弦波表是用来存储一段正弦波的数据。可以使用公式y=sin(2πx/N)生成正弦波表,其中N是正弦波表大小,x是当前位置,y是对应的采样值。然后将正弦波表数据放入内存中。 3. 配置DMA传输数据 使用DMA将内存中的正弦波表数据传输到DAC数据寄存器中。可以配置DMA的传输模式、方向、缓存等参数。 4. 设置DAC触发模式 设置DAC触发模式为DMA触发,并选择DMA通道。 5. 启动DAC和DMA传输 启动DAC和DMA传输即可输出正弦波信号。 总体代码示例: ``` c #define SAMPLE_RATE 100 #define TABLE_SIZE 128 uint16_t sinetable[TABLE_SIZE]; void build_sinetable() { for(int i = 0; i < TABLE_SIZE; i++) { float tmp = sinf(2 * PI * i / TABLE_SIZE) * 2047 + 2047; sinetable[i] = (uint16_t)tmp; } } void DAC_DMA_Init() { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_1, &DAC_InitStructure); DAC_Cmd(DAC_Channel_1, ENABLE); DMA_DeInit(DMA1_Stream5); DMA_InitStructure.DMA_Channel = DMA_Channel_7; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_BufferSize = TABLE_SIZE; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R1); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)sinetable; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_Init(DMA1_Stream5, &DMA_InitStructure); DAC_DMACmd(DAC_Channel_1, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / SAMPLE_RATE / TABLE_SIZE - 1; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); TIM_Cmd(TIM6, ENABLE); DMA_Cmd(DMA1_Stream5, ENABLE); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值