STM32CubeMx チュートリアル (5) - PWM を使用してブザーを制御し、孤独な勇者を歌う

この章では、STM32CubeMx を使用してタイマーを設定し、PWM を使用してパッシブ ブザーの周波数性能を制御する方法について説明します。

 序文

1. ソフトウェアの準備: STM32CubeMx、Keil5_MDK

2. ハードウェアの準備: STM32F103 最小システム ボード、パッシブ ブザー モジュール、複数の DuPont ライン

この実験で使用されたすべてのデバイス リストとプロジェクトのソース コードは、Baidu Netdisk にアップロードされています。

リンク: https://pan.baidu.com/s/11HC05dnI-CEzDaU9OL2ugA?pwd=80o8 
抽出コード: 80o8

1. ブザーの鳴動原理

 ブザー回路は図のようになります。

一般的に、DC 3.3V によって生成される電気信号電力はブザーを駆動して可聴音を鳴らすには小さすぎるため、モジュール全体に電流増幅モジュール (図のトランジスタ) が存在します。図の増幅回路は一般的なエミッタ接地接続で、コレクタにブザーを接続して電流増幅を実現しています(トランジスタ増幅回路の詳しい原理については「アナログ電子技術」を参照してください)。

ブザーにはアクティブとパッシブの 2 種類があります。いわゆるソースとは内部発振源のことで、アクティブブザーの発振器は一般にマルチバイブレータであり、その原理はアナログ回路におけるRC発振器の一般原理(増幅回路、正帰還、位相差90°、電圧安定化回路)を使用しているため、アクティブブザー内部の発振源の周波数は固定されており、使用時に周波数を調整することはできず、入力電気信号はDCである必要があります。

これに対し、パッシブブザーは内部に発振源を持たず、音の基本原理は電磁誘導で、内部の基本構造はコイルとマイクロスピーカーです。発振源がなく、主な内部構造はコイルであるため、動作中の電気信号入力は非常に低い周波数のDCではなくACでなければなりません(DCは無負荷のコイルを通過できず、担当のコイルが焼損します)ショートによる不良です)。アクティブ ブザーと同様に、パッシブ ブザーも入力信号の出力を高めるために増幅回路を使用する必要があります。

2. PWMパルス幅変調信号

パルス幅変調 (PWM) は、回路の制御に最も一般的に使用されるデジタル信号です。この信号は、事前定義された時間と速度でハイ (5v または 3.3v) およびロー (0v) に設定されます。通常、PWM のハイレベルを 1、ローレベルを 0 と呼びます。

PWM には主に、 PWM 周波数 (f)、PWM 周期 (T)、PWM デューティ サイクルなどのパラメータが含まれます。

PWM 周波数: 1 秒以内にハイレベル時間からローレベル時間、そしてローレベルからハイレベルに切り替わる瞬間の数、つまり 1 秒間に何回の PWM サイクルがあるかを指します。f = T / 1(HZ)。

PWM周期:1秒以内のハイレベル時間からローレベル時間までの時間を指します、T = f / 1(s)。

 PWM デューティ サイクル:サイクル内の合計時間に対するハイ レベル時間の比率を指します。

例: PWM の周期が 1ms、高レベル時間は 0.5ms、低レベル時間は 0.5ms、周波数は 1kHz、デューティ サイクルは 50% です。

図に示すように、オシロスコープの場合

pwmの調整機能は「占有期間」の幅制御によるもので、「占有期間」が広くなると出力エネルギーが増加し、抵抗容量変換回路を介して得られる平均電圧値も増加します。 「占有期間」が狭くなり、出力電圧信号の平均電圧が低下し、抵抗容量変換回路で得られる平均電圧値も低下します。

つまり、特定の周波数ではデューティ比によって異なる出力アナログ電圧が得られるため、PWM 出力周波数を制御することでブザーの音を制御することができます。

3. 音色の変化

ソース画像を表示

図に示すように、さまざまなトーンに対応する周波数が示されていますが、タイマー psc を変更することで、さまざまな周波数に対応するトーンを変更できます。

 

は計算された割り込み周期、 はオートリロード値、はプリスケーラ周波数、は対応するクロック周波数です。

トーンをタイマー周波数に対応させるには、ベースの DO を例として、得られる値を 上記の式に代入し、異なるトーンに対応するように異なる値を変更します。 

タイマー周期の計算式から、Tclk はタイマーに接続されたクロック バスの周波数、arr はタイマーの自動リロード値、f はさまざまなトーンの周波数であることがわかります。図中の「dao」は262で、pscを各音色のタイマーに割り当てて計算したものです。

すべてのトーンを計算し、.h ファイルのマクロ定義に入れます。

4. 簡単な記譜法知識

(1) トーン

音階はアルト、高音、低音に分かれており、上の点が高音、点のないものがアルト、下の点が低音です。

(2)音の長さ

数字表記は、横線なしの場合を 1 拍、横線 1 本の場合は 2 拍、横線 2 本の場合は 1/4 拍に相当します。音階番号の後ろに半拍が付加され、横線で拍が付加されます。

