mysqldumpでフルバックアップとリストア
MySQLのバックアップにはいくつか方法があります。その中でも最もオーソドックスな方法であるmysqldumpを使った方法についてまとめておきます。
mysqldumpを使った方法の特徴としては
- 手軽である
- 無停止でバックアップが取れる(オンラインバックアップ)
- データのダンプを出力する(論理バックアップ)
- リストアに時間がかかる
などがあります。
1. セットアップ
2. ダンプの取得
以下のようにmysqldumpコマンドを使いダンプデータを取得します。
$ sudo mysqldump example > backup/backup-$(date +%Y%m%d).sql
以上です。簡単。
リストア
リストアのためDROP TABLE
しておきます。
リストアの際には先ほどのダンプデータをリダイレクトで入力するだけ。
$ sudo mysql example < backup/backup-20181029.sql
リストアも簡単。
全てのデータベースをバックアップしたい
--all-databases
オプションを使います。
$ sudo mysqldump --all-databases > backup/backup-$(date +%Y%m%d).sql
これならDROP DATABASE
した状態でも以下でリストア可能。
$ sudo mysql < backup/backup-20181029.sql
バックアップを圧縮して取りたい
gzip
にパイプすれば圧縮も簡単。
$ sudo mysqldump --all-databases | gzip > backup/backup-$(date +%Y%m%d).sql.gz
リストアもgunzip経由で。
$ gunzip < backup/backup-20181029.sql.gz | sudo mysql
cronで定期的にバックアップしたい
最後にcronの設定をしてみます。MySQL接続のため.my.cnf
は事前に設定しておきましょう。
例えば毎日午前3時にバックアップを取りたかったらcrontab -e
に以下を追加します。
0 3 * * * /usr/bin/mysqldump -u root --all-databases > /path/to/home/backup/full-$(date +\%Y\%m\%d).sql
参考
MySQLサーバーの設置
チュートリアルなどでMySQLサーバーが欲しいことがよくあるので手順をまとめておきます。OSはUbuntu18.04TLSです。
【参考】
1. インスタンスの作成
自分の環境に合わせてインスタンスをセットアップします。今回はGCP上に設置します。
$ gcloud compute instances create mysql-example3 --machine-type=f1-micro --image=ubuntu-1804-bionic-v20181029 --image-project=ubuntu-os-cloud Created [https://www.googleapis.com/compute/v1/projects/playground-192621/zones/europe-west1-b/instances/mysql-example3]. NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS mysql-example3 europe-west1-b f1-micro 10.132.0.5 35.205.118.215 RUNNING
2. 作成したインスタンスにSSHする
$ gcloud computh ssh mysql-example3
3. mysqlのダウンロード
$ sudo apt-get update && sudo apt-get install -y mysql-server
これだけ。一応ps aux | grep mysql
で確認しておきます。
4. .my.cnf
の設置
便利のためにホームディレクトリに.my.cnf
ファイルを設置しておきます。中身はこんな感じ(userとpassは適宜変えてね)。
[client] user = root password =
5. ダミーデータの作成と導入
ここのサイトでダミーのデータを簡単に作れます。
6. .sql
ファイルを作成したらインスタンスに送る。
$ gcloud compute scp data.sql mysql-example3:~
7. データベースの作成
$ sudo mysql -e 'create database example;'
7. リダイレクトでmysql
コマンドに繋ぐ
$ sudo mysql -- example < data.sql
ここまで5分でできるようになろう。
【メモ】AWKについて
AWKについて調べた際のメモおよび「『シェル芸』に効くAWK処方箋」の読書メモです。
- マニュアルはここ(あとで読む)
- 【 awk 】コマンド(基本編)――テキストの加工とパターン処理を行う
awk ‘pattern {action}’ filename
$番号
でフィールドを指定- スクリプトをファイルに保存して実行することもできる
- 入力の一行目を削除したい場合はパイプラインの前段に
sed 1d
を通しておく - いくつか組み込み変数がある
- デフォルトで拡張正規表現でパターンの位置に
/pattern/
で記述する &&
や||
で条件をつなぐことができる~
はマッチ演算子で例えば$4 ~ /pattern/
というようにどのフィールドのマッチングをとるか指定できるBEGIN { … }
で全行処理前のアクション、END { … }
で全行処理後のアクションを記述できる- アクション内では複数の処理を実行してもいい
- shebangは
#! /usr/bin/awk -f
- 一行単位の処理では不可能な条件分岐は制御構文を使う
- if, switch ~ case, while, do ~ while, forなど一通り使える
- いくつかの組み込み関数が使える
- [初心者向け]Awkの使い方
- AWKのまとめ
- 関数定義は
function name(args) { … }
で記述できる
- 関数定義は
- AWK リファレンス
- AWK - wikipedia
- awk とはどんな言語か
- AWKコマンドの使い方
- getline関数で次の行を取得できる
- 実例でわかる awk: 第 1 回
- はじめてのAWK
- Getting Started with awk
- なるべく書かないawkの使い方
- 実用 awk ワンライナー
- 「シェル芸」に効くAWK処方箋
- 第1章:導入
- 第2章:行操作
- 第3章:列操作
- 第4章:文字列関数
- AWKのインデックスは1から始まるので注意
- substr関数とindex関数の組み合わせで文字列を抜き出す
- match関数は組み込み変数に結果を代入するので後から参照できる
grep -o
と等価なので文字数の少ないそっちがおすすめ
- sub/gsubの返り値は置換した個数であり置換結果ではないので注意
- 第5章:数値演算
- 数字は全て倍精度不動少数点数扱い
- 第6章:配列・連想配列
- 配列はインデックスが数値、連想配列は文字列なだけで同じデータ構造
for i in array
でループ処理できるがiに入るのは値ではなくインデックス- split関数で手軽に配列を作成できる
if “key” in array
で配列の検査ができる
- 第7章:GNU AWKの拡張機能
- match関数の第3引数でマッチした値を参照できる
- 第8章:パイプ
- 第9章:GNU拡張とCSVファイルの扱い
- 第10章:もっとGNU拡張
- 第11章:実践
- 第12章:Podcastダイジェスト
まとめ
- awkはAWKという処理系の実装であり両者は別物
awk ‘pattern {action}’ [filename]
、特にパターン・アクションの組み合わせの集合が全て- 独立したスクリプト言語なのでサーバプログラムも作れる
とりあえずなんとか読むことはできるはず。書けるようになるのはまた今度頑張る。
【読了】新しいシェルプログラミングの教科書
一介のソフトウェアエンジニアとしてシェルスクリプトくらいさらさらと書けますよね?......僕は書けません。というわけで「新しいシェルプログラミングの教科書」を読んだのでその際のメモです。
- Chapter01: シェルとは
- Chapter02: シェルスクリプトとは
- Chapter03: 基本
- Chapter04: 変数
- 値は文字列として解釈される
- $をつけて参照
- 明示的に参照するときは${}で囲む
- 変数のすぐ後ろに入力がある時使える
- 環境変数 = コマンドに引き継がれる変数
- コマンドから参照できるかどうか
- exportで変数を環境変数にする
- 慣例として変数名を大文字にする
- $1, $2, $3 … でスクリプトに渡された引数を参照できる
- $*, $@で全てを一度に参照できる
- 通常は$@で参照
- IFSは区切り文字を表し、参照する際は
echo "$IFS" | od -a
とする - 特殊パラメータ
- $# ... 引数の個数
- $? ... 前回コマンドの終了ステータス
- $$でプロセスIDを取得、tmpのファイル名などに利用
- declareコマンドで変数の型を宣言できる
- 整数型の場合代入の右辺は算術評価される
- 配列の宣言はvar=(a b c)、要素の参照は${var[i]}、追加は
var+=(value1 value2)
、削除はunset var[i]
、要素数の取得は${#var[@]}
- 連想配列を作る際はdeclare -Aで明示する必要がある
- Chapter05: 展開・クオーティング
- 展開の種類 ... パス名展開、ブレース展開、チルダ展開、パラメータ展開、コマンド置換、算術評価・展開、プロセス置換、履歴展開
- パス名展開
- マッチするファイルが存在する場合のみ有効
- 正規表現とまた違うマッチング規則なので注意
- ドットで始まるファイルを展開したいときは明示する必要がある
- ブレース展開
- マッチするファイルがなくてもいい
- 新しいファイルを作るときなどに利用
- マッチするファイルがなくてもいい
- チルダ展開
- ホームディレクトリのパスの展開
- パラメタ展開
- $varとか${var}とかのこと
- ${name:-value} ... デフォルト値の指定
- ${name:=value} ... デフォルト値を代入して返す
- ${name:?value} ... 値がない時のエラーメッセージの指定
- それぞれ
:
を除くと値が未設定の時のみの動作になり、空文字のときは空文字がそのまま返る - ${name:index:length}で文字列のスライシングができる
- ${#name} ... 文字数が返る
- ${name#pattern} ... 先頭から最短マッチでpatternを切り落とす
- ファイル名の取得
${path##*/}
- ファイル名の取得
- ${name%pattern} ... 末尾から最短マッチでpatternを切り落とす
- ディレクトリ名の取得
${path%/*}
- ディレクトリ名の取得
- それぞれ記号を二つ重ねると最長マッチになる
- ${name/pattern/substring} ... マッチするパターンを置換して返す
- 使い所不明
- コマンド置換
- $()と``は等価
- 算術評価・展開
((算術式))
... 終了ステータスが返る$((算術式))
... 評価結果が返る- exprコマンドでもいいけどこっちの方が早い
- letも等価だが、読みやすさを考えると代入のみに使うのがおすすめ
- プロセス置換
- <()で標準入力が二つ欲しい時にパイプラインの代わりとして使える
- (パイプラインの本質は一時ファイルなんだなー...。)
- 履歴展開
!
から始まる入力でコマンドの実行履歴を参照できる- スクリプトで使うことはまずない
- クオーティングで特殊文字を無効化する
- Chapter06: 制御構造
- 条件分岐
if (条件); then ~ elif ~ else ~ fi
- 条件はコマンドとして実行され、終了ステータスが0のとき真、0以外のとき偽に評価される
[]
はtestという"コマンド"- 演算子は覚えようね;)
- :はヌルコマンドといい、必ず正常終了する
command1 && command2
... command1の終了ステータスが0のときのみcommand2を実行するcommand1 || command2
... command1の終了ステータスが0以外のときのみcommand2を実行する[]
に対して[[]]
を使う最大のモチベーションは"読みやすさ"[[]]
はコマンドではなく構文- パターンマッチも使える
- ループ
for (変数) in (単語リスト) do ~ done
- break、continueが使える
case (文字列) in (パターン1) ~ ;; (パターン2) ~ ;; ... esac
*)
でデフォルト句を表す
- whileとその逆のuntilもあるよ
- 条件分岐
- Chapter07: リダイレクト・パイプ
- 標準入出力がファイルだからリダイレクト(元|先)つまり標準入出力の切り替え先もファイルだよ
(ファイルディスクリプタ番号)> (接続先ファイル)
が基本形&(ファイルディスクリプタ番号)
で他の接続先を指定できる- 標準出力にエラー出力を繋ぐ
2>&1
は定型文
- 標準出力にエラー出力を繋ぐ
- 出力を捨てるときは
/dev/null
を接続先に指定- 標準出力を捨てるのはifの条件部など
- 標準エラーを捨てるのはエラーを無視する時
- 両方捨てる決まり文句は
> /dev/null 2>&1
>
で上書き、>>
で追記(コマンド) <<< (終了文字列) ~ (終了文字列)
でヒアドクが書ける- 終了文字列をクオーティングすることでクオーティングのルールを適用できる
- パイプラインは一時ファイルが本質
{}
、()
で複数コマンドのグループ化ができる- 複数コマンドの出力をまとめて出力したいときとか
{}
は同一プロセス内、()
はサブシェル内で実行される→変数を参照する時注意
- Chapter08: 関数
- 三通りの書き方の中で
(関数名)() { ~ }
が一般的 - ローカルスコープで変数を宣言したいときは必ず
local
を使う - 引数の参照は同様に位置パラメータを使う
return
で終了ステータスを明示的に返すことができる
- 三通りの書き方の中で
- Chapter09: 組み込みコマンド
- :
- 無限ループが作れる
- printf
printf '%s\n' "~"
をよく使う
- command, builtin
- commandは組み込みコマンドと実行可能ファイル、builtinは組み込みコマンドから探す
- type
- コマンドの種別を調べたい時
- shift
- 解析済みの位置パラメータを削除するとき
- オプションの解析とかで意外とよく使う
- set
- 目的が複数あるという意味で一番UNIXらしくないコマンド
- 1)シェルのオプションの表示・変更、2)位置パラメータの設定
- unset
- 変数を削除したい時
- read
- 標準入力から一行取り出すとき
- ループのリスト部によく使う例えば
while IFS= read -r line do ~ done
- 入力行がlineに代入される、変数名を複数指定したときはIFS区切りでそれぞれ代入される
- trap
- 指定したシグナルを補足して指定の処理をする
- 終了前の後処理を記述したいときとか
- wait
- バックグラウンドで実行した処理の終了を待ちたいとき
- exec
- 現在のシェルをコマンドのプロセスに差し替えたいとき
- 現在のシェルのリダイレクト先を変更するときにも使う
- eval
- :
- Chapter10: 正規表現・文字列操作
- Chapter11: シェルスクリプトの実行
- Chapter12: 具体例
- Chapter13: シェル補完の書き方とか
- Chapter14: テスト・デバッグ
まとめ
「新しいLinuxの教科書」が読みやすかったので期待しましたが期待通りでした。シェルスクリプトを学ぼうという方には非常におすすめです。文法がわかったのでどんどん書いて身につけていこうというところですが実務ではあんまり使わないのでどうしたものか......。
7~9月振り返り
久し振りになってしまいました。
やったこと
- 書籍
- はじめて学ぶソフトウェアのテスト技法
- 知識ゼロから学ぶソフトウェアテスト
- ソフトウェアテスト技法
- テスト駆動開発
- 実践テスト駆動開発
- The Art of Software Testing
- リファクタリング
- エクストリームプログラミング
- レガシーコード改善ガイド
- Agile Testing
- オブジェクト指向でなぜつくるのか
- クリーンコード
- アジャイルソフトウェア開発の奥義
- パターンハッチング
- ソフトウェアアーキテクチャ(POSA)
- エンタープライズアプリケーションアーキテクチャパターン
- ドメイン駆動開発
- 不正アクセス対策
- 体系的に学ぶ 安全なWebアプリケーションの作り方
- おうちで学べる セキュリティのきほん
- この一冊で全部わかるセキュリティの基本
- 動かして学ぶ セキュリティ入門講座
- セキュリティコンテストチャレンジブック
- サイバーセキュリティプログラミング - Pythonで学ぶハッカーの思考
- ハッカーの学校
- HACKING:美しき策謀
- Object oriented software construction
今回はテーマが月ごとに1つずつありました。それぞれ7月テスト/TDD・8月オブジェクト指向・9月セキュリティです。このテーマで勉強を始めるにあたって結構な不安がありました。それは設計という正解のないテーマに対して、成長を実感できるか、本を読んだだけで何も変化を感じずモヤモヤして終わるのではないかというものです。結論から言うと心配していたことは全く起こりませんでした。つまり、3ヶ月前の自分と比べて今書いているコードが段違いにきれいになっていることを実感しています。具体的にどうしているかは別の機会に紹介したいと思いますが、TDDを積極的に取り入れています。主なメリットは 1) 仕様漏れを実装前に発見できる 2) 内部実装を知る前にあるべきインターフェイスを検討できる 3) テストさえ通れば中身がどうあれ動くことを確認できるなどです。また今年の頭に読んだもののモヤモヤしていたパターンという分野があります。そのモヤモヤへの答えはケントベックのTDD入門にありました。これまで"良い設計"が実装されるものだとずっと思い込んでいたのですが「設計と実装は互いにフィードバックする」というきれいなコードを書く人にとっておそらく常識といえる考え方に出会えたのはこの三ヶ月で最も価値のあることでした。パターンとの付き合い方がわかったことで本に書かれていることと実際とのギャップが埋まった感覚があります。
セキュリティに関してはテーマは非常に面白かったものの時間不足でした。せめてCTFに参加してみたかったです。
良かった点・反省点・改善点
- ✅いっぱい読んだ
- オブジェクト指向に関わる有名な本は一通り触れることができたと思います。おそらくこの分野の本であればどんな本でもすっと読めるだけのバックグラウンドが揃ったのではないでしょうか。
- ✅即実践
- 仕事にダイレクトに活かせる分野だったのでフィードバックが早く、学んだことを効率よく身につけることができました。
- ❌本しか読んでない
- インプットのチャンネルを増やしたいと思う次第です。
- ❌学習のプランが大雑把だった
- 目標を設定するのが難しかったし、前提の知識が少なかったため想像しにくい部分もありましたが、やはり目標があってこそ効率的に学習できるので、プランニングの時間をしっかりとるべきでした。
- ❌アウトプットできなかった
- 正解のないテーマに対してどの角度で切り込んでいけば、本に書いていることをただ紹介するだけではない切り口を見いだせるのかずっと考えていたものの結局思いつくことができませんでした。この先もコードを書く以上常に向き合っていくテーマなのでいつか自分の言葉で語れればと思います。
- それと同時にアウトプットを仕組化する必要を感じています。
この三ヶ月は旅行に熱心になっていて、勉強が途切れ途切れになってしまったのがやや寂しくもあります。今年残り三ヶ月も頑張っていきます。
4~6月振り返り
やったこと
- 書籍
- 30日でできる! OS自作入門
- はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ
- プログラムはなぜ動くのか 第2版 知っておきたいプログラムの基礎知識
- オペレーティングシステムの仕組み
- Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識
- はじめて読む486―32ビットコンピュータをやさしく語る
- Linuxカーネル2.6解読室
- BareMetalで遊ぶ Raspberry Pi
- コンピュータの構成と設計 第5版 上 (途中まで)
- UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI (途中まで)
- Unix考古学 Truth of the Legend
- Raspberry Pi
- 書いたもの
- その他
学んだことに関する振り返りは以下にまとめました。
当初はOSの勉強というテーマで、Linuxディストリビューションや運用など上の方に伸びていくことを想定していましたが、CPUやハードウェアなど低いレベルの方向に向かってしまいました。実務に直接役立つ知識は得られませんでしたが結果オーライだと思っています。動機は記事にも書いたように「基礎を知れば最新技術に素早く対応できる」という説を確かめることです、がもう少し掘り下げたいと思います。学生時代の陸上で経験したことの一つに「身体能力を十分高めた(雑に言えば筋トレを頑張った)人の方が技術面の向上も早く、記録の伸びが大きい」という発見、もっと言えば反省がありました。プログラマとしてこれまで新しいことを学んでも上滑りする、思ったように理解が深まらない、と感じる原因の一つとしてプログラミングにおける基礎能力の不足があるのではないかという疑問を抱いていました。コンピュータサイエンスの知識を基礎能力とする妥当性はさておきこれが今回システムを学んだ背景です。3ヵ月の勉強ではこれが正しい(あるいは間違っている)と確信するには至りませんでしたが、「システムプログラミングを学ぶのは楽しい」という発見がありました。前回学んでいた機械学習は「面白いけどもういいかな」という分野でしたがシステムの勉強はまだ興味が尽きないという意味で割に自分に向いている、と言えるかもしれません。コンパイラなど触れていないトピックはたくさんあるので、一度時間を置いてまた帰ってきたいと思います。
良かった点・反省点・改善点
- 実際に手を動かした
- 実際に手を動かすことが学習効率に影響することは認識していたため、当初から題材を探していました。Raspberry Piという案を閃き、実際にハードウェアと格闘しながらシステムについて学べたのは非常に大きかったです。最終的な成果を出すところまでは至りませんでしたが、手を動かして学ぶことの重要性を再認識しました。今後も強く意識して続けて行きたいと思います。
- 中だるみしてしまった
- Raspberry Piに実際システムを組んでみる段階に至って、ハードウェア開発の難しさからモチベーションを維持するのが難しくなってしまいました。加えて旅行が立て込んである期間すっぽり抜けてしまったため最後中途半端な形で終えてしまったのは非常に残念です。旅行が続いたのは季節柄なので仕方ないとして、モチベーションを維持する工夫の必要性を感じました。定期的なアウトプットを自分に課す、など思い浮かびますがみなさんどうしているのでしょう。
- より多角的に学べた
- 前回の反省を活かし、なるだけ多くの資料を手元に用意して、読んだり読まなかったり一部だけ読んだりといろんな角度から学ぶことで立体的な知識を得ることができました。
- (ついに)英語でのアウトプットを始めた
- たったのブログ一本、しかも日本語で書いたことの翻訳ですが英語でのアウトプットを果たしました。今後もコンスタントに続けていけたらいいなと思います。
【Raspberry Pi】システムタイマ
Raspberry PiでLチカ - 技術について語るときに僕の語ることでLED点滅をしたときにdelay(50000)
という関数を使いましたが、「CPU50000クロックってどんだけやねん」という話なのでシステムタイマを利用して秒で指定できるようにしたいと思います。
なお主に以下の書籍の第5章およびサンプルコードを参考にしています。
- BareMetalで遊ぶ Raspberry Pi - 達人出版会
- RPi_Micon_C85book/timer.c at master · jitomesky/RPi_Micon_C85book · GitHub
システムタイマ
システムタイマのレジスタもGPIOと同じようにメモリマップト方式でメモリ上にマップされています。ペリフェラルマニュアルのp.172を参照するとシステムタイマが0x20203000
に存在することがわかります1。
システムタイマもいくつかレジスタを持ちますが今回は64bitのフリーランニングカウンタを使いたいと思います。
get_systime()関数
システムタイマの値を読む、get_systime()関数を定義します。
uint64_t get_systime(void) { uint32_t clo, chi; chi = *(volatile uint32_t *) 0x20003008; clo = *(volatile uint32_t *) 0x20003004; return (chi << 32) + clo; }
先ほどのフリーランニングカウンタは32bitずつLOWとHIGHの2つのレジスタに分かれており、メモリ上アドレスはそれぞれ0x20203004
と0x20203008
になります。それぞれclo、chiに読み込んだのち、HIGHを32bit分繰り上げLOWを足して返しています。
ここでもしHIGHを読んだ直後、LOWを読む前にLOWがオーバーフローした場合、HIGHの値がインクリメントされてしまうので以下のようにもう一度読み直すことでこれに対応します。なおオーバーフローの間隔は70分程度あるので一回チェックすれば十分です。
uint64_t get_systime(void) { uint64_t t; uint32_t clo, chi; chi = *(volatile uint32_t *) 0x20003008; clo = *(volatile uint32_t *) 0x20003004; if (chi != *(volatile uint32_t *) 0x20003008) { chi = *(volatile uint32_t *) 0x20003008; clo = *(volatile uint32_t *) 0x20003004; } t = (chi << 32) + clo; return t; }
delay_s()関数
このget_systime()関数を使って秒で指定するdelay関数を作りたいと思います。流れは以下の通りです。
- 現在時刻+delayを目標時刻とする。
- ループ条件で現在時刻を再度取得し、目標時刻を過ぎていたらループを抜ける。
関数は以下の通りです。
void delay_s(uint32_t delay) { uint64_t target = get_systime() + delay * 1000 * 1000; // 1 while (get_systime() < target); // 2 return; }
再びLチカ
点灯と消灯の間にdelay_s()関数を挟んでLEDを点滅させます。
void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { (void) r0; (void) r1; (void) atags; *(volatile uint32_t *) 0x20200010 = (1 << 21); while (1) { *(volatile uint32_t *) 0x20200020 = (1 << 15); delay_s(1); *(volatile uint32_t *) 0x2020002C = (1 << 15); delay_s(1); } }
ちなみにPWM的に制御したい時には以下のコードを参考にします。
実装にあたりdelay関数のマイクロ秒版を用意しました。
void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { (void) r0; (void) r1; (void) atags; uint32_t brightness = 255, speed = 16, up = 0; *(volatile uint32_t *) 0x20200010 = (1 << 21); while (1) { if (brightness > 0) { // turn off LED for "brightness" us *(volatile uint32_t *) 0x2020002C = (1 << 15); delay_us(brightness); } if ((255 - brightness) >= 0) { // turn on LED for "255 - brightness" us *(volatile uint32_t *) 0x20200020 = (1 << 15); delay_us(255 - brightness); } // decrement speed speed--; if (speed == 0) { // recover it speed = 16; // if the brightness is getting brighter if (up) { // not maximum yet if (brightness < 255) // increment brightness brightness++; // hit the maximum if (brightness == 255) // go downward up = 0; } else { // LED is getting dimmer // not minimum yet if (brightness > 0) // decrement brightness brightness--; // hit the minimum if (brightness == 0) // go upward up = 1; } } } }
明るさを255段階に分け、255マイクロ秒のうちbrightnessマイクロ秒だけLEDを点灯させます。これをspeed回繰り返したのちup = 1
であれば明るさを一つあげ、up = 0
であれば一つさげ、明るさが0または255に達した時にはupを反転させます。