fc2ブログ

4桁7セグで遊ぶ(7)


 前回の続きです。今回、UART通信でWi-FiモジュールのESP8266へデータを飛ばして、iPadからデータを確認できるようにしました。基本的には以前のブログに記載のArduinoのサンプルプログラムAdvancedWebserverを利用しました。

完成品は写真の通りです。ESP8266setup.png前回PICはMAX3232ECPE経由でPCに接続していましたが、今回はESP8266に直接接続します。注意点はPICのTX、RXをそれぞれESP8266のRXD、TXDに接続することです。iPadから確認した画面はこんな感じです。表示画面170528文字情報だけでは分かりにくいのでトレンドグラフも追加しました。5秒間隔でWebページを更新することにし、問題なくデータが推移していることを確認しました。

 PICプログラムの変更点は、気温、気圧、湿度、不快指数のデータ転送する際に、それぞれT、P、H、Dの識別子を追加したこと。受け取るESP8266側で何のデータが転送されたかを識別させるためです。一点はまってしまったのは、小数点データの文字変換の際にsprintf関数を使ってうまく行かなかった点。しばらくこんな表示で悩んでいました。異常表示170528ネットで調べてみると、このサイトにC/C++で普通に使えるfloat形のsprintf関数がArduinoで使えず、代わりにdtostrf関数を使いなさいとのこと。
//temperature_s: char型, temperature_f: float型
sprintf(temperature_s, "%2.1f", temperature_f); //NG
dtostrf(temperature_f,5,1,temperature_s); //OK
調べてみないと分からないことが多くありますね。

 プログラムは、それぞれの計測項目について、過去40データ分をグラフに表示させます。グラフはサンプルプログラムのままScalable Vector Graphics(SVG)形式で描画しています。コードはいろいろ詰め込みすぎてかなりごちゃごちゃしていますが・・。
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *ssid = "*****"; //user setting
const char *password = "*****"; //user setting

ESP8266WebServer server ( 80 );
IPAddress ip( 192, 168, 11, 200 );
IPAddress subnet( 255, 255, 255, 0 );

char buff[16];
char buff_temp[16];
char temperature[16];
char atmospheric_pressure[16];
char humidity[16];
char discomfort_index[16];

int counter = 0;
float temperature_f[40];
float atmospheric_pressure_f[40];
float humidity_f[40];
float discomfort_index_f[40];

void drawGraph() {
String out = "";
char temp[800];
int ost_x = 100;
int ost_y = 20;
float Tmax = 30.0;
float Tmin = 20.0;
float Pmax = 1010.0;
float Pmin = 990.0;
float Hmax = 80.0;
float Hmin = 30.0;
float Dmax = 85.0;
float Dmin = 65.0;
char lbl[5];

out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"500\" height=\"820\">\n";
for(int i=0;i<4;i++){
sprintf(temp, "<rect x=\"%d\" y=\"%d\" width=\"400\" height=\"160\" fill=\"rgb(204, 204, 255)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n",ost_x,ost_y+200*i);
out += temp;
for(int j=0;j<3;j++){
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" fill=\"none\" stroke=\"gray\" stroke-width=\"1\" stroke-dasharray=\"5 5\" />\n", ost_x, ost_y+200*i+40*(j+1), ost_x+400, ost_y+200*i+40*(j+1));
out += temp;
}
}
out += "<g stroke=\"black\">\n";

