单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil   V5.31

HSE 为8MHZ
HSI为16MHZ

一、DAC输出实验

主函数

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(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    key_init();                             /* 初始化按键 */
    lcd_init();                             /* 初始化LCD */
    adc_init();                             /* 初始化ADC */
    dac_init(1);                            /* 初始化DAC1_OUT1通道 */
    
    lcd_show_string(30,  50, 200, 16, 16, "STM32", 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, "KEY1:+  KEY0:-", RED);
    
    lcd_show_string(30, 130, 200, 16, 16, "DAC VAL:", BLUE);
    lcd_show_string(30, 150, 200, 16, 16, "DAC VOL:0.000V", BLUE);
    lcd_show_string(30, 170, 200, 16, 16, "ADC VOL:0.000V", BLUE);
 
    while (1)
    {
        t++;
        key = key_scan(0);          /* 按键扫描 */

        if (key == KEY1_PRES)
        {
            if (dacval < 4000)
            {
                dacval += 200;
            }
            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval); /* 输出增大200 */
        }
        else if (key == KEY0_PRES)
        {
            if (dacval > 200)
            {
                dacval -= 200;
            }
            else 
            {
                dacval = 0;
            }
            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval); /* 输出减少200 */
        }

        if (t == 10 || key == KEY0_PRES || key == KEY1_PRES)        /* KEY0/KEY1按下了,或者定时时间到了 */
        {
            adcx = HAL_DAC_GetValue(&g_dac_handle, DAC_CHANNEL_1);  /* 读取前面设置DAC1_OUT1的值 */
            lcd_show_xnum(94, 130, adcx, 4, 16, 0, BLUE);           /* 显示DAC寄存器值 */
            
            temp = (float)adcx * (3.3 / 4096);                      /* 得到DAC电压值 */
            adcx = temp;
            lcd_show_xnum(94, 150, temp, 1, 16, 0, BLUE);           /* 显示电压值整数部分 */
            
            temp -= adcx;
            temp *= 1000;
            lcd_show_xnum(110, 150, temp, 3, 16, 0X80, BLUE);       /* 显示电压值的小数部分 */
            
            adcx = adc_get_result_average(ADC_ADCX_CHY, 20);        /* 得到ADC1通道3的转换结果 */
            temp = (float)adcx * (3.3 / 4096);                      /* 得到ADC电压值 */
            adcx = temp;
            lcd_show_xnum(94, 170, temp, 1, 16, 0, BLUE);           /* 显示电压值整数部分 */
            
            temp -= adcx;
            temp *= 1000;
            lcd_show_xnum(110, 170, temp, 3, 16, 0X80, BLUE);       /* 显示电压值的小数部分 */
            
            LED0_TOGGLE();                                          /* LED0闪烁 */
            t = 0;
        }

        delay_ms(10);
    }
}

配置

void dac_init(uint8_t outx)
{
    GPIO_InitTypeDef gpio_init_struct;
    DAC_ChannelConfTypeDef dac_ch_conf;
    
    __HAL_RCC_DAC_CLK_ENABLE();                                     /* 使能DAC1的时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();                                   /* 使能DAC OUT1/2的IO口时钟(都在PA口,PA4/PA5) */
    
    gpio_init_struct.Pin = (outx==1)? GPIO_PIN_4 : GPIO_PIN_5;      /* STM32单片机, 总是PA4=DAC1_OUT1, PA5=DAC1_OUT2 */
    gpio_init_struct.Mode = GPIO_MODE_ANALOG; 
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);

    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输出缓冲关闭 */
    
    switch(outx)
    {
        case 1:
            HAL_DAC_ConfigChannel(&g_dac_handle,&dac_ch_conf,DAC_CHANNEL_1);    /* DAC通道1配置 */
            HAL_DAC_Start(&g_dac_handle,DAC_CHANNEL_1);                         /* 开启DAC通道1 */
            break;
        case 2:
            HAL_DAC_ConfigChannel(&g_dac_handle,&dac_ch_conf,DAC_CHANNEL_2);    /* DAC通道2配置 */
            HAL_DAC_Start(&g_dac_handle,DAC_CHANNEL_2);                         /* 开启DAC通道2 */
            break;
        default:break;
    }

}
void dac_set_voltage(uint8_t outx, uint16_t vol)
{
    double temp = vol;
    temp /= 1000;
    temp = temp * 4096 / 3.3;

    if (temp >= 4096)temp = 4095;                                               /* 如果值大于等于4096, 则取4095 */

    if (outx == 1)      /* 通道1 */
    {
        HAL_DAC_SetValue(&g_dac_handle,DAC_CHANNEL_1,DAC_ALIGN_12B_R,temp);     /* 12位右对齐数据格式设置DAC值 */
    }
    else                /* 通道2 */
    {
        HAL_DAC_SetValue(&g_dac_handle,DAC_CHANNEL_2,DAC_ALIGN_12B_R,temp);     /* 12位右对齐数据格式设置DAC值 */
    }
}

