DATE: 2018/08/16(木)   CATEGORY: Nucleoマウス
Nucleo-32boardを使ったクラシックマウスの開発その15 ~LCD Part 2~

AQM1248AというLCDを使う話の続きです。

最初に復習です。このうち、②まで終わりました。
① LCDの初期化
→初期設定
② 2値化画像データの描画
→LCDの描画方法に慣れる(遊び)
③ フォントの確認
→フォントデータから文字を描画
④ 文字列の出力
→任意の文字列を描画
⑤ 変数の値を出力
→可変長引数関数の勉強

残りを終えてLCDの実装を終えましょう。

・フォントの確認

LCDに文字を出力しましょう。
文字を出すにはフォントデータが重要です。

今回はこちらからフォントデータをいただきました。

漢字表示グラフィック液晶表示ライブラリ

これは5×7ピクセルで描けるフォントデータらしいです。
こちらをfor文で出力してみました。




ありがたいですね。
こういうの無かったら自分で打つのか、、、
ってなってましたね。

しかし、このLCDで出力すると、
文字が小さいので倍サイズで使っています。
1bitあたりを2×2倍にして出力しているだけです。


・文字列の出力

フォントを得たので、
次は任意の文字列を出力できるようにしましょう。

C言語経験者はここは簡単だと思います。
未経験者の人はしっかり学びましょう。
→マウスを走らせるだけならこういう知識はいらないですね

実は文字には一つ一つ数が割り当てられています。
これを文字コードと呼びます。
その中でもアルファベットや記号をでは
ASCIIコード
というものが用いられます。

ASCIIコード表

上の参考記事の最後の部分なんかが分かりやすいです。

例として、
0x48といった値があったとします。
これは文字の'H'としても扱えるってことです。
その逆で文字の'H'は0x48という値としても使えます。


printf("%x\n",0x48); //48と出力される
printf("%c\n",0x48); //Hと出力される


結局今回は何をやりたいかというと、
任意の文字列の値を読む
→対応したフォントデータの配列を読み出す

といった関数を作ればいいわけです。

先ほどいただいたフォントデータは
0x20(スペース)が0として始まっている配列
です。
ということは、
自分が表示させたい文字の位置は、
文字の値-0x20
ということになります。
面倒なので、その他のはエラーにしましょう。

ということで、
そんなことを考えながら以下の出力関数を作ってみました。
引数は、出力位置の指定、コントラスト、任意の文字列としました。
11は1行あたりの最大文字数です。
UARTの_write関数と同じように、
1文字づつ出力していきます。


void printLCDString(uint8_t row, uint8_t column,
uint8_t contrast, char *string) {
int i;
i = 0;

while (string[i] != 0) {
if ((string[i] - 0x20) < 0) {
continue;
}
bigFont(string[i] - 0x20, row + (column + i) / 11,
(column + i) % 11,contrast);
i++;
if (row + (column + i) / 11 >= 3) {
return;
}
}
}


好きな文字列配列を作って出力してみましょう。

出力結果





・変数の値を出力

これで文字列さえあればLCDに任意の文字を
出力できるようになりました。
しかし、UARTのときと同じでこれでは使いにくいです。

ですので、printf的に変数の値を表示できるようにしましょう。
そこで登場するのが、可変長引数関数vsprintf関数です。

可変長引数関数についての説明はこちら

va_list、可変長引数の仕組みを理解してvprintf関数を使う

vsprintf関数についての説明はこちら

vsprintf -C言語関数辞典

流れとしては、
可変長引数で変数の値を複数入力できるようにする
vsprintf関数で文字列化する
文字列出力関数に渡して出力
です。

参考記事をもとに作ってみました。


void printfLCD(uint8_t row, uint8_t column, uint8_t contrast,
const char* fmt, ...) {

va_list ap;
char buffer[1024];

va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
printLCDString(row, column, contrast, buffer);

va_end(ap);

}


これでprintf的に出力できるようになったかと思います。





で完全に余談なんですが、
こんなんLCD以外で何に使うの?
って思ってる人もたくさんいると思います。

Miceのみなさんには大好きな秘伝のタレがありますよね?
あの大変お世話になってきたmyprintf先生です。
あの関数の中身を覗いてみてください。
少しわかった気になれますよ。

そのくらいです。


さて、これでようやく
LED、タクトスイッチ、スピーカー、LCD
と全てのインターフェースが解禁されました。