for(int i=0;i<5;i++){ //y目盛
memset(lbl,'\0',strlen(lbl));
dtostrf(Tmax-i*(Tmax-Tmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Pmax-i*(Pmax-Pmin)/4,5,0,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 200+ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Hmax-i*(Hmax-Hmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 400+ost_y+i*40,lbl);
out += temp;
memset(lbl,'\0',strlen(lbl));
dtostrf(Dmax-i*(Dmax-Dmin)/4,5,1,lbl);
sprintf(temp, "<text x=\"%d\" y=\"%d\">%s</text>\n", 65, 600+ost_y+i*40,lbl);
out += temp;
}

//yラベル
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",50,"気温[℃]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",250,"気圧[㍱]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",450,"湿度[%]");
out += temp;
sprintf(temp, "<text writing-mode=\"tb\" x=\"45\" y=\"%d\">%s</text>\n",650,"不快指数[%]");
out += temp;

for (int x=38;x>-1;x--) { //グラフプロット
int Ty1 = 160 + ost_y - (int)((temperature_f[x+1]-Tmin)*160.0/(Tmax-Tmin));
int Ty2 = 160 + ost_y - (int)((temperature_f[x]-Tmin)*160.0/(Tmax-Tmin));
if(Ty1>160+ost_y){Ty1=160+ost_y;}
if(Ty2>160+ost_y){Ty2=160+ost_y;}
if(Ty1<ost_y){Ty1=ost_y;}
if(Ty2<ost_y){Ty2=ost_y;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Ty1, (39-x+1)*10+ost_x, Ty2);
out += temp;

int Py1 = 360 + ost_y - (int)((atmospheric_pressure_f[x+1]-Pmin)*160.0/(Pmax-Pmin));
int Py2 = 360 + ost_y - (int)((atmospheric_pressure_f[x]-Pmin)*160.0/(Pmax-Pmin));
if(Py1>360+ost_y){Py1=360+ost_y;}
if(Py2>360+ost_y){Py2=360+ost_y;}
if(Py1<ost_y+200){Py1=ost_y+200;}
if(Py2<ost_y+200){Py2=ost_y+200;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Py1, (39-x+1)*10+ost_x, Py2);
out += temp;

int Hy1 = 560 + ost_y - (int)((humidity_f[x+1]-Hmin)*160.0/(Hmax-Hmin));
int Hy2 = 560 + ost_y - (int)((humidity_f[x]-Hmin)*160.0/(Hmax-Hmin));
if(Hy1>560+ost_y){Hy1=560+ost_y;}
if(Hy2>560+ost_y){Hy2=560+ost_y;}
if(Hy1<ost_y+400){Hy1=ost_y+400;}
if(Hy2<ost_y+400){Hy2=ost_y+400;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Hy1, (39-x+1)*10+ost_x, Hy2);
out += temp;

int Dy1 = 760 + ost_y - (int)((discomfort_index_f[x+1]-Dmin)*160.0/(Dmax-Dmin));
int Dy2 = 760 + ost_y - (int)((discomfort_index_f[x]-Dmin)*160.0/(Dmax-Dmin));
if(Dy1>760+ost_y){Dy1=760+ost_y;}
if(Dy2>760+ost_y){Dy2=760+ost_y;}
if(Dy1<ost_y+600){Dy1=ost_y+600;}
if(Dy2<ost_y+600){Dy2=ost_y+600;}
sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", (39-x)*10+ost_x, Dy1, (39-x+1)*10+ost_x, Dy2);
out += temp;
}
out += "</g>\n</svg>\n";
server.send ( 200, "image/svg+xml", out);
}

void handleRoot() {
char temp[1000];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;

snprintf ( temp, 1000,
"<html>\
<head>\
<meta http-equiv='refresh' content='5'/>\
<title>BME280 Measure</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h2>BME280 Measurement</h2>\
<h2><p>Uptime: %02d:%02d:%02d</p></h2>\
<h2><p>Temperature: %s [°C]</p></h2>\
<h2><p>Atmospheric pressure: %s [hPa]</p></h2>\
<h2><p>Humidity: %s [%]</p></h2>\
<h2><p>Discomfort Index: %s [%]</p></h2>\
<img src=\"/test.svg\" />\
</body>\
</html>",
hr, min % 60, sec % 60,temperature,atmospheric_pressure,humidity,discomfort_index
);
server.send ( 200, "text/html", temp );
}

void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";

for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}
server.send ( 404, "text/plain", message );
}

