GD - GD32350R_EVAL - PWM实验和验证2 - EmbeddedBuilder - 无源蜂鸣器

news2024/9/20 18:40:30

文章目录

    • GD - GD32350R_EVAL - PWM实验和验证2 - EmbeddedBuilder - 无源蜂鸣器
    • 概述
    • 笔记
    • 先前失败的实验电路图
    • 本次成功的图 - 无源蜂鸣器电路模块
    • 接入实验模块
    • 实验软件工程
    • 主循环实现
    • PWM频率改变蜂鸣器声音大小
    • 实验结果和官方给的蜂鸣器频率响应曲线基本一样
    • 看看实际波形
    • END

GD - GD32350R_EVAL - PWM实验和验证2 - EmbeddedBuilder - 无源蜂鸣器

概述

前面做了一个实验(GD - GD32350R_EVAL - PWM实验和验证1), 确认了如何生成指定频率的PWM波。

今天做了一个实验,用PWM驱动无源蜂鸣器发出声音。

笔记

有源蜂鸣器没找到工业级别的。

无源蜂鸣器有压电式和电磁式。
为了省电,拟采用压电式无源蜂鸣器。

根据自己用的无源蜂鸣器型号,确定发声最高时对应的PWM频率。
现在采用的压电蜂鸣器频率响应曲线对应的最高声音频率为4KHZ.

先前失败的实验电路图

在这里插入图片描述

为了省电,想着用PMOS管来控制蜂鸣器电路通断。做了板子实验完,发现不行(蜂鸣器基本不发声,不是频率不对,而是真的就基本没声音),用示波器看波形,不是方波(而是上升沿为90度,中间会有一个电压保持的平台,然后是一段线性下降的下降沿),且压差只有2.2V。
应该是PMOS没进入饱和状态导致的。
查了资料,为了使MOS进入饱和状态,UGS压差要10V以上。
UGS > UGSth 只是能将MOS导通,对于信号传递来说没问题。
但是对于电压波形来说,就不合适了。
怪不得查的资料中,没有人用MOS管来控制蜂鸣。

没实验的情况:

  1. R9我用的是100R, 按照这次实验来说,我应该用0R. 不用限流
  2. 官方推荐在蜂鸣器2边并联1K的电阻,在失败图上我没并联。

实验的没那么细致,需要时间成本。等以后有时间,再继续实验,看看失败图是否可以改进为有效控制蜂鸣器。

本次成功的图 - 无源蜂鸣器电路模块

在这里插入图片描述
在这里插入图片描述

为了微调,在电路中串入了电阻(R_ADJ_1/R_ADJ_2), 实验中没有调整,R1/R6都是0R. R2/R3/R4/R7/R8/R9都是NC
用跳线连接了R_ADJ1/R_ADJ_1A, R_ADJ2/R_ADJ2A, 联通了电路。
剩下的元件都是按照电路图来。
接口端子为VCC_3V3/GND/GPIO_BEEP.

接入实验模块

实验平台为 GD32350R_EVAL
找合适的端子接入VCC_3V3/GND.
PA8接入GPIO_BEEP
在这里插入图片描述

实验软件工程

直接在 EmbeddedBuilder_v1.4.1.23782\examples\GD32F3x0\examples\CMP\CMP_pwm_signal_control 官方工程上改的。
拿官方工程跑一遍(图形化产生代码,编译,run),蜂鸣器可以发声。这时PWM是100HZ, 蜂鸣器声音不是很大。

主循环实现

将主循环代码,改一下,让每次run都能听到连续的滴滴声,听清楚了,就不发声了。

int main(void)
{
    /* user code [local 0] begin */
	int beep_cnt = 0;
    /* user code [local 0] end */

    msd_system_init();
    msd_clock_init();
    /* user code [local 1] begin */

    /* user code [local 1] end */
    msd_gpio_init();
    msd_cmp0_init();
    msd_timer0_init();

    /* user code [local 2] begin */
    // hal_cmp_start(&cmp0_info);
    // hal_timer_output_compare_start(&timer0_info, TIMER_CH_0);
    /* user code [local 2] end */

    while(1){
    /* user code [local 3] begin */
    	if (beep_cnt < 200)
    	{
    		beep_cnt++;

        	hal_timer_output_compare_start(&timer0_info, TIMER_CH_0);
        	hal_sys_basetick_delay_ms(30);

        	hal_timer_output_compare_stop(&timer0_info, TIMER_CH_0);
        	hal_sys_basetick_delay_ms(70);
    	}

    /* user code [local 3] end */
    }
}