これらを使って、自分の好きなモード選択関数を作ってみましょう。
モード選択関数の実装は後回しにしがちですが、
やるなら今だと思います。
頑張ってみてください。

スポンサーサイト
DATE: 2018/08/14(火)   CATEGORY: Nucleoマウス
Nucleo-32boardを使ったクラシックマウスの開発その14 ~SPIとLCD Part 1~


SPI通信機能を使って
AQM1248AというLCDを使う話です。
このシリーズを書いていて、
一番書いておきたいポイントだったので楽しみです。

・SPI通信

SPI通信とは??
を説明するのは面倒なので自分で調べてください。
→ググって上から読んでいってわかりやすかったリンクです

「SPI」の解説 -しなぷすのハード製作記

結局、
大事な信号線が4本あって
通信方式はスレーブ側に合わせて
ってことですね。
なるほどなるほど。


・AQM1248A(LCD)

「STUmu」にて使用したLCDは以前紹介した通り
AQM1248Aモジュールを使用します。

こちらのデータシートを見てみますと
こちらも信号線4本で制御するみたいですね。

マイコンとのインターフェース

ん?でもSPI通信で学んだ内容と微妙に違いますね。
そうなんです。
AQM1248AモジュールはMISOの代わりに
RSという信号線がいる
ようです。
つまり、マイコン側は送信のみを行い受信は気にしなくていいようです。

簡単に必要な信号線をまとめますと、
SPI通信線
/CS:チップセレクト
MOSI:マスタ送信スレーブ受信
MISO:マスタ受信スレーブ送信
→いらない
SCLK:クロック

GPIO
RS:データとコマンド選択
→ディスプレイに表示させたいときに切り替える

といった感じですね。

通信規格ですが、こちらもデータシートを読むとわかります。

信号の説明

/CS:アクティブLow
→通信以外はH、通信直前でLにする
MOSI:立ち上がりエッジ、8 bitづつ送信
SCLK:通信以外はH
RS:描画はH、設定はL

これらの仕様がわからない方は下のリンクの図と照らし合わせてみてください。

SPI Transfer Modes


ということなのでCube MXにてこの仕様通りに設定していきます。

PinoutにてSPI1のモードを選びます。
これはマスタ側の送信のみでいいので
Transmit Only Master」を選択
→PA5とPA7が緑になる。
また、GPIOで/CS→PA6、RS→PF1としました。

SPI1の設定

Configurationはこんな感じ
コントローラICのデータシートから最大20 Mbpsで通信できるようですが、
とりあえず半分くらいの通信速度に設定しました。

SPI1Configuration.png


・LCDの開発手順

自分がLCDを使うにあたっての開発手順を示します。

① LCDの初期化
→初期設定
② 2値化画像データの描画
→LCDの描画方法に慣れる(遊び)
③ フォントの確認
→フォントデータから文字を描画
④ 文字列の出力
→任意の文字列を描画
⑤ 変数の値を出力
→可変長引数関数の勉強

Part 1では①、②までやります。


・LCDの初期化

LCDの初期設定をします。
初めに任意のコマンド送信関数を作ります。
HAL_SPI_Transmit関数で送信します。
HAL_SPI_Transmit関数の前後で
/CS及びRSを操作できるようにします。
→GPIOのH/Lできる関数は自分で使いやすいようにまとめてます


void spiWriteAQM1248A(uint8_t txData, uint8_t rs) {
uint8_t txDataAQM1248A;
txDataAQM1248A = txData;

lcdRS(rs);
lcdCS(LOW);
HAL_SPI_Transmit(&hspi1,
    (uint8_t *) &txDataAQM1248A, 1, 1000);
lcdCS(HIGH);

lcdRS(RS_OFF);
}


このコマンド送信関数を使って初期化していきます。
初期化の内容はデータシート通りにしました。
具体的に書かれているのでわかりやすいです。
→ただレジスタマップは死ぬほどわかりにくかった

初期化のみだと、ゴミデータが描画されて不格好なので
resetDisplay関数にてゴミデータを消しましょう。


