【電子工作C++編】A-4.7Segもクラスにしてしまおう
さてさて、
今度は、7Seg制御をC++のクラスにしていこう!
まず、
7セグをクラスとして作成するにあたり、
必要になるポートは、、
* // A
* // ----
* // F | G |B
* // ----
* // E | |C
* // ---- . Dot
* // D
8Pinですね。 (ドットを使わなければ7Pin)
Arduinoには14Pin(Nanoは13Pin)ありますので、
使うPinはだいたい決まってきます。
なので、これらのPin配置は、
クラス内で決め打ちでもいいのですが。。
場合によっては、ほかの用途で先に使ってしまうこともあります。
(Arduinoの場合、そこまで頻繁に衝突はしないですが、
通常のマイコンだと、PPGやIRQ、ADポートとよく衝突します。)
そのたびに、コードを置き換えるのは面倒ですよね。
前回、LEDを制御するクラスで行ったように、
コンストラクタで、設定情報を受け渡すようにすれば
汎用が効きますね!

ところが、
先ほど書いた通り、
7Segをコントロールするには、
8Pinも情報が必要になります。
さらにさらに、今後2桁とか4桁のセグを制御しようとすると、
もっと大量に引数が必要になります。
// コンストラクタ //
SegControl(int aApin,int aBpin, ・・・・・・ int aDodPin);
みたいなことをやってもいいですが、
ダサい。。。
あと、うっかり順番を間違えそうですよね。
では、どうするか?
SAIは構造体クラス(Tクラスって呼んでいます)を使って、
以下のようにパッケージングして引数にしています。
// コンストラクタ //
SegControl(const T7SegSetter& aPort);
引数のT7SegSetterはどんなものかというと、
7セグの情報、PinをLOWでONするか、HIGHでONするかの設定を
パッケージにしています。
↓↓↓↓↓↓
class T7SegSetter
{
public:
// LED=ONがLOWかHIGHかを設定する/
int iLED_ON;
int iLED_OFF;
// 各ポートの番号を設定する/
int iASeg;
int iBSeg;
int iCSeg;
int iDSeg;
int iESeg;
int iFSeg;
int iGSeg;
int iDotSeg;
};
(本当はこの構造体クラスにもコンストラクタを付けるのがいいですよ)
最近試した
https://ameblo.jp/saiduke/entry-12661613651.html
この記事で、”最近のコンパイラだと”うまいこと設定できることが分かったしね。
もし、何か他にも引き渡したい情報が必要になったら、
コンストラクタの引数を修正するのではなく、
クラスにメンバーを追加することで
対応できますね!
そのほかに、
7セグを制御するためには・・・
↑の日記で書いている通り、
int の数字から、 7SEGの各数字に変換する関数を
外部からは見えない、privateな関数にしておくとよいですね。
というわけで、
こんなクラスを作成します。
-----------------------------------------
/*
* @file CSegControlClass
* @brief Lesson A_4 7Segを制御するクラスを作成してみよう。
* @author SAI
* @date 2021/04/04
* @note 7Segを簡単に操作できるようにするよ
*/
class CSegControlClass
{
public:
/* costructor */
CSegControlClass(const T7SegSetter& aPort);
/* destructor */
~CSegControlClass();
/* 出力設定 0-9まで */
void SetOutput(int aOutput);
private:
//Display function 0
void zero();
//Display function 1
void one();
//Display function 2
void two();
//Display function 3
void three();
//Display function 4
void four();
//Display function 5
void five();
//Display function 6
void six();
//Display function 7
void seven();
//Display function 8
void eight();
//Display function 9
void nine();
private:
T7SegSetter iPort;
};
-----------------------------------------
こんなクラスを作ってしまえば、
今度からは表示したい数字の関数を呼ぶのではなく、
表示したい数値を引数で渡してやるだけで済みますね。
↓こんな感じで、intの引数を入れたら表示できるので、
呼び出し元の処理がめちゃくちゃ簡単になりますよ!
-----------------------------------------
CSegControlClass lSegCtrlClass(C_7SegSetter);
/* 3つを同時に点灯 */
for(int i=0 ; i < 10;i++)
{
lSegCtrlClass.SetOutput( i );
delay(1000);
}
-----------------------------------------
簡単に10まで表示できますね!
ところで、
コンストラクタの引数の設定が面倒じゃんと思ったあなた。
その通り。
セッタークラスの設定面倒くさそうに見えますよね。
C言語ソースに書くと、こんな感じになりますか。
------------------------------
T7SegSetter l7SegSetter;
// ON/OFF情報を設定
l7SegSetter.iLED_ON = LOW;
l7SegSetter.iLED_OFF = HIGH;
// 各ポートの番号を設定する/
l7SegSetter.iASeg = ASeg;
l7SegSetter.iBSeg = BSeg;
l7SegSetter.iCSeg = CSeg;
l7SegSetter.iDSeg = DSeg;
l7SegSetter.iESeg = ESeg;
l7SegSetter.iFSeg = FSeg;
l7SegSetter.iGSeg = GSeg;
l7SegSetter.iDotSeg = DotSeg;
CSegControlClass lSegCtrlClass(l7SegSetter);
------------------------------
さすがにSAIも、
処理の途中で、こんなべたべたなことを書くのは嫌いです。
じゃ、どうするか?
SAIだと、T7SegSetter型の定数を定義しておきますよ!
↓こんな感じの方法で、セグ設定を確保しておくんです。
------------------------------
const T7SegSetter C_7SegSetter =
{
// ON/OFF情報を設定
LOW
,HIGH
// 各ポートの番号を設定する/
,ASeg
,BSeg
,CSeg
,DSeg
,ESeg
,FSeg
,GSeg
,DotSeg
};
------------------------------
処理の途中に書くわけではないので、
可読性も落ちませんよね!
それでは、
動かしてみましょう!
※ソースコードは文末にあるので
コピペして試してみてね。

