脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

秋月のコイル(SMD Power Inductor) NR10050T100Mのライブラリを作った

以下の秋月のコイルのEagleのライブラリが見つからなかったので作成しました
akizukidenshi.com
データシート
http://akizukidenshi.com/download/ds/taiyouyuden/NR10050T100M.pdf

ライブラリ作成の開始

File > New > Libraryを選択すると新規ライブラリ作成画面が表示される
f:id:portaltan:20180601113208p:plain
まずはこの時点でライブラリ名を決めて保存してしまう
今回は『smd-power-inductor.lbr』とした
基本的にライブラリ名は英小文字と数字とハイフンで作られているので、それに従ったほうがよさそう

次から実際のライブラリ作成を進めていく。大きな流れは以下のようになる
1. Packageの作成 : パターン図に表示される
2. Symbolの作成 : 回路図に表示される
3. Deviceの作成 : 作成したPackageとSymbolを連携させる

Packageの作成

f:id:portaltan:20180601113418p:plain
Packageアイコンを選択して、名前を決める
(今回はNR10050とした)
以下のようなパターン図作成のような画面が表示される
f:id:portaltan:20180601114303p:plain

Gridの設定

まずはGridの設定を行う
今回は部品が小さいので、Sizeを0.1mm、Altを0.05mmにした
f:id:portaltan:20180601114529p:plain

Smdの設置

次にSmdの設置を行う
smdは表面実装用のpadで、pinはその名の通りピン用のホールを作成する
今回のコイルは表面実装コイルなのでsmdを選択する
f:id:portaltan:20180601114617p:plain

まずボード上に配置したら、Propertiesから調整をする

  • Name:1へ変更
  • position: 0,0へ変更
  • Smd Size: 2.6 x 4.5

f:id:portaltan:20180601115103p:plain
Smd SizeはデータシートのRecommeded Land Patterns通りにした
f:id:portaltan:20180601115804p:plain

つぎに見やすいようにスケーラをつける
f:id:portaltan:20180601115243p:plain
スケーラ自体もデフォルトは太すぎて見にくいので細く小さくする

  • Size: 0.3048へ変更
  • Layer: 47 Measuresに変更
  • Line Width: 0.01へ変更

f:id:portaltan:20180601115603p:plain
もしMeasuresのLayerを非表示にしている場合は見えなくなってしまうので、その場合はLayer Settingから47番を表示にする
f:id:portaltan:20180601115713p:plain
同じく高さ(データシートのC)もスケーラをつけた
f:id:portaltan:20180601120037p:plain

次に作成したsmdをコピーしてもう一つ作成する
smd間の距離はデータシートの通り5.4mmにする
f:id:portaltan:20180601120241p:plain

外形の作成

今回はコイルが丸型なので外形として円を書きます
大きさ等はデータシートを参考にします。ちょっと楕円になっていますが、ほぼ変わらないので半径は5mmとします。
f:id:portaltan:20180601120723p:plain

Circleを選んで適当に配置したら、Propertiesで調整します

  • Position: 4,0へ変更
  • Layer: 21 tPlaceへ変更
  • Radius: 5へ変更

f:id:portaltan:20180601120656p:plain

Descriptionの追加

下部のDescriptionというリンクをクリックして説明文を追加します
f:id:portaltan:20180601121147p:plain

Packageの完成

以上でPackageの完成です、保存をして次のSymbolの作成に移ります
f:id:portaltan:20180601121336p:plain

Symbolの作成

まずはSymbolアイコンをクリックして名前をつけます
f:id:portaltan:20180601121434p:plain
そうすると回路図の画面が表示されます
ここで実際に回路図に表示される記号を作成していきます
f:id:portaltan:20180601121649p:plain

コイル記号の作成

Arcアイコンを利用してコイルの記号を作成します
f:id:portaltan:20180601121808p:plain

pinのアタッチ

pinアイコンを選択して、以下のように配置します
f:id:portaltan:20180601121914p:plain
これもPropertiesで調整します

  • Length: shortへ変更
  • Visible: offへ変更

f:id:portaltan:20180601122039p:plain

Symbolの完成

以上でSymbolの作成は完了です。保存してDeviceの作成にすすみます
f:id:portaltan:20180601122139p:plain

Deviceの作成

Deviceアイコンをクリックして名前をつけます
f:id:portaltan:20180601122300p:plain
以下のような画面が表示されます
f:id:portaltan:20180601122354p:plain

Symbolの追加

