学習用・備忘録
個人的に作っているので間違いを記述している場合がある。
進数の記述方法
0b00000001, B00000001 - 2進数を表す為に先頭に0bまたはBを加える
0x00000001 - 16進数を表すために先頭に0xを加える
ピンの入力や出力、HIGH、LOWを設定するときに使う。
基本は2進数で記述する。
よく使われる標準ライブラリ
#include <avr/io.h>
全AVRデバイスで使われているポート入出力用のライブラリである。
DDRB = 0b00001111;
PORTB |= 0b00000001;
#include <util/delay.h>
実行中のコードの途中でスリープ(待機)を入れることが出来るライブラリである。
_delay_ms(100); // 100ms (0.1s)
_delay_us(100); // 100us (10^-6s)
#include <avr/interrupt.h>
割り込み処理をすることが出来るライブラリである。
論理演算子
"|" OR演算子
左と右どちらかに1があれば1を返す。
IN1 | IN2 | OUT |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
使用用途
元の設定を崩さずに新しい設定を追加したい場合に用いる。
少し専門的な言葉で表すと、ビットを立てるという。
DDRB = 0b01000000;
DDRB = DDRB | 0b00100000; // PB5を出力ポートに設定するときにも使われる
// DDRB |= 0b00100000; 省略したかたち
// 結果:DDRB -> 0b01100000
"^" XOR演算子
左右が異なれば1を返す。
IN1 | IN2 | OUT |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
使用用途
ビットの反転に使われる。
具体的な使用例としては、**「ループでLEDを点灯、消灯を1秒ごとに繰り返すコード」**で使う。
while(){
PORTB = PINB ^ 0b00000001;
_ms_delay(1000);
}
PORTB = 0b00100000;
PORTB = PINB ^ 0b00100000;
// 結果:PORTB -> 0b00000000
"~" NOT演算子
反転した結果を返す。
IN | OUT |
---|---|
0 | 1 |
1 | 0 |
PORTB = ~0b00100000;
// 結果:PORTB -> 0b11011111
"&" AND演算子
左右が1であれば1を返す。
IN1 | IN2 | OUT |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
使用用途
特定のピンがオンかオフかを調べたり、特定のピンを操作したりするために用いる。
少し専門的な言葉で表すと、ビットマスクという。
PORTB = 0b00111111;
PORTB = PINB & 0b00000001;
// 結果:PORTB -> 0b00000001
シフト演算子
ビット列を指定数分ずらす
" << " 左シフト
" >> " 右シフト
int result;
int data = 0b00000011;
result = data << 3; // dataを3bit左にシフトする
// 結果:00011000
レジスタのコントロール
PORTレジスタ
ポートのデータレジスタ。読み書き可能なレジスタ。
レジスタ | ピン番号 |
---|---|
PORTB | デジタルピン 8~13 |
PORTC | アナログピン |
PORTD | デジタルピン 0~7 |
// ピンを出力設定
PORTB = 0b01000000;
PINレジスタ
PIN情報の読み取り専用のレジスタ。
// 情報を読み取ってデータビットの反転
PORTB = PINB ^ 0b00100000;
// 結果:PORTB -> 0b00000000
DDRレジスタ
ポートの入出力を設定するレジスタ。 読み書き可能
0 - 入力ポート
1 - 出力ポート
DDRB |= 0b11110000; // 右端の2bitはRXとTXが占領
DDRB = 0b00110000; // PORTB4,5を出力設定
PORTB = 0b00110000; // PORTB4,5をHIGHにする
プロトタイプ宣言
プロトタイプ宣言は、コンパイラに対して関数の情報を与えるためのものである。
複数の関数を個別のファイルに分けて整理したり、main関数の下に関数を書いたりすることができる。
プロトタイプ宣言を用いて関数を別のファイルに記述した例
#include "sum.h"
int main(void) {
int result;
result = sum(3, 5); // sum関数の内容は別のファイルに記述
printf("3+5 = %d", result);
return 0;
}
#ifndef SUM_H_
#define SUM_H_
// ヘッダーファイル
int sum(int a, int b); // プロトタイプ宣言
#end
#include "sum.h"
int sum(int a, int b){
return a + b;
}
クラスと継承
クラスとは、構造体にメンバ関数を追加したものである。
メンバ関数とは、クラスが持つ関数のことである。
継承とは簡単に表すと、メンバ関数をクラスの外で書くことができることである。
class Rectangle { // クラス
public: // どこからでもアクセス可能
int Area() { // メンバ関数
return height * width;
}
int height;
int width;
private: // クラス内のみアクセス可能
int rect_area;
}
クラスにはアクセス制限があり、「public」「private」「protected」の3つがある。
publicとは:「公開」であり、下のメンバ関数や変数はどこからでもアクセスできる。
privateとは:「非公開」であり、下のメンバ関数や変数はクラス内のみアクセスできる。
protectedとは:クラス内及び継承した派生クラスからのみアクセス可能
オーバーロード
作成中...
テンプレート関数
テンプレート関数は、一つの関数で異なるデータ型を受け取ることができる関数である。
オーバーロード関数の簡略化した関数である。
オーバーロードとの違いは、型で処理内容を変えることができないことである。
汎用関数とも呼ばれる。
// typeは関数が呼ばれたとき、その型として動く。
template <class type> type comp(type a, type b) {
if(a < b) {
return b;
}else{
return a;
}
}
float res;
res = comp(1, 2.5); // どのデータ型でも指定できる
printf("%f", res);
A/D変換
センサーが使うアナログピンから値を読み取るため、アナログデータからデジタルデータに変換する。
基準電圧(リファレンス電圧)と入力電圧、AD変換用レジスタを使ってA/D変換をする。
読み取れる範囲は0~基準電圧までである。
A/D変換用レジスタとは:計測した電圧を(10bitで)格納するレジスタ。ADCH, ADCLレジスタに格納される。
入力電圧とは:ピンから入力される電圧。
基準電圧とは:ADMUXレジスタで基準電圧の選択が出来る。範囲は0~電源電圧(5V)
ATmega328PのA/D変換用レジスタは10bitを採用している。
[ ADCSRA ] - A/D制御/状態レジスタA
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | ADEN | ADCS | ADATE | ADIF | ADIE | ADPS2 | ADPS1 | ADPS0 |
名称 | bit | 動作モード |
---|---|---|
ADEN | 1 | A/D許可(電源制御) |
ADCS | 1 | A/D変換開始(変換開始時に1を書く) |
ADATE | 1 | A/D自動起動許可 |
ADIF | 1 | A/D完了割り込み要求フラグ |
ADIE | 1 | A/D変換完了割り込み許可 |
ADPS2 | ADPS1 | ADPS0 | A/D変換クロック選択 |
---|---|---|---|
0 | 0 | 0 | 分周比2 |
0 | 0 | 1 | 分周比2 |
0 | 1 | 0 | 分周比4 |
0 | 1 | 1 | 分周比8 |
1 | 0 | 0 | 分周比16 |
1 | 0 | 1 | 分周比32 |
1 | 1 | 0 | 分周比64 |
1 | 1 | 1 | 分周比128 |
[ ADMUX ] - A/D多重器選択レジスタ
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | REFS1 | REFS0 | ADLAR | - | MUX3 | MUX2 | MUX1 | MUX0 |
REFS1 | REFS0 | 基準電圧選択 |
---|---|---|
0 | 0 | AREFピンの電圧 |
0 | 1 | AVCC (5V) - 標準 |
1 | 0 | (予約) |
1 | 1 | 内部1.1V基準電圧 |
名称 | bit | 動作モード |
---|---|---|
ADLAR | 1 | 変換データレジスタ左揃え |
MUX3 | MUX2 | MUX1 | MUX0 | A/Dチャンネル選択 |
---|---|---|---|---|
0 | 0 | 0 | 0 | ADC0 |
0 | 0 | 0 | 1 | ADC1 |
0 | 0 | 1 | 0 | ADC2 |
0 | 0 | 1 | 1 | ADC3 |
0 | 1 | 0 | 0 | ADC4 |
0 | 1 | 0 | 1 | ADC5 |
0 | 1 | 1 | 0 | ADC6 |
0 | 1 | 1 | 1 | ADC7 |
1 | 0 | 0 | 0 | ADC8 (温度) |
1 | 1 | 1 | 0 | 1.1V |
1 | 1 | 1 | 1 | 0V |
[ADCL,ADCH] - A/D変換データレジスタ上位/下位
計測した電圧の結果を格納するレジスタ。
- ADLARが0のとき
ADCH | ADCL |
---|---|
- - - - - - 0 0 | 0 0 0 0 0 0 0 0 |
- ADLARが1のとき
ADCH | ADCL |
---|---|
0 0 0 0 0 0 0 0 | 0 0 - - - - - - |
↑ 0の箇所に10bitのデータが格納される |
ATmega328PのAD変換用レジスタは8ビットレジスタを2個使って10ビットを表現する。
#define F_CPU 16000000UL
#include <avr/io.h>
int main(void){
ADSCRA = 0b10000000; // AD起動時設定 テンプレ
ADMUX = 0b01100000; // AD起動時設定 テンプレ
result = ADCH<<2 + ADCL>>6; // ADCHとADCLを結合して10bit分取得する
}
割り込み処理
タイマ割り込み
設定した時間ごとに割り込みを発生させる。
[Timer0] - 8ビットタイマ
時計の役割をする。0~255までカウントできる。それを超えるとオーバーフローして0に戻る。
[Timer1] - 16ビットタイマ
時計の役割をする。0~65535までカウントできる。それを超えるとオーバーフローして0に戻る。
タイマーには主に4つのモードがある。
・標準動作
・CTC動作
・位相基準PWM
・高速PWM
プリスケーラとは
クロックで時計を扱うには速すぎて使いにくい場合のために、
クロックを割り引いて(分周 最大1/1024)使うことが出来る。
500msで割り込むプログラム
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(TIMER1_COMPA_vect){ // 割り込み関数
// 処理内容
PORTD = (PIND & 0b00000001) ^ 0b00000001; // Arduino上のLED点灯(確認用)
}
int main(void){
// 16ビットタイマ
TCNT1 = 0; // タイマカウンタ初期化
OCR1A = 31250; // 256分周で500ms
TCCR1A = 0b00000000; // OC1A / OC1Bを標準ポート動作に設定
TCCR1B = 0b00001100; // CTC動作、プリスケーラ1/256
TIMSK1 = 0b00000010; // 割り込み許可レジスタ
TIFR1 = 0b00100111; // TCNT1割り込み要求フラグレジスタ
sei();
PORTD |= 0b00000000; // Arduino上のLED設定(確認用)
DDRD |= 0b00000001; // Arduino上のLED設定(確認用)
while (1){}
return 0;
}
Timer0 - 8ビットタイマ
[ TCCR0A ] - 制御レジスタA
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | COM0A1 | COM0A0 | COM0B1 | COM0B0 | - | - | WGM01 | WGM00 |
[ TCCR0B ] - 制御レジスタB
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | FOC0A | FOC0B | - | - | WGM02 | CS02 | CS01 | CS00 |
COM0A1 | COM0A0 | 動作モード |
---|---|---|
0 | 0 | 標準ポート動作(OCR0A切断) |
0 | 1 | WGM02が0のときは、標準操作(OC0A切断)、WGM02が1のときは、比較一致で出力を反転。 |
1 | 0 | タイマとOCR0Aとの比較一致でLOW、タイマが0になるとHIGH。 |
1 | 1 | タイマとOCR0Aとの比較一致でHIGH、タイマが0になるとLOW。 |
COM0B1 | COM0B0 | 動作モード |
---|---|---|
0 | 0 | 標準ポート動作(OCR0B切断) |
0 | 1 | OCR0Bとの比較一致で交互出力。 |
1 | 0 | タイマとOCR0Bとの比較一致でLOW、タイマが0になるとHIGH。 |
1 | 1 | タイマとOCR0Bとの比較一致でHIGH、タイマが0になるとLOW。 |
WGM02 | WGM01 | WGM00 | 動作モード |
---|---|---|---|
0 | 0 | 0 | 標準動作(標準) |
0 | 0 | 1 | 8ビット位相基準PWM動作 |
0 | 1 | 0 | 比較一致タイマ/CTC動作 |
0 | 1 | 1 | 8ビット高速PWM動作 |
1 | 0 | 0 | (予約) |
1 | 0 | 1 | 位相基準PWM動作 |
1 | 1 | 0 | (予約) |
1 | 1 | 1 | 高速PWM動作 |
CS02 | CS01 | CS00 | 動作モード |
---|---|---|---|
0 | 0 | 0 | クロックなし |
0 | 0 | 1 | 分周比1 |
0 | 1 | 0 | 分周比8 |
0 | 1 | 1 | 分周比64 |
1 | 0 | 0 | 分周比256 |
1 | 0 | 1 | 分周比1024 |
1 | 1 | 0 | 外部クロック。立下りでオン。 |
1 | 1 | 1 | 外部クロック。立ち上がりでオン。 |
FOC0A | 動作モード |
---|---|
1 | WGMの設定がPWM動作でない場合、OCR0A出力がPWM動作になる。 |
FOC0B | 動作モード |
---|---|
1 | WGMの設定がPWM動作でない場合、OCR0B出力がPWM動作になる。 |
[ TIMSK0 ] - 割り込み設定レジスタ
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | - | - | - | - | - | OCIE0B | OCIE0A | TOIE0 |
OCIE0B | 動作モード |
---|---|
1 | タイマ/カウンタ0比較B割り込み許可(OCR0BとTCNT0の一致) |
OCIE0A | 動作モード |
---|---|
1 | タイマ/カウンタ0比較A割り込み許可(OCR0AとTCNT0の一致) |
TOIE0 | 動作モード |
---|---|
1 | カウンターがTOP(OCR0Aで設定した値)に来た時に割り込み処理を行う。 |
[ OCR0A ] - タイマ/カウンタ0比較Aレジスタ(TOP値)
カウンタ(TCNT0)と比較を行うためのレジスタ。
設定しない場合、225がMAXなので225がTOPとなる。
8ビットでは255で0に戻すがこれに値を入れるとその値で0に戻る。
[ OCR0B ] - タイマ/カウンタ0比較Bレジスタ(TOP値)
OCR0Aと同じ。
[ TCNT0 ] - タイマ/カウンタ0計測レジスタ
クロックを数えるカウンタ。
タイマ情報を読み取れる。
外部割込み
スイッチの状態変化を捕らえられる処理。
特定のピンがHIGHになると割り込みを開始する。
AVRマイコンには、外部割込み端子が最低1つある。
INT0は必ずあり、チップによりINT1、INT2まである。
これらの端子を利用し、スイッチの状態変化を捕らえられる。
ビットの組み合わせは4通り
00 Lowレベル割込み
01 レベル変化割込み
10 ダウンエッジ割込み
11 アップエッジ割込み
シリアル通信 TeraTeam
Arduinoで実行中の状態を確認することができる。
プログラム
シリアル通信するにはUartLib.cとUartLib.hファイルが必要なので、プロジェクトのフォルダに配置しておく。
#include "UartLib.h" // シリアル通信用ヘッダーファイルを読み込み
int main(){
uartInit(); // UartLib準備
printf("Kimetsu\n"); // 送信
}
TeraTeam設定
設定 > 端末に移動
・改行コードの受信と送信をLFに設定する。
・漢字受信と送信をSJISに設定する。
設定 > シリアルポート
・スピードを115200に設定する。
リファレンス
http://wisdom.sakura.ne.jp/programming/cpp/cpp16.html
http://wisdom.sakura.ne.jp/programming/cpp/cpp33.html
http://www.natural-science.or.jp/article/20101215012553.php
http://avrwiki.osdn.jp/cgi-bin/wiki.cgi?page=Timer0
http://avrwiki.osdn.jp/cgi-bin/wiki.cgi?page=Timer1
https://stastaka.wordpress.com/2012/03/20/avr-timer1/
https://garretlab.web.fc2.com/arduino/inside/hardware/arduino/avr/cores/arduino/wiring_analog.c/analogWrite.html
http://avrwiki.osdn.jp/cgi-bin/wiki.cgi?page=Timer1#p8
https://stastaka.wordpress.com/2012/03/20/avr-timer1/
http://usicolog.nomaki.jp/engineering/avr/avrPWM.html