DIPマイコンLPC1114FNでmbed入門 Ledマトリックス ~ その8 人工知能で天気予想~
DIPマイコンLPC1114FNでmbed入門
Ledマトリックスで遊びましょう ~ その8 ~
mbed LPC1114FN(以後、1114FN)は安価に購入できて、mbedクラウド開発環境を使ってプログラムを開発することができるマイコンです。1114FNを使って、8×8ドット=64個のLEDを使ったLEDマトリックスに文字を表示します。
3枚に増やしたLEDマトリックスユニットに、気圧・気温・湿度のスクロール表示に加えて、気圧グラフ表示を搭載することはできましたか。
注)
mbed LPC1114FNは発売からずいぶん経過しており、
Arm社が提供する「Mbed OS」および「Mbedプラットフォーム」は、2026年7月をもって完全にサポートを終了します。期間終了後はウェブサイトがアーカイブされ、オンラインでのプロジェクトビルドやコンパイルは一切できなくなります。回路図やプログラムは参考資料として公表します。
○回路図
前回と同じです。3枚目のLEDマトリックスユニットは2枚目のユニットの出力端子に接続します。
#○プログラミング
■天気予想部
天気予報は難しい分野です。気象庁は日本全国のアメダスや富士山レーダー、人工衛星を動員して精密な天気予報を発表しています。使用する計測ユニットは1000円の測定ユニットBME280だけです。今回は気象庁の予報に対抗するために人工知能を活用し、天気を「予想」します。
本予想プログラムは、気圧変化データを過去8時間分使用し、半日程度未来の天気予想に挑戦します。1時間毎に気圧変化の差を求めて合計し、この合計値により天気を予想します。当初、数式を使って予想するアルゴリズムを考案しましたが、あまり当たりませんでした。
そこで、数週間にわたって、気圧変化グラフと実際の天気を筆者が観測し、2者の関連をプログラムに盛り込みました。筆者の天気予想や天気に対する感覚を盛り込んでいるので、予想部分を人工知能AiPと呼ぶことにしました。
実際にどの程度当たるのかは・・・ぜひ本作品を完成させて、お試しください。
// 天気予想部
henka=0;
for(m=23;m>=17;m--){ //気圧差計算
henka=henka+(hpdata[m]-hpdata[m-1]);
}
load_image[21]=load_image[2];// hedder
if(henka >= 3){ //はれ予想
yosou=1;
load_image[22]=moji_font[23];//は
load_image[23]=moji_font[24];//れ
load_image[24]=moji_font[38];//→
load_image[25]=moji_font[23];//は
load_image[26]=moji_font[24];//れ
load_image[27]=moji_font[34];//斜め上矢印
}
else if(henka ==1 || henka == 2){ //はれ時々くもり
yosou=2;
load_image[22]=moji_font[23];//は
load_image[23]=moji_font[24];//れ
load_image[24]=moji_font[38];//→
load_image[25]=moji_font[25];//く
load_image[26]=moji_font[26];//も
load_image[27]=moji_font[27];//り
}
else if(henka == 0){ //くもり時々はれ
yosou=3;
if(yosou_old <= 3){
load_image[22]=moji_font[25];//く
load_image[23]=moji_font[26];//も
load_image[24]=moji_font[27];//り
load_image[25]=moji_font[34];//斜め上矢印
load_image[26]=moji_font[23];//は
load_image[27]=moji_font[24];//れ
}
else if(yosou_old >= 4){ //くもり後あめ
load_image[22]=moji_font[25];//く
load_image[23]=moji_font[26];//も
load_image[24]=moji_font[27];//り
load_image[25]=moji_font[38];//斜め上矢印
load_image[26]=moji_font[28];//あ
load_image[27]=moji_font[29];//め
}
}
else if(henka == -1 || henka ==-2){ //
yosou=4;
load_image[22]=moji_font[25];//く
load_image[23]=moji_font[26];//も
load_image[24]=moji_font[27];//り
load_image[25]=moji_font[35];//斜め下矢印
load_image[26]=moji_font[28];//あ
load_image[27]=moji_font[29];//め
}
else if(henka <= -3){
yosou=5;
load_image[22]=moji_font[28];//あ
load_image[23]=moji_font[29];//め
load_image[24]=moji_font[38];//→
load_image[25]=moji_font[28];//あ
load_image[26]=moji_font[29];//め
load_image[27]=moji_font[35];//斜め下矢印
}
○プログラム全体
プログラム全体を示します。
// LedMatrix 3mai Ondo,Situdo,Kiatu
#include "mbed.h"
#include "BME280.h"
DigitalOut led(dp28);
BME280 sensor1(dp5,dp27,0x76 << 1);
// spi(mosi,miso,sck)
SPI max72_spi(dp2, NC, dp6);
DigitalOut load(dp14);//spi load
// CPU MT7219
// dp1 mosi(Master In Salve Out) => DIN
// dp2 miso(Master OutSlave) => nc
// dp6 sck (Serial Clock) => clk
// dp14 =>(Slave Select) load
int maxInUse = 3; //change this variable to set how many MAX7219's you'll use
// define max7219 registers
#define max7219_reg_noop 0x00
#define max7219_reg_digit0 0x01
#define max7219_reg_digit1 0x02
#define max7219_reg_digit2 0x03
#define max7219_reg_digit3 0x04
#define max7219_reg_digit4 0x05
#define max7219_reg_digit5 0x06
#define max7219_reg_digit6 0x07
#define max7219_reg_digit7 0x08
#define max7219_reg_decodeMode 0x09
#define max7219_reg_intensity 0x0a
#define max7219_reg_scanLimit 0x0b
#define max7219_reg_shutdown 0x0c
#define max7219_reg_displayTest 0x0f
#define LOW 0
#define HIGH 1
#define MHZ 1000000
#define ON 1
#define OFF 0
double p1,t1,h1,pp1;
void maxSingle( int reg, int col) {
//maxSingle is the "easy" function to use for a
//single max7219
load = LOW; // begin
max72_spi.write(reg); // specify register
max72_spi.write(col); // put data
load = HIGH; // make sure data is loaded (on rising edge of LOAD/CS)
}
void maxAll (int reg, int col) { // initialize all MAX7219's in the system
load = LOW; // begin
for ( int c=1; c<= maxInUse; c++) {
max72_spi.write(reg); // specify register
max72_spi.write(col); // put data
}
load = HIGH;
}
void maxOne(int maxNr, int reg, int col) {
//maxOne is for adressing different MAX7219's,
//while having a couple of them cascaded
int c = 0;
load = LOW;
for ( c = maxInUse; c >= maxNr; c--) {
max72_spi.write(0); // no-op
max72_spi.write(0); // no-op
}
max72_spi.write(reg); // specify register
max72_spi.write(col); // put data
for ( c=maxNr-1; c >= 1; c--) {
max72_spi.write(0); // no-op
max72_spi.write(0); // no-op
}
load = HIGH;
}
void setup () {
// initiation of the max 7219
// SPI setup: 8 bits, mode 0
max72_spi.format(8, 0);
// going by the datasheet, min clk is 100ns so theoretically 10MHz should work...
// max72_spi.frequency(10*MHZ);
maxAll(max7219_reg_scanLimit, 0x07);
maxAll(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits)
maxAll(max7219_reg_shutdown, 0x01); // not in shutdown mode
maxAll(max7219_reg_displayTest, 0x00); // no display test
for (int e=1; e<=8; e++) { // empty registers, turn all LEDs off
maxAll(e,0);
}
maxAll(max7219_reg_intensity, 0x0f & 0x0f); // the first 0x0f is the value you can set
// range: 0x00 to 0x0f
}
void get_sensor1(void){
t1=sensor1.getTemperature();
if(t1 > 85.0){
t1=t1-409.0-1;
}
h1=sensor1.getHumidity();
pp1=sensor1.getPressure();
pp1=pp1+int(700/9);// kiatu kani hosei
}
int main(void) {
const uint64_t moji_font[] = {// bold font , kagami moji font
/*0x3c66666e76663c00,//0~9
0x7e1818181c181800,
0x7e060c3060663c00,
0x3c66603860663c00,
0x30307e3234383000,
0x3c6660603e067e00,
0x3c66663e06663c00,
0x1818183030667e00,
0x3c66663c66663c00,
0x3c66607c66663c00,*/
0x1c2222222222221c,//0~9
0x1c08080808080c08,
0x3e0408102020221c,
0x1c2220201820221c,
0x20203e2224283020,
0x1c2220201e02023e,
0x1c2222221e02221c,
0x040404081020203e,
0x1c2222221c22221c,
0x1c22203c2222221c,
0x6666663e06060600,// 10 h
0x06063e66663e0000,// 11 p
0x1818000000000000,// 12 .
0x30480848340a0a04, // 13 dc
0x1010157555770101,// 14 hp
0x0010107c10100000,// 15 +
0x0000007e00000000,// 16 -
0x082a1c771c2a0800, //17 asuta1
0x007e424a52427e00, // 18 sikaku2
0x0000000000000000, // 19 blank
0x60660c1830660600, // 20 %
0x4242665a5a7e1800, // 21 uchi
0x220424692e2a2c00, // 22 soto
0x126a3a22227a2200,// 23 ha は
0x44c6444c56640400,// 24 re れ
0x2010080408102000,// 25 ku く
0x1028483e083e1000,// 26 mo も
0x1020404044444400,// 27 ri り
0x2874d27c107c1000,// 28 a あ
0x449a9aaaaa7c2800,// 29 me め
0x6c927cc482443800,// 30 kumo
0x30309254ba10aa28,// 31 ame
0x082a1c771c2a0800,// 32 hare
0x1010101054381000,// 33 ue yajirusi ↑
0x0002044850607800,// 34 naname ue 斜め上矢印
0x0078605048040200,// 35 naname sita 斜め下矢印
0x1038541010101000, // 36 sita ↓
0x0000183c3c180000, // 37 asuta2
0x0010207e20100000, // 38 onaji yajirusi
0x5050557553550503 // 39 RH
};
/*
const uint64_t moji_font[]={
0x006e333e301e0000,//a
0x003b66663e060607,//b
0x001e3303331e0000,//c
0x006e33333e303038,//d
0x001e033f331e0000,//e
0x000f06060f06361c,//f
0x1f303e33336e0000,//g
0x006766666e360607,//h
0x001e0c0c0c0e000c,//i
0x1e33333030300030,//j
0x0067361e36660607,//k
0x001e0c0c0c0c0c0e,//l
0x00636b7f7f330000,//m
0x00333333331f0000,//n
0x001e3333331e0000,//o
0x0f063e66663b0000,//p
0x78303e33336e0000,//q
0x000f06666e3b0000,//r
0x001f301e033e0000,//s
0x00182c0c0c3e0c08,//t
0x006e333333330000,//u
0x000c1e3333330000,//v
0x00367f7f6b630000,//w
0x0063361c36630000,//x
0x1f303e3333330000,//y
0x003f260c193f0000 //z
};
*/
// // Jissainiha konoyouni mieru
// maxSingle(1,1); |-| -------+
// maxSingle(2,2); |-| ------+-
// maxSingle(3,4); |-| -----+--
// maxSingle(4,8); |-| ----+---
// maxSingle(5,16); |-| ---+----
// maxSingle(6,32); |-| --+-----
// maxSingle(7,64); |-| -+------
// maxSingle(8,128); |-| +-------
int i,j,k,m,n;
uint8_t bitsum[22][9],bit1gyou,bitline[250];
uint64_t moji1,load_image[35];
long hpascal,ttemp,sitemp;
int hpketa[4],tpketa[3],siketa[3];
int gdot[]={128,64,32,16,8,4,2,1};
int gbit[24],gbit_s[48];
long wtime=0;
long hpdata[24],hprange,hpmax,hpmin;
long hpcenter;
int dotdata[24],fstloop,fshuuki;
double hpscope;
double gctrim=0.0;
int henka=0;
int yosou=1,yosou_old;
int mojisu;
setup();
wait(0.1);
get_sensor1();
hpascal=long(pp1);
hpmin=hpascal;
hpmax=hpascal;
hpscope=1;
hprange=0;
for(i=0;i<24;i++){
hpdata[i]=hpascal-3;
}
while(1){
get_sensor1();
hpascal=long(pp1);
ttemp=long(t1*10); // seisuuchi henkan
sitemp=long(h1);
hpketa[0]=int(hpascal/1000);hpascal=hpascal-hpketa[0]*1000;
hpketa[1]=int(hpascal/100); hpascal=hpascal-hpketa[1]*100;
hpketa[2]=int(hpascal/10); hpascal=hpascal-hpketa[2]*10;
hpketa[3]=hpascal;
tpketa[0]=int(ttemp/100);ttemp=ttemp-tpketa[0]*100;// jyuu noketa
tpketa[1]=int(ttemp/10);ttemp=ttemp-tpketa[1]*10;// ichi no keta
tpketa[2]=int(ttemp); // shousuutenika no keta
siketa[0]=int(sitemp/100);sitemp=sitemp-siketa[0]*100;
siketa[1]=int(sitemp/10);sitemp=sitemp-siketa[1]*10;
siketa[2]=int(sitemp);
load_image[0]=moji_font[19]; //blank
load_image[1]=moji_font[19]; //blank
if(hpdata[23] > hpdata[22]){
load_image[2]=moji_font[34];//naname ue
}
else if(hpdata[23] < hpdata[22]){
load_image[2]=moji_font[35];//naname sita
}
else{
load_image[2]=moji_font[38];//onaji yajirusi
}
for(i=3;i<=6;i++){// kiatu 4keta suuji [3 ~ 6]
for(j=0;j<=9;j++){
if(hpketa[i-3] == j){
load_image[i]=moji_font[j];
}
}
}
load_image[7]=moji_font[14];//hp
load_image[8]=moji_font[19]; //blank
if(t1 >=0){
load_image[9]=moji_font[15];//+
}
else {
load_image[9]=moji_font[16];// -
}
for(i=0;i<=1;i++){// kion seisuuketa
for(j=0;j<=9;j++){
if(tpketa[i] == j){
load_image[i+10]=moji_font[j];
}
}
}
load_image[12]=moji_font[12];// .
for(j=0;j<=9;j++){// kion shousuu keta
if(tpketa[2] == j){
load_image[13]=moji_font[j];
}
}
load_image[14]=moji_font[13]; //dc
load_image[15]=moji_font[19];//blank
for(i=0;i<=2;i++){ // situdo 3 keta
for(j=0;j<=9;j++){
if(siketa[i] == j){
load_image[i+16]=moji_font[j];
}
}
}
if(siketa[0]==0){// 0 shouryaku
load_image[16]=moji_font[39];// situdo
}
load_image[19]=moji_font[20]; // %
load_image[20]=moji_font[19];//blank
// Tenki yosoku
henka=0;
for(m=23;m>=17;m--){
henka=henka+(hpdata[m]-hpdata[m-1]);
}
load_image[21]=load_image[2];// hedder
if(henka >= 3){
yosou=1;
load_image[22]=moji_font[23];//ha
load_image[23]=moji_font[24];//re
load_image[24]=moji_font[38];//onaji yajirusi
load_image[25]=moji_font[23];//ha
load_image[26]=moji_font[24];//re
load_image[27]=moji_font[34];//naname ue
}
else if(henka ==1 || henka == 2){
yosou=2;
load_image[22]=moji_font[23];//ha
load_image[23]=moji_font[24];//re
load_image[24]=moji_font[38];//onaji yajirusi
load_image[25]=moji_font[25];//ku
load_image[26]=moji_font[26];//mo
load_image[27]=moji_font[27];//ri
}
else if(henka == 0){
yosou=3;
if(yosou_old <= 3){
load_image[22]=moji_font[25];//ku
load_image[23]=moji_font[26];//mo
load_image[24]=moji_font[27];//ri
load_image[25]=moji_font[34];//naname ue
load_image[26]=moji_font[23];//ha
load_image[27]=moji_font[24];//re
}
else if(yosou_old >= 4){
load_image[22]=moji_font[25];//ku
load_image[23]=moji_font[26];//mo
load_image[24]=moji_font[27];//ri
load_image[25]=moji_font[38];//onaji yajirusi
load_image[26]=moji_font[28];//a
load_image[27]=moji_font[29];//me
}
}
else if(henka == -1 || henka ==-2){
yosou=4;
load_image[22]=moji_font[25];//ku
load_image[23]=moji_font[26];//mo
load_image[24]=moji_font[27];//ri
load_image[25]=moji_font[35];//naname sita
load_image[26]=moji_font[28];//a
load_image[27]=moji_font[29];//me
}
else if(henka <= -3){
yosou=5;
load_image[22]=moji_font[28];//a
load_image[23]=moji_font[29];//me
load_image[24]=moji_font[38];//onaji yajirusi
load_image[25]=moji_font[28];//a
load_image[26]=moji_font[29];//me
load_image[27]=moji_font[35];//naname sita
}
load_image[28]=moji_font[19];//blank
load_image[29]=moji_font[19];//blank
load_image[30]=moji_font[19];//blank
mojisu=31;//0~30 31 moji
for(i=0;i< mojisu;i++){
moji1=load_image[i];
for(j=0;j<8;j++){// bitsum[1]
bitsum[i][j]=0;
}//j
for(j=0;j<8;j++){
bit1gyou=moji1 & 0xff;
for(k=0;k<8;k++){// kagami moji no font
//for(k=8;k>=1;k--){ // futuu no font
bitsum[i][k]=bitsum[i][k]+(bit1gyou & 0x01)*pow((double)2,(double)(j));
bit1gyou=bit1gyou >> 1;
}//k
moji1=moji1 >> 8;
}//j
}// i
k=0;// bitline henkan
for(i=0;i<mojisu;i++){
for(j=0;j<8;j++){
bitline[k]=bitsum[i][j];
k++;
}
}
for(i=0;i<=(mojisu*8-1-23);i++){// bitline hyouji
k=i;
maxOne(1,1,bitline[k]);
maxOne(1,2,bitline[k+1]);
maxOne(1,3,bitline[k+2]);
maxOne(1,4,bitline[k+3]);
maxOne(1,5,bitline[k+4]);
maxOne(1,6,bitline[k+5]);
maxOne(1,7,bitline[k+6]);
maxOne(1,8,bitline[k+7]);
maxOne(2,1,bitline[k+8]);
maxOne(2,2,bitline[k+9]);
maxOne(2,3,bitline[k+10]);
maxOne(2,4,bitline[k+11]);
maxOne(2,5,bitline[k+12]);
maxOne(2,6,bitline[k+13]);
maxOne(2,7,bitline[k+14]);
maxOne(2,8,bitline[k+15]);
maxOne(3,1,bitline[k+16]);
maxOne(3,2,bitline[k+17]);
maxOne(3,3,bitline[k+18]);
maxOne(3,4,bitline[k+19]);
maxOne(3,5,bitline[k+20]);
maxOne(3,6,bitline[k+21]);
maxOne(3,7,bitline[k+22]);
maxOne(3,8,bitline[k+23]);
wait(0.1);
}
hpascal=long(pp1);
hpdata[23]=hpascal;
for(m=1;m<24;m++){
if(hpmax <= hpdata[m]){
hpmax=hpdata[m];
}
if(hpmin >= hpdata[m]){
hpmin=hpdata[m];
}
}//for
hprange=hpmax-hpmin;
hpscope=double(hprange)/8.0;//auto range
if(hprange < 4){
gctrim=double(3-hprange);// auto center trim
}
else {
gctrim=0;
}
for(m=1;m<24;m++){
dotdata[m]=int(double(hpdata[m]-hpmin)/hpscope)+gctrim;
if(dotdata[m] < 0){
dotdata[m]=0;
}
if(dotdata[m] > 7){
dotdata[m]=7;
}
gbit[m]=gdot[dotdata[m]];
}
gbit[0]=gdot[int(hpscope+0.5)];//range hyouji
for(i=0;i<24;i++){// graph scroll data
gbit_s[i]=0; // zenhan 0
}
for(i=24;i<48;i++){// kouhan jitu data
gbit_s[i]=gbit[i-24];
}
for(k=0;k<24;k++){
maxOne(1,1,gbit_s[k]);// graph scroll
maxOne(1,2,gbit_s[k+1]);
maxOne(1,3,gbit_s[k+2]);
maxOne(1,4,gbit_s[k+3]);
maxOne(1,5,gbit_s[k+4]);
maxOne(1,6,gbit_s[k+5]);
maxOne(1,7,gbit_s[k+6]);
maxOne(1,8,gbit_s[k+7]);
maxOne(2,1,gbit_s[k+8]);
maxOne(2,2,gbit_s[k+9]);
maxOne(2,3,gbit_s[k+10]);
maxOne(2,4,gbit_s[k+11]);
maxOne(2,5,gbit_s[k+12]);
maxOne(2,6,gbit_s[k+13]);
maxOne(2,7,gbit_s[k+14]);
maxOne(2,8,gbit_s[k+15]);
maxOne(3,1,gbit_s[k+16]);
maxOne(3,2,gbit_s[k+17]);
maxOne(3,3,gbit_s[k+18]);
maxOne(3,4,gbit_s[k+19]);
maxOne(3,5,gbit_s[k+20]);
maxOne(3,6,gbit_s[k+21]);
maxOne(3,7,gbit_s[k+22]);
maxOne(3,8,gbit_s[k+23]);
wait(0.1);
}
k=0;
maxOne(1,1,gbit[k]);// kiatu graph hyouji
maxOne(1,2,gbit[k+1]);
maxOne(1,3,gbit[k+2]);
maxOne(1,4,gbit[k+3]);
maxOne(1,5,gbit[k+4]);
maxOne(1,6,gbit[k+5]);
maxOne(1,7,gbit[k+6]);
maxOne(1,8,gbit[k+7]);
maxOne(2,1,gbit[k+8]);
maxOne(2,2,gbit[k+9]);
maxOne(2,3,gbit[k+10]);
maxOne(2,4,gbit[k+11]);
maxOne(2,5,gbit[k+12]);
maxOne(2,6,gbit[k+13]);
maxOne(2,7,gbit[k+14]);
maxOne(2,8,gbit[k+15]);
maxOne(3,1,gbit[k+16]);
maxOne(3,2,gbit[k+17]);
maxOne(3,3,gbit[k+18]);
maxOne(3,4,gbit[k+19]);
maxOne(3,5,gbit[k+20]);
maxOne(3,6,gbit[k+21]);
maxOne(3,7,gbit[k+22]);
maxOne(3,8,gbit[k+23]);
for(i=0;i<4;i++){
wait(0.5);
maxOne(3,8,0);
maxOne(1,1,0);
wait(0.5);
maxOne(1,1,gbit[k]);
maxOne(3,8,gbit[k+23]);
}
fshuuki=130;// kousin jikan
wtime++;
if(wtime == fshuuki){
yosou_old=yosou;
for(m=1;m<=22;m++){
hpdata[m]=hpdata[m+1];
}
wtime=0;
}
}//while
}//main
○完成
雨降りの日のグラフ変化と天気予想をご覧ください。家族からは「まあまあ当たるんじゃない。」と言われています。
このプログラムを使用し、業務(インターネットへの公開を含む)として天気予報を行うには、気象予報士の資格が必要です。個人でお楽しみください。
投稿者の人気記事

-
taketea2018
さんが
2026/07/21
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する