Addアイコンから今作ったNR10050 Symbolをaddします
f:id:portaltan:20180601122507p:plain

Packageの追加

次に右下のNewボタンからNR10050 Packageをaddします
f:id:portaltan:20180601122549p:plain

Connect

まだPackageとSymbolは別のものとして関係がないので、Packageのsmdとsymbolのpinをconnectします
右下のConnectボタンを選択し、接続したいpinとpadを選択してConnectをクリックします
f:id:portaltan:20180601122752p:plain

Prefixの追加

右下のPrefixを選択し、Lと1文字いれてOKを押します
これで、同じ部品が呼び出されたときにL1, L2・・・と名前が自動で付加されていきます
(PackageとSymbolで名前を付け忘れていたのでつけています)
f:id:portaltan:20180601123045p:plain

Desciptionの追加

左下のDescriptionアイコンをクリックして説明文を入力します
f:id:portaltan:20180601123308p:plain

Deviceの完成

以上でDevideの完成です。これが最後の工程なのでライブラリの完成となります。
f:id:portaltan:20180601123430p:plain

確認

実際にライブラリを呼び出して確認してみましょう
Libraries一覧で確認をして、
f:id:portaltan:20180601123727p:plain
新規プロジェクトで呼び出すと以下のように先ほど作成したコイルが表示されるのが確認できます
f:id:portaltan:20180601123859p:plain

メモ

今回はやっていないんですが、パッケージ作成時の最後に中心点をパーツの真ん中にしておくと、実際にライブラリを使う際に便利です
(中心じゃないとrotate時に位置がずれてしまうので)

gitで親ブランチのない空ブランチを作成する

gitで親ブランチの空ブランチを作成する方法です
私はgit利用開始時に色々なversionのソースがあって、それらをgit上でmergeしていきたいときになど使います

--orphanオプション

# 親のないブランチの作成
$ git checkout --orphan <new_branch>

# 管理対象ファイルの指定
$ git add <file you want to add>

# commit
$ git commit

# push
$ git push origin <new_branch>

これでネットワークグラフなどで、どのブランチともつながっていないブランチが作成されます
ちなみにすでにmasterブランチなどで開発を開始してcommitをしている場合、git addの履歴は残っているのでaddしなおさなくて大丈夫です
git commit はしないといけません

Gitメモ

大昔に書いたgitのメモ

Install Git

環境設定
vi ~/.gitconfig
[user]
  name = nouziru          # username
  email = foo@bar.com # mail address
[core]
  editor = vim           # gitで利用するeditorの指定

$ git config --list            # 現在の設定の表示

clone repository

clone other brach
$ git branch -a  # (リモート上の全てのブランチを表示)
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/develop
  remotes/origin/test
  remotes/origin/master
  
### CUIから作成する場合
# 1. 今いるブランチの状態がbaseとする場合
$ git branch [つけたいbranch名]
$ git branch
   master
 * develop

# 2. 現在の HEAD (デフォルト)以外の場所から始まるブランチを作成するには
$ git branch new test           # "test" ブランチのHEADから開始するブランチ "new" を作成
$ git branch new v1.2.3     # タグ v1.2.3 から開始するブランチ "new" を作成
$ git branch new HEAD^     # 最新のコミットの1つ前の位置から分岐するブランチを作成
$ git branch new HEAD^^   # 最新のコミットの2つ前の位置から分岐するブランチを作成
$ git branch new test~10     # ブランチ "test" の10個前の位置から分岐するブランチを作成

### 既にGUIでdevelopブランチを作成している場合
$ git checkout -b develop remotes/origin/develop
$ git branch
   master
 * develop

Merge

リポジトリ内の場合
### masterからmerge用(確認用)ブランチを作成
git branch merge master
 
### merge処理(確認)
git checkout merge # merge(受け入れ側)ブランチに移動
git merge --no-ff dev #merge(差出側)ブランチを指定してmerge
git push http://github.com/xxxxxxxxx/xxxxxxx.git merge:merge
  
### merge(リリース)
git checkout master
git merge --no-ff merge
git push http://github.com/xxxxxxxxx/xxxxxxx.git merge:merge
Forkしてきた場合
###Fork元の最新ver.のコードからremoteブランチを作成する
git remote add fork_master http://github.com/xxx/xxx.git
  
#ブランチ確認
git branch -a
  develop
* release
  remotes/fork_master/master
  remotes/origin/HEAD -> origin/master
  remotes/origin/develop
  
