第 6 回 トレイニングボード

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

6-1. Arduino 開発環境

今後のプログラミング演習のために、7seg LED と押しボタンのあるトレー ニングキットを作成します。 部品、回路図を提供しますので、各自作成してきてください。

部品表

機材 数量
arduinoシールド用基板1
コンデンサ0.1μF2
タクトスイッチ3
ダイオード1N40074
トランジスタ2SA14412
トランジスタ2SC18152
NchMOSFET 2SK40172
モータドライバSN7544101
ピンソケット1x61
ピンソケット1x81
ピンヘッド1x401
フォトトランジスタL-51ROPT1D11
マブチモータ FA-130RA1
ラッピングワイヤ10cm
錫メッキ線30cm
7segLEDカソードコモン1
LED(3or5mm,赤or黃or緑)7
LED3mm(赤or黃or緑)4
三色LED OSTA5131A1
三色LED用キャップ1
セメント抵抗0.1Ω5W1
半固定抵抗5kΩ3
抵抗100Ω2
抵抗120Ω3
抵抗1MΩ1
抵抗1kΩ6
抵抗220Ω1
抵抗22kΩ2
抵抗330Ω25
電池9V1
電池単33
9V電池用スナップ1
単3電池2本用ボックス1
単3電池3本用ボックス1
オシロスコープ一式
ブレッドボード一式

回路図

回路図

実体配線図

基板表面
基板裏面

青い線は基板裏面の配線。赤い線は基板表面の配線。黄色い線は無視すること。

完成写真

基板表面

抵抗のリードは曲げて配線に使う。


基板表面

抵抗とジャンパを取り付ける。ジャンパは片方をはんだ付けして、反対側 の必要な長さにペンで印を付け、被覆を落としてはんだ付けする。


基板表面

Arduino との接続は、Arduino にピンを差してはんだ付けするとぴったり 揃う。


基板裏面

デバッグ

チェック
デバッグ
  1. スイッチの直上、左のLEDの下の抵抗の下の部分(写真の青い部分)が GND になっているので、 右下のGND端子と導通があるかをテスターで確認 する。
  2. 3Vの電池ケースに電池を入れ、青い部分に黒のマイナス端子をつけ、赤 のプラス端子を図の黄色い部分の端子に付けると、正常に配線されていれば 対応するLEDが点灯する。
  3. 7SEGのLEDが全く点灯しない場合は、GNDのライン(青い部分)をチェックする

テストプログラム

C言語版

const byte out[] = {6,7,8,9,10,11,12,13,A0,A1,A2,A3,0xff};
const byte button1 = 4;
const byte button2 = 5;
void setup() {
  for(byte i = 0; out[i] != 0xff; i++){
    pinMode(out[i], OUTPUT);
  }
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
}

void writeArray(bool signal){
  for(byte i = 0; out[i] != 0xff; i++){
    digitalWrite(out[i], signal);
  }
}
void loop() {
  static bool prev = HIGH;
  static bool now = HIGH;
  static bool condition = HIGH;

  now = digitalRead(button2);
  if(now == HIGH && prev == LOW){
    condition ^= true;
  }
  prev = now;
  writeArray(condition == digitalRead(button1));
}

アセンブリ言語版

;
; switchtraining.asm
;
; Created: 2018/09/17 4:39:20
; Author : sakamoto
;

.cseg
.org	0x0000
		rjmp	reset
.org	INT_VECTORS_SIZE
reset:
	ldi     r16,high(RAMEND)
	out     SPH,r16 
		ldi		r16,low(RAMEND)
		out		SPL,r16
.equ	onb	= 0b00111111
.equ	ond	= 0b11000000
.equ	pullup	= 0b00110000
.equ	onc	= 0b00001111
		ldi		r16,onb
		out		ddrb, r16
		ldi		r16,ond
		out		ddrd, r16
		ldi		r16,pullup
		out		portd, r16
		ldi		r16,onc
		out		ddrc, r16
.def	now	= r17
.def	prev	= r18
.def	cond	= r19
		clr		prev
		ser		cond


.macro	clrport
		in	r16,@0
		andi	r16,~@1
		out	@0,r16
.endmacro
.macro setport
		in	r16,@0
		ori	r16,@1
		out	@0,r16
.endmacro


main:
		in	now,pind
		sbrc	prev,pind5
		rjmp	pressed
		sbrs	now,pind5
		rjmp	notpressed
nowpressed:
		ldi	r16,1<<pind4
		eor	cond,r16
notpressed:
pressed:
		andi	prev,~(1<<pind5)
		or	prev,now
		eor	now, cond
		sbrc	now,pind4
		rjmp	swon
swoff:
		clrport portb,onb
		clrport	portd,ond
		clrport portc,onc
		rjmp	main
swon:
		setport portb,onb
		setport	portd,ond
		setport portc,onc
		rjmp	main

.exit

6-2. C,C++クリニック

演習6-1

volatile 宣言を使う

スケッチ例の Blink を改造して、自分の1秒待つ関数 mydelay を作ろう。

