测量周期和测量开始阈值允许使用 M5Stack LCD 和按钮进行选择。 记录的数据作为 csv 文件写入 SD 卡,并在 LCD 上显示。
[mw_shl_code=arduino,true]// 用INA 226 PRC测量每4毫秒3000次、12秒的电流值,并写在SD卡上
#include <M5Stack.h>
#include <Wire.h>
#include "INA226PRC.h"
#include "menu.h"
INA226PRC ina226prc;
void beep(int freq, int duration, uint8_t volume);
#define TIMER0 0
hw_timer_t * samplingTimer = NULL;
#define NSAMPLES 3000 // 4ms x 3000 = 12秒
short ampbuf[NSAMPLES];
short voltbuf[NSAMPLES];
int sampling = 4; // 采样间隔(毫秒)
int startthreshold = 3; // 开始记录的电流值(毫安)
Menu menu;
volatile int t0flag;
void IRAM_ATTR onTimer0() {
t0flag = 1;
}
int selectitem(int *candi, int items, int val, char *tail) {
int focused;
for (int i = 0; i < items; i++) {
if (candi == val) {
focused = i;
}
}
M5.Lcd.fillScreen(BLACK);
menu.setMenu("up", "OK", "down");
bool first = true;
while (true) {
bool modified = false;
M5.update();
if (M5.BtnA.wasPressed()) {
focused--;
modified = true;
}
if (M5.BtnC.wasPressed()) {
focused++;
modified = true;
}
if (M5.BtnB.wasPressed()) {
M5.Lcd.fillScreen(BLACK);
return candi[focused];
}
if (first || modified) {
first = false;
beep(1000, 100, 2);
for (int i = 0; i < items; i++) {
M5.Lcd.setCursor(100, 40 + i * 20);
int16_t textcolor = ((focused % items) == i) ? BLACK : WHITE;
int16_t backcolor = ((focused % items) == i) ? WHITE : BLACK;
M5.Lcd.setTextColor(textcolor, backcolor);
M5.Lcd.printf(" %d ", candi);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.print(tail);
}
}
}
}
void config() {
int focused = 2;
const int nItems = 3;
int thresholds[] = {2, 3, 5, 10, 20};
int samplings[] = {2, 4, 10, 20, 50};
bool first = true;
while (true) {
bool modified = false;
M5.update();
if (M5.BtnA.wasPressed()) {
focused--; // upボタン
modified = true;
}
if (M5.BtnC.wasPressed()) {
focused++; // downボタン
modified = true;
}
if (M5.BtnB.wasPressed()) { // changeボタン
modified = true;
switch (focused % nItems) {
case 0:
startthreshold = selectitem(thresholds, sizeof(thresholds) / sizeof(int), startthreshold, "mA");
break;
case 1:
sampling = selectitem(samplings, sizeof(samplings) / sizeof(int), sampling, "ms");
break;
case 2:
default:
return;
}
}
if (first || modified) { //
first = false;
beep(1000, 100, 2);
menu.setMenu("up", "GO", "down");
M5.Lcd.setCursor(20, 40);
M5.Lcd.print("Start threshold: ");
if ((focused % nItems) == 0) M5.Lcd.setTextColor(BLACK, WHITE);
M5.Lcd.printf(" %d ", startthreshold);
if ((focused % nItems) == 0) M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.print("mA");
M5.Lcd.setCursor(20, 100);
M5.Lcd.print("Sampling period: ");
if ((focused % nItems) == 1) M5.Lcd.setTextColor(BLACK, WHITE);
M5.Lcd.printf(" %d ", sampling);
if ((focused % nItems) == 1) M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.print("ms");
M5.Lcd.setCursor(20, 160);
if ((focused % nItems) == 2) M5.Lcd.setTextColor(BLACK, WHITE);
M5.Lcd.print(" DONE ");
if ((focused % nItems) == 2) M5.Lcd.setTextColor(WHITE, BLACK);
}
}
}
#define X0 10
#define Y0 220
void drawData(short maxamp) {
M5.Lcd.fillRect(0, 0, 320, 220, BLACK);
maxamp = ((maxamp / 100) + 1) * 100;
for (int i = 0; i < 299; i++) {
int y0 = map(ampbuf[i * 10], 0, maxamp, Y0, 0);
int y1 = map(ampbuf[(i + 1) * 10], 0, maxamp, Y0, 0);
M5.Lcd.drawLine(i + X0, y0, i + 1 + X0, y1, WHITE);
Serial.printf("%d, %d, %d, %d\r\n", ampbuf[i * 10], ampbuf[(i + 1) * 10], y0, y1);
}
M5.Lcd.drawLine(X0, Y0, 310, Y0, WHITE);
M5.Lcd.drawLine(X0, 0, X0, Y0, WHITE);
}
void setup() {
M5.begin();
Wire.begin();
ina226prc.begin();
Serial.print("Manufacture ID: ");
Serial.println(ina226prc.readId(), HEX);
M5.Lcd.setTextSize(2);
config();
M5.Lcd.fillScreen(BLACK);
beep(1000, 100, 2);
menu.setMenu("start", "", "");
M5.Lcd.setCursor(20, 100);
M5.Lcd.print("Press A button");
M5.Lcd.setCursor(40, 120);
M5.Lcd.print("to start sampling");
while (true) {
M5.update();
if (M5.BtnA.wasPressed()) break;
}
M5.Lcd.fillScreen(BLACK);
beep(2000, 100, 2);
samplingTimer = timerBegin(TIMER0, 80, true); //
timerAttachInterrupt(samplingTimer, &onTimer0, true); //
timerAlarmWrite(samplingTimer, sampling * 1000, true); //
timerAlarmEnable(samplingTimer); //
bool started = false;
int indx = 0;
short maxamp = 0;
M5.Lcd.fillRect(50, 100, 200, 10, BLACK);
while (true) {
t0flag = 0;
while (t0flag == 0) { //
delay(0);
}
short amp = ina226prc.readCurrentReg();
short volt = ina226prc.readVoltageReg();
if (!started) {
// 如果电流值小于阈值(startthreshold),则不开始测量
if (amp * 0.1 > -(float)startthreshold && amp * 0.1 < (float)startthreshold) {
continue;
}
started = true; //
}
ampbuf[indx] = amp; //
voltbuf[indx] = volt; //
maxamp = max(amp, maxamp);
M5.Lcd.setCursor(100, 100);
M5.Lcd.print(indx * 100 / NSAMPLES); M5.Lcd.print(" %");
if (++indx >= NSAMPLES) { //
break;
}
}
timerAlarmDisable(samplingTimer); //
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(20, 100);
beep(2000, 400, 2);
char fname[20];
sprintf(fname, "/curLog.csv");
for (int i = 0; SD.exists(fname); i++) {
sprintf(fname, "/curLog(%d).csv", i + 1);
}
File f = SD.open(fname, FILE_WRITE);
if (f) {
f.println("time, current(mA), volt(mV)");
for (int i = 0; i < NSAMPLES; i++) {
f.printf("%d, %.2f, %.2f\r\n", sampling * i, ampbuf * 0.1, voltbuf * 1.25);
}
f.close();
M5.Lcd.print("Data written to");
M5.Lcd.setCursor(40, 120);
M5.Lcd.print(fname);
} else {
M5.Lcd.printf("open error %s", fname);
}
menu.setMenu("view", "", "");
M5.Lcd.setCursor(40, 160);
M5.Lcd.print("Press A button");
M5.Lcd.setCursor(40, 180);
M5.Lcd.print("to view data");
while (true) {
M5.update();
if (M5.BtnA.wasPressed()) {
drawData(maxamp);
}
}
}
void loop()
{
}
[/mw_shl_code]