void setup ( void ) {
//変数初期化
for(int i=0;i<40;i++){
temperature_f[i]=0.0;
atmospheric_pressure_f[i]=0.0;
humidity_f[i]=0.0;
discomfort_index_f[i]=0.0;
}

Serial.begin ( 19200 );

WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ip, ip, subnet);
WiFi.softAP(ssid, password);
server.begin();

server.on ( "/", handleRoot );
server.on ( "/test.svg", drawGraph );
server.on ( "/inline", []() {
server.send ( 200, "text/plain", "this works as well" );
} );

server.onNotFound ( handleNotFound );
server.begin();
Serial.println ( "HTTP server started" );
}

void loop ( void ) {
if(Serial.available()>0){
if(counter == 0){memset(buff,'\0',strlen(buff));}
char data = Serial.read();
buff[counter] = data;

if (data == '\n'){
buff[counter]='\0';
memset(buff_temp,'\0',strlen(buff_temp));
strncpy(buff_temp,buff,strlen(buff)-2); //T, P, H, Dの文字削除

if(strstr(buff,"T") != NULL){ //気温
for(int i=38;i>-1;i--){temperature_f[i+1] = temperature_f[i];}
temperature_f[0] = atof(buff_temp) / 10.0;
memset(temperature,'\0',strlen(temperature));
dtostrf(temperature_f[0],5,1,temperature);
}
else if(strstr(buff,"P") != NULL){ //気圧
for(int i=38;i>-1;i--){atmospheric_pressure_f[i+1] = atmospheric_pressure_f[i];}
if(buff_temp[0]=='9'){
atmospheric_pressure_f[0] = atof(buff_temp) / 100.0;
}else{
atmospheric_pressure_f[0] = atof(buff_temp) / 10.0;
}
memset(atmospheric_pressure,'\0',strlen(atmospheric_pressure));
dtostrf(atmospheric_pressure_f[0],5,0,atmospheric_pressure);
}
else if(strstr(buff,"H") != NULL){ //湿度
for(int i=38;i>-1;i--){humidity_f[i+1] = humidity_f[i];}
humidity_f[0] = atof(buff_temp) / 10.0;
memset(humidity,'\0',strlen(humidity));
dtostrf(humidity_f[0],5,1,humidity);
}
else if(strstr(buff,"D") != NULL){ //不快指数
for(int i=38;i>-1;i--){discomfort_index_f[i+1] = discomfort_index_f[i];}
discomfort_index_f[0] = atof(buff_temp) / 100.0;
memset(discomfort_index,'\0',strlen(discomfort_index));
dtostrf(discomfort_index_f[0],5,1,discomfort_index);
}
counter = 0;
}
else{
counter++;
}
}
server.handleClient();
}
 このテーマ、長々とやってきましたが、ようやく一通り目処が立ちましたので、クローズにしたいと思います。
スポンサーサイト



SimCity BuildItでようやく200万人突破

 iPadで遊んでいる「SimCity BuildIt」でようやく200万人を突破しました。SimCityBuildIt_170521.png
 自分が市長になって街を成長させていくゲームで、昔(私が学生時代:20年前)からありました。学生時代に友人から違法コピー(当時は意識が低かった・・?)のインストールフロッピーを何枚も借りて、PC9801に入れて遊んだことを懐かしく思い出していました。

 2年以上前に、体を壊して会社を休んでいた頃に、iPadにインストールして、その後の「私の退屈しのぎのパートナー」になっていました。課金制のゲームですが、原則セコイのでお金は一切かけていません。気長に街を大きくしていったため2年近くかかってしまいましたが、その分、無料でかなり楽しませてもらっています。
 定期的にアップデートされるのでユーザを飽きさせない所もありますが、よくシステムがダウンして、ソフトが立ち上がらない(起動後すぐに落ちる)こともあります(無料なので仕方ないかもしれませんが・・)。

 これからさらに街を成長させていきたいのですが、余った土地が全くなく、拡張が難しいですね。そろそろ土地拡張のプレゼントが欲しいなぁと思う今日この頃です・・。