以下のプログラムで1秒点灯するように ??? の部分に数字を入れよう。


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
void mydelay(){
  for(volatile long i=0; i< ???; i++){
  }
}
void loop(){
  digitalWrite(LED_BUILTIN, HIGH);
  mydelay();
  delay(10);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

演習6-2

volatile 宣言を使う

演習6-1の volatile 宣言を外すと動きがどう変化するか確かめよう。

演習6-3

static 宣言を使う

以下のプログラムの長短を考えよう。

プログラム1


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
bool flag = true;
void loop(){
  digitalWrite(LED_BUILTIN, flag);
  flag = !flag;
  delay(1000);
}

プログラム2


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
void loop(){
  static bool flag = true;
  digitalWrite(LED_BUILTIN, flag);
  flag = !flag;
  delay(1000);
}

プログラム3


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
void loop(){
  bool flag = true;
  digitalWrite(LED_BUILTIN, flag);
  flag = !flag;
  delay(1000);
}

演習6-4

クラス宣言を使う

以下のプログラムの動作を考えよう。

プログラム1


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  bool flag = true;
public:
  void invert(){
  flag = !flag;
  digitalWrite(LED_BUILTIN, flag);
  }    
};
Led led;
void loop(){
  led.invert();
  delay(1000);
}

プログラム2


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  bool flag = true;
public:
  void invert(){
  flag = !flag;
  digitalWrite(LED_BUILTIN, flag);
  }    
};
void loop(){
  static Led led;
  led.invert();
  delay(1000);
}

プログラム3


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  bool flag = true;
public:
  void invert(){
  flag = !flag;
  digitalWrite(LED_BUILTIN, flag);
  }    
};
void loop(){
  Led led;
  led.invert();
  delay(1000);
}

プログラム4


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  bool flag = true;
public:
  void invert(){
  flag = !flag;
  digitalWrite(LED_BUILTIN, flag);
  }    
};
void loop(){
  static Led* p = new Led();
  p->invert();
  delay(1000);
}

演習6-5

クラスを使って機能を抽象化

以下のプログラムの動作を考えよう。

プログラム1


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  int times;
  void blinkLed(){
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  }
public:
  Led(int t):times(t){}
  void flash(){
    for(int i=0; i<times; ++i){ 
      blinkLed();
    }    
    delay(1000);
  }
};
void loop(){
  static Led led(3);
  led.flash();
}

プログラム2


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  int times;
  void blinkLed(){
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  }
public:
  Led(int t):times(t){}
  void flash(){
    for(int i=0; i<times; ++i){ 
      blinkLed();
    }    
    delay(1000);
  }
};
void loop(){
  static Led* leds[]={new Led(1), new Led(2), new Led(3), NULL};
  for(Led** p = leds; *p != NULL; ++p){
    (*p)->flash();
  }
}

プログラム3


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  int times;
  void blinkLed();
public:
  Led(int t);
  void flash();
};
Led::Led(int t):times(t){}
void Led::blinkLed(){
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}
void Led::flash(){
  for(int i=0; i<times; ++i){ 
    blinkLed();
  }    
  delay(1000);
}
void loop(){
  static Led* leds[]={new Led(1), new Led(2), new Led(3), NULL};
  for(Led** p = leds; *p != NULL; ++p){
    (*p)->flash();
  }
}

プログラム4

右のメニューから複数タブを作って、プログラムを分割する。

BlinkCpp

#include "Led.h"
void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
void loop(){
  static Led* leds[]={new Led(1), new Led(2), new Led(3), NULL};
  for(Led** p = leds; *p != NULL; ++p){
    (*p)->flash();
  }
}
Led.h

class Led {
  int times;
  void blinkLed();
public:
  Led(int t);
  void flash();
};
Led.cpp

#include "Arduino.h"
#include "Led.h"
Led::Led(int t):times(t){}
void Led::blinkLed(){
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  digitalWrite(LED_BUILTIN, LOW);
  delay(100);
}
void Led::flash(){
  for(int i=0; i<times; ++i){ 
    blinkLed();
  }    
  delay(1000);
}

演習6-6

演習6-1を利用して、1秒間の間だけ高速で点滅させて半分の明るさにする halfBlink メソッドを作りなさい。

演習6-7

だんだん明るくなってだんだん暗くなるような softBlink メソッドを作りなさい。

おまけ

やり過ぎ感のある、継承によるオブジェクトの作り分け


void setup(){
  pinMode(LED_BUILTIN,OUTPUT);    
}
class Led {
  void blinkLed(){
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  }
protected:
  virtual int times()=0;
public:
  virtual ~Led(){}
  void flash(){
    for(int i=0; i<times(); ++i){ 
      blinkLed();
    }    
    delay(1000);
  }
};
class Led2 : public Led {
protected:
  virtual int times(){
    return 2;
  }
};
class Led3 : public Led {
protected:
  virtual int times(){
    return 3;
  }
};
void loop(){
static Led* leds[]={new Led2(), new Led3(), NULL};
  for(Led** p = leds; *p != NULL; ++p){
    (*p)->flash();
  }
}