
こんにちは、Habr。 彼のエンジニアリングの若さを思い出して、私は再び腺をいじりたかった。 PICとacmeプログラミングに戻ることは率直に言って怠け者でした(i2cとHD44780バスを備えたサードパーティライブラリなしの手作業の心的外傷の子供時代の思い出)。
一見すると、これがまさにノスタルジックな衝動を満たすために必要なものであることがわかりました。 1週間前、キットが購入されました。 5年の経験を持つ元の電子技術者にLEDを点滅させることは、どういうわけかうまくいきませんでした。そのため、戦車の統計メーターのアイデアが生まれました(私はそれが罪だと告白します...)。 これが私の「ハロー、ハブラー!」と「ハロー、ワールド!」です。
アイデアは簡単です-Wargaming統計サーバーを監視し、ユーザーにゲームの成功(またはターンアラウンド)を通知する 無関係なリソースのWebページを解析するという考えは、W5100コントローラーのネットワークシールドへのアクセスに使用されるRAMのサイズ(受信あたり8 KB)にかかっていたため、Wargaming APIを使用して監視することにしました。
情報を表示するために、手元にあるもの、つまり標準ディスプレイ1602を取りましたが、それはそれほど簡単ではないため、シフトレジスタ74HC595を介して接続することにしました。 簡単な検索で、すべてが私たちの前にすでに発明されていたという古い真実が証明されました: link 。 ディスプレイはSPIバス上にあり、さらに1つのピンを使用してデバイスを選択します(3番目のものがあります)。 コンパイルを成功させるには、LiquidCrystalライブラリを上記のリンクから変更したライブラリに置き換える必要があります。 また、上記のリンクから、著者はディスプレイのr / wピンを地面に置くのを忘れていたため、最初は例が機能していないと考えていました。 念のため、私のクレイジーボード:
ブレッドボード

