小梅哥Xilinx FPGA学习笔记20——无源蜂鸣器驱动设计与验证(音乐发生器设计)

目录

一:章节导读

二:无源蜂鸣器驱动原理

三:PWM 发生器模块设计

3.1 PWM 发生器模块框图

3.2 PWM 发生器模块接口功能描述

3.3 PWM波生成设计文件代码

3.4 测试仿真文件

3.5 测试仿真结果

3.6 板级调试与验证之顶层文件设计

四:基于 PWM 波的音乐发生器设计

4.1 “天空之城”乐谱

4.2 get_pitch 模块的代码

4.3 rom配置

4.4 coe文件

4.5 顶层文件设计

4.6 仿真验证代码

4.7 仿真结果

4.8 板上验证 


一:章节导读

       蜂鸣器是一种产生声音的器件。其广泛应用于报警器、电子玩具、汽车电子设备、定时器等电子产品中作为发声器件。本章将介绍 ACZ702 开发板上使用的蜂鸣器电路,并使用 FPGA 来实现驱动 无源蜂鸣器按照“哆来咪发梭拉西”7个音调发声。并在此基础上实现 “天空之城”的音乐发生器。

     蜂鸣器按照构造方式的不同,可分为压电式蜂鸣器电磁式蜂鸣器两种类型,由于两种蜂鸣器发音原理不同,压电式结构简单耐用但音调单一音色差,适用于报警器等设备。而电磁式由于音色好,所以多用于语音、音乐等设备。 

       蜂鸣器按照驱动电路的不同可以分为有源蜂鸣器无源蜂鸣器。有源蜂鸣器内部带震荡源,所以只要通电就会鸣叫;而无源蜂鸣器内部不带震荡源,因此如果用直流信号无法令其鸣叫,这就需要用 2K-5K 的方波(声音频率)去驱动。ACZ702 开发板上使用了一枚 3.3V 直流电压驱动的电磁式无源蜂鸣器。其原理图如下图所示:

BEEP 端口接FPGA 输出管脚,使用时只需要在 BEEP 信号上输入 2~5KHz PWM 波,就能
驱动蜂鸣器按照既定的频率产生振动信号。

二:无源蜂鸣器驱动原理

       通过前面对无源蜂鸣器的特点介绍可知,要使无源蜂鸣器能够正常发声,需要在控制端 BEEP 给出相应频率的 PWM 波。因此,对于无源蜂鸣器的控制, 就转化为了设计一个 PWM 波发生电路。因此,接下来将介绍 PWM 波的发生部 分相关设计。
       PWM 波即脉冲宽度调制,以下为周期为 1KHz ,脉冲宽度(占空比)为 20%的示意图

       由上图可知,当信号周期一定,信号高电平时间所占信号周期的百分比不一样,即为不同占空比的 PWM 波。而除了调整 PWM 信号的占空比, PWM 信号的周期也是可以调整的, 对于不同的器件,对驱动信号的频率要求也不一样,还需要能够对 PWM 波的频率进行调整。
       通过以上分析,可以看出,要设计一个 PWM 发生电路,需要能够实现对信号的频率和占空比的调节。 单片机或者 DSP 中,产生 PWM 波的方法就是 使用片上定时器进行循环计数,通过设定定时器的一个定时周期时长来确定对 应输出 PWM 信号的频率,同时还有一个比较器,该比较器比较定时器的实时 计数值与用户设定的比较值的大小,根据比较结果来控制输出信号的电平高低。
通过设定不同的比较值,即可实现不同占空比的 PWM 信号输出。使用定时器产生 PWM 原理图如下:

三:PWM 发生器模块设计

对于 FPGA 来说,要产生 PWM 波,也可以借鉴单片机或 DSP 使用定时器产生 PWM 波的思路。依据 PWM 模块发生器原理可知需设计两个主要电路:定 时器 / 计数器电路以及输出比较电路。

3.1 PWM 发生器模块框图