测试结果:

二、DAC输出三角波实验

主函数

int main(void)
{     
    uint8_t t = 0;
    uint8_t key;
    
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    key_init();                             /* 初始化按键 */
    lcd_init();                             /* 初始化LCD */
    dac_init(1);                            /* 初始化DAC1_OUT1通道 */
    
    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, "ATOM@ALIENTEK", 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)                                               /* 高采样率 , 约88.5Hz波形 */
        {
            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)                                          /* 低采样率 , 约100Hz波形 */
        {
            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);
    }
}
void dac_init(uint8_t outx)
{
    GPIO_InitTypeDef gpio_init_struct;
    DAC_ChannelConfTypeDef dac_ch_conf;
    
    __HAL_RCC_DAC_CLK_ENABLE();                                 /* 使能DAC的时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();                               /* 使能DAC OUT1/2的IO口时钟(都在PA口,PA4/PA5) */
    
    gpio_init_struct.Pin = (outx==1)? GPIO_PIN_4 : GPIO_PIN_5;  /* STM32单片机, 总是PA4=DAC1_OUT1, PA5=DAC1_OUT2 */
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);

    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输出缓冲关闭 */
    
    switch(outx)
    {
        case 1:
            HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);  /* DAC通道1配置 */
            HAL_DAC_Start(&g_dac_handle,DAC_CHANNEL_1);                         /* 开启DAC通道1 */
            break;
        case 2:
            HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_2);  /* DAC通道2配置 */
            HAL_DAC_Start(&g_dac_handle,DAC_CHANNEL_2);                         /* 开启DAC通道2 */
            break;
        default:break;
    }
}
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(samples > ((maxval + 1) * 2))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);
        }
    }
}

实验结果:

用示波器观察PA4波形。

三、DAC输出正弦波

主函数

int main(void)
{         
    HAL_Init();                             /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);     /* 设置时钟,168Mhz */
    delay_init(168);                        /* 延时初始化 */
    usart_init(115200);                     /* 串口初始化为115200 */
    led_init();                             /* 初始化LED */
    lcd_init();                             /* 初始化LCD */
    gtim_timx_int_init(10-1,84-1);          /* 初始化定时器,定时触发DAC */
    dac_init(1,100);                        /* 初始化DAC1_OUT1通道,100个点,正弦波频率1k Hz */
    
    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);
    
    while (1)
    {      
        LED0_TOGGLE();                      /* LED0翻转 */
        delay_ms(1000);
    }
}

配置