void initAQM1248A(void) {

lcdCS(HIGH);
lcdRS(LOW);

HAL_Delay(3);
   //Display = OFF
spiWriteAQM1248A(0xAE, RS_OFF);
   //ADC = normal
spiWriteAQM1248A(0xA0, RS_OFF);
   //Common output = reverse
spiWriteAQM1248A(0xC8, RS_OFF);
//bias = 1/7
spiWriteAQM1248A(0xA3, RS_OFF);

HAL_Delay(3);
//power control 1
spiWriteAQM1248A(0x2C, RS_OFF);
HAL_Delay(3);
//power control 2
spiWriteAQM1248A(0x2E, RS_OFF);
HAL_Delay(3);
//power control 3
spiWriteAQM1248A(0x2F, RS_OFF);

HAL_Delay(3);
//Voltage resistor ratio set
spiWriteAQM1248A(0x23, RS_OFF);
//Electronic volume mode set
spiWriteAQM1248A(0x81, RS_OFF);
//Electronic volume value set
spiWriteAQM1248A(0x1C, RS_OFF);

HAL_Delay(3);
//display all point = normal(全点灯しない)
spiWriteAQM1248A(0xA4, RS_OFF);
//display start line = 0
spiWriteAQM1248A(0x40, RS_OFF);
//Display normal/revers = normal(白黒反転しない)
spiWriteAQM1248A(0xA6, RS_OFF);
//Display = ON
spiWriteAQM1248A(0xAF, RS_OFF);

HAL_Delay(10);
resetDisplay();

}

void resetDisplay(void) {

uint8_t pageAddress, columnAddress;

for (pageAddress = 0; pageAddress < 8;
pageAddress++) {
spiWriteAQM1248A((0xB0 | pageAddress),
RS_OFF);
spiWriteAQM1248A(0x10, RS_OFF);
spiWriteAQM1248A(0x00, RS_OFF);
for (columnAddress = 0;
columnAddress < 132; columnAddress++) {
spiWriteAQM1248A(0x00, RS_ON);
}
}

}



・2値化画像データの描画

2値化画像を描画してこのLCDの扱いに慣れましょう。

AQM1248Aモジュールでは描画領域として、
RAMに8行132列だけ用意されています。
しかし、実際に出力できる部分は6行128列分だけらしいです。
→詳しくはデータシート参照

基本的な描画の仕方は、表示領域を変更しない場合
① pageを0xB〇で設定
② 列を0x1〇、0x0〇で設定
③ RSをHにしてその行のデータを送り続ける
→列方向は自動でインクリメントされる

resetDisplay関数でやっているのはこれです。

こちらも詳しくはデータシートをご覧ください。

最後にテスト用の画像データ配列を置いときます。
上手く出せたらこのLCDの扱い方は理解できたかと思います。

これ


DATE: 2018/08/10(金)   CATEGORY: Nucleoマウス
Nucleo-32boardを使ったクラシックマウスの開発その13 ~TIM~


TIMを使った割り込みとPWM出力の話です。

特に新しいことはないのでいつもの通り備忘録です。


・割り込み

TIM機能を使って割り込み処理を行ってみたいと思います。
マウスを走らせる上でタイマー割り込みは欠かせません。

タイマーのカウントの仕組みを理解できていれば、
誰でもすぐに使えると思います。
機能のことでわからないことはリファレンスマニュアルを一読しましょう。

割り込み用のタイマーとしてTIM6を使います。
→TIMにはいくつか種類があり機能が異なるようです。
自分の用途に合わせて使用するTIMを選択しましょう。
リファレンスマニュアル参照。

それではCubeMXを使って設定していきましょう。

今回設定する割り込み周期は1 msとします。

TIM6設定

Timerへの供給クロックは72 MHzにしてあります。
プリスケーラは分周比であるのでカウント周期は、
\[1 \mathrm{MHz} = \frac{72 \times 10^6}{Prescaler+1} \]
となります。
これを1000倍すると1 msで割り込みが行えるので、
画像のような設定になります。
カウント値についても、-1することには気をつけましょう。

次にNVICの設定をしましょう。
TIMの設定をしただけでは、
カウントを数えてくれるようになっただけで割り込みは起きません。
どういう要因で割り込みが起きるかを設定します。

TIM6の割り込み要因

その後、System→NVIC
にて割り込み優先度を決定
します。

設定が終わったらコードを再生成して、
Lチカで動作確認を行いましょう。

まずは、自作のwait関数を作ります。
基本的にTIM内のレジスタを書き換える場合にはマクロ関数を使います。
→説明はHALマニュアルに書いてある


volatile uint32_t g_timCount;

void wait_ms(uint32_t waitTime) {

g_timCount = 0;
__HAL_TIM_SET_COUNTER(&htim6, 0);
while (g_timCount < waitTime) {
}

}


