クラス設計をしよう - STM32 Timer編
1. クラス内でする処理を考える
まずは、クラス内でするべき動作を考えます。とりあえず、自分の喫緊の課題になっているものを列挙していきます。
- タイマー機能をPWMで初期化する
- PWM出力を開始する
- PWM出力を設定する
2. 実装方法を決める
続いて実装方法を決めていきます。コンストラクタに乗せるとか、メソッド化するとか、プライベート変数で保持してGetterSetterを作るとかです。
3. 真面目にメソッドやらをきめる
どんなメソッドを作っていくのか決めます。ヘッダファイルを作るといいような気もします。
class TimerPwm { /* ----------------------------------------------------- * public 列挙体、インナークラス * ----------------------------------------------------- */ public: enum EChannel : int { CH1 = 1, CH2 = 2, CH3 = 3, CH4 = 4, }; /* ----------------------------------------------------- * private メンバ変数 * ----------------------------------------------------- */ private: TIM_TypeDef *tim; // 設定対象タイマーのインスタンス。 /* ----------------------------------------------------- * public メソッド * ----------------------------------------------------- */ public: /** * @brief 設定対象タイマーのインスタンスを受け取るのみ。初期化動作は行わない。 * @param TIM_TypeDef _htim [I ]: 設定対象となるタイマーのインスタンス */ TimerPwm(TIM_TypeDef *uart); /** * @brief 初期化を行う関数。各レジスタの設定を行いペリフェラルを初期化する。 * @param period [I ]: PWMの周期幅 * @param prescale [I ]: プリスケーラの値。0の場合プリスケールなし。 * @retval None */ void initialize(uint32_t period, uint32_t prescale); /** * @brief PWM出力を開始する * @param EChannel ch [I ]: 設定するチャンネル */ void start(EChannel ch); /** * @brief 出力値を設定する。 * @param EChannel ch [I ]: 設定するチャンネル * @param uint32_t value [I ]: 設定する値 */ void out(EChannel ch, uint32_t value); };
GY-BNO055をUARTで使う
UARTの設定について
項目 | 値 |
---|---|
ボーレート | 115200 |
データ長 | 8ビット |
パリティビット | なし |
ストップビット | 1ビット |
レジスタへの書き込み方法
以下の順でデータを送ります。
Byte 1 | Start Byte | 0xAA |
---|---|---|
Byte 2 | Write | 0x00 |
Byte 3 | レジスタアドレス | <..> |
Byte 4 | データバイト数 | <..> |
Byte 5 | データバイト1 | <..> |
︙ | ︙ | ︙ |
Byte n+4 | データバイトn | <..> |
センサからの返り値は次のようになっていて、書き込みに成功したかを返します。
Byte 1 | Response Header | 0xEE |
---|---|---|
Byte 2 | Status | 以下の数値 |
0x01: 書き込み成功
0x03: 書き込み失敗
0x04: REGMAP_INVALID_ADDRESS
0x05: REGMAP_WRITE_DISABLED
0x06: WRONG_START_BYTE
0x07: BUS_OVER_RUN_ERROR
0X08: MAX_LENGTH_ERROR
0x09: MIN_LENGTH_ERROR
0x0A: RECEIVE_CHARACTER_TIMEOUT
レジスタからの読み出し
以下の順でデータを送ります。
Byte 1 | Start Byte | 0xAA |
---|---|---|
Byte 2 | Read | 0x01 |
Byte 3 | レジスタアドレス | <..> |
Byte 4 | データバイト数 | <..> |
センサからの返り値は2種類で、読み出しに成功したかと読み出した値を返します。
① 成功した場合は以下のパターンで値を返します。
Byte 1 | Start Byte | 0xBB |
---|---|---|
Byte 2 | データバイト数 | <..> |
Byte 3 | データバイト1 | <..> |
︙ | ︙ | ︙ |
Byte n+2 | データバイトn | <..> |
② 失敗した場合は以下のパターンで値を返します。
Byte 1 | Response Header | 0xEE |
---|---|---|
Byte 2 | Status | 以下の数値 |
0x02: READ_FAIL
0x04: REGMAP_INVALID_ADDRESS
0x05: REGMAP_WRITE_DISABLED
0x06: WRONG_START_BYTE
0x07: BUS_OVER_RUN_ERROR
0X08: MAX_LENGTH_ERROR
0x09: MIN_LENGTH_ERROR
0x0A: RECEIVE_CHARACTER_TIMEOUT
席替えをしたかった
ちょっと諸事情ありまして、席替えプログラムを作っておりました。
で、今回作ったプログラムを題するなら、「お隣さん絶対かわるやーつ」ってところでしょうか。
前後お隣の人がかならず変わります。というか、変わるまで、プログラムは終わりません。
あと、かなりテキトーなプログラムになるので、まさかりは投げないでください。
以下、プログラムになります。
#include<iostream> #include<vector> #include<random> #include<unistd.h> #define X_MAX 6 #define Y_MAX 4 #define KINBOU_N 4 #define NINZU 21 struct Tkumi{ int p1; int p2; bool operator<( const Tkumi& right ) const { return p1 == right.p1 ? p2 < right.p2 : p1 < right.p1; } }; void back_disp(){ printf("\e[5F"); } void disp(int seki[Y_MAX+2][X_MAX+2], char const *name[]){ printf("---------------------------------------------"); printf("---------------------------------------------------\n"); for ( int y = 1; y < Y_MAX+1; y++ ){ for ( int x = 1; x < X_MAX+1; x++ ){ if ( seki[y][x] > 0 ) { printf("%16s", name[seki[y][x]]); }else{ printf(" "); } } printf("\n"); } } int main(int argc, char const *argv[]) { int kinbou_x[KINBOU_N] = { 1, 0, -1, 0 }; int kinbou_y[KINBOU_N] = { 0, 1, 0, -1 }; int set[Y_MAX+2][X_MAX+2] = { // 場所固定の場合はここに値を入れる {-1,-1,-1,-1,-1,-1,-1,-1}, {-1, 0, 0, 0, 0, 0,19,-1}, {-1, 0, 0, 0, 0, 0, 0,-1}, {-1, 0, 0, 0, 0, 0, 0,-1}, {-1, 0,-1, 0,-1, 0,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1} }; int next[Y_MAX+2][X_MAX+2] = { {-1,-1,-1,-1,-1,-1,-1,-1}, {-1, 0, 0, 0, 0, 0, 0,-1}, {-1, 0, 0, 0, 0, 0, 0,-1}, {-1, 0, 0, 0, 0, 0, 0,-1}, {-1, 0,-1, 0,-1, 0,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1} }; int before[Y_MAX+2][X_MAX+2] = { {-1,-1,-1,-1,-1,-1,-1,-1}, {-1, 1, 5, 8,12,15,19,-1}, {-1, 2, 6, 9,13,16,20,-1}, {-1, 3, 7,10,14,17,21,-1}, {-1, 4,-1,11,-1,18,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1} }; int now[Y_MAX+2][X_MAX+2] = { {-1,-1,-1,-1,-1,-1,-1,-1}, {-1, 1, 2, 3, 4, 5, 6,-1}, {-1, 7, 8, 9,10,11,12,-1}, {-1,13,14,15,16,17,18,-1}, {-1,19,-1,20,-1,21,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1} }; char const *name[NINZU+1] = { "nonono", "name01", "name02", "name03", "name04", "name05", "name06", "name07", "name08", "name09", "name10", "name11", "name12", "name13", "name14", "name15", "name16", "name17", "name18", "name19", "name20", "name21" }; std::vector<Tkumi> kinshi; Tkumi dmy = { 0, 0 }; // 禁止リストを作成 for ( int y = 1; y < Y_MAX+1; y++ ){ for ( int x = 1; x < X_MAX+1; x++ ){ if ( now[y][x] >= 0 ) { // -1じゃなければ、4近傍を検索 for ( int k = 0; k < KINBOU_N; k++ ) { int hikaku = now[y+kinbou_y[k]][x+kinbou_x[k]]; if ( hikaku > 0 ){ // -1じゃなければ追加 dmy.p1 = now[y][x]; dmy.p2 = hikaku; if ( dmy.p1 > dmy.p2 ){ int swp = dmy.p1; dmy.p1 = dmy.p2; dmy.p2 = swp; } kinshi.push_back(dmy); } } } } } for ( ;; ) { // printf("---- restart ----\n"); // disp(next, name); int not_decide = 0; int ok = 0; // 固定値を設定 for ( int y = 1; y < Y_MAX+1; y++ ){ for ( int x = 1; x < X_MAX+1; x++ ){ if ( set[y][x] >= 0 ) { if ( set[y][x] == 0 ) not_decide++; next[y][x] = set[y][x]; } } } // 確定フェーズへ // 乱数生成 std::random_device rnd; // 非決定的な乱数生成器を生成 std::mt19937 mt(rnd()); // メルセンヌ・ツイスタの32ビット版、引数は初期シード値 std::uniform_int_distribution<> rand(1, NINZU); // [0, 99] 範囲の一様乱数 ok = 1; for ( int y = 1; y < Y_MAX+1; y++ ){ for ( int x = 1; x < X_MAX+1; x++ ){ if ( next[y][x] == 0 ) { // 席が未決かを確認 // 1席を決定 int maybe; for ( ;; ) { maybe = rand(mt); int maybe_cnt = 0; // 表内を探索して、同一番号があれば、乱数を振り直す for ( int y = 1; y < Y_MAX+1; y++ ){ for ( int x = 1; x < X_MAX+1; x++ ){ if ( next[y][x] == maybe ) { maybe_cnt++; } } } if ( maybe_cnt == 0 ) { // かぶり無しなので、この座席で仮決定 next[y][x] = maybe; break; } } back_disp(); disp(next, name); usleep(50000); // 禁止組み合わせを確認 // 4近傍を検索 for ( int k = 0; k < KINBOU_N; k++ ) { int hikaku = next[y+kinbou_y[k]][x+kinbou_x[k]]; if ( hikaku > 0 ){ // 近傍の席が配置済み for ( auto v = kinshi.begin(); v != kinshi.end(); v++ ) { if ( v->p1 == hikaku && v->p2 == maybe ) { ok = 0; break; } if ( v->p1 == maybe && v->p2 == hikaku ) { ok = 0; break; } } } } } if ( ok == 0 ) break; } if ( ok == 0 ) break; } if ( ok == 1 ){ break; } } printf("-----------------finale-------------\n"); printf("-----------------finale-------------\n"); printf("-----------------finale-------------\n"); disp(next, name); return 0; }
Elecrowで注文してみた
最近Twitterで広告を見なくなったElecrowですが、気が向いたので注文してみました。いろいろな関係で写真や基板データは見せられないのですが…
1. 所感
思ったより早く到着しました。ちょうど2週間なので早い方では?ただ、基板のパッドがヘアライン加工されているみたいな跡がついているのはなぜだろう?べつに完成したあとの基板の性能を左右するもんでもないので、問題ないのですが。
2.基板について
基板の詳細はこちら。特に何の変哲もない70×40[mm]の基板です。
2layers PCB 1.6mm 70mm x 40mm 5pcs Red
PCB Qty:5pcs
Layer:2layers
PCB Thickness:1.6mm
Dimensions:70mm * 40mm
Castellated Hole:No
PCB Color:Red
Surface Finish:HASL
Copper Weight:1oz
Text Color:White
Same Design:1
3. お値段
送料が一番安いのでもこれだったので、やむなく有料のにしました。たしか、Registered Airmailだったかな?
小計 $4.90
配送料と手数料 $5.34
割引価格 (196 points used) -$1.96
合計 $8.28
4. 日付
2018年5月15日 02:30:30 JST 注文と支払い完了
2018年5月15日 16:30:24 JST 注文受注
2018年5月15日 11:42:00 JST 出荷メール受領
2018年5月28日 11時頃 書留にて到着
5. 最後に
設計ミスした…
シングルボードコンピュータのまとめメモ
完全に自分用ですが…
Windowsを搭載できるシングルボードコンピュータをつらつらと並べていきます。
追記で情報を足していくかも??
1 . UP Core
- 価格:99$
- 長所
- 56.5×66mm、40gと小型で軽量
- 短所
- イーサーネット非対応
- 入手が難しそう?(ラズパイコンパチブルはAmazonにあり)
3 . Latte Panda Alpha
Latte Pandaの後継機に当たる
4 . UDOO X86 Basic
- 価格:99$
- 長所
- 短所
- 入手が難しそう?(Kickstarterのプロジェクト)
5 . UDOO X86 Ultra
- 価格:99$
- 長所
- 短所
- 入手が難しそう?(Kickstarterのプロジェクト)
MATLABの関数
関数について
MATLABは関数型言語に分類される。なので、関数の中で関数が宣言できたりもする。関数と関数ファイルは関係性が深い。それらの関係性から、関数は大きく分けて「基本関数」と「サブ関数」に分類される。
- 基本関数 -> 関数ファイルと同じ名前で、ファイルの一番最初に記述される関数。
- サブ関数 -> 関数ファイル内で、基本関数以外の関数。
1. 関数の呼び出し方
関数には入力引数と出力引数が存在して(C言語での引数と返り値に相当)、それぞれ複数指定可能である。基本文法は次のような感じ。
[y1, y2, …] = func(x1, x2, …)
出力引数が1つの場合は[]が省略できる。また、引数がない場合は、()が省略できる。下のは呼び出し方の例。
A = [1 3 5] B = [10 6 4] max(A) max(A, B) [maxA, location] = max(A)