学習メモ|重要な原理|デバウンス|ボタン照明の 4 つのモード|STC32G マイクロコントローラー ビデオ開発チュートリアル (Brother Chong)|エピソード 7: ボタン照明

エピソード 6 (パート 2) 放課後演習の答え: SOS 遭難照明プログラミング

遭難信号の原理

出典: Asking Knowledge: SOS をライトでどのように表現しますか?
短い 3 つ、長い 3 つ、短い 3 つ
SOS は世界共通の遭難信号です。光信号で表すと、3 つの短いライトは S の文字を表し、3 つの長いライトは文字を表します。ライトは文字 O を表し、その後に続く 3 つの短いライトは S を表します。
ライトの長い点灯時間は短い点灯時間の3倍、短い点灯時間はLEDの2つの点灯時間の間隔と同じであり、また、文字間の短い点灯時間の3倍の消灯間隔があります。そして次の手紙。

Chongge コードと分析

モジュール設計:

math.h:

#ifndef __MATH_H  //if no define
#define __MATH_H

#include "stc.h"		//调用头文件,具体引用路径根据options选择的调用路径而定
#include "usb.h"

#define MAIN_Fosc 24000000UL		//定义一个IRC系统时钟

int  Add( int parm1,int parm2  );		//加法
int  Sub( int parm1,int parm2  );		//减法
int  Mul( int parm1,int parm2  );		//乘法


void SOS_Led(void);
void delay_ms(u16 ms);	//unsigned int


#endif

math.c:

関数定義を追加します。

#include "math.h"

int  Add( int parm1,int parm2  )
{
	return parm1 + parm2;
}


int  Sub( int parm1,int parm2  )
{
	return parm1 - parm2;
}

int  Mul( int parm1,int parm2  )
{
	return parm1 * parm2;
}



void SOS_Led(void)
{
	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);
	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);
	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);

	P60 = 0;			//点亮
	delay_ms(500);
	P60 = 1;			//熄灭
	delay_ms(500);
	P60 = 0;			//点亮
	delay_ms(500);
	P60 = 1;			//熄灭
	delay_ms(500);
	P60 = 0;			//点亮
	delay_ms(500);
	P60 = 1;			//熄灭
	delay_ms(500);

	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);
	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);
	P60 = 0;			//点亮
	delay_ms(200);
	P60 = 1;			//熄灭
	delay_ms(200);

	delay_ms(3000);

}

void delay_ms(u16 ms)	//unsigned int
{
	u16 i;
	do
	{
		i = MAIN_Fosc/6000;
		while(--i);
	}while(--ms);
}

メインプログラムのdemo.c: #include "math.h" で、メイン関数本体のmain()関数でSOS_Led()を直接呼び出して、SOS関数を実装します。
まず、ヘッダー ファイル math.h に void SOS_Led(void) と void late_ms(u16 ms) の関数宣言を配置します。

次に、 void SOS_Led(void) と void late_ms(u16 ms) の関数定義を math.c に移動します。

MAIN_Fosc は遅延関数で使用されるため、増やす必要があります。main.c 内:

#define MAIN_Fosc 24000000UL  //#define 名称 需要定义的内容

一方、メインプログラム部分

while(1)		//死循环
	{
		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();


			printf("计算Add( 1,2 )结果为:%d\r\n",Add( 1,2 ));

			printf("计算Sub( 5,2 )结果为:%d\r\n",Sub( 5,2 ));

			printf("计算Mul( 5,3 )结果为:%d\r\n",Mul( 5,3 ));

		}
		P40 = 0;	//三极管引脚输出低电平

		SOS_Led();
	}

通常通りにコンパイルし、フラッシュを開始します。

ボタンの照明(下)

1.ボタンの原理

ボタンは奇妙に見えますが、本質的には 2 つのピン間の接続です。
ここに画像の説明を挿入
ボタンを押した後に2つのピンが接続される場合と、
ボタンを押した後に2つのピンが切断される場合があります。
回路図:
ここに画像の説明を挿入
ボタンが押されていない場合、プルアップ抵抗があります。これは完全な切断信号です。
マイクロコントローラーの 3.2 ピンは VCC に接続されています。VCC は R10 および R82 を介して P3.2 INT0 の IO ポートに流れます。ボタンを押すと、抵抗の後部が GND に接続され、
配線のすべての位置が 0V になります。R10 は IO ポートを保護するための電流制限抵抗です。分析後、押されていない場合は高レベル、押されている場合は低レベルになります。
上記の方法を使用して、ボタンが押されたかどうかを判断できます。

ヒント: キーストロークの排除