4桁7セグで遊ぶ(6)

 前回の続きです。このトピックも途中で挫折?等があり、長々と続けています。今回は、PICのプログラムです。以前のブログで紹介したプログラムを骨格として、ネット上にある参考プログラムを継ぎはぎして作成しました。プログラムは、メイン、I2C通信(PIC-BME280)、UART通信(PIC-パソコン)、7セグ表示の4部構成にしました。それぞれについて、変更設定箇所等を説明します。

 まず、I2C通信ですが、全面的にこのサイトのプログラムを参考(利用)させていただきました。ありがとうございました。レジスタ単位で設定したのは、SSPCON1、SSPADDです。それぞれSPI、I2Cの選択とモード設定、I2Cの通信クロック設定で以下の通りです。I2C_SSPCON1_170520.pngここでSSPMは以下の設定です。I2C_SSPM_170520.png I2Cの通信クロックは標準的な100kHzを使いました。PICのクロックFosc(今回はセラロック(*):20MHzを使用)との関係は、マニュアルから
 I2Cクロック = Fosc / (ADD + 1) * 4 と表されるので、
 100 [kHz] = 20 [MHz] /(ADD + 1) * 4
 ADD = 49 (31h)
この31hをSSPADDレジスタに設定しました。I2C_SPPADD_170520.png (*) 新しくなったパソコンで「セラロック」を変換すると「世良ロック」と変換された・・。我々の世代では分らんでもないけど・・(笑)。正しくは村田製作所の登録商標の「セラミック発振子」のことですね。

 次に、UART通信です。今回のPIC16F1938が、PIC16F873Aと異なる所は、BRG(Baud Rate Generator)が8bit/16bitを選択できる所で、今回はF873Aと同じ条件の8bitを選択しましたので、細かい設定は変える必要はありませんでした。それぞれの設定条件は以下の通りです。UART_TXSTA(F1938)_170520.pngUART_RCSTA(F1938)_170520.pngUART_BaudRateCalc_170520.pngUART_SPBRGセッティング_170520 プログラムは、このサイトのライブラリ類(skUARTlib.c、skUARTlib.h)を参考にさせていただきました。大変感謝です。

 次に7セグ表示部の小数点対応です。以前のブログのプログラムを変更し、SetDigit関数の引数8個のうち前半の4個を数字、後半の4個を小数点の有無信号(0 or 1)に変更し、小数点がある場合は数字と小数点(cSeg[10])を合成するようにしました。
//7seg digit set 
void SetDigit(int dg1,int dg2,int dg3,int dg4,int dt1,int dt2,int dt3,int dt4){
RA0=1;
if(dt1 == 1){
PORTB=cSeg[dg1] | cSeg[10];
}else{
PORTB=cSeg[dg1];
}
__delay_ms(1);
RA0=0;
PORTB = 0b00000000;

RA1=1;
if(dt2 == 1){
PORTB=cSeg[dg2] | cSeg[10];
}else{
PORTB=cSeg[dg2];
}
__delay_ms(1);
RA1=0;
PORTB = 0b00000000;

RA2=1;
if(dt3 == 1){
PORTB=cSeg[dg3] | cSeg[10];
}else{
PORTB=cSeg[dg3];
}__delay_ms(1);
RA2=0;
PORTB = 0b00000000;

RA3=1;
if(dt4 == 1){
PORTB=cSeg[dg4] | cSeg[10];
}else{
PORTB=cSeg[dg4];
}__delay_ms(1);
RA3=0;
PORTB = 0b00000000;
}

 最後にメインですが、1sec間隔で気温、気圧、湿度、不快指数の順に7セグに表示させるようにしました。1sec間隔は、PICのtimer0を用いて設定(OPTION_REG)しました。測定は気温を表示させる前にのみ行いました(4sec周期)。timer0_OPTION_REG_170520.pngtimer0_プリスケーラ_170520 プリスケーラは、1:256を選択し、PICのFoscは20MHzなので、Timerの周期を計算すると以下の通りです。
 内部クロック(カウンタ)の周期 = 1 / Fosc ×4 より
 1 / (20MHz) * 4 = 0.2μsec