# remotes/fork_master/masterをbaseにrelease用ブランチに作成
git checkout -b release remotes/fork_master/master
  
### 開発してきたブランチをmerge
git checkout release
git merge --no-ff remotes/origin/develop # merge(差出側)ブランチを指定してmerge
git push http://github.com/xxx/xxx.git merge:merge

### merge(リリース)
git checkout master
git merge --no-ff merge
git push http://github.com/xxx/xxx.git master:master
  
### このままではWEB上で表示されて、かつローカルにもブランチはあるが、remoteにはない(remotes/origin/****がない)という状態になるはずなので以下を実行
# pull(fetch + merge)してもよい
git remote -v
git fetch origin

焦電人感センサーSB612Aをラズベリーパイで使ってみた

以下の秋月で販売している焦電型赤外線センサーをラズベリーパイで使ってみました(¥600)
f:id:portaltan:20180516092309p:plain
akizukidenshi.com

仕様

  • 電源電圧:3.3V~12V(3.3VのLDOによりモジュール内部で安定化されています)
  • 最大検知距離:8m(気温等の環境条件によります)
  • 検知角度:120度
  • 検知出力保持時間:2秒~80分

ハードウェアサイ

SB612A側

画像のようにメスメスケーブルをさしていきます。
色はあわせなくていいですが、右から赤(VCC), 緑(信号出力). 黒(GND)です
f:id:portaltan:20180515182953j:plain

ラズベリーパイ

それぞれケーブルを以下のようにラズベリーパイに接続します

  • 赤:2番pin(5V)
  • 黒:6番pin(GND)
  • 緑:12番pin(GPIO 18)

f:id:portaltan:20180515183239j:plain
f:id:portaltan:20180515183307p:plain

この状態でラズパイの電源をいれるとSB612Aに5V電源が供給されます

ソフトウェアサイ

確認

まずはちゃんと動いているか確認をします

## GPIO設定
sudo echo 18 > /sys/class/gpio/export
sudo echo in > /sys/class/gpio/gpio18/direction

### 確認
## 検知していない時
cat /sys/class/gpio/gpio18/value
0

## 検知中
cat /sys/class/gpio/gpio18/value
1

LED連携

センサーが動体を検知すると31番ピン(GPIO6)にさしたLEDが光るようにします

#!/usr/bin/env python

import RPi.GPIO as GPIO

### setup
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN) # GPIO 18 : human detect sensor
GPIO.setup(6, GPIO.OUT) # GPIO 6: LED

# initialize
if GPIO.input(18):
  GPIO.output(6, 1)
else:
  GPIO.output(6, 0)

while True:
  GPIO.wait_for_edge(18, GPIO.BOTH)
  if GPIO.input(18):
    print "detected!"
    GPIO.output(6, 1)
  else:
    GPIO.output(6, 0)

  time.sleep(1)

GPIO.cleanup()

GPIO.wait_for_edgeは電圧がLOWからHIGH、またはその逆を検知します
引数にはピン番号とGPIO.RAISING or GPIO.FALLINGを渡すことで電圧の動きをチェックします
両方取得したいときはGPIO.BOTHでとれます
単純にLoopで毎秒チェックとかにするよりは低負荷になります

その他設定

感度

SENSと書かれたつまみを右に回すほど感度が高くなります

検知出力保持時間

DELAYと書かれたつまみを左にまわすほど保持時間が長くなります
保持時間とは、一度動体を検知した際に何秒間検知状態のままにするかという設定です

Windows7でVagrant2.0を使ってVirtualBoxにUbuntu16.04の仮想環境をつくってteratermでアクセスする

環境

手順

1. VirtualBoxのダウンロード

Virtual Boxのインストール
http://www.virtualbox.org/
f:id:portaltan:20180302142838p:plain

Imageの配置場所の変更
f:id:portaltan:20180302155543p:plain

  • 自分はD:\VirtualBoxServersという名前のディレクトリにしました
2. Vagrantのダウンロードします

Vagrantのインストール
http://downloads.vagrantup.com/
f:id:portaltan:20180302142909p:plain

  • ちなみに私はCドライブ直下に作るのが嫌なのでC:\Program Files (x86)\HashiCorp\Vagrantにインストールしました

vagrantの確認

> vagrant -v
Vagrant 2.0.2

> vagrant -h
.
.
.

box(osのイメージ)の配置場所の指定