3.2 PWM 发生器模块接口功能描述

最终输出 PWM 波的频率计算公式为:

                                      

其中,这里的 counter_arr 是自减计数器的预重装值,计数器是从 counter_arr开始递减到 1 。因此,当输出频率确定时,可计算得到预重装值,计算公式为:

                                     

例如,当希望设置输出信号频率为 5KHz

因此,只需要设置 counter_arr 值为 10000 即可使得最终输出信号频率为5KHz
       当输出 PWM 频率确定后,其输出占空比计算则为输出比较值与预重装值
之商。计算公式为:

                                   

因此,当输出占空比确定时,可计算得到输出比较值,计算公式为:

                    

       在运行过程中,修改预重装值可以设置输出 PWM 信号的频率,并将同时影响输出占空比,而在预重装值确定的情况下,修改输出比较值,则可以设置 输出占空比。

3.3 PWM波生成设计文件代码

module pwm_gen(
    input clk,
    input reset_n,
    input pwm_gen_en,//使能信号
    input [31:0]counter_arr,//预重装值,用来设定频率
    input [31:0]counter_crr,//比较值,用来调节占空比
    output reg pwm_out//输出pwm波
    );
   
reg [31:0]pwm_gen_cnt;
    
always@(posedge clk or negedge reset_n)
    if(!reset_n)    
        pwm_gen_cnt <= counter_arr;
    else if(pwm_gen_en)begin
        if(pwm_gen_cnt <= 1)    
            pwm_gen_cnt <= counter_arr;  //计数减到 1,加载预重装寄存器值  
        else
            pwm_gen_cnt <= pwm_gen_cnt - 1;   //计数器自减 1
    end
    else               //未使能时,计数器值等于预重装寄存器值
        pwm_gen_cnt <= counter_arr;
        
 always@(posedge clk or negedge reset_n)
    if(!reset_n)      
        pwm_out <= 0;//复位时,PWM 输出低电平
    else if(pwm_gen_cnt <= counter_crr)  //计数值小于比较值,PWM 输出高电平
        pwm_out <= 1;   
    else   
        pwm_out <= 0;        //计数值大于比较值,PWM 输出低电平     
endmodule

3.4 测试仿真文件