void dac_init(uint8_t outx,uint16_t cndtr)
{
    GPIO_InitTypeDef gpio_init_struct;
    DAC_ChannelConfTypeDef DACCH1_Config;
    
    __HAL_RCC_DAC_CLK_ENABLE();                                             /* 使能DAC的时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();                                           /* 使能DAC OUT1/2的IO口时钟(都在PA口,PA4/PA5) */
    __HAL_RCC_DMA1_CLK_ENABLE();
    
    gpio_init_struct.Pin = (outx==1)? GPIO_PIN_4 : GPIO_PIN_5;              /* STM32单片机, 总是PA4=DAC1_OUT1, PA5=DAC1_OUT2 */
    gpio_init_struct.Mode = GPIO_MODE_ANALOG; 
    gpio_init_struct.Pull = GPIO_PULLUP;      
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);

    g_dma_dac_handle.Instance = DMA1_Stream5;                               /* DMA1数据流5 */
    g_dma_dac_handle.Init.Channel = DMA_CHANNEL_7;                          /* 通道7 */
    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;    /* 外设数据长度:16位 */
    g_dma_dac_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;       /* 存储器数据长度:16位 */
    g_dma_dac_handle.Init.Mode = DMA_CIRCULAR;                              /* 循环模式 */
    g_dma_dac_handle.Init.Priority = DMA_PRIORITY_LOW;                      /* 中等优先级 */
    g_dma_dac_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;                  /* 不开启FIFO */
    HAL_DMA_Init(&g_dma_dac_handle);                                        /* 初始化DMA */

    __HAL_LINKDMA(&g_dac_dma_handle,DMA_Handle1,g_dma_dac_handle);          /* 把DAC和DMA关联 */
    
    g_dac_dma_handle.Instance = DAC;
    HAL_DAC_Init(&g_dac_dma_handle);                                        /* 初始化DAC */

    DACCH1_Config.DAC_Trigger = DAC_TRIGGER_T2_TRGO;                        /* 使用定时器2的TRGO事件触发DAC转换 */
    DACCH1_Config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;              /* DAC1输出缓冲关闭 */
    
    dac_creat_sin_buf(2048,cndtr);                                          /* 产生正弦波序列,即画点 */
    
    switch(outx)
    {
        case 1:
            HAL_DAC_ConfigChannel(&g_dac_dma_handle,&DACCH1_Config,DAC_CHANNEL_1);                                    /* DAC通道1配置 */
            HAL_DAC_Start_DMA(&g_dac_dma_handle,DAC_CHANNEL_1,(uint32_t *)g_dac_sin_buf,cndtr,DAC_ALIGN_12B_R);       /* 开启DAC通道1 */
            break;
        case 2:
            HAL_DAC_ConfigChannel(&g_dac_dma_handle,&DACCH1_Config,DAC_CHANNEL_2);                                    /* DAC通道2配置 */
            HAL_DAC_Start_DMA(&g_dac_dma_handle,DAC_CHANNEL_2,(uint32_t *)g_dac_sin_buf,cndtr,DAC_ALIGN_12B_R);       /* 开启DAC通道2 */
            break;
        default:break;
    }   
}
void dac_creat_sin_buf(uint16_t maxval, uint16_t samples)
{
    uint8_t i;
    float outdata = 0;
    
    if(maxval <= (samples / 2))return ;         /* 数据不合法 */
    
    /* 
     * 正弦波最小正周期为2π,约等于2 * 3.1415926
     * 曲线上相邻的两个点在x轴上的间隔 = 2 * 3.1415926 / 采样点数量
     */
    float inc = (2 * 3.1415926) / samples;      /* 计算相邻两个点的x轴间隔 */

    for (i = 0; i < samples; i++)               /* 连续打samples个点 */
    {
        /* 
         * 正弦波函数解析式:y = Asin(wx + φ)+ b
         * 计算每个点的y值,将峰值放大maxval倍,并将曲线向上偏移maxval到正数区域
         * 注意:DAC无法输出负电压,所以需要将曲线向上偏移一个峰值的量,让整个曲线都落在正数区域
         */
        outdata = maxval * sin(inc * i) + maxval;
        
        if (outdata > 4095)
        {
            outdata = 4095;                     /* 上限限定 */
        }
        g_dac_sin_buf[i] = outdata;
    }
}
#define GTIM_TIMX_INT                       TIM2
#define GTIM_TIMX_INT_IRQn                  TIM2_IRQn
#define GTIM_TIMX_INT_IRQHandler            TIM2_IRQHandler
#define GTIM_TIMX_INT_CLK_ENABLE()          do{ __HAL_RCC_TIM2_CLK_ENABLE(); }while(0)      /* TIM2 时钟使能 */


void gtim_timx_int_init(uint16_t arr, uint16_t psc)
{
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    
    GTIM_TIMX_INT_CLK_ENABLE();                                 /* 使能TIMx时钟 */

    g_timx_handle.Instance = GTIM_TIMX_INT;                     /* 通用定时器x */
    g_timx_handle.Init.Prescaler = psc;                         /* 预分频系数 */
    g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP;        /* 递增计数模式 */
    g_timx_handle.Init.Period = arr;                            /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handle);

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;        /* 定时器更新事件用于触发 */
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&g_timx_handle, &sMasterConfig);

    HAL_TIM_Base_Start(&g_timx_handle);                         /* 使能定时器x */
}

测试结果:

示波器观察PA4波形。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