5. プログラムの実施

この実験も STM32CubeMx を通じて実装されています。

以前に作成したプロジェクトを開きます

psc と arr を設定します。この実験は psc を変更してタイマー周波数を制御するため、psc の初期化値は任意であり、arr の値はデューティ サイクルのサイズに影響します。通常は 1000 に設定されます。計算に便利です。

 デューティ サイクルを 50% に設定し、残りの設定はデフォルトのままにします。セットアップが完了したらコードを生成します。

周波数マクロに対応するトーンテーブルに従ってトーンを定義します。

#define  proport          72000 	//Tclk/(arr+1)=72000000/(1000)

//根据Tout= ((arr+1)*(psc+1))/Tclk推出psc值就是本句define定义的值,Tout为音调频率131Hz的倒数,Tclk=72MHz                                                
#define  L1       ((proport/262)-1)//低调 do 的频率
#define  L2       ((proport/296)-1)//低调 re 的频率
#define  L3       ((proport/330)-1)//低调 mi 的频率
#define  L4       ((proport/349)-1)//低调 fa 的频率
#define  L5       ((proport/392)-1)//低调 sol 的频率
#define  L6       ((proport/440)-1)//低调 la 的频率
#define  L7       ((proport/494)-1)//低调 si 的频率
                                               
#define  M1       ((proport/523)-1)//中调 do 的频率
#define  M2       ((proport/587)-1)//中调 re 的频率
#define  M3       ((proport/659)-1)//中调 mi 的频率
#define  M4       ((proport/699)-1)//中调 fa 的频率
#define  M5       ((proport/784)-1)//中调 sol的频率
#define  M6       ((proport/880)-1)//中调 la 的频率
#define  M7       ((proport/988)-1)//中调 si 的频率

#define  H1       ((proport/1048)-1)//高调 do 的频率
#define  H2       ((proport/1176)-1)//高调 re 的频率
#define  H3       ((proport/1320)-1)//高调 mi 的频率
#define  H4       ((proport/1480)-1)//高调 fa 的频率
#define  H5       ((proport/1640)-1)//高调 sol的频率
#define  H6       ((proport/1760)-1)//高调 la 的频率
#define  H7       ((proport/1976)-1)//高调 si 的频率

#define  Z0       0//

 これまでのところ、最下層は基本的に記述されており、次のステップは、曲の番号付き楽譜を見つけて機能を実現することです。

おすすめの楽譜検索サイトはこちらイーソン・チャン「The Lonely Brave」ギタータブ譜

 トーンに応じて次のコードを記述します

「孤独な戦士」

/**
* NAME: void Solitary_brave(void)
* FUNCTION : Solitary_brave
*/
void Solitary_brave(void)
{
	int16_t solitary_brave[]=
	{
		M6,50,M7,50,H1,50,H2,50,M7,50,H1,50,H1,100,Z0,10,	//爱你孤身走暗巷
		H1,50,M7,50,H1,50,H2,50,M7,50,H1,50,H1,100,Z0,10, 	//爱你不跪的模样
		H1,50,H2,50,H3,50,H2,50,H3,50,H2,50,H3,100,H3,50,H3,50,H2,50,H3,100,H5,100,H3,100,Z0,10 //爱你对峙过绝望不肯哭一场
		
	};
	int length = sizeof(solitary_brave)/sizeof(solitary_brave[0]);
	for(uint8_t i=0;i<(length/2);i++)
	{
		buzzer_on(solitary_brave[i*2],200);
		HAL_Delay(5*solitary_brave[i*2+1]);
	}
}

「風が強くなった」 