どうでしたか?
7Segが0~9まで順番に表示されましたか?
呼び出し元が簡単になったはずですので、
呼び出し方を色々工夫してみて、
遊んでみてください。
それではSAIでした。





























雑談
既に
タイマークラスを2タイプ作成しているのですが、
どっちが使いやすいか考えています。
組み込み系をやっている人ならわかると思いますが、
10msとか100msとかで周期的にメイン関数を呼び出してもらい、
中でカウントするタイプがC言語には多いと思います。
つまり、原始的に、各機能の専用の関数を、順番に呼び出す。
機能を追加するたびに、周期処理を作っている人に追加してもらう。
というもの。
ところが、
WindowやVC++など、アプリケーションを作る人にとっては、
10秒後にコールバックしてもらう。(または、Onxx()が呼び出される)
というような作りの方が
うれしいはずなんですよね。
機能面で見ると、
メイン処理部、orタイマ呼び出し部の方にお願いして、
外部インターフェースの追加になってしまうのです。
本職ではやりたくないですよね。
SAIがC言語で作るなら、
コールバック関数を、関数ポインタで渡してもらう。
or
関数ポインタ配列をぐるぐる回すだけにしておいて、
外部IF整合時には、定型としておき、関数を登録するだけにする。
static int callback(int a); // ←こんなコールバック関数を
SetObserver(&callback); // こんな感じで関数のポインタを渡してもらい
必要なタイミングで、
int (*icallbackPtr)(a);
みたいな・・・
この時点で、話は全然途中なのですが、
文章だと、意味不明な人が増えてきたと思います。
C言語でコールバック関数の設定、呼び出しを
理解している人には説明が楽なのですが、
この先、純粋仮想関数の説明をするにあたり、
悩んでます。
一旦中抜きで記事だけ書いて、後で捕捉する形にしようかな。。
じゃないと先に進まない。
というわけで、日記に悩んでるSAIでした。





























またねっ!