`timescale 1ns / 1ps
module pwm_gen_tb();

reg clk;
reg reset_n;
reg pwm_gen_en;
reg [31:0]counter_arr;
reg [31:0]counter_crr;
wire pwm_out;

pwm_gen pwm_gen_inst(
    .clk         (clk) ,
    .reset_n     (reset_n) ,
    .pwm_gen_en  (pwm_gen_en) ,//使能信号
    .counter_arr (counter_arr) ,//预重装值,用来设定频率
    .counter_crr (counter_crr) ,//比较值,用来调节占空比
    .pwm_out     (pwm_out)    //输出pwm波
);

initial clk =1;
always #10 clk = ~clk;

initial begin
    reset_n = 0;
    pwm_gen_en = 0;
    counter_arr =0;
    counter_crr = 0;
    #201;
    reset_n = 1;
    #201;
    counter_arr = 1000; //设置输出信号频率为 50KHz
    counter_crr = 400; //设置输出 PWM 波占空比为 40%
    #100;
    pwm_gen_en = 1; //启动计数以产生 PWM 输出
    #100050;
    counter_crr = 700; //设置输出 PWM 波占空比为 70%
    #100050;
    pwm_gen_en = 0; //停止计数以关闭 PWM 输出
     
    counter_arr = 500; //设置输出信号频率为 100KHz
    counter_crr = 250; //设置输出 PWM 波占空比为 50%
    #100;
    pwm_gen_en = 1; //启动计数以产生 PWM 输出
    #50050;
    counter_crr = 100; //设置输出 PWM 波占空比为 20%
    #50050;
    pwm_gen_en = 0; //停止计数以关闭 PWM 输出
    #200;
    $stop;       
end
endmodule

3.5 测试仿真结果

放大局部波形可知满足测试仿真文件的要求。

3.6 板级调试与验证之顶层文件设计

module pwm_gen_test(
    input clk,
    input reset_n,
    output beep
    );
    
reg  [27:0]delay_500ms; //500ms延时计数器
reg  [2:0] bit_cnt;//位计数器 
reg  [31:0]counter_arr; //预重装值寄存器 
wire [31:0]counter_ccr; //输出比较值   

parameter  MCNT_500ms = 2500_0000;   
//7个音调的预重装值,也叫频率周期
localparam  D1 = 170068, //D 调音 1 
            D2 = 151515, //D 调音 2 
            D3 = 142857, //D 调音 3 
            D4 = 127227, //D 调音 4 
            D5 = 113379, //D 调音 5 
            D6 = 101010, //D 调音 6 
            D7 = 89928 ; //D 调音 7
            
//输出比较值为预重装值一半
assign   counter_ccr = counter_arr >> 1;//右移一位,数值变为一半

pwm_gen pwm_gen_inst(
    .clk                (clk)    ,
    .reset_n            (reset_n)    ,
    .pwm_gen_en         (1)    ,//使能信号
    .counter_arr        (counter_arr)    ,//预重装值,用来设定频率
    .counter_crr        (counter_ccr)    ,//比较值,用来调节占空比
    .pwm_out            (beep)      //输出pwm波
    );   
//500ms持续计数逻辑    
always@(posedge clk or negedge reset_n)
    if(!reset_n)    
        delay_500ms <= 0;
    else if(delay_500ms == MCNT_500ms - 1)
        delay_500ms <= 0;
    else 
        delay_500ms <= delay_500ms + 1;
 //每 500ms 切换一次音调   
always@(posedge clk or negedge reset_n)
    if(!reset_n)    
        bit_cnt <= 0;
    else if(delay_500ms == MCNT_500ms - 1)
        bit_cnt <= bit_cnt + 1;
    else 
        bit_cnt <= bit_cnt;    
    
//根据音调编号给预重装值给相应的值   
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        counter_arr <= 1;
    else begin
        case(bit_cnt)
            0:counter_arr <= 1 ;  
            1:counter_arr <= D1;
            2:counter_arr <= D2;
            3:counter_arr <= D3;
            4:counter_arr <= D4;
            5:counter_arr <= D5;
            6:counter_arr <= D6;
            7:counter_arr <= D7;
        endcase 
    end
endmodule

3.7 管脚约束文件列表

set_property IOSTANDARD LVCMOS33 [get_ports beep]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
set_property PACKAGE_PIN G15 [get_ports beep]
set_property PACKAGE_PIN U18 [get_ports clk]
set_property PACKAGE_PIN F20 [get_ports reset_n]

     以上代码即可实现蜂鸣器即开始循环播放“哆来咪发梭拉西”7 个音。

基于 PWM 波的音乐发生器设计

前面已经实现并上板验证了使用 PWM 产生模块实现对 哆来咪发梭拉 西 ”音调的产生。 现在将在此基础上结合模块化设计思想,利用蜂鸣器实现播放 一段音乐的功能。
这里选取乐谱相对简单点的一首乐谱“天空之城”,在ACZ702 开发板上实现音乐播放。

4.1 “天空之城”乐谱

                        
从简谱看,该音乐是 D 调的,这里的各音符对应的频率对应的是上表中 D调的部分。另外,该音乐为四分之四拍,每个对应为 1 拍。(音符节奏分为一拍、 半拍、 1/4 拍、 1/8 拍,)几个特殊音符说明如下(我们规定一拍音符的时间为 1 半拍为 0.5 1/4 拍为 0.25 1/8 拍为 0.125…… )。
1 ) 普通音符。如音符 7 ,对应频率 556 ,占 1 拍。
2 ) 带下划线音符,表示 0.5 拍;两个下划线是四分之一拍( 0.25 )。
3 ) 有的音符后带一个点,表示多加 0.5 拍,即 1+0.5
4 ) 有的音符后带一个“—”,表示多加 1 拍,即 1+1
5 有的两个连续的音符上面带弧线,表示连音,可以稍微改下连音后面那个音的频率,比如减少或增加一些数值(需自己调试),这样表现会更 流畅,其实不做处理,影响也不大。
这里我们采用 ROM 来存储乐谱,然后通过依次读取 ROM 的数据,然后产生对应的音调。存储式采用 5bit 数据对音调进行编码,高 2bit 数据数值 3 2 1 作为高中低音编码,低 3bit 数据数值 1~7 作为 哆来咪发梭拉西 的编码。例如 存储的数据 5’b01_011 表示的是低音“ 3 ”。通过这种形式将乐谱进行编码存储在 ROM 中。
在节拍的设计上,如果以 250ms 时间为一拍的时间,半拍的时间是 125ms ,通过上面的乐谱来看,没有低于半拍的,那设计时就以 125ms 为基本单位时间, 1 拍就是 2 个单位时间,半拍是一个单位时间。 get_pitch 模块一方面产生这 125ms 的单位时间,另一方面在一个个单位时间的控制下产生获取 rom 里音符 的编码地址。

4.2 get_pitch 模块的代码

module get_pitch(
    input clk,
    input reset_n,
    output reg [8:0]pitch_num //获取音符 rom 的地址编号
    );
    
reg [23:0]cnt_125ms; //125ms 延时计数器,每个节拍的时间
  
parameter MCNT_125ms_MAX = 6250000; 
//125ms持续计数逻辑   
always@(posedge clk or negedge reset_n)   
    if(!reset_n)    
        cnt_125ms <= 0;       
    else if(cnt_125ms == MCNT_125ms_MAX - 1)
        cnt_125ms <= 0;
    else 
        cnt_125ms <= cnt_125ms + 1;
 
//每125ms切换一次音调的位控制逻辑 (每125ms获取一次音符 rom 的地址编号(递增))
always@(posedge clk or negedge reset_n)   
    if(!reset_n)    
        pitch_num <= 0;       
    else if(cnt_125ms == MCNT_125ms_MAX - 1)
        pitch_num <= pitch_num + 1;
    else 
        pitch_num <= pitch_num ; 
endmodule

4.3 rom配置

存放数据是以“天空之城”的乐谱实际不超过 256 个音符,也就是说初始化文件的数据不超过 512 个数据(数据以半拍为单位进行存储,一个节拍用两 个数据存储),这里 ROM 的深度设置为 512 ,没有初始化的 ROM 数据选择使用 0 来进行填充。这样正好让两次音乐播放之间还能留有一定的时间间隔。

4.4 coe文件

文件在下面的百度网盘里
链接:https://pan.baidu.com/s/1w3spnKZWKi7u2du7ML6Prw
提取码:qzof

4.5 顶层文件设计

module music_gen(
    input clk,
    input reset_n,
    output beep
    );
 
reg [31:0]counter_arr ;//预重装值寄存器
wire [31:0]counter_crr; //输出比较值

wire [8:0]pitch_num; //音乐的音调编号,0-->最大值 循环递增
wire [4:0]pitch;   //音乐的音调 
    
localparam       DL1 = 340136, //D 调低音 1
                 DL2 = 303030, //D 调低音 2
                 DL3 = 285714, //D 调低音 3
                 DL4 = 255102, //D 调低音 4
                 DL5 = 226244, //D 调低音 5
                 DL6 = 201613, //D 调低音 6
                 DL7 = 179856, //D 调低音 7
                 D1 = 170068, //D 调音 1 
                 D2 = 151515, //D 调音 2 
                 D3 = 142857, //D 调音 3 
                 D4 = 127227, //D 调音 4 
                 D5 = 113379, //D 调音 5 
                 D6 = 101010, //D 调音 6 
                 D7 = 89928 , //D 调音 7 
                 DH1 = 84889, //D 调高音 1 
                 DH2 = 75643, //D 调高音 2 
                 DH3 = 71429, //D 调高音 3 
                 DH4 = 63613, //D 调高音 4 
                 DH5 = 56689, //D 调高音 5 
                 DH6 = 50505, //D 调高音 6 
                 DH7 = 44964; //D 调高音 7
                 
//根据 rom 存储输出不同的音调输出不同的预置数
always@(posedge clk or negedge reset_n)
    if(!reset_n) 
        counter_arr <= 1;
    else begin
        case(pitch)
            5'b01_001:counter_arr = DL1; //D 调低音 1
            5'b01_010:counter_arr = DL2; //D 调低音 2
            5'b01_011:counter_arr = DL3; //D 调低音 3
            5'b01_100:counter_arr = DL4; //D 调低音 4
            5'b01_101:counter_arr = DL5; //D 调低音 5 
            5'b01_110:counter_arr = DL6; //D 调低音 6
            5'b01_111:counter_arr = DL7; //D 调低音 7
            
            5'b10_001:counter_arr = D1; //D 调音 1 
            5'b10_010:counter_arr = D2; //D 调音 2 
            5'b10_011:counter_arr = D3; //D 调音 3 
            5'b10_100:counter_arr = D4; //D 调音 4 
            5'b10_101:counter_arr = D5; //D 调音 5 
            5'b10_110:counter_arr = D6; //D 调音 6 
            5'b10_111:counter_arr = D7; //D 调音 7
            
            5'b11_001:counter_arr = DH1; //D 调高音 1 
            5'b11_010:counter_arr = DH2; //D 调高音 2
            5'b11_011:counter_arr = DH3; //D 调高音 3
            5'b11_100:counter_arr = DH4; //D 调高音 4 
            5'b11_101:counter_arr = DH5; //D 调高音 5
            5'b11_110:counter_arr = DH6; //D 调高音 6
            5'b11_111:counter_arr = DH7; //D 调高音 7
            default: counter_arr = 32'd1;//休止符
        endcase
    end    


//rom例化
blk_mem_gen_0 your_instance_name (
  .clka(clk),    // input wire clka
  .addra(pitch_num),  // input wire [8 : 0] addra
  .douta(pitch)  // output wire [4 : 0] douta
);

get_pitch  get_pitch(
    .clk(clk),
    .reset_n(reset_n),
    .pitch_num(pitch_num)
    );
              
pwm_gen pwm_gen(
    .clk             (clk),
    .reset_n         (reset_n),
    .pwm_gen_en(1),//使能信号
    .counter_arr(counter_arr),//预重装值,用来设定频率
    .counter_crr(counter_crr),//比较值,用来调节占空比
    .pwm_out(beep)//输出pwm波
);                 
 //设置输出比较值为预重装值一半                
assign  counter_crr = counter_arr >> 1;           
                 
endmodule  

4.6 仿真验证代码

`timescale 1ns / 1ps
module music_gen_tb();

