VIDEO
CANにリクエストするのは失敗しましたが、お目当ての車速がゲットできたので完成に一歩近づいてきました。
必要なライブラリは以下の2つ。先にインストールしておきます。
・greiman / SSD1306Ascii
・coryjfowler / MCP_CAN_lib
SSD1306Asciiはスケッチ量がとても軽いのが特徴で自分が失敗して購入した168pでも26%ほどの余裕が生まれました。Adafruit純正やu8glibでは容量的に厳しいものがありました。
ライブラリの開発者様には本当に感謝ですね。
動作機序なんてほとんど理解できていなくてもそれなりのものが簡単に仕上がるのってすごいと思います。
DS1307 のRTCモジュールが届いたので、ブレッドボードで
実験 してみました。iPhoneのストップウォッチと並べてみてしばらく眺めていたところ、3分に1回程度ランダムに1秒割り込みが漏れてしまう現象が発生していたので、
コードを書き直し ました。
6つのフラグ変数を1バイトで合わせて処理していたのでそれが原因のようでした。
(下記のコードは修正済みのものです)
しばらくiPhoneのストップウォッチと見比べていましたが気になるようなズレはなかったので
問題なく動作 しているものと思われます。
DS1307の乗ったTiny RTC I2Cモジュール 、電池ホルダーを挟んで両側にピンを接続できるようになっています 。どっちに繋いでも同じように動作 します。
SQWの1Hz信号を使うので7つ開いてるほうにピンヘッダをはんだ付けしました。
ネットで探すとどの写真でも5つ開いてるほうにピンヘッダを取り付けている例しか見ることができなかったので反対側は使えないのかと思っていましたがそうではなさそう です。
容量が大きいArduino nano 328p版も別の基板から引っぺがしてきたのでこれで好き放題プログラムが書けるようになりました。
SQWの信号を割り込ませるだけで、RTCモジュールの
時計機能を全く使用していない ので、かなり
勿体ない 気がしています。
//LED関係
//LED関係
#define LED_PIN 6
#define BLINK_INTERVAL 50//ms
bool states;
//RTC関係
#include
#define RTC_ADDRESS 0x68
//CAN関係
#include
#include
#define CAN0_INT 2
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
short int rpm = 0;
short int gas_pedal = 0;
bool brk = 0;
float kmh = 0;
MCP_CAN CAN0(10); //CS pin10
//OLED関係
#include "SSD1306AsciiAvrI2c.h"
#define OLED_ADDRESS 0x3C
SSD1306AsciiAvrI2c oled;
//タイマー関係
#define H4 14400UL//4時間分の秒数4*60*60
short int h4Timer = H4 - 1UL; //H4;
unsigned short int stopTimer = 0;//停止時間計測 秒
short int stopKakutei = 0;//確定した停車時間の積算
short int stopKakutei_old = 0;//停止時間計測 h4Timerに加算検出用
unsigned int timerBlink;
char str[32];//OLED文字バッファ
volatile bool Flg_1HZ = false;
bool Flg_STOP = false;
short int stopTimeBuf[3] = {0, 0, 0};
void setup() {
pinMode(LED_PIN, OUTPUT);//LED出力
CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ);
CAN0.setMode(MCP_NORMAL);
pinMode(CAN0_INT, INPUT);
oled.begin(&Adafruit128x64, OLED_ADDRESS);
//RTC初期化 pin3は、SQW1秒クロック割り込み
iniRTC();
pinMode(3, INPUT_PULLUP);//pin3
attachInterrupt(1, sec_cnt, FALLING);//pinD3
/*
//デバッグモード
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, OUTPUT);
//OLED割り込み
pinMode(2, INPUT_PULLUP);
attachInterrupt(0, oled_prn, FALLING);//pinD2-D9
*/
}
void loop() {
CAN0.readMsgBuf(&rxId, &len, rxBuf);
switch (rxId) {
case 0x0c9:
rpm = ((rxBuf[1] * 256) + rxBuf[2]) / 4;//回転数
gas_pedal = (rxBuf[4] * 100) / 256;//アクセルペダル踏込み量
brk = rxBuf[5];//ブレーキのオフオン
break;
case 0x3E9:
kmh = ((rxBuf[0] * 100) + rxBuf[1]) * 0.04;//車速
break;
}
/*//デバッグモード
rpm = 0;
brk = 0;
if(!digitalRead(7)){
rpm = 1700;
}
if(!digitalRead(8)){
brk = 1;
}
*/
//回転数が一定値以上でLED警告
states = LOW;
if (kmh < 55){//55キロ未満 一般道シフトアップリミット
if(rpm >= 1677){
states = HIGH;
}
}else if(kmh < 70){//70キロ未満 一般道 5速60キロリミット
if(rpm >= 1480){
states = HIGH;
}
}else{//70キロ以上 高速道90キロリミット
if(rpm >= 1620){
states = HIGH;
}
}
//rpm = 3000 * (1+(float)gas_pedal) / 100;//デバッグ用
//ブレーキ操作時
if (brk == 1) {
switch (gas_pedal) {
case 99:
software_RESET();
break;
default:
//ブレーキのみ踏んでいる場合
digitalWrite(LED_PIN, LOW);
break;
}
}else{//アクセル操作時
digitalWrite(LED_PIN, !(states));
}
//車速が入ればflgオン
if (kmh == 0) {
Flg_STOP = true;
} else {
Flg_STOP = false;
}
/*タイマカウント部*/
if (Flg_1HZ) {
Flg_1HZ = false;
//4時間タイマーカウントダウン
h4Timer --;
if (h4Timer <= 0) { //4時間タイマーがゼロ時の動作
h4Timer = 0;
}
//停車時間タイマカウントアップ
//停車中---------------
if ( Flg_STOP ) {
//停車カウンタインクリメント
stopTimer += 1;
if(stopTimer >= 60000){//999分59秒より大きくなったら1秒戻す
stopTimer -= 1;
}
//今の有効な停車分数+バッファの合計停車分
stopKakutei = stopTime_calc( stopTimer ) + stopTime_sum();
if (stopKakutei >= 30) { //30分以上は30分固定
stopKakutei = 30;
h4Timer ++;//h4タイマー停止
}
//確定した有効な停車分数をh4タイマーに戻す
if (stopKakutei != stopKakutei_old) {
h4Timer += (stopKakutei - stopKakutei_old) * 60;
stopKakutei_old = stopKakutei;
}
}//走行中-----------------
else {
//30分の休憩確定で初期化リセット
if (stopKakutei >= 30) {
software_RESET();
}
//30分未満の有効な停車分数をバッファに書き込み
stopTimeBuf_write( stopTime_calc( stopTimer ) );
stopTimer = 0;
}
}
/*----------------------------*/
//noInterrupts(); //割り込み禁止
//oled_prn();
//interrupts();
}
//RTCの初期化
void iniRTC() {
Wire.beginTransmission(RTC_ADDRESS);//DS1307
Wire.write(0x00);//Register 先頭アドレス
Wire.write(0x00);//RTC 0秒開始
Wire.write(0x00);//RTC 分
Wire.write(0x00);//RTC 時
Wire.write(0x00);//RTC 週
Wire.write(0x00);//RTC 日
Wire.write(0x00);//RTC 月
Wire.write(0x00);//RTC 年
Wire.write(0x10);//RTC SQW 1Hz
Wire.endTransmission();
}
void oled_prn(){
oled.set1X();
oled.setFont(Adafruit5x7);
oled.setCursor(0, 0);
sprintf_P(str, PSTR("\nHR4\nTMR"));
oled.print(str);
//車速、回転数、ブレーキ,アクセルペダル表示
oled.setCursor(0, 7);
sprintf(str, "%3dkm %4drpm B%d A%2d", (int)kmh, rpm, brk, gas_pedal);
oled.print(str);
//STOP TIMEの文字表示
oled.setCursor(75, 4);
oled.print(F("STOP"));
oled.setCursor(75, 5);
oled.print(F("TIME"));
//H4タイマカウンタ表示
oled.setFont(lcdnums14x24);
sprintf_P(str, PSTR("%d:%02d:%02d"), s_to_h(h4Timer) , s_to_m(h4Timer), s_to_s(h4Timer) );
oled.setCursor(20, 0);
oled.print(str);
//停車時間タイマカウンタ表示
oled.setFont(lcdnums12x16);
oled.setCursor(0, 4);
if (stopTimer <= 0) {
sprintf_P(str, PSTR("---:--"));
} else {
sprintf_P(str, PSTR("%03d:%02d"), s_to_m(stopTimer) + (s_to_h(stopTimer) * 60), s_to_s(stopTimer) );
}
oled.print(str);
//停車時間確定カウンタ表示
oled.set2X();
oled.setFont(Adafruit5x7);
oled.setCursor(100, 4);
if (stopKakutei == 0) {
sprintf_P(str, PSTR(" "));
} else {
sprintf_P(str, PSTR("%d"), stopKakutei);
}
oled.print(str);
}
void sec_cnt() { //割り込み用(1秒クロック)
Flg_1HZ = true;
oled_prn();
}
short int stopTime_calc(unsigned short int i) { //引数:停車(秒数) 戻値:有効な停車(分数)
i = s_to_m(i) + (s_to_h(i) * 60); //分数に変換
if (i >= 30) {
i = 30;
} else if (i >= 20) {
i = 20;
} else if (i >= 15) {
i = 15;
} else if (i >= 10) {
i = 10;
} else {
i = 0;
}
return i;
}
short int stopTime_sum() { //バッファの合計値(分数)を求める
short int sum = 0;
for (int x = 0; x < 3; x++) {
sum += stopTimeBuf[x];
}
return sum;
}
void stopTimeBuf_write(short int i) { //バッファ未使用領域に停車(分数)を書き込む
for (int x = 0; x < 3; x++) {
if (stopTimeBuf[x] == 0) {
stopTimeBuf[x] = i;
break;
}
}
}
void software_RESET() { //強制リセット
asm volatile (" jmp 0");
}
void digitalWrite_A(int pin, bool val, float per){//LED明るさ調整
analogWrite(pin, (255*(per/100)) * val );
}
/*----- タイマー演算用 -----*/
int s_to_h(unsigned long s) {
return s / 3600;
}
int s_to_m(unsigned long s) {
return (s % 3600) / 60;
}
int s_to_s(unsigned long s) {
return s % 60;
}
/*----------------------------*/
Posted at 2022/02/06 00:07:06 | |
トラックバック(0) |
Arduino | パソコン/インターネット