STM32 HAL库F103系列之DAC实验(二)

DAC输出正弦波实验

实验简要

1,功能描述

        通过DAC1通道1(PA4)输出正弦波,然后通过DS100示波器查看波形

2,使用定时器7 TRGO事件触发转换

        TEN1位置1TSEL1[2:0]=010 

3,关闭输出缓冲

        BOFF1位置1

4,使用DMA模式

        DMAEN1位置1

5,使用12位右对齐模式

        将数字量写入DAC_DHR12R1寄存器

配置步骤

1,初始化DMA 

        HAL_DMA_Init()

2,将DMAADC句柄联系起来

        __HAL_LINKDMA()

3,初始化DAC

        HAL_DAC_Init()

4DAC MSP初始化

        HAL_DAC_MspInit()     配置NVICCLOCKGPIO

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.3
    float 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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/572157.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无人机+遥控器:工业级手持地面站(支持安卓系统)功能技术详解

手持地面站是一种专为无人机设计的便携式设备&#xff0c;用于实现飞行控制、任务规划、数据链路通信等功能。由于支持安卓系统&#xff0c;这种地面站设备在软件生态上具有极大的灵活性&#xff0c;能够兼容并运行众多基于安卓平台的无人机控制应用程序。 在硬件方面&#xff…

vue中的mixin(局部混入、全局混入)

一、mixin是什么 Mixin是面向对象程序设计语言中的类&#xff0c;提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类&#xff1b;Mixin类通常作为功能模块使用&#xff0c;在需要该功能时“混入”&#xff0c;有利于代码复用又避免了多继承的复杂 Vue中的mixin…

如何在 Ubuntu 14.04 上配置 StatsD 以收集 Graphite 的任意统计数据

介绍 Graphite 是一个图形库&#xff0c;允许您以灵活和强大的方式可视化不同类型的数据。它通过其他统计收集应用程序发送给它的数据进行图形化。 在之前的指南中&#xff0c;我们讨论了如何安装和配置 Graphite 本身&#xff0c;以及如何安装和配置 collectd 以编译系统和服…

python实现视频剪辑

即刻关注&#xff0c;获取更多 实现目标 因上传某盘等文件大小限制&#xff0c;无法上传视频&#xff0c;故需要对视频进行压缩 参考资料 ffmpeg文档参考: https://ffmpeg.org/ffmpeg.html 依赖条件 已经安装好python3.11 &#xff0c;原则上更高版本也可以 安装 ffmpeg 依赖 p…

21.3K star!推荐一款可视化自动化测试/爬虫/数据采集神器!功能免费且强大!

大家好&#xff0c;我是狂师&#xff01; 在大数据时代&#xff0c;信息的获取与分析变得尤为重要。对于开发者、数据分析师乃至非技术人员来说&#xff0c;能够高效地采集网络数据并进行分析是一个强有力的工具。今天&#xff0c;我要向大家推荐的是一款功能强大、操作简单且…

线上申报开放时间!2024年阜阳市大数据企业培育认定申报条件、流程和材料

2024年阜阳市大数据企业培育认定申报条件、流程和材料&#xff0c;线上申报开放时间整理如下 一、2024年阜阳市大数据企业培育认定申报要求 &#xff08;一&#xff09;经营范围 申请认定的企业应当从事以下生产经营活动&#xff1a; 1.从事数据收集、存储、使用、加工、传输、…

HotSpot JVM 中的应用程序/动态类数据共享

0.前言 本文的目的是详细讨论 HotSpot JVM 自 JDK 1.5 以来提供的一项功能&#xff0c;该功能可以减少启动时间&#xff0c;但如果在多个 JVM 之间共享相同的类数据共享 (CDS) 存档&#xff0c;则还可以减少内存占用。 1.类数据共享 (CDS) CDS 的想法是使用特定格式将预处理…

多分辨率展开

1.,首先这个图居然给出了基和对偶基相等这个概念。我需要说明一下这个概念的来源。 1.1.,对偶基一开始是来自高等代数的线性空间&#xff0c;然后是泛函分析中的赋范线性空间的共轭空间。至于基的概念&#xff0c;赋范线性空间并没有&#xff0c;可能是因为正交需要内积来定义&…

Python基础知识(二)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》 《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 1.输入和输出函数1.1输出函数1.2输入函数 2.常见运算符2.1赋值运算符2.2比较运算符2.3逻辑运算符2.4and逻辑与2.5or逻辑或2.6not逻…

超纯水抛光树脂MB-115的使用及装填注意事项