reg clk;//系统时钟输入,50M
reg reset_n; //复位信号输入,低有效
wire beep;//pwm 输出信号

music_gen  music_gen(
    .clk(clk),
    .reset_n(reset_n),
    .beep(beep)
);

defparam music_gen.get_pitch.MCNT_125ms_MAX = 24'd6250;//缩短仿真时间

    initial clk = 1;
    always #10 clk = ~clk;

    initial 
    begin
    reset_n = 0;    
    #201;
    reset_n = 1;
    wait(music_gen.pitch_num == 512);//一轮播放结束
    #200;
    $stop;
 
    end
endmodule

4.7 仿真结果

从波形上可以看出,循环音乐循环播放之间有一定的时间间隔,这个与设计预期是一致的。可以放大波形后看,其波形也是与预期设计是一致的。

4.8 板上验证 

set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports reset_n]
set_property IOSTANDARD LVCMOS33 [get_ports beep]
set_property PACKAGE_PIN G15 [get_ports beep]
set_property PACKAGE_PIN F20 [get_ports reset_n]
set_property PACKAGE_PIN U18 [get_ports clk]

至此“天空之城”音乐发生器设计完毕。

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

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

相关文章

neo4j图数据库安装和测试

neo4j图数据库安装和测试 1. 下载合适的neo4j软件版本。 https://we-yun.com/doc/neo4j/ https://neo4j.com/deployment-center/#enterprise 2. 下载JAVAJDK 由于neo4j是一个用Java编写的图形数据库&#xff0c;因此在安装和运行Neo4j之前&#xff0c;需要先安装Java Developm…