★メインのinoファイル
/*
* @file CPP_L_A_3_TestCLASS
* @brief Lesson A_3 Classをcppファイルに分離みよう。
* @author SAI
* @date 2021/04/03
* @note Classをcppファイルに分離みよう。
*/
/* *** Include List *** */
#ifndef __SegControlClass_
#include "SegControlClass.h"
#endif // __SegControlClass_
/* *** Define 定義 *** */
const int ASeg = 13;
const int BSeg = 12;
const int CSeg = 11;
const int DSeg = 10;
const int ESeg = 9;
const int FSeg = 8;
const int GSeg = 7;
const int DotSeg = 6;
const int Keta1Seg = 5;
const int Keta2Seg = 4;
const int Keta3Seg = 3;
const int Keta4Seg = 2;
const T7SegSetter C_7SegSetter =
{
// ON/OFF情報を設定
LOW
,HIGH
// 各ポートの番号を設定する/
,ASeg
,BSeg
,CSeg
,DSeg
,ESeg
,FSeg
,GSeg
,DotSeg
};
/*
* @note Arduinoで最初に呼ばれる関数
*/
void setup()
{
//今回はなし
pinMode(Keta1Seg, OUTPUT);
pinMode(Keta2Seg, OUTPUT);
pinMode(Keta3Seg, OUTPUT);
pinMode(Keta4Seg, OUTPUT);
digitalWrite(Keta1Seg, HIGH);
digitalWrite(Keta2Seg, HIGH);
digitalWrite(Keta3Seg, HIGH);
digitalWrite(Keta4Seg, HIGH);
}
/*
* @note ぐるぐるループ
*/
void loop()
{
// --------------- こんな方法で設定してもいいけど --------- //
/* スタック上にクラスを生成 */
// T7SegSetter l7SegSetter;
//
// ON/OFF情報を設定
// l7SegSetter.iLED_ON = LOW;
// l7SegSetter.iLED_OFF = HIGH;
// 各ポートの番号を設定する/
// l7SegSetter.iASeg = ASeg;
// l7SegSetter.iBSeg = BSeg;
// l7SegSetter.iCSeg = CSeg;
// l7SegSetter.iDSeg = DSeg;
// l7SegSetter.iESeg = ESeg;
// l7SegSetter.iFSeg = FSeg;
// l7SegSetter.iGSeg = GSeg;
// l7SegSetter.iDotSeg = DotSeg;
// CSegControlClass lSegCtrlClass(l7SegSetter);
// -------- ↓のようにconst定数を作って設定したほうが楽だよね --------- //
CSegControlClass lSegCtrlClass(C_7SegSetter);
/* 3つを同時に点灯 */
for(int i=0 ; i < 100;i++)
{
lSegCtrlClass.SetOutput(i);
delay(1000);
}
/* 関数終了時にスタックが解放されて、デストラクタが走る
同時に、デストラクタでLEDを消灯する*/
}














セグコントロールクラスのヘッダ
// 多重Lncludeの防止 //
#ifndef __SegControlClass_
#define __SegControlClass_
/*
* @file T7SegSetter
* @brief Lesson A_4 Class用。
* @author SAI
* @date 2021/04/04
* @note 7SegのPin設定用のクラス。コンストラクタはないので、自身で設定してね。
* // A
* // ----
* // F | G |B
* // ----
* // E | |C
* // ---- . Dot
* // D
*/
class T7SegSetter
{
public:
// LED=ONがLOWかHIGHかを設定する/
int iLED_ON;
int iLED_OFF;
// 各ポートの番号を設定する/
int iASeg;
int iBSeg;
int iCSeg;
int iDSeg;
int iESeg;
int iFSeg;
int iGSeg;
int iDotSeg;
// int iKeta1Seg;
// int iKeta2Seg;
// int iKeta3Seg;
// int iKeta4Seg;
};
/*
* @file CSegControlClass
* @brief Lesson A_4 7Segを制御するクラスを作成してみよう。
* @author SAI
* @date 2021/04/04
* @note 7Segを簡単に操作できるようにするよ
*/
class CSegControlClass
{
public:
/* costructor */
CSegControlClass(const T7SegSetter& aPort);
/* destructor */
~CSegControlClass();
/* 出力設定 0-9まで */
void SetOutput(int aOutput);
private:
//Display function 0
void zero();
//Display function 1
void one();
//Display function 2
void two();
//Display function 3
void three();
//Display function 4
void four();
//Display function 5
void five();
//Display function 6
void six();
//Display function 7
void seven();
//Display function 8
void eight();
//Display function 9
void nine();
private:
T7SegSetter iPort;
};
#endif // __SegControlClass_