プリスケーラで256分周されているから
 0.2μsec×256 = 51.2μsec ごとにカウントアップが入ることになります。
結局、8bitのTMR0が0~255までカウントアップして、割り込み(TMR0IF)が入りますので、Timer0のIntervalは
 51.2×256 = 13.1msec です。今回、1sec間隔で表示を切り替えたいので、
 1000 [msec] / 13.1 [msec/count] = 76.33 [count]
で約77回カウントすれば、1sec間隔の処理ができそうです。

プログラムは、以下の通りで1sec経過したらフラグを立てて、測定・表示を行うような形にしました。ごちゃごちゃして、まだ整理できていない所はありますが、問題なく動作しました。
/*
* File: BME280Measure.c
* Author: Dr. BobT
*
* Created on 2017/05/03, 7:01
*/

// CONFIG1
#pragma config FOSC = HS // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled)
#pragma config PLLEN = OFF // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "skUARTlib.h"
#include "7segControl.h"
#include "I2C.h"
#include "BME280.h"

#define _XTAL_FREQ 20000000 /* for delay use */
#define UART_RX_SIZE 8

int n, selno;
int idig[8];
char cdig[2];

signed int temperature=0;
unsigned int pressure=0;
unsigned int humidity=0;
unsigned int dcindex=0;
float calc_temp = 0.0;
char rbuf_temp[8];
char rbuf_press[8];
char rbuf_humid[8];
char rbuf_dcindex[8];

bool Tflag = false; //Timer flag
unsigned int counter = 0;

//initialize PIC
void InitPic(void)
{
//PortA
// bit0:RA0 2 Out(0) DEG1 COM
// bit1:RA1 3 Out(0) DEG2 COM
// bit2:RA2 4 Out(0) DEG3 COM
// bit3:RA3 5 Out(0) DEG4 COM
// bit4:RA4 6 Out(0)
// bit5:RA5 7 Out(0) DEG5 COM
// bit6:RA6 - Out(0)
// bit7:RA7 - Out(0)
TRISA = 0b00000000;

//PortB
// bit0:RB0 21 Out(0) SEG A
// bit1:RB1 22 Out(0) SEG B
// bit2:RB2 23 Out(0) SEG C
// bit3:RB3 24 Out(0) SEG D
// bit4:RB4 25 Out(0) SEG E
// bit5:RB5 26 Out(0) SEG F
// bit6:RB6 27 Out(0) SEG G
// bit7:RB7 28 Out(0) SEG DP
TRISB = 0b00000000;

//PortC
// bit0:RC0 11 Out(0)
// bit1:RC1 12 Out(0)
// bit2:RC2 13 Out(0)
// bit3:RC3 14 IN(1) SCK/SCL
// bit4:RC4 15 IN(1) SDI/SDA
// bit5:RC5 16 Out(0)
// bit6:RC6 17 Out(0) TX
// bit7:RC7 18 IN(1) RX
TRISC = 0b10011000;

//IO Initialize
PORTA = 0b00000000;
PORTB = 0b00000000;
PORTC = 0b00000000;
}

//interrupt
void interrupt InterFunction(void){
if(Tflag){
InterUART(); // USARTの受信割り込み
}else{
T0IF = 0; // TMR0割り込み禁止
counter++;
if (counter == 77) //countが77(1000ms)になったら,
{
Tflag = true; // フラグを立てて,
counter = 0; //countを0に戻す。
}
}
}