看了gd32f3x0_hal_timer.h, 没看到有方便改变占空比的API.
就用 hal_timer_output_compare_start 开始PWM, 用 hal_timer_output_compare_stop 停止PWM
先这么着.

PWM频率改变蜂鸣器声音大小

做实验时,需要改的初始化代码为PWM载入计数和方波计数。这时,直接改就行,不再需要图形化配置。
反正频率范围也不宽,就手工改,改一次,跑一下,听一下声音,然后和官方的蜂鸣器频率响应图对一下。

void msd_timer0_init(void)
{
    /* user code [timer0_init local 0] begin */
    /* user code [timer0_init local 0] end */
    hal_gpio_init_struct gpio_init_parameter;
    hal_timer_init_struct timer0_init_parameter;
    hal_timer_output_compare_struct timer0_output_compare_parameter;
    hal_timer_clear_source_struct timer0_clear_source_parameter;
    hal_timer_break_struct timer0_break_parameter;

    hal_rcu_periph_clk_enable(RCU_TIMER0);
    hal_gpio_struct_init(&gpio_init_parameter);

    gpio_init_parameter.mode = GPIO_MODE_AF_PP;
    gpio_init_parameter.pull = GPIO_PULL_NONE;
    gpio_init_parameter.ospeed = GPIO_OSPEED_50MHZ;
    gpio_init_parameter.af = GPIO_AF_2;
    hal_gpio_init(GPIOA, GPIO_PIN_8, &gpio_init_parameter);

    hal_timer_struct_init(HAL_TIMER_INIT_STRUCT, &timer0_init_parameter);
    hal_timer_struct_init(HAL_TIMER_DEV_STRUCT, &timer0_info);
    hal_timer_struct_init(HAL_TIMER_OUTPUT_COMPARE_STRUCT, &timer0_output_compare_parameter);
    hal_timer_struct_init(HAL_TIMER_CLEAR_SOURCE_STRUCT, &timer0_clear_source_parameter);
    hal_timer_struct_init(HAL_TIMER_BREAK_STRUCT, &timer0_break_parameter);

    timer0_init_parameter.prescaler = 107;
    timer0_init_parameter.alignedmode = TIMER_COUNTER_EDGE;
    timer0_init_parameter.counter_direction = TIMER_COUNTER_UP;

    // PWM = 100HZ,  1 / PWM = 0.01S = 0.01 * 1000000us = 10000us,
    // 				auto_load = 10000 - 1
    // 				pulse =auto_load / 2 - 1 = 5000 - 1

    // PWM = 200HZ,  1 / PWM = 0.005S = 0.005 * 1000000us = 5000us,
    // 				auto_load = 5000 - 1 = 4999
    // 				pulse =auto_load / 2 - 1 = 5000/2 - 1 = 2500 - 1 = 2499

    // PWM = 300HZ,  1 / PWM = 0.003S = 0.003 * 1000000us = 3000us,
    // 				auto_load = 3000 - 1 = 2999
    // 				pulse =auto_load / 2 - 1 = 3000/2 - 1 = 1500 - 1 = 1499

    // PWM = 400HZ,  1 / PWM = 0.0025S = 0.0025 * 1000000us = 2500us,
    // 				auto_load = 2500 - 1 = 2499
    // 				pulse =auto_load / 2 - 1 = 2500/2 - 1 = 1250 - 1 = 1249

    // PWM = 500HZ,  1 / PWM = 0.002S = 0.002 * 1000000us = 2000us,
    // 				auto_load = 2000 - 1 = 1999
    // 				pulse =auto_load / 2 - 1 = 2000/2 - 1 = 1000 - 1 = 999

    // PWM = 600HZ,  1 / PWM = 0.0016S = 0.0016 * 1000000us = 1600us,
    // 				auto_load = 1600 - 1 = 1599
    // 				pulse =auto_load / 2 - 1 = 1600/2 - 1 = 800 - 1 = 799

    // PWM = 700HZ,  1 / PWM = 0.0014S = 0.0014 * 1000000us = 1400us,
    // 				auto_load = 1400 - 1 = 1399
    // 				pulse =auto_load / 2 - 1 = 1400/2 - 1 = 700 - 1 = 699

    // PWM = 800HZ,  1 / PWM = 0.00125S = 0.00125 * 1000000us = 1250us,
    // 				auto_load = 1250 - 1 = 1249
    // 				pulse =auto_load / 2 - 1 = 1250/2 - 1 = 625 - 1 = 624

    // PWM = 900HZ,  1 / PWM = 0.001111S = 0.001111 * 1000000us = 1111us,
    // 				auto_load = 1111 - 1 = 1110
    // 				pulse =auto_load / 2 - 1 = 1111/2 - 1 = 556 - 1 = 555

    // PWM = 1000HZ,  1 / PWM = 0.001000S = 0.001000 * 1000000us = 1000us,
    // 				auto_load = 1000 - 1 = 999
    // 				pulse =auto_load / 2 - 1 = 1000/2 - 1 = 500 - 1 = 499

    // 8.3333333333333333333333333333333e-4
    // PWM = 1200HZ,  1 / PWM = 0.000833S = 0.000833 * 1000000us = 833us,
    // 				auto_load = 833 - 1 = 832
    // 				pulse =auto_load / 2 - 1 = 833/2 - 1 = 417 - 1 = 416

    // 7.1428571428571428571428571428571e-4
    // PWM = 1400HZ,  1 / PWM = 0.000714S = 0.000714 * 1000000us = 714us,
    // 				auto_load = 714 - 1 = 713
    // 				pulse =auto_load / 2 - 1 = 714/2 - 1 = 357 - 1 = 356

    // 0.000625
    // PWM = 1600HZ,  1 / PWM = 0.000625S = 0.000625 * 1000000us = 625us,
    // 				auto_load = 625 - 1 = 624
    // 				pulse =auto_load / 2 - 1 = 625/2 - 1 = 313 - 1 = 312

    // 0.000555
    // PWM = 1800HZ,  1 / PWM = 0.000555S = 0.000555 * 1000000us = 555us,
    // 				auto_load = 555 - 1 = 554
    // 				pulse =auto_load / 2 - 1 = 555/2 - 1 = 278 - 1 = 277

    // 0.000500
    // PWM = 2000HZ,  1 / PWM = 0.000500S = 0.000500 * 1000000us = 500us,
    // 				auto_load = 500 - 1 = 499
    // 				pulse =auto_load / 2 - 1 = 500/2 - 1 = 250 - 1 = 249

    // 0.000416
    // PWM = 2400HZ,  1 / PWM = 0.000416S = 0.000416 * 1000000us = 416us,
    // 				auto_load = 416 - 1 = 415
    // 				pulse =auto_load / 2 - 1 = 416/2 - 1 = 208 - 1 = 207

    // 0.000357
    // PWM = 2800HZ,  1 / PWM = 0.000357S = 0.000357 * 1000000us = 357us,
    // 				auto_load = 357 - 1 = 356
    // 				pulse =auto_load / 2 - 1 = 357/2 - 1 = 179 - 1 = 178

    // 0.000313
    // PWM = 3200HZ,  1 / PWM = 0.000313S = 0.000313 * 1000000us = 313us,
    // 				auto_load = 313 - 1 = 312
    // 				pulse =auto_load / 2 - 1 = 313/2 - 1 = 157 - 1 = 156

    // 0.000277
    // PWM = 3600HZ,  1 / PWM = 0.000277S = 0.000277 * 1000000us = 277us,
    // 				auto_load = 277 - 1 = 276
    // 				pulse =auto_load / 2 - 1 = 277/2 - 1 = 139 - 1 = 138

    // 0.000250
    // PWM = 4000HZ,  1 / PWM = 0.000250S = 0.000250 * 1000000us = 250us,
    // 				auto_load = 250 - 1 = 249
    // 				pulse =auto_load / 2 - 1 = 250/2 - 1 = 125 - 1 = 124

    timer0_init_parameter.period = 249;
    timer0_init_parameter.clock_division = TIMER_CKDIV_DIV1;
    timer0_init_parameter.repetition_counter = 0;
    timer0_init_parameter.autoreload_shadow = TIMER_CARL_SHADOW_DISABLE;
    timer0_init_parameter.master_slave_mode = DISABLE;
    timer0_init_parameter.trgo_selection = TIMER_TRI_OUT_SRC_RESET;
    hal_timer_init(&timer0_info,TIMER0,&timer0_init_parameter);

    timer0_output_compare_parameter.compare_mode = TIMER_OC_MODE_PWM1;
    timer0_output_compare_parameter.oc_pulse_value = 124;
    timer0_output_compare_parameter.oc_polarity = TIMER_OC_POLARITY_HIGH;
    timer0_output_compare_parameter.oc_idlestate = TIMER_OC_IDLE_STATE_LOW;
    timer0_output_compare_parameter.oc_shadow = TIMER_OC_SHADOW_DISABLE;
    timer0_output_compare_parameter.oc_fastmode = TIMER_OC_FAST_DISABLE;
    timer0_output_compare_parameter.oc_clearmode = TIMER_OC_CLEAR_ENABLE;
    hal_timer_output_compare_config(&timer0_info,TIMER_CH_0,&timer0_output_compare_parameter);

    timer0_clear_source_parameter.clear_source = TIMER_OCPRE_CLEAR_SOURCE_CLR;
    hal_timer_ocpre_clear_source_config(&timer0_info,&timer0_clear_source_parameter);

    timer0_break_parameter.run_offstate = TIMER_ROS_STATE_DISABLE;
    timer0_break_parameter.idel_offstate = TIMER_IOS_STATE_DISABLE;
    timer0_break_parameter.break_polarity = TIMER_BREAK_POLARITY_HIGH;
    timer0_break_parameter.output_autostate = TIMER_OUTAUTO_DISABLE;
    timer0_break_parameter.protect_mode = TIMER_CCHP_PROT_OFF;
    timer0_break_parameter.break_state = TIMER_BREAK_DISABLE;
    hal_timer_break_config(&timer0_info,&timer0_break_parameter);

    /* user code [timer0_init local 1] begin */
    // Prescaler value = 107 = 108MHZ / (107 + 1) = 1MHZ
    // 不理会“Clock division” !!!
    // TIMER0实际执行时钟的周期 = (1 / 1MHZ)s = (1 / 1000,000)s = 0.000001s = 1us 一个TIMER0时钟周期 = 1us
    // 4KHZ的周期 = (1 / 4000)s = 0.00025s = 250 us
    // 那么4KHZ的PWM波的时钟(TIMER0实际执行时钟的周期)个数 = 250us / 1us = 250个计数 => 自动重装值  = (250 - 1)= 249
    // 驱动无源蜂鸣器的PWM波占空比要求是50%, 那么PWM波的比较值 = 250个 * 50% = 125个计数 => CMP比较值 = (125 - 1) = 124

    /* user code [timer0_init local 1] end */
}