ボタン SW17 が放されると P3.2 はハイレベルになり、ボタンが押されると P3.2 はローレベルになるとします。
ボタンはメカニカルです. メカニカルスイッチを押して飛び出すと振動します. 振動時間は下図の通りです.
ここに画像の説明を挿入
ローレベルが10ms後に再び検出されます. まだローレベルの場合は, 10ms は処理が必要なデバウンス時間です。
押したり放したりする過程で、電圧は上下に変動します。

2. キーコード実装プロセス

サンプルコード 1:

if( KEY == 0 )
{
    Delay_ms(10);
    if( KEY == 0 )
        {
        执行功能
        }
}

サンプルコード 2:

if( KEY == 0 )
{
    Delay_ms(10);
    if( KEY == 0 )
        {
        while(KEY == 0);
        执行功能
        }
}

プロジェクト例

テンプレート プロジェクト フォルダー 1.C-Printf をコピーし、名前を変更します。 3. ボタン コントロール LED。
概略図に従って、2 つの KEY を定義します。

#define KEY1 P32  //定义一个按键引脚KEY1
#define KEY2 P33  //定义一个按键引脚KEY2

Delay_ms 関数をコピーして宣言します。
制御コードを追加します。

		if( KEY1 == 0 )
			{
				Delay_ms(10);
				if( KEY1 == 0 )
					{
						printf("按键P32已经按下!\r\n");

					}
			}
		if( KEY2 == 0 )
			{
				Delay_ms(10);
				if( KEY2 == 0 )
					{
						printf("按键P33已经按下!\r\n");

					}
			}

シリアルポートの印刷出力

ここに画像の説明を挿入

3. ボタンの応用

  • 3.1 ボタンを押すと LED が点灯し、離すと消灯します
    コード P22 = 0 と P23 = 0 を追加すると LED が点灯しますが、ボタンを放しても消灯しません。
    解除と消灯を実現するための判定も追加する必要があり、基板上の元のインジケーターライトは同じ状態でオン/オフになります。
    完全なコード:
		if( KEY1 == 0 )
			{
				Delay_ms(10);
				if( KEY1 == 0 )
					{
						printf("按键P32已经按下!\r\n");
						P22 = 0;

					}
			}
		else //如果没有按下
			{
				P22 = 1;
			}

		if( KEY2 == 0 )
			{
				Delay_ms(10);
				if( KEY2 == 0 )
					{
						printf("按键P33已经按下!\r\n");
						P23 = 0;

					}
			}
		else //如果没有按下
			{
				P23 = 1;
			}
  • 3.2 ボタンを押すと LED が消灯し、放すと点灯します
    P22 と P23 ポートのレベルを反転し (invert~ 操作を使用するだけです)、ボタンを放すと、元の点灯とは逆に点灯します。ボードインジケータライトの状態。
    実装コード:
		if( KEY1 == 0 )
			{
				Delay_ms(10);
				if( KEY1 == 0 )
					{
						printf("按键P32已经按下!\r\n");
						P22 =  0;  //实现按下点亮,抬起熄灭
						//P22 = !0;  //取反操作实现按下熄灭,抬起点亮

					}
			}
		else //如果没有按下
			{
				P22 =  1;
				//P22 = !1; //取反操作实现按下熄灭,抬起点亮
			}

		if( KEY2 == 0 )
			{
				Delay_ms(10);
				if( KEY2 == 0 )
					{
						printf("按键P33已经按下!\r\n");
						P23 =  0;  //实现按下点亮,抬起熄灭
						//P23 = !0;  //取反操作实现按下熄灭,抬起点亮

					}
			}
		else //如果没有按下
			{
				P22 =  1;
				//P23 = !1; //取反操作实现按下熄灭,抬起点亮
			}
  • 3.3 ボタンを 1 回押すと、LED の状態が 1 回変化します
    最初の考え方は、ボタンを押すと IO 状態が反転し (P23 = !P23)、
    押した後の待機状態は間違っています。遅延を増やす必要があります: Delay_ms(200); //検出が速すぎるのを防ぎますが、
    ボタンを長押し (押し続ける) と LED が点滅します。1 回だけ実行する制限コードを追加する必要があります。
						printf("按键P33已经按下!\r\n");
						P23 =  !P23; //LED取反1次
						while( KEY2 == 0 ) //如果按键一直是按下,一直空循环,实现只执行1次
						{

						}