用前须知 01.抛光树脂是由高度纯化、转型的H型阳树脂和OH型阴树脂混合而成&#xff0c;如果装填和操作得当&#xff0c;在最初的周期中即可制备出电阻率大于18.0MΩcm和TOC小于10ppb的超纯水&#xff0c;无需化学再生。 02.树脂开封后长时间暴露在空气中会吸收二氧化碳&#…

k8s日常动手实践 ~~ pod访问 pod请求 k8s api ~ 含新版带curl的busybox镜像

前言&#xff1a; 可以使用 Kubernetes API 获取集群信息。使用 Service Account&#xff08;SA&#xff09;进行身份验证&#xff0c;可以以安全的方式访问 Kubernetes API&#xff0c;而无需在 Pod 中使用明文凭据。 以下是一个使用 Service Account 访问 Kubernetes API 获…

HAWE比例多路阀驱动放大器

HAWE比例多路阀驱动放大器是一种在工程机械和工业自动化领域中广泛使用的高精度控制元件&#xff0c;它通过电气信号来控制流体的流动方向、流量及压力等参数。多路比例阀品牌技术的核心在于高性能、低成本、智能化控制、高频响、安全性以及技术创新等方面。这些技术的发展不仅…

Web前端开发之HTML_1

第一个前端程序VS Code安装VS Code 快捷键 1. 第一个前端程序 使用记事本&#xff0c;新建一个文本文档&#xff0c;重命名为Welcome.html&#xff0c;如下图&#xff1a; 用记事本打开文档&#xff0c;内容输入如下&#xff1a; <html> <head> <t…

<计算机网络自顶向下>网络层导论

在计算机网络中&#xff0c;网络层包括数据平面和控制平面&#xff0c;它们分别负责网络数据转发和网络路由控制。以下是它们之间的区别&#xff1a; 数据平面&#xff08;Data Plane&#xff09;&#xff1a; 数据平面负责实际的数据传输和转发&#xff0c;它处理网络中的数据…

IDEA本地将镜像推送到coding制品仓库

创建制品仓库 假设仓库名称为docker 在IDEA 添加Docker 注册表 IDEA必须先安装docker插件 地址 用户名和密码就是coding的登录名和密码服务器 最好本地安装docker桌面版&#xff0c;更容易操作 测试连接成功 推送镜像到coding的docker制品仓库 选中某个镜像 鼠标右键 注册表…

金蝶云星空和旺店通·企业版单据接口对接

金蝶云星空和旺店通企业版单据接口对接 接入系统&#xff1a;旺店通企业版 慧策最先以旺店通ERP切入商家核心管理痛点——订单管理&#xff0c;之后围绕电商经营管理中的核心管理诉求&#xff0c;先后布局流量获取、会员管理、仓库管理等其他重要经营模块。慧策的产品线从旺店通…

画家-qt-surce

void GraphicView::paintEvent(QPaintEvent *pe) { QPainter painter(viewport()); painter.setRenderHint(QPainter::SmoothPixmapTransform);//升级画家 painter.drawImage(rect(),musicImage); } 分析&#xff1a; 这段代码是用于绘制图形视图的部分。 1. void GraphicV…

Hbase中二级索引与Phoenix二级索引实现

1、引入 HBase本身只提供基于行键和全表扫描的查询&#xff0c;而行键索引单一&#xff0c;对于多维度的查询困难。 所以我们引进一个二级索引的概念。二级索引的本质就是建立各列值与行键之间的映射关系 。 图解&#xff1a; 2、常见实现二级索引的方案&#xff1a; HBase…

go版本1.16.5 运行项目出现undefined: math.MaxInt报错

问题描述 go版本 go1.16.5 项目引用了 包go-sqlite3 v1.14.17 github.com/mattn/go-sqlite3 v1.14.17运行报错 # github.com/mattn/go-sqlite3 D:\GoPATH\pkg\mod\github.com\mattn\go-sqlite3v1.14.17\sqlite3_opt_serialize.go:41:26: undefined: math.MaxInt原因分析&…

离散数学之一阶逻辑基本概念与等值演算思维导图+大纲笔记(期末复习,考研,学习笔记,知识点总结)

大纲笔记 基本概念 一阶逻辑命题符号化 个体词 个体常项 个体变项 个体域 个体总域 谓词 谓词常项 谓词变项 零元谓词 特性谓词 引入规则 量词 全称量词 存在量词 一阶逻辑1公式及解释 基本概念 原子公式 谓词公式 自由变元与约束变元 自由变元 换名规则 约束变元 带入规则 闭…
最新文章