实验结果和官方给的蜂鸣器频率响应曲线基本一样

在这里插入图片描述
只实验到了PWM = 4KHZ,确实声音是最大的,但是离近了(300mm)听,有点刺耳。
当PWM = 1.8KHZ时,声音虽然小了点,但是声音听起来舒服,不刺耳。
看官方推荐,2KHZ的声音样本比较悦耳。
再去找找,看有没有工业级别的2KHZ压电无源蜂鸣器。

看看实际波形

在这里插入图片描述
示波器夹子,一端在GND, 另一端在蜂鸣器2脚
看到PWM频率为4KHZ
波形幅度为2.44V
波形也不是方波,而是三角波。

前面失败图,波形不是这种三角波。波形幅度差不多。
是不是没有在蜂鸣器两边并联1K电阻引起的。等后续有时间再实验。
如果能用MOS来控制蜂鸣器,我还是倾向于用MOS来控制。

END

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧交通基于yolov8的行人车辆检测计数系统python源码+onnx模型+精美GUI界面

【算法介绍】 智慧交通中&#xff0c;基于YOLOv8的行人车辆检测计数系统是一项高效、准确的技术解决方案。该系统利用YOLOv8这一先进的目标检测算法&#xff0c;结合深度学习技术&#xff0c;能够实时检测并准确计数道路上的行人和车辆。YOLOv8在保证检测速度的同时&#xff0…