【shell漫步】1 变量定义和使用

碎碎念 转眼间已经使用了一个月的shell了&#xff0c;作为一个纯小白&#xff0c;我特别理解刚入门的时候对于linux和shell一头雾水的状态&#xff0c;尤其是打算开始学&#xff0c;但是又找不到学习的“入口函数”的那种感受。所以打算整理一下shell的骨架。shell给我的感触就…

【C#】知识点实践序列之UrlEncode在线URL网址编码、解码

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是2024年第8篇文章&#xff0c;此篇文章是C#知识点实践序列文章&#xff0c; 博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 地址编码大家应该比较经常遇到和使用到&…

记一次使用mpvue开发微信小程序动画播放播放完成再播放下一个动画,实现动画队列的实战操作

微信小程序wxss支持Css的keyframes动画&#xff0c;我们想通过事件监听&#xff0c;在动画开始、动画播放阶段、动画播放结束的时候进行下一步动作。如下图&#xff0c;有一个从右飘入&#xff0c;然后从左侧出去的动画&#xff0c;我们希望的是&#xff0c;前一个出去后&#…

微众区块链观察节点的架构和原理 | 科普时间

践行区块链公共精神&#xff0c;实现更好的公众开放与监督&#xff01;2023年12月&#xff0c;微众区块链观察节点正式面向公众开放接入功能。从开放日起&#xff0c;陆续有多个观察节点在各地运行&#xff0c;同步区块链数据&#xff0c;运行区块链浏览器观察检视数据&#xf…