//main
void main(void){

InitPic(); // PIC初期化
InitUART(64); // USART初期化(8bit,StopBit:1, No Parity, No flow,19200bps)
init_i2c(); // I2C初期化
init_comb_sens();
__delay_ms(12); // 測定待ち

//timer0設定
OPTION_REG = 0x87; // プリスケーラは256
TMR0IF = 0; //TMR0は0からスタート(フリーラン)
TMR0IE = 1; // TMR0割り込み許可

selno= 0; //表示選択番号

while(1){
//1sec待ち
if (Tflag) {
Tflag = false;
selno++;

if(selno==1){ //データ読み込み
comb_sens_get();
read_TPH10x(&temperature,&pressure,&humidity); //計測
}

switch(selno){
case 1://気温データ
memset(rbuf_temp,0,strlen(rbuf_temp)); //気温データバッファ初期化
itoa(rbuf_temp,temperature,10);

n=strlen(rbuf_temp);
rbuf_temp[n] = 0x0d;//CR
rbuf_temp[n+1] = 0x0a;//LF
UART_Send(rbuf_temp,n+2);//送信
UART_Flush();//受信バッファクリア

for(int i=0;i<4;i++){
memset(cdig,0,strlen(cdig));//初期化
strncpy(cdig,rbuf_temp+i,1); //1文字抽出
cdig[1]='\0';
idig[i]=atoi(cdig);
}
idig[4]=0;
idig[5]=1;
idig[6]=0;
idig[7]=0;
break;
case 2://気圧データ
memset(rbuf_press,0,strlen(rbuf_press)); //気圧データバッファ初期化
itoa(rbuf_press,pressure,10);

n=strlen(rbuf_press);
rbuf_press[n] = 0x0d;//CR
rbuf_press[n+1] = 0x0a;//LF
UART_Send(rbuf_press,n+2);//送信
UART_Flush();//受信バッファクリア

for(int i=0;i<4;i++){
memset(cdig,0,strlen(cdig));//初期化
strncpy(cdig,rbuf_press+i,1); //1文字抽出
cdig[1]='\0';
idig[i]=atoi(cdig);
}
if(idig[0]==9){//気圧が1000hPa未満の時
for(int i=3;i>0;i--){
idig[i] = idig[i-1];
}
idig[0]= 12; //blank
}
idig[4]=0;
idig[5]=0;
idig[6]=0;
idig[7]=0;
break;
case 3://湿度データ
memset(rbuf_humid,0,strlen(rbuf_humid)); //湿度データバッファ初期化
itoa(rbuf_humid,humidity,10);

n=strlen(rbuf_humid);
rbuf_humid[n] = 0x0d;//CR
rbuf_humid[n+1] = 0x0a;//LF
UART_Send(rbuf_humid,n+2);//送信
UART_Flush();//受信バッファクリア

for(int i=0;i<4;i++){
memset(cdig,0,strlen(cdig));//初期化
strncpy(cdig,rbuf_humid+i,1); //1文字抽出
cdig[1]='\0';
idig[i]=atoi(cdig);
}
idig[4]=0;
idig[5]=1;
idig[6]=0;
idig[7]=0;
break;
case 4://不快指数データ
//不快指数計算
// 計算式 = 0.81*temperature + 0.01*humidity*(0.99*temperature - 14.3) + 46
calc_temp = 0.81*(float)(temperature/10) + 0.01*(float)(humidity/10)*(0.99*(float)(temperature/10) - 14.3) + (float)46;
dcindex = calc_temp * (float)100; //小数点以下2桁分を整数化
memset(rbuf_dcindex,0,strlen(rbuf_dcindex)); //湿度データバッファ初期化
itoa(rbuf_dcindex,dcindex,10);

n=strlen(rbuf_dcindex);
rbuf_dcindex[n] = 0x0d;//CR
rbuf_dcindex[n+1] = 0x0a;//LF
UART_Send(rbuf_dcindex,n+2);//送信
UART_Flush();//受信バッファクリア

for(int i=0;i<4;i++){
memset(cdig,0,strlen(cdig));//初期化
strncpy(cdig,rbuf_dcindex+i,1); //1文字抽出
cdig[1]='\0';
idig[i]=atoi(cdig);
}
idig[4]=0;
idig[5]=1;
idig[6]=0;
idig[7]=0;
selno = 0;
break;
default:
break;
}
}
//表示
SetDigit(idig[0],idig[1],idig[2],idig[3],idig[4],idig[5],idig[6],idig[7]);
}
}
 次回は、UART通信でWi-FiモジュールのESP8266へデータを飛ばして、iPadからでもデータを確認できるようにしようと思います。