视图(mysql)

一、什么是视图 视图是⼀个虚拟的表&#xff0c;它是基于⼀个或多个基本表或其他视图的查询结果集。视图本⾝不存储数 据&#xff0c;⽽是通过执⾏查询来动态⽣成数据。⽤⼾可以像操作普通表⼀样使⽤视图进⾏查询、更新和管 理。视图本⾝并不占⽤物理存储空间&#xff0c;它仅…

linux命令用于删除文本文件中的重复行的命令uniq详解

目录 一、概述 二、基本用法 1、uniq 命令的基本语法 2、常用选项 3、获取帮助 三、主要功能 1. 识别并删除相邻重复行 2. 保留重复行的第一个实例 3. 统计重复次数 4. 忽略指定列的比较 四、示例 1. 删除相邻重复行 2. 显示每一行及其重复次数 3. 只显示重复行 4. …

【Hot100】LeetCode—136. 只出现一次的数字

目录 1- 思路题目识别技巧 2- 实现⭐136. 只出现一次的数字——题解思路 原题链接&#xff1a;136. 只出现一次的数字 1- 思路 题目识别 识别1 &#xff1a;给定一个数组&#xff0c;里面元素均出现两次&#xff0c;只有一个数只出现一次。 技巧 一个数和 0 的异或是这个数…

前端网页代码编辑器 Monaco Editor

前端网页代码编辑器 Monaco Editor Monaco Editor Monaco Editor 是由 Microsoft 开发的一款基于 Web 技术的开源代码编辑器&#xff0c;它是 Visual Studio Code 编辑器的核心。Monaco Editor 可以嵌入到网页中&#xff0c;提供类似于 Visual Studio Code 的编辑体验。 官方…

华为SMU02B1管理模块WEB登录与账户密码信息

1、将电脑的IP地址与SMU02B1的IP地址配置在同一个网段中。例如&#xff0c;如果监控的IP地址为192.168.0.11&#xff0c;子网掩码为255.255.255.0&#xff0c;默认网关为192.168.0.1&#xff0c;则电脑的IP地址设置成192.168.0.12&#xff0c;子网掩码设置成255.255.255.0&…

基于微信小程序的垃圾分类(lw+演示+源码+运行)

摘 要 随着生态文明体制改革的不断推进,可持续发展的环保理念逐渐成为社会共识,而在推行环保措施的过程中却困难重重.针对生活废弃物肆意无序投放的问题,尽管目前各大城市相继推出垃圾分类强制性执行的政策法规,但因市民欠缺对垃圾种类的正确认识而导致垃圾分类的施行难度和成…

【Docker系列】环境准备-VirtualBox虚拟机安装

前言 最近一段时间研究了一下Docker容器方面的技术&#xff0c;发现容器技术还是蛮好玩的。但是自己手头上没啥Linux操作系统机器&#xff0c;于是就想到利用一些虚拟机软件工具&#xff0c;在自己的Windows操作系统上安装几个Linux操作系统环境。我这里给大家介绍的是一款常用…

【代码随想录训练营第42期 Day58打卡 - 图论Part8 - 拓扑排序

目录 一、拓扑排序介绍 定义 特点 实现方法&#xff08;2种&#xff09; 应用 二、题目与题解 题目&#xff1a;卡码网 117. 软件构建 题目链接 题解&#xff1a;拓扑排序 - Kahn算法&#xff08;BFS&#xff09; 三、小结 一、拓扑排序介绍 对于拓扑排序&#xff0c…

【传纸条 / NOIP / Google】

题目 代码&#xff08;还是我的好理解&#xff0c;(●◡●)&#xff09; #include <bits/stdc.h> using namespace std; const int N 55; int w[N][N]; int f[2*N][N][N]; int main() {int m, n;cin >> m >> n;for(int i 1; i < m; i){for(int j 1; j…

ASPCMS靶场漏洞复现

浏览器访问环境 1.进入后台管理 aspcms默认的后台登录地址为/admin_aspcms/index.asp 用户名&#xff1a;admin 密码&#xff1a;123456 2.点击扩展功能里面的幻灯片设置 3.在保存的时候抓包 抓包修改slideTextStatus参数为一句话木马 1%25><%25Eval(Request (chr(65…

【CSS】选择器(基本选择器、复合选择器、属性匹配选择器、结构伪类选择器、伪元素选择器)

选择器 引入方式基础选择器复合选择器属性匹配选择器结构伪类选择器伪元素选择器 引入方式 1&#xff1a;外联 <!-- css引入方式1&#xff1a;外联 外联与内嵌优先级相同&#xff0c;取决于加载顺序 --><link rel"stylesheet" href"./样式.css"…

基于SpringBoot+Vue的养老院管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

Spring Cloud常见面试题

1.请说说你用过Spring Cloud哪些组件&#xff1f;这些组件分别有什么作用&#xff1f; 1、注册中心&#xff1a;Eureka、Nacos、Zookeeper、Consul&#xff1b;&#xff08;服务注册&#xff09; 2、负载均衡&#xff1a;Ribbon、LoadBalancer&#xff1b;&#xff08;客户端的…

文件误删危机应对:数据恢复全解析

文件误删&#xff1a;数字化时代的隐形挑战 在数字化的浪潮中&#xff0c;文件已成为我们工作、学习和生活中不可或缺的一部分。它们记录着我们的思想、成果与回忆&#xff0c;是连接现实与虚拟世界的桥梁。然而&#xff0c;这份便捷与高效背后&#xff0c;却隐藏着文件误删这…

集群聊天服务器项目【C++】(三)muduo库的简单介绍

在上一讲中介绍了Json库的相关知识&#xff0c;本次接着介绍muduo库的相关内容&#xff0c;这些知识在本项目中都会使用到。 1.muduo库简介 muduo库顶层就是epoll&#xff08;IO复用技术&#xff09; Linux的pthread多线程&#xff0c;所以只能安装在Linux系统中。此外它依赖…

Transformer学习(4):位置编码 Positional Encoding

为什么需要位置编码 在自注意力编码中&#xff0c;所有 a a a的计算都并行同时执行得到对应的 b b b&#xff0c;可以并行就代表着 a a a之间是不存在先后顺序关系的&#xff0c;这存在问题。 在不使用位置编码时&#xff0c;将 a 2 a_2 a2​与 a 3 a_3 a3​的顺序打乱&#…

java项目之疫情下图书馆管理系统源码(springboot)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的疫情下图书馆管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息。 项目简介&#xff1a; 疫情下图书馆管理系…

实景三维赋能低空经济:探索天空之城的未来图景

在数字化转型的大潮中&#xff0c;低空经济作为新兴业态正逐渐崭露头角&#xff0c;它不仅拓宽了航空业的边界&#xff0c;也为智慧城市、应急救援、物流配送、旅游观光等领域带来了前所未有的发展机遇。而实景三维技术&#xff0c;作为地理信息与遥感领域的前沿科技&#xff0…

java环境配置 | 基础铺垫

cmd命令 dir : 罗列目录下所有的文件展示出来cd xx : 进入xx文件夹cd … 返回上一级cls : 清除屏幕内容exit : 退出命令提示窗口环境变量 就是存储某个应用路径的变量,通过这个变量可以快速访问到某个应用exe 为什么要配置环境变量? 我们想要在任意的目录下都可以打开指…