セグコントロールクラスの関数
/*
* @file CSegControlClass
* @brief Lesson A_4 7Segを制御するクラスを作成してみよう。
* @author SAI
* @date 2021/04/04
* @note 7Segを簡単に操作できるようにするよ
*/
#include "Arduino.h"
#ifndef __SegControlClass_
#include "SegControlClass.h"
#endif // __SegControlClass_
/*
* @fn 初期設定
* @brief コンストラクタ
* @param aPort 7SegLEDを制御するポート番号
*/
CSegControlClass::CSegControlClass(const T7SegSetter& aPort)
:iPort(aPort)
{
//出力設定/
pinMode(iPort.iASeg, OUTPUT);
pinMode(iPort.iBSeg, OUTPUT);
pinMode(iPort.iCSeg, OUTPUT);
pinMode(iPort.iDSeg, OUTPUT);
pinMode(iPort.iESeg, OUTPUT);
pinMode(iPort.iFSeg, OUTPUT);
pinMode(iPort.iGSeg, OUTPUT);
pinMode(iPort.iDotSeg, OUTPUT);
// pinMode(iPort.iKeta1Seg, OUTPUT);
// pinMode(iPort.iKeta2Seg, OUTPUT);
// pinMode(iPort.iKeta3Seg, OUTPUT);
// pinMode(iPort.iKeta4Seg, OUTPUT);
}
/*
* @fn 終了設定
* @brief デストラクタ
* @note 終了時には必ずリソースを終了状態にする。
* 生成したヒープ、つないだセッションなど開放する
*/
CSegControlClass::~CSegControlClass()
{
digitalWrite(iPort.iASeg, iPort.iLED_OFF);
digitalWrite(iPort.iBSeg, iPort.iLED_OFF);
digitalWrite(iPort.iCSeg, iPort.iLED_OFF);
digitalWrite(iPort.iDSeg, iPort.iLED_OFF);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_OFF);
digitalWrite(iPort.iGSeg, iPort.iLED_OFF);
digitalWrite(iPort.iDotSeg, iPort.iLED_OFF);
}
/* 出力設定 */
void CSegControlClass::SetOutput(int aOutput)
{
int lDigit = aOutput % 10;
switch(lDigit)
{
case 1:
one();
break;
case 2:
two();
break;
case 3:
three();
break;
case 4:
four();
break;
case 5:
five();
break;
case 6:
six();
break;
case 7:
seven();
break;
case 8:
eight();
break;
case 9:
nine();
break;
case 0:
default:
zero();
break;
}
}
//Display function 0
void CSegControlClass::zero() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_ON);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_OFF);
}
//Display function 1
void CSegControlClass::one() {
digitalWrite(iPort.iASeg, iPort.iLED_OFF);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_OFF);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_OFF);
digitalWrite(iPort.iGSeg, iPort.iLED_OFF);
}
//Display function 2
void CSegControlClass::two() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_OFF);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_ON);
digitalWrite(iPort.iFSeg, iPort.iLED_OFF);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 3
void CSegControlClass::three() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_OFF);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 4
void CSegControlClass::four() {
digitalWrite(iPort.iASeg, iPort.iLED_OFF);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_OFF);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 5
void CSegControlClass::five() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_OFF);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 6
void CSegControlClass::six() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_OFF);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_ON);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 7
void CSegControlClass::seven() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_OFF);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_OFF);
digitalWrite(iPort.iGSeg, iPort.iLED_OFF);
}
//Display function 8
void CSegControlClass::eight() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_ON);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}
//Display function 9
void CSegControlClass::nine() {
digitalWrite(iPort.iASeg, iPort.iLED_ON);
digitalWrite(iPort.iBSeg, iPort.iLED_ON);
digitalWrite(iPort.iCSeg, iPort.iLED_ON);
digitalWrite(iPort.iDSeg, iPort.iLED_ON);
digitalWrite(iPort.iESeg, iPort.iLED_OFF);
digitalWrite(iPort.iFSeg, iPort.iLED_ON);
digitalWrite(iPort.iGSeg, iPort.iLED_ON);
}