回答編集履歴
2
サンプル追加
answer
CHANGED
@@ -4,4 +4,198 @@
|
|
4
4
|
パルスのエッジの記録は「割り込み」による。割り込みハンドラ内でmicros()の値を配列に保存
|
5
5
|
Z相が来たら記録面を切り替えて、記録済の面をSDカードに書き出す、とかいうところでしょうか。
|
6
6
|
|
7
|
-
(話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
|
7
|
+
(話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
面倒といいながら、SD書き込み中にちゃんと割り込みがかかるか等、色々と気になったので作ってみました。ただし、ターゲットはArduino m0/PROで、そのままDueに持っていけるかどうかは知りません。どちらもATMELのARMだし、m0の方が低クロック少メモリなので期待は出来ますが。
|
12
|
+
|
13
|
+
動作チェックとして他のマイコンで2s/555μs/694μs(それぞれ設定値、パルス同士は同期をとっていません)のパルスを作ってそれを突っ込んで大体2.0002s/22b(555)~22d(557)/ 2b6(694)~2b7(695)ぐらいの値が出ているのでそこそこかと。
|
14
|
+
|
15
|
+
SDカードの書き出しは数字で打ちたかったのですが、2秒に確実に収まるとは言えない感じだったのでバイナリにしています。書き込み時間は200~500msぐらいでばらつきます。Dueの方がCPUが早いのでもしかしたら数字でも出せるかもしれませんが、SDのI/Fが律速しているのかも。
|
16
|
+
|
17
|
+
```Arduino
|
18
|
+
//Items.h
|
19
|
+
#include <cstddef>
|
20
|
+
#include <SD.h>
|
21
|
+
|
22
|
+
class Items {
|
23
|
+
//バッファ管理変数
|
24
|
+
volatile unsigned short *buf[2];
|
25
|
+
//データインデックス管理
|
26
|
+
volatile size_t idx[2];
|
27
|
+
//データ最大数
|
28
|
+
size_t bufSize;
|
29
|
+
//周数
|
30
|
+
volatile unsigned int round;
|
31
|
+
//周の最初の立ち上がりエッジ保存
|
32
|
+
unsigned long t0[2];
|
33
|
+
//前回の立ち上がり時刻保存
|
34
|
+
volatile unsigned long tPrev[2];
|
35
|
+
//周の初回判定
|
36
|
+
bool start;
|
37
|
+
|
38
|
+
public:
|
39
|
+
Items(size_t );
|
40
|
+
//割り込みハンドラ本体
|
41
|
+
void handle();
|
42
|
+
//周送り処理
|
43
|
+
void turnRound();
|
44
|
+
//データ書き出し
|
45
|
+
void logWrite(File);
|
46
|
+
};
|
47
|
+
```
|
48
|
+
```Arduino
|
49
|
+
//Itmes.cpp
|
50
|
+
#include <Arduino.h>
|
51
|
+
#include <cstddef>
|
52
|
+
#include <SD.h>
|
53
|
+
#include "Items.h"
|
54
|
+
|
55
|
+
Items::Items(size_t sz) : bufSize(sz) {
|
56
|
+
start = false;
|
57
|
+
round = 0;
|
58
|
+
buf[0] = new unsigned short[bufSize];
|
59
|
+
buf[1] = new unsigned short[bufSize];
|
60
|
+
};
|
61
|
+
|
62
|
+
//割り込みハンドラ本体
|
63
|
+
void Items::handle() {
|
64
|
+
unsigned long tt = micros();//時刻取得
|
65
|
+
size_t rr = round % 2; //使用バッファブロック選択
|
66
|
+
if (!start) { //周の初回の処理
|
67
|
+
idx[rr] = 0;
|
68
|
+
t0[rr] = tt;
|
69
|
+
tPrev[rr] = tt;
|
70
|
+
start = true;
|
71
|
+
}
|
72
|
+
if (idx[rr] < bufSize) { //バッファに余裕あるなら
|
73
|
+
buf[rr][idx[rr]++] = tt - tPrev[rr]; //前回との差分値を保存
|
74
|
+
}
|
75
|
+
tPrev[rr] = tt;//今回値を保存(次回差分計算用)
|
76
|
+
}
|
77
|
+
|
78
|
+
//周送り
|
79
|
+
void Items::turnRound() {
|
80
|
+
round += 1;
|
81
|
+
start = false;
|
82
|
+
}
|
83
|
+
|
84
|
+
//データ書き出し
|
85
|
+
void Items::logWrite(File logFile) {
|
86
|
+
if (round > 0) {
|
87
|
+
size_t rr = (round - 1) % 2;
|
88
|
+
//前回の周の最初の立ち上がりエッジ時刻
|
89
|
+
unsigned long tmp = t0[rr];
|
90
|
+
logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
|
91
|
+
//前回の周のデータ数
|
92
|
+
tmp = idx[rr];
|
93
|
+
logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
|
94
|
+
//データ本体書き込み
|
95
|
+
for (unsigned int i = 0; i < idx[rr]; i++) {
|
96
|
+
unsigned short tmp;
|
97
|
+
tmp = buf[rr][i];
|
98
|
+
logFile.write((uint8_t*)&tmp, sizeof(unsigned short));
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
```
|
103
|
+
```Arduino
|
104
|
+
//main.ino
|
105
|
+
#include <SPI.h>
|
106
|
+
#include <SD.h>
|
107
|
+
|
108
|
+
#include "Items.h"
|
109
|
+
|
110
|
+
typedef const int Pin;
|
111
|
+
Pin PhA = 6;
|
112
|
+
Pin PhB = 4;//m0のD2は割り込みを受けないみたいなので変更
|
113
|
+
Pin PhZ = 5;
|
114
|
+
|
115
|
+
//Z相読み出しのレイテンシを見込んで少し余裕を持たせる
|
116
|
+
const int RATIOA = 2880 + 32;
|
117
|
+
const int RATIOB = 3600 + 32;
|
118
|
+
|
119
|
+
Items pha(RATIOA), phb(RATIOB);
|
120
|
+
|
121
|
+
volatile bool isSDtriggered = false;//カード書き込みトリガ
|
122
|
+
|
123
|
+
volatile unsigned int roundZ = 0;//回転回数
|
124
|
+
volatile unsigned long bufZ[2];//Z相時刻
|
125
|
+
|
126
|
+
File logFile;
|
127
|
+
|
128
|
+
//A相割り込みハンドラ
|
129
|
+
void handleA() {
|
130
|
+
pha.handle();
|
131
|
+
}
|
132
|
+
|
133
|
+
//B相割り込みハンドラ
|
134
|
+
void handleB() {
|
135
|
+
phb.handle();
|
136
|
+
}
|
137
|
+
|
138
|
+
//Z相割り込みハンドラ
|
139
|
+
void handleZ() {
|
140
|
+
if (isSDtriggered) {
|
141
|
+
return; //前の処理が終わっていない
|
142
|
+
}
|
143
|
+
bufZ[++roundZ % 2] = micros();//時刻記録
|
144
|
+
pha.turnRound();//A相次の周へ
|
145
|
+
phb.turnRound();//B相次の周へ
|
146
|
+
isSDtriggered = true;//一周回ったので記録開始(SD操作はmainコンテキストで)
|
147
|
+
}
|
148
|
+
|
149
|
+
void setup() {
|
150
|
+
Serial.begin(115200);
|
151
|
+
pinMode(PhA, INPUT);
|
152
|
+
pinMode(PhB, INPUT);
|
153
|
+
pinMode(PhZ, INPUT);
|
154
|
+
//各相割り込み設定
|
155
|
+
attachInterrupt(digitalPinToInterrupt(PhA), handleA, RISING);
|
156
|
+
attachInterrupt(digitalPinToInterrupt(PhB), handleB, RISING);
|
157
|
+
attachInterrupt(digitalPinToInterrupt(PhZ), handleZ, RISING);
|
158
|
+
|
159
|
+
if (!SD.begin(10)) {
|
160
|
+
Serial.println("SD initialization failed!");
|
161
|
+
while (1);//カード初期化失敗したら停止
|
162
|
+
}
|
163
|
+
Serial.println("SD initialization done.");
|
164
|
+
}
|
165
|
+
|
166
|
+
void loop() {
|
167
|
+
if (isSDtriggered) { //SD書き込みトリガ掛かっていたら書き込み
|
168
|
+
if ( roundZ > 1&& roundZ<11) { //1周目完=2周目~9周目完=10周目のときSD書き込み
|
169
|
+
char fname[128];//ファイル名生成
|
170
|
+
|
171
|
+
Serial.println("SD start");
|
172
|
+
sprintf(fname, "/enc/round%d.txt", roundZ - 1); //round周数.txt
|
173
|
+
Serial.println("File: " + String(fname));
|
174
|
+
logFile = SD.open(fname, FILE_WRITE & ~O_APPEND); //ファイル先頭から書き込み
|
175
|
+
if (!logFile) {
|
176
|
+
Serial.println("File open error.");
|
177
|
+
while (1); //ファイルオープン失敗したら停止
|
178
|
+
}
|
179
|
+
unsigned long tmp = roundZ - 1; //現在(収集中)の前の周(収集完了)のデータ
|
180
|
+
logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
|
181
|
+
tmp = bufZ[(roundZ - 1) % 2];
|
182
|
+
logFile.write((uint8_t*)&tmp, sizeof(unsigned long));
|
183
|
+
pha.logWrite(logFile); //A相データ書き込み
|
184
|
+
phb.logWrite(logFile); //B相データ書き込み
|
185
|
+
logFile.close();
|
186
|
+
Serial.println("SD done");
|
187
|
+
}
|
188
|
+
isSDtriggered = false;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
/*ファイルフォーマットは
|
192
|
+
* 4byte 周ナンバー
|
193
|
+
* 4byte Z相立ち上がり時刻(micros値)
|
194
|
+
* 4byte A相立ち上がり時刻(micros値)
|
195
|
+
* 4byte A相データ数
|
196
|
+
* 2byte x データ数 A相間隔データ
|
197
|
+
* 4byte B相立ち上がり時刻(micros値)
|
198
|
+
* 4byte B相データ数
|
199
|
+
* 2byte x データ数 B相間隔データ
|
200
|
+
*/
|
201
|
+
```
|
1
表記変更
answer
CHANGED
@@ -4,4 +4,4 @@
|
|
4
4
|
パルスのエッジの記録は「割り込み」による。割り込みハンドラ内でmicros()の値を配列に保存
|
5
5
|
Z相が来たら記録面を切り替えて、記録済の面をSDカードに書き出す、とかいうところでしょうか。
|
6
6
|
|
7
|
-
(話だけでわかるかとも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
|
7
|
+
(話だけでわかるか? とも思うけど、サンプルを書けとかいわれるとちょっと面倒だなぁ...)
|