4桁7セグで遊ぶ(5)

 前回の続きです。今回製作したシステムは写真の通りで、7セグ表示、PIC、BME280とRS-232C USART変換の4つから構成しました。温度結果170512 PICが問題なくデータ収集をしていることは、7セグ表示で確認できますが、将来、PICからUART通信でWi-FiモジュールのESP8266へデータを飛ばそうと考えているので、今回はまず手始めにパソコンにデータを飛ばす確認をしました。PICとBME280は「I2C通信」、PICとパソコン間は「UART通信」を用いるシステムにしました。1sec間隔で、気温(℃)、気圧(hPa)、湿度(%)と不快指数(%)を表示できました。気温170512気圧170512湿度170512不快指数170512パソコン側(Tera Term)の表示は以下の通りです。問題なくデータが取り込めています。実行結果近所の気象台のデータと比較する限り、気圧が数hPaほど小さめに出てる感はありますが、問題のないレベルと判断しました。不快指数は、気温と湿度から下式で求めることができます。
0.81Td + 0.01H(0.99Td -14.3) + 46.3
Td:気温(℃)、H:湿度(%)
これからの時期、湿度も上がって蒸し蒸ししてくるので、モニターするのも良いかも知れませんね。個人的には、急な気圧変化で体調を崩しやすいので、その変化を検知してお知らせしてくれるようなシステムに将来的にしようと思います。

 配線図は以下の通りです。回路図170512 PICの回路は以前のブログでお話ししたことがあるPIC16F873AがPIC16F1938に変わっただけです。pin1~pin13は7seg表示回路に接続するピンです。PICとパソコン間は、MAX3232ECPEを介して配線し、PICとBME280はI2CモードでPICの14pin(SCK)、15pin(SDA)をそれぞれBME280の6pin(SCK)、4pin(SDI)に接続しますが、ここで落とし穴にハマってしまいました。各配線にプルアップ抵抗が必要と気付かず、なぜ動かないのか、しばらく悩んでいました。
 この前、Raspberry Piでやったときはプルアップ抵抗は必要なかったので、今回も同じようにしていました・・。ネットで調べると、確かにプルアップ抵抗は必要でした。取説を見ると、いまさらですが、ジャンパ1(J1)とジャンパ2(J2)をハンダ付けしてつなげば、4.7kΩのプルアップ抵抗が有効になるとの記載がありました。それを知らずに、手元にあった10kΩの抵抗を2個使って、プルアップすることでようやく動作しました。
 それにしても、Raspberry Piで問題なく動作したのはなぜだろうと調べていると、このサイトにその回答が書かれてありました。Raspberry Piの3pin(SDA)と5pin(SCL)が1.8kΩの抵抗で3.3V電源につながれている(プルアップされている)とのこと。納得しました。大変勉強になりました。次回はプログラムの話をしようと思います。