> SETX VAGRANT_HOME D:\Vagrant\.vagrant.d
> echo "%VAGRANT_HOME%"
  • デフォルトの配置場所は『(ユーザフォルダ)/.vagrant.d』
  • Dドライブに変更する理由は、今後色々な環境を作成していくので容量が大きいドライブでboxを管理しておきたいからです
  • 実際の保管場所は.vagrant.d以下のboxesディレクトリになります
3. PC再起動
4. 仮想環境を構築準備

ディレクトリの作成
今から構築するubuntu16.04用のディレクトリを作成します

### 仮想環境用のディレクトリを作成
> cd /d d:/Vagrant
> mkdir "servers/ubuntu1604_1"
> cd servers/ubuntu1604_1

boxを検索
VagrantCloudから欲しいパッケージを検索します

> vagrant init ubuntu/xenial64

Vagrantfileの編集

> notepad Vagrantfile
################################
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.ssh.insert_key = false
  config.vm.provider "virtualbox" do |vb|
    vb.name = "ubuntu1604_1"
  end
end
################################
5. 仮想環境を構築準備

Vagrant起動(boxダウンロード&サーバー作成)

> vagrant up #環境とかPCスペックによっては時間がかかります
6. 確認

Host OSから確認(via コマンドプロンプト)

### boxがちゃんとdownloadされているか確認
> vagrant box list
ubuntu/xenial64 (virtualbox, 20180228.1.0)

### ステータス確認
> vagrant status
Current machine states:

default runnning (virtualbox)
........

VMの管理画面でも以下のように仮想環境が作成されているのを確認できます
f:id:portaltan:20180302190604p:plain

Guest OSから確認(via teraterm)
teratermからVagrantfileで指定したprivate ipへsshでアクセスします
f:id:portaltan:20180302190650p:plain

ユーザ名はvagrant
秘密鍵は先ほど上書きせずにinsecure_keyを利用する設定をしたので、私と同じ環境で作った方は「D:\Vagrant\.vagrant.d\insecure_private_key」にあります
f:id:portaltan:20180302190818p:plain

あとはログインできることを確認します
f:id:portaltan:20180302191024p:plain

マウントされているかの確認
GuestOS

vagrant@ubuntu-xenial:/$ ls -la /vagrant/
total 72
drwxrwxrwx  1 vagrant vagrant     0 Mar  2 09:53 .
drwxr-xr-x 24 root    root     4096 Mar  2 09:59 ..
-rwxrwxrwx  1 vagrant vagrant 44317 Mar  2 09:57 ubuntu-xenial-16.04-cloudimg-console.log
drwxrwxrwx  1 vagrant vagrant     0 Mar  2 09:52 .vagrant
-rwxrwxrwx  1 vagrant vagrant   296 Mar  2 09:57 Vagrantfile

HostOS
f:id:portaltan:20180302191255p:plain
f:id:portaltan:20180302191355p:plain

以上で構築完了です

RasbperryPi3 のACT LEDをheartbeatにしてGPIO出力する

ラズベリーパイ3は基板上に電源ランプのLED(赤)とSDアクセスランプ(緑)の2つがありますが、ACT LEDはGPIOを介して外部LEDに機能をわりあてることができます

ACT LED(緑)を外部LEDにする

まずはrc.localとかで使いたい
github.com
GPIOのmodeをout(出力モード)にします
今回はGPIO8(pin24)を利用します

/usr/local/bin/gpio -g mode 8 out

次に/boot/config.txt上でACT LEDをGPIO上で利用する設定を追加します

# for ACT LED
dtoverlay=pi3-act-led,gpio=8

後は再起動すればラズパイ基板上の緑LEDは消えてGPIOの方へさしたLEDが点滅するようになります

LEDパターンをheartbeatにする

通常ACT LEDはSDへのアクセスで点滅しますが、これをheartbeatモードにすると一定間隔で点滅し続けるようになります
設定は簡単で、/boot/config.txtに更に1行追加するだけです

# for ACT LED
dtparam=act_led_trigger=heartbeat
dtoverlay=pi3-act-led,gpio=8

注意

  • ラズベリーパイのモデルやkernelのversionによって方法が異なるようです
  • このデフォルトの基板上のLEDからGPIOへの切り替えは起動後に行われるので、起動してすぐとshutdownの最後の数秒は基板上のLEDへコントロールが戻ります

reference

ソフトウェアエンジニアがarduinoの割り込みタイマーライブラリを読んでみた