次に実際の割り込み処理を書いていきます。
割り込み関数はstm32f3xx_it.c内に定義されています。

今回は、関数内で割り込み回数を数えるだけでいいのでこれだけです。


void TIM6_DAC1_IRQHandler(void) {
/* USER CODE BEGIN TIM6_DAC1_IRQn 0 */

/* USER CODE END TIM6_DAC1_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC1_IRQn 1 */
g_timCount++;
/* USER CODE END TIM6_DAC1_IRQn 1 */
}


最後にmain文での動作を書いて終了です。
起動関数はいろいろ種類があるので、
用途によってどれを使うか確認しましょう。
何度も言いますが詳しくはHALマニュアルに書いてあります。

今回はカウントして割り込みができればいいので、
HAL_TIM_Base_Start_IT関数を使います。


/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
wait_ms(1000);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */
}


Lチカできたら終了です。


・PWM出力

PWMの出力についてです。
スピーカーを使って確認してみます。

スピーカーはPA8に繋いであるので、
TIM1のCH1を使います。
項目が微妙に異なりますが、
基本は同じですね。

TIM1設定

コードを再生成したら、
HAL_TIM_PWM_Start関数でPWMを出せます。

音が鳴ったら確認完了です。

どうせなので、スピーカーの関数を作りましょう。

参考記事はこちら
タイマを使ったマイコンによる演奏 -AYATAKA WORKs

といっても簡単な物でいいので、
・音程を変えられる関数
・音楽データを再生する関数

くらいあればいいのではないでしょうか。

音程の周波数とカウンタ周期の関係は,
\[カウンタ周期= \frac{1\ \mathrm{MHz}}{目標周波数\ \mathrm{[Hz]}}-1 \]
ですね。

また、音データは音程と長さだけとして構造体を作りました。


typedef struct {
float interval;
uint16_t waittime;
} soundData;

const float DO = 261.626;
const float RE = 293.665;
const float MI = 329.628;
const float FA = 349.228;
const float SO = 391.995;
const float LA = 440.000;
const float SI = 493.883;

uint16_t calSoundCount(float tarHz) {
uint16_t tarCount;
if (tarHz == 0) {
tarCount = 0;
} else {
tarCount = (uint16_t) (1000000.0 / tarHz - 1.0);
}
return tarCount;
}