4桁7セグで遊ぶ(4)

 前回PIC16F873Aを用いて、ボッシュ製のBME280を搭載した温湿度、気圧モジュールのデータ取り込みを試みました。しかし、このPICのデータメモリ(DATA SRAM、ユーザが自由に使える変数およびデータエリア)が192バイトしかなく、結局PICを断念してRaspberry Piで組み直しました。今回は、そのリベンジです。
 今回は、PIC16F1938を使いました。スペックは以下の通り。PIC16F1938_spec170507.png データメモリはF873Aの5倍以上あり、その他の性能も良いです。ピン数もF873Aと同じ28ピンで、構成・配置も同じなので、プログラムも変更なく使えそうです。京都に出かけた時、寺町のマルツで購入しました。ただし、高いですね(@360円也)。名古屋の大須の部品屋さんで見た時も相場は同じぐらいでした。秋月で確認すると、@190円也。送料500円を考慮すると、単品で購入するのはナンセンスですが、いろいろな部品を買うついでに一緒に購入するのがベターですね・・(余談です)。

 本番プログラムを組む前に、Lチカでもして、まずF1938が問題なく動作することを確認することにしました。MPLAB_setting1_170507.pngMPLAB_setting2_170507.png MPLABを起動して、PIC16F1938を選択し、先に進むと、SELECT TOOLの所で、えっ、今使っているWriterのPIC Kit2(物持ちが良い・・)に対応していない??何か、嫌な予感??PIC Kit3を購入しなくてはならないのか??360円の騒ぎじゃないなぁ・・とブルーになり、一旦思考停止・・。

 何か裏技はないかなぁ?とネット上で調べていた所、ありました、ありました。PIC Kit2の「PK2DeviceFile.dat」というファイルを最新版に更新(置き換え)すれば、新しいPIC(F1938)にも対応してくれるというものでした。先ほどのMPLABのSELECT TOOLの所はPIC Kit3に暫定設定してプログラミングしました。
 ビルド後に、PIC Kit2を起動し、いざ書き込みです。Device FamilyのMidrangeの1.8V Minの中に目的のPIC16F1938がありました。PIC_KIT2_Setting1_170507.pngPIC_KIT2_Setting2_170507.png 選択後、書き込みを実施。Lチカ動作も問題なく行えました。PIC Kit3を購入しなくても済んでまずは一安心です・・。
 またまた、本題にたどり着く前に長くなりましたので、続きは次回にします。

jupyter notebookでOpenCV 3.1を動かす(2)

 前回、jupyter notebookでpythonからOpenCV 3.1を動かしましたが、処理途中の画像を外部ファイルとして出力していました。notebook上に処理画像を表示したいと思いつつ、ネットで情報を探していると、matplotlibというライブラリを用いれば良いことが分かりました。早速確認してみました。

 In[3]でnotebook上でmatplotlibライブラリを使用する際に必要な記述と、ライブラリのインポートを行います。matplotlib_setting170507.png In[4]で生画像を読み込み、imshowメソッドで簡単に表示できました。大変便利です。
 続いて、Gray処理、二値化処理の表示を行ったところ、色のついた結果が得られました。何か設定が足りません。gray_before170507.pngthreshold_before170507.png 再度、ネットで調べていると、グレースケールで描画できるgrayメソッドがありました。気を取り直して、In[3]の最後にグレースケール設定を追加し、再度実行です。graydisp_setting170507.png In[4]でカラー画像を表示させると問題なく、グレースケール設定とはいえ、カラー画像が表示されました。
 問題だったGray処理、二値化処理の表示を確認すると、今度は問題なく表示できました。gray_after170507.pngthreshold_after170507.png OpenCVをpythonで操作する。何かと遊べそうですね。

ご訪問者数

(Since 24 July, 2016)

タグクラウド


プロフィール

Dr.BobT

Author: Dr.BobT
興味のおもむくままに生涯考え続けるエンジニアでありたい。

月別アーカイブ

メールフォーム

名前:
メール:
件名:
本文: