ARM32开发——PWM蜂鸣器案例

news2024/12/25 9:04:15

🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

文章目录

    • 需求
    • 原来的驱动
    • 移植操作
      • 替换初始化
    • 更新Play函数
    • 完整代码

需求

在这里插入图片描述
通过控制PB9来播放音乐,PB9对应的定时器通道:Timer1 CH1

原来的驱动

#ifndef __BUZZER_H__
#define __BUZZER_H__

#include "config.h"

// 初始化蜂鸣器
void Buzzer_init();

// 按照指定频率播放
void Buzzer_play(u16 hz_val);

// 按照指定的音调播放 1,2,3,4,..7
void Buzzer_beep(u8 hz_val_index);

// 停止播放
void Buzzer_stop();

#endif
#include "Buzzer.h"

#include "GPIO.h"
#include "PWM.h"
//			   C	 D    E 	F	 G	 A	  B	   C`
//u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};

//            C			D			E			 F			G			A			B		  C`
u16 hz[] = { 1047, 1175, 1319,  1397, 1568, 1760, 1976, 2093 };

static void GPIO_config(void) {
    GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义
    GPIO_InitStructure.Pin  = GPIO_Pin_0;		//指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_OUT_PP;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}

void Buzzer_init(){
    GPIO_config();
}

void Buzzer_beep(u8 hz_val_index){ // 1,2,3,4 ... 7

    u16 hz_val = hz[hz_val_index - 1];

    Buzzer_play(hz_val);
}

void Buzzer_play(u16 hz_val){

    u16 Period = MAIN_Fosc / hz_val;

    PWMx_InitDefine		PWMx_InitStructure;
    // 总配置
    // (MAIN_Fosc / 1000 - 1) 周期计数值
    PWMx_InitStructure.PWM_Period   		= Period - 1;	//周期时间,   0~65535
    PWMx_InitStructure.PWM_DeadTime 		= 0;								//死区发生器设置, 0~255
    PWMx_InitStructure.PWM_EnoSelect		= ENO5P;	//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
    PWMx_InitStructure.PWM_PS_SW    		= PWM5_SW_P00;//切换端口

    // 具体PWM端口配置
    // pwm5
    PWMx_InitStructure.PWM5_Mode    		= CCMRn_PWM_MODE1;	//模式,		CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
    PWMx_InitStructure.PWM5_Duty    		= Period / 2;			//PWM4占空比时间, 0~Period	 声音的大小、响度

    // pwm5
    PWMx_InitStructure.PWM_CC5Enable   = ENABLE;				//开启PWM6P输入捕获/比较输出,  ENABLE,DISABLE

    // PWM启动配置
    PWMx_InitStructure.PWM_MainOutEnable= ENABLE;				//主输出使能, ENABLE,DISABLE
    PWMx_InitStructure.PWM_CEN_Enable   = ENABLE;				//使能计数器, ENABLE,DISABLE
    PWM_Configuration(PWMB, &PWMx_InitStructure);				//初始化PWM,  PWMA,PWMB
}


void Buzzer_stop(){

    PWMx_InitDefine		PWMx_InitStructure;
    PWMx_InitStructure.PWM_MainOutEnable= DISABLE;				//主输出使能, ENABLE,DISABLE
    PWMx_InitStructure.PWM_CEN_Enable   = DISABLE;				//使能计数器, ENABLE,DISABLE
    PWM_Configuration(PWMB, &PWMx_InitStructure);				//初始化PWM,  PWMA,PWMB
}

#include "config.h"
#include "delay.h"
#include "GPIO.h"
#include "Buzzer.h"

// 两只老虎 
// 音符
u8 code notes[] = {
    1, 2, 3, 1,					1, 2, 3, 1,					3, 4, 5,		3, 4, 5,
    5, 6, 5, 4, 3, 1, 	5, 6, 5, 4, 3, 1, 	1, 5, 1,		1, 5, 1,
};

// 延时时长
u8 code durations[] = {
    4, 4, 4, 4,					4, 4, 4, 4,					4, 4, 8,		4, 4, 8,
    3, 1, 3, 1, 4, 4,		3, 1, 3, 1, 4, 4,		4, 4, 8,		4, 4, 8,
};

int main() {
    u8 i = 0;
    u8 len = 0;
    u16 delay = 0;

    Buzzer_init();

    len = sizeof(notes) / sizeof(u8);
    while(1) {

        for(i = 0; i < len; i++){
            Buzzer_beep(notes[i]);
            delay = durations[i] * 100;

            // 声响延时
            delay_X_ms(delay);

            // stop
            Buzzer_stop();
            delay_ms(20);
        }
        // stop
        Buzzer_stop();

        delay_ms(250);
        delay_ms(250);
        delay_ms(250);
        delay_ms(250);

    }
}

移植操作

替换初始化


void timer_gpio_config(uint32_t gpio_rcu, uint32_t gpio_port, uint32_t gpio_pin, uint32_t gpio_af){
    rcu_periph_clock_enable(gpio_rcu);                                             
		/* 设置gpio模式 */															  
    gpio_mode_set(gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_pin);              
    gpio_output_options_set(gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, gpio_pin);  
    gpio_af_set(gpio_port, gpio_af, gpio_pin);                                     
}

void timer_init_config(uint32_t timer_periph, uint16_t t_prescaler, uint32_t t_period) {
    /*初始化参数 */
    timer_parameter_struct initpara;
    /* initialize TIMER init parameter struct */
    timer_struct_para_init(&initpara);
    /* 根据需要配置值 分频系数 (可以实现更低的timer频率) */
    initpara.prescaler 	= t_prescaler - 1;
    /* 1个周期的计数(period Max: 65535) Freq >= 2564  */
    initpara.period		= t_period - 1;
    /* initialize TIMER counter */
    timer_init(timer_periph, &initpara);
    /* enable a TIMER */
    timer_enable(timer_periph);
}


void timer_channel_config(uint32_t timer_periph, uint16_t channel) {
    /* TIMER 通道输出配置 */
    timer_oc_parameter_struct ocpara;
    /* initialize TIMER channel output parameter struct */
    timer_channel_output_struct_para_init(&ocpara);
    ocpara.outputstate  = (uint16_t)TIMER_CCX_ENABLE;
    /* 配置输出参数 configure TIMER channel output function */
    timer_channel_output_config(timer_periph, channel, &ocpara);
    /* 配置通道输出输出比较模式 configure TIMER channel output compare mode */
    timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}

#define TIMER_RCU		RCU_TIMER1
#define TIMER_PERIPH 	TIMER1
#define TIMER_CHANNEL	TIMER_CH_1
#define PRESCALER  		10

void Buzzer_init() {
    // PB9 Timer1_CH1 AF2
    // GPIO ----------------------------------------
    timer_gpio_config(RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_AF_1);

    // TIMER----------------------------------------
    rcu_periph_clock_enable(TIMER_RCU);
    timer_deinit(TIMER_PERIPH);
    /* 升级频率*/
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
    // 通道配置 -------------------------------------
    timer_channel_config(TIMER_PERIPH, TIMER_CHANNEL);
}

将原有的初始化逻辑修改为新的pwm更新

更新Play函数

//            C			D			E			 F			G			A			B		  C`
u16 hz[] = { 1047, 1175, 1319,  1397, 1568, 1760, 1976, 2093 };

void Buzzer_beep(u8 hz_val_index) { // 1,2,3,4 ... 7

    u16 hz_val = hz[hz_val_index - 1];
    Buzzer_play(hz_val);
}

void Buzzer_play(u16 hz_val) {
    // 根据系统主频和分频系数,计算周期
    uint16_t period = SystemCoreClock / (hz_val * PRESCALER);
    // 设置分频系数和周期计数值
    timer_init_config(TIMER_PERIPH, PRESCALER, period);
    // 设置输出脉冲值,范围是[0, 周期计数值)
    timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CHANNEL, (uint32_t)(period * 0.5f));
}

void Buzzer_stop() {
    timer_disable(TIMER_PERIPH);
}

● 分频问题需要解决
● 分频根据hz值来设定

完整代码

#ifndef __BSP_BUZZER_H__
#define __BSP_BUZZER_H__

#include "gd32f4xx.h"


#ifndef u32
#define u32 uint32_t
#endif

#ifndef u16
#define u16 uint16_t
#endif

#ifndef u8
#define u8 uint8_t
#endif

// 初始化蜂鸣器
void Buzzer_init();

// 按照指定频率播放
void Buzzer_play(u16 hz_val);

// 按照指定的音调播放 1,2,3,4,..7
void Buzzer_beep(u8 hz_val_index);

// 停止播放
void Buzzer_stop();

#endif
#include "bsp_buzzer.h"
//			   C	 D    E 	F	 G	 A	  B	   C`
//u16 hz[] = {523, 587, 659, 698, 784, 880, 988, 1047};

//            C			D			E			 F			G			A			B		  C`
u16 hz[] = { 1047, 1175, 1319,  1397, 1568, 1760, 1976, 2093 };
// >= 2564
void timer_gpio_config(uint32_t gpio_rcu, uint32_t gpio_port, uint32_t gpio_pin, uint32_t gpio_af){
    rcu_periph_clock_enable(gpio_rcu);                                             
		/* 设置gpio模式 */															  
    gpio_mode_set(gpio_port, GPIO_MODE_AF, GPIO_PUPD_NONE, gpio_pin);              
    gpio_output_options_set(gpio_port, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, gpio_pin);  
    gpio_af_set(gpio_port, gpio_af, gpio_pin);                                     
}

void timer_init_config(uint32_t timer_periph, uint16_t t_prescaler, uint32_t t_period) {
    /*初始化参数 */
    timer_parameter_struct initpara;
    /* initialize TIMER init parameter struct */
    timer_struct_para_init(&initpara);
    /* 根据需要配置值 分频系数 (可以实现更低的timer频率) */
    initpara.prescaler 	= t_prescaler - 1;
    /* 1个周期的计数(period Max: 65535) Freq >= 2564  */
    initpara.period		= t_period - 1;
    /* initialize TIMER counter */
    timer_init(timer_periph, &initpara);
    /* enable a TIMER */
    timer_enable(timer_periph);
}


void timer_channel_config(uint32_t timer_periph, uint16_t channel) {
    /* TIMER 通道输出配置 */
    timer_oc_parameter_struct ocpara;
    /* initialize TIMER channel output parameter struct */
    timer_channel_output_struct_para_init(&ocpara);
    ocpara.outputstate  = (uint16_t)TIMER_CCX_ENABLE;
    /* 配置输出参数 configure TIMER channel output function */
    timer_channel_output_config(timer_periph, channel, &ocpara);
    /* 配置通道输出输出比较模式 configure TIMER channel output compare mode */
    timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}

#define TIMER_RCU		  RCU_TIMER1
#define TIMER_PERIPH 	TIMER1
#define TIMER_CHANNEL	TIMER_CH_1
#define PRESCALER  		10

void Buzzer_init() {
    // PB9 Timer1_CH1 AF2
    // GPIO ----------------------------------------
    timer_gpio_config(RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_AF_1);

    // TIMER----------------------------------------
    rcu_periph_clock_enable(TIMER_RCU);
    timer_deinit(TIMER_PERIPH);
    /* 升级频率*/
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
    // 通道配置 -------------------------------------
    timer_channel_config(TIMER_PERIPH, TIMER_CHANNEL);
}

void Buzzer_beep(u8 hz_val_index) { // 1,2,3,4 ... 7

    u16 hz_val = hz[hz_val_index - 1];
    Buzzer_play(hz_val);
}

void Buzzer_play(u16 hz_val) {
    // 根据系统主频和分频系数,计算周期
    uint16_t period = SystemCoreClock / (hz_val * PRESCALER);
    // 设置分频系数和周期计数值
    timer_init_config(TIMER_PERIPH, PRESCALER, period);
    // 设置输出脉冲值,范围是[0, 周期计数值)
    timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CHANNEL, (uint32_t)(period * 0.5f));
}

void Buzzer_stop() {
    timer_disable(TIMER_PERIPH);
}

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

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

相关文章

CTF之网站被黑

简单看一下网页和源码没发现什么明显漏洞 那就扫描一下目录 发现了/shell.php文件&#xff0c;访问一下&#xff0c;发现是一个后台管理登录页面 别无他法只能爆破喽&#xff0c;爆破后发现密码是hack flag{25891d9e9d377f006eda3ca7d4c34c4d}

2024第三届钉钉杯大学生大数据挑战赛【A题】完整分享

2024第三届钉钉杯大学生大数据挑战赛已经开赛&#xff0c;小编给大家带来非常实用的助力【A题】完整&#xff0c;&#xff08;看图片下方的说明&#xff09;&#xff0c;资料预览&#xff1a; 微信公众号

【python】批量读取Word文档中的特定表格并保存为Excel文件

批量读取Word文档中的特定表格并保存为Excel文件 在工作中&#xff0c;我们常常需要从多个Word文档中提取数据&#xff0c;然后将这些数据汇总到一个Excel文件中进行分析。下面&#xff0c;我将分享一个Python脚本&#xff0c;它可以从多个Word文档中读取特定的表格数据&#…

暑期c++ 命名空间

有任何不懂的问题可以评论区留言&#xff0c;能力范围内都会一一回答 今天是暑期第一天开始写c笔记&#xff0c;新起点&#xff0c;新开始加油 我们先来看两串代码 这串代码编译没有问题 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int rand 14; int main(…

手机图片如何转化为word文档?分享3种好用的软件。

在数字化时代&#xff0c;手机已经成为我们生活中不可或缺的一部分。随着手机拍照功能的日益强大&#xff0c;我们常常用手机记录下重要的信息和瞬间。但你有没有遇到过这样的烦恼&#xff1a;如何将手机里的图片快速转化为可编辑的Word文档呢&#xff1f;今天&#xff0c;就为…

从工艺到性能:模具3D打印材料不断革新

在模具3D打印领域&#xff0c;材料性能的持续优化与创新是推动模具3D打印的关键因素&#xff0c;近年来&#xff0c;各种3D打印新材料不断涌现&#xff0c;模具3D打印材料也开始重工艺导向逐步向性能导向发展&#xff0c;如毅速公司推出的ESU-EM191/191S及ESU-EM201不锈钢粉末、…

C语言 | Leetcode C语言题解之第299题猜数字游戏

题目&#xff1a; 题解&#xff1a; #define MIN(a, b) ((a) < (b) ? (a) : (b))char * getHint(char * secret, char * guess){int A 0;int B 0;int dicS[10] {0};int dicG[10] {0};int i 0;while(secret[i]){if(secret[i] guess[i]){//同位置且相等&#xff08;完…

【React】useState:状态管理的基石

文章目录 一、什么是 useState&#xff1f;二、useState 的基本用法三、useState 的工作原理四、高级用法五、最佳实践 在现代前端开发中&#xff0c;React 是一个非常流行的库&#xff0c;而 useState 是 React 中最重要的 Hook 之一。useState 使得函数组件能够拥有自己的状态…

RHEL 7.6 安装oracle database 19c Real Application Cluster Part5: RU配置

RHEL 7.6 安装oracle database 19c Real Application Cluster Part1: 基础环境配置 RHEL 7.6 安装oracle database 19c Real Application Cluster Part2: Grid Infrastructure配置 RHEL 7.6 安装oracle database 19c Real Application Cluster Part3: ASM磁盘组配置 RHEL 7.…

《程序猿入职必会(5) · CURD 页面细节规范 》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

深入理解多态:发工资

看完目录就可以大概理解了&#xff0c;然后就需要去敲一敲代码&#xff0c;不过这个多态还确实挺厉害的。 目录 做一件事 员工1&#xff1a;干第一个过程 员工2&#xff1a;干第二个过程 员工3&#xff1a;干第三个过程 员工4&#xff1a;干第四个过程 员工5&#xff1a;…

Live555源码阅读笔记:哈希表的实现(C++)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

重生之“我打数据结构,真的假的?”--6.排序

1.排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使⼀串记录&#xff0c;按照其中的某个或某些关键字的⼤⼩&#xff0c;递增或递减的排列起来的 操作。 1.1排序分类 2.排序算法实现 2.1插入排序 直接插⼊排序是⼀种简单的插⼊排序法&#xff0c;其基本思想是&#…

深入探索Python3网络爬虫:构建数据抓取与解析的强大工具

前言 在当今这个信息爆炸的时代&#xff0c;数据成为了驱动各行各业发展的关键要素。无论是市场分析、用户行为研究&#xff0c;还是内容聚合与推荐系统&#xff0c;都需要从海量的互联网数据中提取有价值的信息。而网络爬虫&#xff0c;作为自动化获取网页数据的技术手段&…

FPGA开发——按键的使用及其消抖方法

一、概述 我们在进行各种硬件开发时通常都会实现多效果的综合和实现&#xff0c;而在实际的开发中&#xff0c;每个时刻只会显示单个效果&#xff0c;这就需要涉及到效果之间的切换了&#xff0c;而要实现状态切换最好的就是使用按键进行按键&#xff0c;所以按键在我们的日常…

Redis知识点总价

1 redis的数据结构 2 redis的线程模型 1&#xff09; Redis 采用单线程为什么还这么快 之所以 Redis 采用单线程&#xff08;网络 I/O 和执行命令&#xff09;那么快&#xff0c;有如下几个原因&#xff1a; Redis 的大部分操作都在内存中完成&#xff0c;并且采用了高效的…

深度学习系列69:模型部署的基础知识

参考https://mp.weixin.qq.com/s?__bizMzI4MDcxNTY2MQ&mid2247488952&idx1&sn880d3ad47a8fb3eab56514135f0e643b&chksmebb51d5adcc2944c276af19e8cff5e73c934f8811706be0a94c5f47f9e767c902939903e6b95&scene21#wechat_redirect 1. 基本流水线 1.1 介绍…

掀桌子了!原来是咱们的大屏设计太酷,吓着前端开发老铁了

掀桌子了&#xff01;原来是咱们的大屏设计太酷&#xff0c;吓着前端开发老铁了 艾斯视觉观点认为&#xff1a;在软件开发的世界里&#xff0c;有时候创意和设计的火花会擦得特别亮&#xff0c;以至于让技术实现的伙伴们感到既兴奋又紧张。这不&#xff0c;我们的设计团队刚刚…

故障诊断 | 基于Transformer故障诊断分类预测(Matlab)

文章目录 预测效果文章概述程序设计参考资料预测效果 文章概述 Transformer故障诊断/分类预测 | 基于Transformer故障诊断分类预测(Matlab) Transformer 模型本质上都是预训练语言模型,大都采用自监督学习 (Self-supervised learning) 的方式在大量生语料上进行训练,也就是…

【Django】开源前端库bootstrap,常用

文章目录 下载bootstrap源文件到本地项目引入bootstrap文件 官网&#xff1a;https://www.bootcss.com/V4版本入口&#xff1a;https://v4.bootcss.com/V5版本入口&#xff1a;https://v5.bootcss.com/ 这里使用成熟的V4版本&#xff0c;中文文档地址&#xff1a;https://v4.b…