void playSoundData(uint16_t dataMaxNum
, soundData *playData) {

uint16_t i;
uint16_t cycleCount;

for (i = 0; i < dataMaxNum; i++) {
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
cycleCount = calSoundCount(playData[i].interval);
__HAL_TIM_SET_AUTORELOAD(&htim1 ,
cycleCount);
__HAL_TIM_SET_COMPARE(&htim1,
TIM_CHANNEL_1, cycleCount / 2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_Delay(playData[i].waittime);
}
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
}

#define TESTSOUNDNUM 8
soundData g_testSound[TESTSOUNDNUM];
void inputTestSound(void) {
g_testSound[0].interval = DO * 1.0;
g_testSound[0].waittime = 500;

g_testSound[1].interval = RE * 1.0;
g_testSound[1].waittime = 500;

g_testSound[2].interval = MI * 1.0;
g_testSound[2].waittime = 500;

g_testSound[3].interval = FA * 1.0;
g_testSound[3].waittime = 500;

g_testSound[4].interval = SO * 1.0;
g_testSound[4].waittime = 500;

g_testSound[5].interval = LA * 1.0;
g_testSound[5].waittime = 500;

g_testSound[6].interval = SI * 1.0;
g_testSound[6].waittime = 500;

g_testSound[7].interval = DO * 2.0;
g_testSound[7].waittime = 500;
}







DATE: 2018/07/27(金)   CATEGORY: Nucleoマウス
Nucleo-32boardを使ったクラシックマウスの開発その12 ~UART~

UARTを使ってターミナル上に
printfでHello Worldする話です。

基本的に送信関数しか扱いません。

今回はほぼほぼ自分用の備忘録です。

・UARTの設定

参考記事はこちら。
STM32でUARTをやってみる1 -ガレスタさんのDIY日記

基本的に上の通りでやっていれば、動くと思います。

F303ボードではあらかじめ、
USART2用のピンが接続されています。
間違えないように。

Configurationについてです。
今回はこんな設定にしました。

USART2のConfiguration

これについてですが、
出力先のターミナルと設定を合わせる必要があります。

TrueSTUDIOの場合、あらかじめシリアルターミナル
のプラグインが入っているのでこちらを使って表示させます。


プラグインのターミナル

送信関数についてですが、
しっかりHALのマニュアルを読んでおきましょう。


/* USER CODE BEGIN 2 */
uint8_t hello[] = "Hello World\n\r";
HAL_UART_Transmit(&huart2, hello, sizeof(hello), 1000);
/* USER CODE END 2 */


無事にHello WorldがでればOKです。

HelloWorld.png


・printfについて

UART機能が使えることが確認できました。
しかし、HAL_UART_Transmit関数は任意の文字列を出力できる関数であって、
実際に使うことを考えると不便です。

フォーマット指定子を使える形に対応させます。

参考記事はこちら
STM32でUARTをやってみる6 -ガレスタさんのDIY日記

SW4STM32の場合は参考記事通りにやって動きました。
TrueSTUDIOでも同様の方法でやっていきますが、
少し違う部分もあるので備忘録。

そもそもなんでsyscalls.cが必要なのか。

自分もそこまで詳しくないですが、
printf関数は_write関数という関数に従って出力を行うようです。
_write関数の出力先をUARTに設定することで、
printfの出力先をシリアルターミナルにします。

この_write関数が含まれるのがsyscalls.cみたいです。
→詳しい人が教えてくれると信じたい

まずは、syscalls.cを作ってもらいましょう。
ファイル→新規→C Projectです。
TrueSTUDIOではこうやれば作れました。

Embedded C Project→Atollic ARM Toolsを選択

とりあえずプロジェクト作成

一応ハードウェアを選択

ハードウェアの選択

syscalls.cを生成できるように選択

syscallsの生成を選択

終了→syscalls.cがある

syscallsがある

syscall.cを自分のプロジェクトのSrcにコピーして、
作ったプロジェクトは消しましょう。


次にこのsyscall.cを開いて
_write関数の中身を書き換えます。
このとき、
#include "usart.h"
をすることは忘れないこと。


int _write(int32_t file, uint8_t *ptr, int32_t len) {
/* Implement your write code here,
this is used by puts and printf for example */
/* return len; */

int DataIdx;

for (DataIdx = 0; DataIdx < len; DataIdx++) {
HAL_UART_Transmit(&huart2, ptr++, 1, 1);
}
return len;
}


これは_write関数の中で
文字列を1byteづつ送信する
といった内容です。

これを見て愚か者が想像できる範囲では、
printfの流れは、
① フォーマット指定子に従って値を文字列に変換
② _write関数にて1文字づつ出力する
といった物だということがわかりました。

この「文字列に変換→1文字づつ出力する」
といった流れはLCDのときにも使うので覚えておいてください。
Mice伝統の秘伝のタレも基本は同じです


ところで、これでprintf関数が使えるようになったと思います。
→M_PIを使うには#include <math.h>を忘れない。


/* USER CODE BEGIN 2 */
uint8_t hello[] = "Hello World\n\r";
setbuf(stdout, NULL);
printf("hello=%s", hello);
uint8_t hoge = 3;
printf("hoge=%d\n\r", hoge);
printf("M_PI=%f\n\r", M_PI);
/* USER CODE END 2 */


出力結果

printfの確認

printfが動いてますね。
ん?%fが使えていない??


・floatに対応させる

ではprintfをfloat型に対応させましょう。
といってもその方法も先ほどの参考記事に書いてあります。

プロジェクト→プロパティ→C/C++Build→Settings→Tool Settings→C Linker→Miscellaneous→Other options
に「-u _printf_float」を追加するだけです。

無事にfloat型も出せたら終了です。

float確認


・やっぱりTera Termがいい

シリアルターミナルの話です。
今回はプラグインのシリアルターミナルを使用しましたが、
やっぱりTera Termの方が使いやすいと思いました。
→設定が柔軟にできる。体に染みついている。\rを書きたくない。

設定を保存して、Tera Termをタスクバーに置いておく方が
自分には合っているなと感じたので、
今後シリアルターミナルを使うときがあったら
Tera Termを使います(笑)



あとは余談ですが、
せっかくデバッガが使えるならデバッガのウインドウに
出力してみると面白そうだなと思いました。(参考
→気が向いたら読みたいのでブックマーク代わりに貼る

自分の技術力が足りていなく、
デバッガの使い方がわかっていないのが残念過ぎる。


DATE: 2018/07/26(木)   CATEGORY: Nucleoマウス
Nucleo-32boardを使ったクラシックマウスの開発その11 ~GPIO&クロック設定~


GPIOの使い方とクロックの設定についてです。

前回で開発環境を整え、
HALドライバを用いLチカの確認を行いました。

しかし、え?どこからこの関数見つけてきたの?
と思った方も少なくないと思います。
今回はそういった人のための最低限これは読もうの話です。
→残りは他の設定の備忘録。


HALドライバの使い方は、
検索すればたくさん出てきます。

ですが、それをただコピペして
書いていくことは止めた方がいいです。

いくらHALドライバを使えば簡単と言っても、
知識0で扱えるものではありません。


ある程度自分で学んだ上で、
参考記事を見て理解を深めていくといった開発をお勧めします。
後で動かなくなったときに、詰みます。(戒め)


基本的にはこの2つがあれば大抵なんとかなります。

Description of STM32F3 HAL and low-layer drivers

STM32F3xx Reference Manual

(日本語版)STM32F3xx Reference Manual


・出力ピン

一番簡単なGPIOを例にして、
これらの資料を読む練習をしましょう。
関数がたくさんあってわからない><
という人ほど一度読んで見ることをお勧めします。

基本的にはHALのマニュアルの
各章のHow to use this driverを読めば大丈夫です。
試しに見てみましょう。

GPIOの使い方

1~3は初期化の話です。
これは、MX_GPIO_Init関数(gpio.c)内に書かれています。
CubeMXで設定したことが反映されています。
他のモジュールの場合でも、同様に書いてあります。

今回重要なのは4、5です。(6以降は大したこと書いてないので省略します)

大抵ここら辺に、そのモジュールの使うべき関数が書いてあります。
読んでみると、
入力はHAL_GPIO_ReadPin関数
出力はHAL_GPIO_WritePin関数/HAL_GPIO_TogglePin関数
を使えばいいと書いてあります。

今回は出力なので、
HAL_GPIO_WritePin関数/HAL_GPIO_TogglePin関数
の内容を見にいきます。

HAL_GPIO_TogglePin.png

HAL_GPIO_TogglePin関数は、
特定のGPIOピンの状態を切り替える関数であり、
引数は、GPIOx(xはA~F)とGPIO_Pinで定義された定数を
与えればいいことが読み取れます。
→定義されているマクロも下の方に書いてあります

これで前回の記事のLチカプログラムが理解できるわけです。
また、今回HAL_GPIO_WritePin関数も使えることがわかったので
前回のLチカ関数はこうも書けます。


/* USER CODE BEGIN WHILE */
while (1) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3
, GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3
, GPIO_PIN_RESET);
HAL_Delay(1000);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */


GPIO程度なら、
How to use this driverの章を読むだけで理解できます。
他のモジュールにおいても、
ここだけでも目を通しておけば、
参考記事の内容もすらすら理解できるようになると思います。



あとは備忘録。

・入力ピン

次は入力ピンの設定を行います。
タクトスイッチはPB4とPB5に繋いであるので、
これをGPIO_Inputに設定します。

PB4_5をGPIO_Intputに設定

Configuration→GPIOでPB4,5をPull Upに設定。

InputPinのPullUp

ソースコード再生成でスイッチの動作確認。
→/* USER CODE BEGIN ** */と/* USER CODE END ** */の間に書きましょう


/* USER CODE BEGIN WHILE */
while (1) {
//スイッチの動作確認
while ((HAL_GPIO_ReadPin(GPIOB
, GPIO_PIN_4) == 1)
&& (HAL_GPIO_ReadPin(GPIOB
, GPIO_PIN_5) == 1)) {
}
HAL_Delay(3);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
while ((HAL_GPIO_ReadPin(GPIOB
, GPIO_PIN_4) == 0)
|| (HAL_GPIO_ReadPin(GPIOB
, GPIO_PIN_5) == 0)) {
}
    HAL_Delay(3);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}



・クロック設定

PinoutにてRCCをBYPASS Clock Sourceに設定
→PF0が緑になる

MCOの設定

Clock Configurationにて以下の部分を書き換える。

ClockConfiguration.png

コード再生成にて72 MHzのキレで動作できるようになります。


Copyright © うむ夫の歩み. all rights reserved.