STM32 内部 EEPROM 读写

STM32 的某些系列 MCU 自带 EEPROM。笔者使用的 STM32L151RET6 自带 16 KB 的 EEPROM&#xff0c;可以用来存储自定义的数据。在芯片选型时&#xff0c;自带 EEPROM 也可以作为一个考量点&#xff0c;省去了在外接 EEPROM 的烦恼。 下面简单介绍下 STM32 内部 EEPROM 的读写流…

区块链技术与应用 【全国职业院校技能大赛国赛题目解析】第一套区块链系统部署与运维

第一套区块链系统部署与运维题目 环境 : ubuntu20 fisco : 2.8.0 子任务1-2-1: 搭建区块链系统并验证 题意: 要求搭建一条四节点的区块链系统,我们选择使用fisco作为此次测试的链子 我们使用build_chain.sh进行构建单机四节点,并且使用官方的默认端口【正式比赛大概率不…

Python 操作 JMeter 探索:pymeter 实操指南

概要 JMeter 是一个流行的性能测试工具&#xff0c;用于测试 Web 应用程序的性能和负载。它通常与 GUI 一起使用&#xff0c;但如果您想在自动化测试中集成 JMeter&#xff0c;或者以编程方式创建和运行测试计划&#xff0c;那么 pymeter 库将是一个强大的工具。本文将介绍如何…

快速、准确地检测和分类病毒序列分析工具 ViralCC的介绍和详细使用方法, 附带应用脚本

介绍 viralcc是一个基因组病毒分析工具&#xff0c;可以用于快速、准确地检测和分类病毒序列。 github&#xff1a;dyxstat/ViralCC: ViralCC: leveraging metagenomic proximity-ligation to retrieve complete viral genomes (github.com) Instruction of reproducing resul…

