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

本日の内容


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

3-1. Arduino 開発環境

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

部品表

SN754410 1
機材 数量
arduinoシールド用基板1
1x40ピンヘッド 1
1x8ピンソケット 1
1x6ピンソケット 1
タクトスイッチ 3
錫メッキ線 30cm
ラッピングワイヤ 10cm
5W0.1Ωセメント 1
100Ω 2
120Ω 3
220Ω 1
330Ω 25
1kΩ 6
22kΩ 2
5kΩ半固定 3
0.1μF 1
電池スナップ 1
単3電池2本用ボックス 2
3mmLED(赤or黃or緑) 4
LED(3or5mm,赤or黃or緑) 7
カソードコモン7segLED 1
3色LED 1
3色LED用キャップ 1
FA-130RAモータ 1
1N4007 4
2sc1815 2
2sk4017 2
2sb1018A 2
SN7544101

回路図

回路図

実体配線図

基板表面
基板裏面

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

完成写真

基板表面

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


基板表面

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


基板表面

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

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

演習3-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);
}

演習3-2

volatile 宣言を使う

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

演習3-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);
}

演習3-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);
}

演習3-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);
}

演習3-6

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

演習3-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();
  }
}