リリースしてから実行するように変更できますか? マニュアルの側面を長押しするのと同様に、コードを見てください。

						while( KEY2 == 0 ) //如果按键松开,则结束空循环,则执行以下程序
						{

						}
						printf("按键P33已经松开!\r\n");
						P23 =  !P23; //LED取反1次
  • 3.4 ボタンを 1 回押すと、LED が左に 1 ステップ移動します (流れる光の効果)。
    ライトのグループを操作するには、例として P2 を取り上げます
    : P2 = 0xFE; //1111 1110 初期状態を設定します。
    ここに画像の説明を挿入
    初期状態では、一番右のライトが先に点灯し、1111 1101が
    左に1桁ずらして2番目のライトが点灯し、右が最後の桁になります0を加えると1番目と2番目のライトが両方点灯します, 1111 1100 であり、変更は
    ライトのみを点灯したい場合は +1 操作が必要で、次のようになります: 1111 1101 2 番目のライトのみがオンです。
    ここでは、別の変数を使用して計算し、P2 ポートを使用します。特定のキーを押した後のステータスが取得され、値が割り当てられます。
u8 LED_Data = 0XFD; //8个2进制位的变量
P2 = LED_Data;  //1111 1110 设定初始状态

制御コード:

		if( KEY2 == 0  )	//判断按键有没有按下
		{
			Delay_ms(10);
			if( KEY2 == 0 )		//按键确实按下了
			{
				printf("按键P33已经按下,led左移一个\r\n");

				LED_Data = ( (LED_Data<<1) +1 );		//本来是直接输出P2,先计算,后输出


				if( LED_Data == 0xFF )
					LED_Data = 0xFD;

				P2 = LED_Data;
				while(KEY2 == 0);		//如果按键一直是按下的,一直执行while
										//while函数体如果无实际执行需要,即花括号内为空,可以直接跟;结束语句,
//				{
//
//				}

			}
		}

: while 関数本体が判定のみに使用され、実際のコードを実行する必要がない場合、つまり中かっこが空の場合は、ステートメントを直接「;」で終了できます。
STC-ISP シリアル ポート ツールの設定
シリアル ポート出力データを簡素化するために、表示プログラムに文字を送信するためのシリアル ポート ツールの簡略化された設定を実行できます。
ここに画像の説明を挿入

宿題: P32 (KEY1) を 1 回押すと、ライトが 1 つ右に移動します。

  • 4.
    配列の使用 配列の使用は 2 つのステップに分かれています
    。 1.
    型名 [長さ] = {値} を定義します。
    ここに画像の説明を挿入

たとえば、流水ランプを実装するには、いくつかの状態は次のとおりです。
1111 1110 0XFE
1111 1101 0XFD
1111 1011 0XFB
1111 0111 0XF7
1110 1111 0XEF 1101 1111 0XDF 1011 1111
0XBF 0111 1
111
0 X7F
がランニング ライトを実装したい場合は、上記ステータスを直接出力します。
たとえば、メインの while ループの最後の行にテスト コードを追加します。

		P2 = 	0XFB;	Delay_ms(500);
		P2 = 	0XF7;	Delay_ms(500);
		P2 = 	0XEF;	Delay_ms(500);
		P2 = 	0XDF;	Delay_ms(500);
		P2 = 	0XBF;	Delay_ms(500);
		P2 = 	0X7F;	Delay_ms(500);

効果:流水ランプが右から左に500msずつ点灯し、順次点灯します。
2.
割り当てを使用します: name [index] = value
. 前述の流水ランプを例にとると、データは次のとおりです: 0XFB、符号なし 8 ビット、インデックス (総データ量) は 8、定義データは次のとおりです。

u8 LED_DataTab[8] = {0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F};

縦列選択文字:選択したい文字の左側をカーソルで選択し、alt+shiftを押しながらドラッグして選択したい行または列を選択し、反転してコピーできます。
変数 num を使用して流水ランプを実装します。

		P2 = 	LED_DataTab[num+1]; Delay_ms(500);//1111 0111  0XF7
		num++;

上記のコードは、流水ランプを一度実装すると、すべてオンになります。
問題のトラブルシューティングとその理由: num++ には範囲があり、制限する必要があります: if (num > 7) num = 1; //num は 7 までしか指定できません。7 に達すると、1 から開始して右端に戻ります。 。
照明制御は、LED_DataTab 配列の値を変更することで実現できます。たとえば、値が割り当てられている場合: LED_DataTab[3] = 0XFD;、最初のライトは 3 回目でも点灯します。
データを自由に変更して、派手な照明を実現できます。

要約する

1. キーの使用方法を学ぶ
2. 配列をマスターする

授業後の演習: ボタンを押して、LED 出力をさまざまな効果に切り替えます。

4 つのライトと 4 つのライトが点灯する、または 3 つのライトと 3 つのライトが点灯する、2 つと 2 つのライトが左に移動する、というようになります。主要な機能を実装するためのコーディングに熟練している。

おすすめ

転載: blog.csdn.net/Medlar_CN/article/details/132360277