大数据StarRocks(三) StarRocks数据表设计

1. 列式存储 1.1 列式存储方式有以下几个优点&#xff1a; 1.快速的数据查询 由于数据是按照列进行存储的&#xff0c;所以查询某个列时只需要读取该列所在的块&#xff0c;而不是整行数据&#xff0c;从而大大提高了查询效率。 2.压缩效率高 由于列式存储的数据块中只有一…

LLM Agent之再谈RAG的召回信息密度和质量

话接上文的召回多样性优化&#xff0c;多路索引的召回方案可以提供更多的潜在候选内容。但候选越多&#xff0c;如何对这些内容进行筛选和排序就变得更加重要。这一章我们唠唠召回的信息密度和质量。同样参考经典搜索和推荐框架&#xff0c;这一章对应排序重排环节&#xff0c;…

Flink实时电商数仓之旁路缓存

撤回流的处理 撤回流是指流式处理过程中&#xff0c;两表join过程中的数据是一条一条跑过来的&#xff0c;即原本可以join到一起的数据在刚开始可能并没有join上。 撤回流的格式&#xff1a; 解决方案 定时器&#xff1a;使用定时器定时10s&#xff08;数据最大的时间差值&am…

【数据结构—二叉树的链式结构实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、二叉树的存储结构 二、二叉树链式结构的实现 2.1手动构建一课树 2.2二叉树的遍历 三、二叉树链式结构的实现 3.1前序遍历(递归) 3.2中序遍历(递归) 3.3后序…

如何成为ChatGPT 优质Prompt创作者

如何提问&#xff1f; 我想让你成为我的Prompt创作者。你的目标是帮助我创作最佳的Prompt&#xff0c;这个Prompt将由你ChatGPT使用。你将遵循 以下过程&#xff1a;1.首先&#xff0c;你会问我Prompt是关于什么&#xff1f;我会告诉你&#xff0c;但我们需要 通过不断的重复来…

LCR 176. 判断是否为平衡二叉树

解题思路&#xff1a; class Solution {public boolean isBalanced(TreeNode root) {return recur(root) ! -1;}private int recur(TreeNode root) {if (root null) return 0;int left recur(root.left);if(left -1) return -1;int right recur(root.right);if(right -1) …

使用通用MCU实现无人机飞行任务的快速二次开发

使用通用MCU实现无人机飞行任务的快速二次开发 ---TIDronePilot外部控制offboard模式介绍 无名小哥 2024年1月1日 传统飞控二次开发方法和主要存在的问题简介 通过对前面几讲中《零基础竞赛无人机积木式编程指南》系列开发教程的学习可知&#xff0c;在以往TI电赛真题的学习…

2023APMCM亚太数学建模C题 - 中国新能源汽车的发展趋势(2)

五&#xff0e;问题二模型建立和求解 5.1 问题二模型建立和求解 针对题目二&#xff0c;题目要求收集中国新能源电动汽车行业发展数据&#xff0c;建立数学模型描述&#xff0c;并预测未来十年的发展。由于在第一文中&#xff0c;我们已经收集了一定的新能源行业发展数据&…

Quartus II 13.1的安装及使用

Quartus II 13.1的安装及使用_quartus13.1-CSDN博客1.3 Verilog 环境搭建 | 菜鸟教程 学习 Verilog 做仿真时&#xff0c;可选择不同仿真环境。FPGA 开发环境有 Xilinx 公司的 ISE&#xff08;目前已停止更新&#xff09;&#xff0c;VIVADO&#xff1b;因特尔公司的 Quartu…

【React系列】JSX核心语法和原理

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. ES6 的 class 虽然目前React开发模式中更加流行hooks&#xff0c;但是依然有很多的项目依然是使用类组件&#x…

imgaug库指南(三):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…