また、達成度ログをSDカードに実装することを望んでいましたが、将来のために残しておくことと、監視結果のある小さなWebサーバーを残すことにしました。
スケッチ
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>
#define ETHERNET_PIN 10
#define LCD_PIN 3
//ネットワーク上の強制IPアドレス
IPAddress ip(192、168、1、40);
// MAC
バイトmac [] = {0x42、0x42、0x42、0x42、0x42、0x42};
//サーバー、登録済みideshnik、プロファイル番号
const char server [] = "api.worldoftanks.ru";
const char application_id [] = "demo";
const char account_id [] = "4848655";
//ミリ秒単位の更新レート
const unsigned int UpdateDelta = 20000;
//更新まで放置
unsigned int UpdateTime = 0;
//ネットワーククライアント
EthernetClientクライアント。
// LCD
LiquidCrystal lcd(LCD_PIN);
バイトnewChar1 [8] = {
B00100、
B01110、
B10101、
B00100、
B00100、
B00100、
B00100、
B00000
};
バイトnewChar2 [8] = {
B00100、
B00100、
B00100、
B00100、
B10101、
B01110、
B00100、
B00000
};
//解析ステータス
列挙型ReadStatusEnum {
WiteTag、
ReadTag、
価値
} ReadStatus = WiteTag;
文字列のニックネーム= "Unknown Noob";
long WG_rating、pre_WG_rating、buf_WG_rating = 0;
符号なしの長いバトル、pre_battles、buf_battles = 0;
符号なしロングウィン、pre_wins、buf_wins = 0;
符号なしの長い損傷、pre_damage、buf_damage = 0;
符号なしの長いフラグメント、pre_frags、buf_frags = 0;
文字列LCD_strings [6];
//タグの中から目的のものを検索します
void FilterData(文字列SectionTagName、文字列TagName、文字列値)
{
if(SectionTagName.compareTo( "statistics")== 0){
if(TagName.compareTo( "nickname")== 0)
ニックネーム=値;
if(TagName.compareTo( "global_rating")== 0)
buf_WG_rating = Value.toInt();
}
if(SectionTagName.compareTo( "all")== 0){
if(TagName.compareTo( "battles")== 0)
buf_battles = Value.toInt();
if(TagName.compareTo( "wins")== 0)
buf_wins = Value.toInt();
if(TagName.compareTo( "damage_dealt")== 0)
buf_damage = Value.toInt();
if(TagName.compareTo( "frags")== 0)
buf_frags = Value.toInt();
}
}
void readServer()
{
//接続します
if(client.connect(server、80)){
client.print( "GET / wot / account / info /?application_id =");
client.print(application_id);
client.print( "&account_id =");
client.print(account_id);
client.println( "HTTP / 1.1");
client.print( "Host:„);
client.println(サーバー);
client.println(「ユーザーエージェント:arduino-ethernet」);
client.println( "Accept:text / html");
client.println( "接続:閉じる");
client.println();
//準備ができているのを待っています
bool Wait = true;
unsigned int Time = 0;
while(待機)
{
待機=!Client.available();
if(Time> 200)Wait = false;
時間++;
遅延(10);
}
文字記号= '';
char pre_symbol = '';
文字列TagName = "";
文字列SectionTagName = "";
文字列値= "";
文字列PreSectionTagName = "";
ReadStatus = WiteTag;
//バッファが空になるまで繰り返します
while(client.available()){
//バッファからバイトを読み取ります
pre_symbol = symbol;
symbol = client.read();
//Serial.print(symbol);
if(ReadStatus == WiteTag && pre_symbol == '"' && symbol!= ':'){
//タグの始まりを見つけました
ReadStatus = ReadTag;
TagName = "";
}
if(ReadStatus == ReadTag){
if(symbol!= '"'){
//タグ名を読み取ります
TagName + =シンボル;
}
他に
{
//タグの終わりが見つかりました
値= "";
ReadStatus = WiteValue;
}
}
if(ReadStatus == WiteValue){
if(symbol == '、' || symbol == '}'){
//値の終わり
ReadStatus = WiteTag;
FilterData(SectionTagName、TagName、Value);
if(symbol == '}'){
//セクションの終わり
SectionTagName = PreSectionTagName;
}
}
その他{
if(symbol == '{'){
//開始セクション
PreSectionTagName = SectionTagName;
SectionTagName = TagName;
ReadStatus = WiteTag;
}
その他{
//値を読み取ります
if(symbol!= ':' && symbol!= '"' && symbol!= '')
値+ =シンボル;
}
}
}
}
}
//クライアントを停止します
client.flush();
client.stop();
}
void generateSrings()
{
if(pre_battles == 0 || battles == 0){
//初期化
pre_WG_rating = buf_WG_rating;
WG_rating = buf_WG_rating;
pre_battles = buf_battles;
バトル= buf_battles;
pre_wins = buf_wins;
wins = buf_wins;
pre_damage = buf_damage;
損傷= buf_damage;
pre_frags = buf_frags;
frags = buf_frags;
}
if(buf_battles>戦闘)
{
//統計の更新がありました
pre_WG_rating = WG_rating;
WG_rating = buf_WG_rating;
pre_battles =バトル。
バトル= buf_battles;
pre_wins = wins;
wins = buf_wins;
pre_damage =損傷;
損傷= buf_damage;
pre_frags = frags;
frags = buf_frags;
}
if(pre_battles == battles)
{
LCD_strings [0] =ニックネーム+ "";
LCD_strings [0] = LCD_strings [0] .substring(0,16);
LCD_strings [1] = "Btl:" +文字列(バトル)+ "-";
LCD_strings [1] = LCD_strings [1] .substring(0,16);
float wins_percent =(float)wins /(float)battles * 100.0;
LCD_strings [2] = "Wins:" +文字列(wins_percent)+ "-";
LCD_strings [2] = LCD_strings [2] .substring(0,16);
float avrage_damage =(float)ダメージ/(float)バトル。
文字列D =文字列(avrage_damage);
D = D.substring(0、D.length()-1);
LCD_strings [3] = "Dmg:" + D + "-";
LCD_strings [3] = LCD_strings [3] .substring(0,16);
float avrage_frags =(float)frags /(float)バトル;
LCD_strings [4] = "Frag:" +文字列(avrage_frags)+ "-";
LCD_strings [4] = LCD_strings [4] .substring(0,16);
LCD_strings [5] = "WG:" +文字列(WG_rating)+ "-";
LCD_strings [5] = LCD_strings [5] .substring(0,16);
}
他に
{
LCD_strings [0] =ニックネーム+ "";
LCD_strings [0] = LCD_strings [0] .substring(0,16);
LCD_strings [1] = "Btl:" +文字列(バトル)+ "" +文字(0x01)+文字列(battles-pre_battles)+ "";
LCD_strings [1] = LCD_strings [1] .substring(0,16);
float wins_percent =(float)wins /(float)battles * 100.0;
float pre_wins_percent =(float)pre_wins /(float)pre_battles * 100.0;
char Delta = char(0x01);
if(wins_percent <pre_wins_percent)Delta = char(0x02);
LCD_strings [2] = "Wins:" + String(wins_percent)+ "" + Delta + String(abs(wins_percent-pre_wins_percent))+ "";
LCD_strings [2] = LCD_strings [2] .substring(0,16);
float avrage_damage =(float)ダメージ/(float)バトル。
float pre_avrage_damage =(float)pre_damage /(float)pre_battles;
Delta = char(0x01);
if(avrage_damage <pre_avrage_damage)Delta = char(0x02);
文字列D =文字列(avrage_damage);
D = D.substring(0、D.length()-1);
LCD_strings [3] = "Dmg:" + D + "" + Delta + String(abs(avrage_damage-pre_avrage_damage))+ "";
LCD_strings [3] = LCD_strings [3] .substring(0,16);
float avrage_frags =(float)frags /(float)バトル;
float pre_avrage_frags =(float)pre_frags /(float)pre_battles;
Delta = char(0x01);
if(avrage_frags <pre_avrage_frags)Delta = char(0x02);
LCD_strings [4] = "フラグ:" +文字列(avrage_frags)+ "" +デルタ+文字列(abs(avrage_frags-pre_avrage_frags))+ "";
LCD_strings [4] = LCD_strings [4] .substring(0,16);
Delta = char(0x01);
if(WG_rating <pre_WG_rating)Delta = char(0x02);
LCD_strings [5] = "WG:" +文字列(WG_rating)+ "" +デルタ+文字列(abs(WG_rating-pre_WG_rating))+ "";
LCD_strings [5] = LCD_strings [5] .substring(0,16);
}
}
void PrintMSG(int LCD_tick、int ScrNum)
{
if(LCD_tick <= 16)
{
lcd.setCursor(0、0);
lcd.print(LCD_strings [ScrNum * 2 + 0] .substring(0、LCD_tick)+ "_");
}
他に
{
lcd.setCursor(0、1);
lcd.print(LCD_strings [ScrNum * 2 + 1] .substring(0、LCD_tick-16)+ "_");
}
}
unsigned int LCD_Screen = 0;
unsigned int LCD_tick = 0;
void UpdateLCD(unsigned int UpdateTime)
{
if(UpdateTime> UpdateDelta / 3 * 2)
{
//最初の画面
if(LCD_Screen!= 0){
LCD_Screen = 0;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
他に
{
if(UpdateTime> UpdateDelta / 3)
{
//セカンドスクリーン
if(LCD_Screen!= 1){
LCD_Screen = 1;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
他に
{
// 3番目の画面
if(LCD_Screen!= 2){
LCD_Screen = 2;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
}
LCD_tick ++;
if(LCD_tick> 32)LCD_tick = 32;
}
ボイド設定()
{
//表示を初期化します
lcd.createChar(1、newChar1);
lcd.createChar(2、newChar2);
lcd.begin(16、2);
//シリアルポートを初期化します
//Serial.begin(57600);
pinMode(ETHERNET_PIN、OUTPUT);
digitalWrite(ETHERNET_PIN、LOW);
遅延(1000);
Ethernet.begin(mac、ip);
遅延(1000);
digitalWrite(ETHERNET_PIN、HIGH);
}
ボイドループ()
{
//像をリクエストする
if(UpdateTime == 0){
UpdateTime = UpdateDelta;
digitalWrite(ETHERNET_PIN、LOW);
readServer();
digitalWrite(ETHERNET_PIN、HIGH);
generateSrings();
}
UpdateLCD(UpdateTime);
遅延(100);
UpdateTime-= 100;
}
#include <Ethernet.h>
#include <LiquidCrystal.h>
#define ETHERNET_PIN 10
#define LCD_PIN 3
//ネットワーク上の強制IPアドレス
IPAddress ip(192、168、1、40);
// MAC
バイトmac [] = {0x42、0x42、0x42、0x42、0x42、0x42};
//サーバー、登録済みideshnik、プロファイル番号
const char server [] = "api.worldoftanks.ru";
const char application_id [] = "demo";
const char account_id [] = "4848655";
//ミリ秒単位の更新レート
const unsigned int UpdateDelta = 20000;
//更新まで放置
unsigned int UpdateTime = 0;
//ネットワーククライアント
EthernetClientクライアント。
// LCD
LiquidCrystal lcd(LCD_PIN);
バイトnewChar1 [8] = {
B00100、
B01110、
B10101、
B00100、
B00100、
B00100、
B00100、
B00000
};
バイトnewChar2 [8] = {
B00100、
B00100、
B00100、
B00100、
B10101、
B01110、
B00100、
B00000
};
//解析ステータス
列挙型ReadStatusEnum {
WiteTag、
ReadTag、
価値
} ReadStatus = WiteTag;
文字列のニックネーム= "Unknown Noob";
long WG_rating、pre_WG_rating、buf_WG_rating = 0;
符号なしの長いバトル、pre_battles、buf_battles = 0;
符号なしロングウィン、pre_wins、buf_wins = 0;
符号なしの長い損傷、pre_damage、buf_damage = 0;
符号なしの長いフラグメント、pre_frags、buf_frags = 0;
文字列LCD_strings [6];
//タグの中から目的のものを検索します
void FilterData(文字列SectionTagName、文字列TagName、文字列値)
{
if(SectionTagName.compareTo( "statistics")== 0){
if(TagName.compareTo( "nickname")== 0)
ニックネーム=値;
if(TagName.compareTo( "global_rating")== 0)
buf_WG_rating = Value.toInt();
}
if(SectionTagName.compareTo( "all")== 0){
if(TagName.compareTo( "battles")== 0)
buf_battles = Value.toInt();
if(TagName.compareTo( "wins")== 0)
buf_wins = Value.toInt();
if(TagName.compareTo( "damage_dealt")== 0)
buf_damage = Value.toInt();
if(TagName.compareTo( "frags")== 0)
buf_frags = Value.toInt();
}
}
void readServer()
{
//接続します
if(client.connect(server、80)){
client.print( "GET / wot / account / info /?application_id =");
client.print(application_id);
client.print( "&account_id =");
client.print(account_id);
client.println( "HTTP / 1.1");
client.print( "Host:„);
client.println(サーバー);
client.println(「ユーザーエージェント:arduino-ethernet」);
client.println( "Accept:text / html");
client.println( "接続:閉じる");
client.println();
//準備ができているのを待っています
bool Wait = true;
unsigned int Time = 0;
while(待機)
{
待機=!Client.available();
if(Time> 200)Wait = false;
時間++;
遅延(10);
}
文字記号= '';
char pre_symbol = '';
文字列TagName = "";
文字列SectionTagName = "";
文字列値= "";
文字列PreSectionTagName = "";
ReadStatus = WiteTag;
//バッファが空になるまで繰り返します
while(client.available()){
//バッファからバイトを読み取ります
pre_symbol = symbol;
symbol = client.read();
//Serial.print(symbol);
if(ReadStatus == WiteTag && pre_symbol == '"' && symbol!= ':'){
//タグの始まりを見つけました
ReadStatus = ReadTag;
TagName = "";
}
if(ReadStatus == ReadTag){
if(symbol!= '"'){
//タグ名を読み取ります
TagName + =シンボル;
}
他に
{
//タグの終わりが見つかりました
値= "";
ReadStatus = WiteValue;
}
}
if(ReadStatus == WiteValue){
if(symbol == '、' || symbol == '}'){
//値の終わり
ReadStatus = WiteTag;
FilterData(SectionTagName、TagName、Value);
if(symbol == '}'){
//セクションの終わり
SectionTagName = PreSectionTagName;
}
}
その他{
if(symbol == '{'){
//開始セクション
PreSectionTagName = SectionTagName;
SectionTagName = TagName;
ReadStatus = WiteTag;
}
その他{
//値を読み取ります
if(symbol!= ':' && symbol!= '"' && symbol!= '')
値+ =シンボル;
}
}
}
}
}
//クライアントを停止します
client.flush();
client.stop();
}
void generateSrings()
{
if(pre_battles == 0 || battles == 0){
//初期化
pre_WG_rating = buf_WG_rating;
WG_rating = buf_WG_rating;
pre_battles = buf_battles;
バトル= buf_battles;
pre_wins = buf_wins;
wins = buf_wins;
pre_damage = buf_damage;
損傷= buf_damage;
pre_frags = buf_frags;
frags = buf_frags;
}
if(buf_battles>戦闘)
{
//統計の更新がありました
pre_WG_rating = WG_rating;
WG_rating = buf_WG_rating;
pre_battles =バトル。
バトル= buf_battles;
pre_wins = wins;
wins = buf_wins;
pre_damage =損傷;
損傷= buf_damage;
pre_frags = frags;
frags = buf_frags;
}
if(pre_battles == battles)
{
LCD_strings [0] =ニックネーム+ "";
LCD_strings [0] = LCD_strings [0] .substring(0,16);
LCD_strings [1] = "Btl:" +文字列(バトル)+ "-";
LCD_strings [1] = LCD_strings [1] .substring(0,16);
float wins_percent =(float)wins /(float)battles * 100.0;
LCD_strings [2] = "Wins:" +文字列(wins_percent)+ "-";
LCD_strings [2] = LCD_strings [2] .substring(0,16);
float avrage_damage =(float)ダメージ/(float)バトル。
文字列D =文字列(avrage_damage);
D = D.substring(0、D.length()-1);
LCD_strings [3] = "Dmg:" + D + "-";
LCD_strings [3] = LCD_strings [3] .substring(0,16);
float avrage_frags =(float)frags /(float)バトル;
LCD_strings [4] = "Frag:" +文字列(avrage_frags)+ "-";
LCD_strings [4] = LCD_strings [4] .substring(0,16);
LCD_strings [5] = "WG:" +文字列(WG_rating)+ "-";
LCD_strings [5] = LCD_strings [5] .substring(0,16);
}
他に
{
LCD_strings [0] =ニックネーム+ "";
LCD_strings [0] = LCD_strings [0] .substring(0,16);
LCD_strings [1] = "Btl:" +文字列(バトル)+ "" +文字(0x01)+文字列(battles-pre_battles)+ "";
LCD_strings [1] = LCD_strings [1] .substring(0,16);
float wins_percent =(float)wins /(float)battles * 100.0;
float pre_wins_percent =(float)pre_wins /(float)pre_battles * 100.0;
char Delta = char(0x01);
if(wins_percent <pre_wins_percent)Delta = char(0x02);
LCD_strings [2] = "Wins:" + String(wins_percent)+ "" + Delta + String(abs(wins_percent-pre_wins_percent))+ "";
LCD_strings [2] = LCD_strings [2] .substring(0,16);
float avrage_damage =(float)ダメージ/(float)バトル。
float pre_avrage_damage =(float)pre_damage /(float)pre_battles;
Delta = char(0x01);
if(avrage_damage <pre_avrage_damage)Delta = char(0x02);
文字列D =文字列(avrage_damage);
D = D.substring(0、D.length()-1);
LCD_strings [3] = "Dmg:" + D + "" + Delta + String(abs(avrage_damage-pre_avrage_damage))+ "";
LCD_strings [3] = LCD_strings [3] .substring(0,16);
float avrage_frags =(float)frags /(float)バトル;
float pre_avrage_frags =(float)pre_frags /(float)pre_battles;
Delta = char(0x01);
if(avrage_frags <pre_avrage_frags)Delta = char(0x02);
LCD_strings [4] = "フラグ:" +文字列(avrage_frags)+ "" +デルタ+文字列(abs(avrage_frags-pre_avrage_frags))+ "";
LCD_strings [4] = LCD_strings [4] .substring(0,16);
Delta = char(0x01);
if(WG_rating <pre_WG_rating)Delta = char(0x02);
LCD_strings [5] = "WG:" +文字列(WG_rating)+ "" +デルタ+文字列(abs(WG_rating-pre_WG_rating))+ "";
LCD_strings [5] = LCD_strings [5] .substring(0,16);
}
}
void PrintMSG(int LCD_tick、int ScrNum)
{
if(LCD_tick <= 16)
{
lcd.setCursor(0、0);
lcd.print(LCD_strings [ScrNum * 2 + 0] .substring(0、LCD_tick)+ "_");
}
他に
{
lcd.setCursor(0、1);
lcd.print(LCD_strings [ScrNum * 2 + 1] .substring(0、LCD_tick-16)+ "_");
}
}
unsigned int LCD_Screen = 0;
unsigned int LCD_tick = 0;
void UpdateLCD(unsigned int UpdateTime)
{
if(UpdateTime> UpdateDelta / 3 * 2)
{
//最初の画面
if(LCD_Screen!= 0){
LCD_Screen = 0;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
他に
{
if(UpdateTime> UpdateDelta / 3)
{
//セカンドスクリーン
if(LCD_Screen!= 1){
LCD_Screen = 1;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
他に
{
// 3番目の画面
if(LCD_Screen!= 2){
LCD_Screen = 2;
LCD_tick = 0;
}
PrintMSG(LCD_tick、LCD_Screen);
}
}
LCD_tick ++;
if(LCD_tick> 32)LCD_tick = 32;
}
ボイド設定()
{
//表示を初期化します
lcd.createChar(1、newChar1);
lcd.createChar(2、newChar2);
lcd.begin(16、2);
//シリアルポートを初期化します
//Serial.begin(57600);
pinMode(ETHERNET_PIN、OUTPUT);
digitalWrite(ETHERNET_PIN、LOW);
遅延(1000);
Ethernet.begin(mac、ip);
遅延(1000);
digitalWrite(ETHERNET_PIN、HIGH);
}
ボイドループ()
{
//像をリクエストする
if(UpdateTime == 0){
UpdateTime = UpdateDelta;
digitalWrite(ETHERNET_PIN、LOW);
readServer();
digitalWrite(ETHERNET_PIN、HIGH);
generateSrings();
}
UpdateLCD(UpdateTime);
遅延(100);
UpdateTime-= 100;
}
そして、ここに仕事のデモンストレーションがあります。 残念ながら、Wargamingサーバーはゲームセッションの終了後にのみ統計を更新します。
更新しました。 既に関係ない、修正されたスケッチ