arduinoのタイマーを使って割り込み処理をするにはMsTimer2とflexitimer2があってそれらを読み込めば簡単に出来るのですが、中身を知らないのもあれだなーと思い今回ソースを呼んでUno用に簡略化してみた
MsTime2: https://github.com/PaulStoffregen/MsTimer2
flexitimer: https://github.com/wimleers/flexitimer2
MsTimer2はミリセカンド単位でタイマー指定できて、flexitimerはマイクロセカンドごとに指定できるらしい
(flexitimerの方はちゃんと読んでないのでもしかしたら厳密には違うかも)

Uno用に簡略化したソース

5V/16MHz駆動でarduino UNO(atmega328P)を利用する場合の割り込みタイマー処理

volatile unsigned long count; // overflowした回数
volatile char overflowing;  // overflow処理中かどうかのフラグ
volatile unsigned int tcnt2; // タイマーのオーバーフローのタイミング調整用変数
unsigned long msecs; // 何秒ごとに任意の処理を実行したいか
float prescaler; // 前置分周(F_CPUが1MHzから16MHzの場合は64.0が多い)


// 初期化や割り込みの許可等の設定
void setTimer2(){
  TIMSK2 &= ~(1<<TOIE2);
  TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
  TCCR2B &= ~(1<<WGM22);
  ASSR &= ~(1<<AS2);
  TIMSK2 &= ~(1<<OCIE2A);
  TCCR2B |= (1<<CS22);
  TCCR2B &= ~((1<<CS21) | (1<<CS20));
  prescaler = 64.0;
}

// timerのスタート
void startTimer(unsigned long ms){
  msecs = ms;
  tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler);  
  count = 0;
  overflowing = 0;
  TCNT2 = tcnt2;
  TIMSK2 |= (1<<TOIE2);
}

// timerのセットアップ
void setup() {
  setTimer2();
  startTimer(1000); // これで1000ミリセカンド単位のタイマーをスタート
}

// 割り込み検知
ISR(TIMER2_OVF_vect) {
  TCNT2 = tcnt2;
  overflow();
}

// 割り込み処理
void overflow(){
  count += 1;

  if (!overflowing && count >= msecs) {
    overflowing = 1;
    count = count - msecs;
    flash();
    overflowing = 0;
  }
}

// 任意のメソッド(1000ミリセカンド毎に実行したい処理)
void flash(){  
  static boolean output = HIGH;
  digitalWrite(13, output);
  output = !output;
}

set timer