void Wind_Rises(void)
{
	int wind_rise[]=
	{	
		//前奏
		L7,25,M1,25,M2,25,M3,25,L3,50,M5,25,M3,25,M3,50,Z0,150, L7,25,M1,25,M2,25,M3,25,L2,50,M5,25,M3,25,M2,25,M3,25,M1,25,M2,25,L7,25,M1,25,L5,25,Z0,25, L7,25,M1,25,M2,25,M3,25,L3,50,M5,25,M3,75,Z0,150,L7,25,M1,25,M2,25,M3,25,L2,50,M5,25,M3,25,M2,25,M3,25,M1,25,M2,25,Z0,20,
		//这一路上走走停停 顺着少年漂流的痕迹
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,25,M3,25,M2,25,M1,25,L6,100,Z0,10,
		//迈出车站的前一刻 竟有些犹豫
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,M2,100,Z0,50,
		//不仅笑着这近乡情怯 仍无法避免
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,L6,100,Z0,10
		//而长野的天 依旧那么暖 风吹起了从前
		M3,25,M2,25,M1,25,M2,25,M1,100, M3,25,M2,25,M1,25,M2,25,M1,50,M1,50, M5,25,M3,25,M2,25,M1,25,M2,25,M1,100,M1,150,Z0,30
		//从前初识这世间 万般留恋 看着天边似在眼前 也甘愿赴汤蹈火去走它一遍
		M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,M5,25,M6,25,M6,25,M5,25,M6,25,M5,25,M6,50,M5,25,M2,25,M2,25,M5,50,M5,50,M3,100,M3,100,Z0,25,
		//如今走过这世间 万般留恋 翻过岁月不同侧脸 措不及防闯入你的笑颜
		M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,H3,25,H3,25,H3,50,M5,50,M6,50,H3,25,H3,25,H3,25,M5,50,M6,25,M6,100,M6,100,M6,100,Z0,25,
		//我曾难自拔于世界之大 也沉溺于其中梦话
		H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25,H3,25,H3,50, H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,
		//不得真假 不做挣扎 不惧笑话
		H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
		//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
		H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
		//短短的路走走停停  也有了几分的距离
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,25,M3,25,M2,25,M1,25,L6,100,Z0,10,
		//不知抚摸的是故事还是段心情
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,M2,100,Z0,50,
		//也许期待的不过是与时间为敌
		M2,50,M2,50,M1,25,M2,50,M2,50,M1,25,M2,50,M3,50,M5,50,M3,50, M2,50,M2,50,M3,25,M2,50,M1,50,L6,100,Z0,10,
		//再次见到你 微凉晨光里 笑的很甜蜜
		M3,25,M2,25,M1,25,M2,25,M1,100, M3,25,M2,25,M1,25,M2,25,M1,50,M1,50, M5,25,M3,25,M2,25,M1,25,M2,25,M1,100,M1,150,Z0,30,
		//从前初识这世间 万般留恋 看着天边似在眼前 也甘愿赴汤蹈火去走它一遍
		M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,M5,25,M6,25,M6,25,M5,25,M6,25,M5,25,M6,50,M5,25,M2,25,M2,25,M5,50,M5,50,M3,100,M3,100,Z0,25,
		//如今走过这世间 万般留恋 翻过岁月不同侧脸 措不及防闯入你的笑颜
		M1,50,M2,50,M3,50,M1,50,M6,50,M5,25,M6,25,M6,50,M6,50, M1,25,M7,50,M6,25,M7,25,M7,100,Z0,5, M7,50,M6,25,M7,25,M7,50,M3,50,H1,25,H2,25,H1,25,M7,25,M6,50,M5,50, M6,50,H3,25,H3,25,H3,50,M5,50,M6,50,H3,25,H3,25,H3,25,M5,50,M6,25,M6,100,M6,100,M6,100,Z0,25,
		//我曾难自拔于世界之大 也沉溺于其中梦话
		H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25,H3,25,H3,50, H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,
		//不得真假 不做挣扎 不惧笑话
		H2,50,H1,25,M6,25,M6,25,H1,50, M6,25,H2,25,H1,25,M6,50,M6,25,H1,50,H1,50, H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,Z0,25,
		//我曾将青春翻涌成她 也曾指尖弹出盛夏 心之所动且就随缘去吧
		H1,50,H2,50,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50, H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H3,50,H3,50, H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,100,H1,100,Z0,10,
		//逆着光行走任风吹雨打吧
		M6,25,H3,50,H3,50,H2,50,H1,25,M6,25,M6,25,H3,50,H2,50,H1,25,M6,25,M6,25,H1,50,H1,50,H1,50,H1,100,Z0,25,
		//晚风吹起你鬓间的白发 抚平回忆留下的疤
		H1,50,H2,50,H2,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,25, H3,25,H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,25,H3,50,H3,50,Z0,5,
		//你的眼中明暗交杂 一笑生花 暮色遮住你蹒跚的步伐
		H2,50,H1,25,M6,25,M6,25,H1,50,M6,25,H2,25,H1,25,M6,50,M6,50, H1,50,H1,50,H3,100,H3,25,H4,25,H3,50,H3,25,H2,50,H2,50,H1,100,H2,100,H3,100,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H2,50,
		//走进床头藏起的画 画中的你(低着头说话)
		H3,50,H6,25,H5,25,H5,50,H6,25,H5,25,H5,50,H6,25,H5,25,H3,100,H3,50,H2,50,H1,25,M6,25,M6,25,H3,50,H3,50,H2,50,H1,25,M6,25,M6,25,H1,100,H1,50,Z0,5,
		//我仍 了 以爱之名你还愿意吗(衔接头有问题)
		H1,50,H2,50,H1,50,H1,100,M6,25,H3,50,H3,50,H2,50,H1,25,H6,25,H6,25,H3,50,H3,50,H2,50,H1,25,H6,25,H6,25,H1,50,H1,50,H1,100,Z0,5
	};
	int length = sizeof(wind_rise)/sizeof(wind_rise[0]);
	
	for(int i=0;i<(length/2);i++)
	{
		buzzer_on(wind_rise[i*2],260);
		HAL_Delay(wind_rise[i*2+1]*5);
	}
}

ビデオを開いてデモンストレーション効果を確認できます 

孤独な勇者を演じるブザー

おすすめ

転載: blog.csdn.net/weixin_49821504/article/details/126783445