TIMSK2 &= ~(1<
  • TIMSK2: タイマ/カウンタ2割り込み許可レジスタ(Timer/Counter 2 Interruput Mask Register)
  • TOIE2: タイマ/カウンタ2溢れ割り込み許可(Timer/Counter 2 Overflow Interrupt Enable)
  • OCIE2A: タイマ/カウンタ比較A割り込み許可(TImer/Counter2 output Compare Match A Interrupt Enable)

f:id:portaltan:20180125120321p:plain

TCCR2A &= ~*1
  • TCCR2A: タイマ/カウンタ制御レジスタA(Timer/Counter 2 Control Register A)
  • WGM21,20: 波形生成種別(Waveform Generation Mode)

f:id:portaltan:20180125114814p:plain

TCCR2B &= ~(1<*2;
  • TCCR2B: タイマ/カウンタ制御レジスタB(Timer/Counter 2 Control Register B)
  • WGM22: 波形生成種別 (Waveform Generation Mode bit 2)
  • CS22,21,20: クロック選択(Clock Select)

f:id:portaltan:20180125114933p:plain

ASSR &= ~(1<
  • ASSR: タイマ/カウンタ2非同期状態レジスタ(TImer/Counter 2 Asynchronous Status Register)
  • AS2: タイマ/カウンタ2非同期動作許可(Asynchronous Timer/Counter2)

f:id:portaltan:20180125115102p:plain

prescaler = 64.0;
  • 前置分周(次の項目で説明)

startTimer

tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler)

指定したミリセカンドぴったりで処理が実行されるようにするための調整値を求めている
F_CPUが16MHzだとして計算を一つ一つ説明

説明①

  • F_CPU(16,000,000Hz) * 0.001 = 16,000(Hz)
    • まずは秒単位ではなくミリセカンド単位で扱うために1/1000している
    • 16MHzなので1秒で16,000,000カウント、1ミリセカンドで16,000カウントされることとなる
    • これだと8bit(256)のカウント内に収まらないため、1ミリセカンド分もカウントできない(カウントできる時間間隔が短すぎる)
    • そこでCPU側で1Hzごとにカウントアップするのではなく、何Hzかごとにまとめて1カウントとするようにしている(この値をプリスケーラといい、チップや駆動電圧によって異なる)
  • 16,000(Hz) / prescaler(64.0) = 250(count)
    • atmega328Pで16MHzの場合prescalerの値は64.0
    • prescalerなしだと1msecで16,000Hz(16,000カウント)だったが、prescaler処理をいれると64Hzに1回しかカウントしなくなるので、1msecで250カウントとなる
    • これで8bit(256)カウント内でおさまるようになった
    • しかし、8bit(256) timerはカウント250回ではなく256回でオーバーフローするため、 毎回6カウントずつずれてしまう。これの調整を以下で行う
  • 256 - 250 = 6
    • ようは6からカウントを開始すれば250カウント経過で256になり、ちょうど1msecでオーバーフローする
    • そのためカウントの開始地点(初期カウント数)をここで求めている
    • 実際にISRで割り込んだ後も毎回カウントの初期値に6をセットしている


説明②(上記と同じ説明を順番を変えて考えただけ)

  • 16,000,000Hz / prescaler(64.0) = 250,000
    • 通常16MHz(16,000,000Hz)なので16,000,000カウントで1秒
    • arduinoにのっているtimerは8bit(256)か16bit(65536)なのでさすがにカウントが速すぎて使いにくい
    • そこでCPU側で毎Hzごとにカウントアップするのではなく、何Hzかごとに1カウントアップするようにしている(この値をプリスケーラといい、チップや駆動電圧によって異なる)
    • atmega328Pの場合は通常64.0
    • これによって実際の16,000,000Hz(16,000,000カウント)毎ではなく、250,000カウント毎に1秒という計算になる
  • 250,000 * 0.001 = 250
    • しかしまだ8bit(256)タイマーでも16bit(65536)タイマーでも値が足らずに1秒間もカウントできない(その前にオーバーフローしてしまう)
    • しかしそもそもマイコンの世界のタイマーで最小単位が秒単位というのは逆に長すぎるので、ミリセカンド単位で管理できるようになればよいので、1/1000している
    • 1秒では250,000カウントだったが、1msecでは250カウントなので、8bitカウンタ(256)でもカウントできるようになった
  • 256 - 250 = 6
    • しかし、8bit(256) timerはカウント250回ではなく256回でオーバーフローするため、 毎回6カウントずつずれてしまう。これの調整を以下で行う
    • ようは6からカウントを開始すれば250カウントで256になり、ちょうど1msecでオーバーフローする
    • そのためカウントの開始地点(初期カウント数)をここで求めている
    • 実際にISRで割り込んだ後も毎回カウントの初期値に6をセットしている
TCNT2 = tcnt2(6)
  • TCNT2: Timer/Counter 2 Counter Value Register

f:id:portaltan:20180125153553p:plain
上記のとおりカウントの値を書き換えて、初期値を0ではなく6にしている

TIMER2_OVF_vect

ISR(TIMER2_OVF_vect) {
  TCNT2 = tcnt2;
  overflow();
}
  • ISR: interrupt service routine
  • TIMER2_OVR_vect: タイマ2のオーバーフロー割り込み
  • 割り込みを検知する処理
  • 上記の設定の結果、1msec毎にtimer2がオーバーフローし、それを検知してこの処理が実行される
  • オーバーフローする毎にカウントが0に戻るので、初期値(6)を毎回代入している

void overflow

void overflow(){
  count += 1;

  if (!overflowing && count >= msecs) {
    overflowing = 1;
    count = count - msecs; // subtract ms to catch missed overflows. set to 0 if you don't want this.

    flash();
    overflowing = 0;
  }
}
  • 1msecごとに実行されてcountを1ずつincrementしていく
    • (このように平行した処理内で値が変わる可能性のある変数は宣言時にvolatile属性をつけておく必要がある)
  • 1msec毎にカウントして、指定のmsec回数を越えたら実際に実行したい処理(このコードではflash();)を実行する
  • 上記の処理中はoverflowingフラグをあげることで、処理が1ミリセカンド以上かかったとしても二重で処理が実行されるのを防ぐことができる
  • しかしこの間もcountのincrementは続いているので、実行する処理が数ミリセカンドかかったとしてもその分次回の処理がずれていくということはない
    • ただし指定したミリセカンド秒数を越える処理遅延が発生する場合は対策が必要(1000msecごとに行いたい処理があるのに、その処理自体が1000msec以上かかる場合など)

*1:1<

*2:1<