TinkerNode NB-IoT 制作看股票的工具

人类社会的进步始终伴随着通讯技术的发展。当我们谈谈及通讯相关历史时,一定会提起中国古代用于示警外族入侵的烽火。但是这种方式信息容量非常小,只能传递“入侵发生”这个信号。类似的,17世纪的法国创建了基于视觉的全国性信号传递系统,具体是通过称作“信号塔” (semaphore towers)的建筑来实现。信号的表示方法接近旗语,每个高塔通过操控机械展示出不同的形状,然后使用接力的方法将消息传递出去。

                                    

              

随着时代发展和科技进步,人类的通讯不再局限于消息的传递,而是更加注重设备之间的互联。这就是“万物互联”的概念。TinkerNode NB-IoT 是 DFRobot 最新出品的物联网开发板。物联网(The Internet of things,IoT)顾名思义,就是物与物相连的互联网。这有两层意思:第一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络;第二,其用户端延伸和扩展到了任何物品与物品之间,进行信息交换和通信。窄带物联网(Narrow Band Internet of Things,NB-IoT)是物联网领域一个新兴的技术,主要用于低移动性、小数据量、对时延不敏感的连接服务,其支持低功耗设备在网络中的数据传输,因此也是一种低功耗广域网(Low Power Wide Area Network,LPWAN)通信技术。相对于被逐渐淘汰的2G通信,NB-IoT具有三大优势:

大连接:海量链接的能力,在同一基站的情况下, NB-IoT 可以比现有无线技术提供 50~100 倍的接入数。一个扇区能够支持,10 万个连接,设备成本与功耗有效降低,网络架构得到优化。

广覆盖:在同样的频段下, NB-IoT比现有的网络增益提升了 20 dB,相当于提升了 100 倍的覆盖面积。

低功耗:NB-IoT借助 PSM(Power Saving Mode,节电模式)和 eDRX(Extended Discontinuous Reception,超长非连续接收)可实现更长待机。

TinkerNode NB-IoT开发板主控芯片是 ESP32,主频:240MHz,内存达到:520KB。

因此,使用它可以方便的完成很多工作。抽烟嚼槟榔吃中药和炒股票是重要的爱国标志,这次我就要用这个板子制作一个能够随时随地显示A股大盘走势的设备。

TinkerNode NB-IoT有着强大的通讯功能,这次用到的是它的WIFI通讯功能。从原理上说:TinkerNode NB-IoT访问一个网址,取得实时的大盘数据,然后将数据显示在液晶屏幕上。

硬件方面,除了TinkerNode NB-IoT还需要一个液晶屏。最终选择的是7寸液晶屏触摸串口屏。这个屏幕的特点首先是尺寸大,分辨率更是800x480。使用串口传输内容让显示非常方便。

多介绍两句这种串口屏。传统的屏幕需要在主机端生成好内容,然后不停的将内容数据发送到屏幕上,因此对于主机和接口有较高的要求。主机需要有足够的内存存放下要显示的内容,同时接口必须足够快并且不断发送数据刷新。而串口屏没有这样的限制,只要有串口就可以实现显示操作。实现的原理是:首先通过屏幕配套的图形化界面设计软件设计界面,比如,在屏幕中央会有一个20字节的字符串需要显示。然后将生成的配置文件烧写到屏幕上。在使用的时候单片机发出“在特定的位置显示字符串”即可。比如,在这次的作品上使用界面设计软件绘制如下:

具体就在800x400 的界面上放上2个显示文本变量外加实时曲线:

其中的文本变量都有对应的地址,比如上图中的“文本变量1”属性如下:

当屏幕串口收到 A5 5A 0E 82 04 86 30 33 31 36 20 34 33 32 32 FF FF 它可以知道一共有 0x0E 个数据,命令是 0x82,访问的地址是 0x0486,后面就是要显示的ASCII。于是就将就将ASCII 显示在文本变量1的位置上。接下来将生成配置文件Copy到U盘上,插入到屏幕的USB 口上电,屏幕自动完成读取。之后就可以使用串口操作了。当然目前串口屏没有统一标准,具体操作需要查看不同厂家手册。

TinkerNode NB-IoT板子上有一组串口,这次就使用它来完成和液晶屏的通讯(实际上只用TXD 即可,因为不需要屏幕反馈数据)

整体供电使用充电宝充电,一路直接提供给液晶屏(屏幕耗电在500MA,因此无法从板子提供),另外一路提供给TinkerNode NB-IoT,直接接入到板子5V位置(实验表明当没有充电电池的时候,太阳能电池板充电输入也无法正常工作)。

代码通过HTTP访问 http://hq.sinajs.cn/list=sh000001 这个网址获得实时信息。取得结果是类似“var hq_str_sh000001="上证指数,2727.0186,2702.1296,2745.6182,2751.8964,2702.4933,0,0,252019507,281583369664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2020-03-20,15:01:59,00,";”这样的信息。细心的朋友也可以猜到sh000001是股票信息,可以通过更换这个代码获得特定股票的实时信息。
/**
 * BasicHTTPClient.ino
 *
 *  Created on: 24.05.2015
 *
 */

#include <Arduino.h>

#include <WiFi.h>
#include <WiFiMulti.h>

#include <HTTPClient.h>

#define USE_SERIAL Serial

WiFiMulti wifiMulti;

void setup() {

    USE_SERIAL.begin(115200);
    Serial2.begin(115200);
/*
    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }
*/
    wifiMulti.addAP("YOUID", "YouPassword");

}

//"var hq_str_sh000001=\"上证指数,3001.7616,2996.7618,2968.5174,3010.0286,2968.5174,0,0,352470970,378766618968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2020-03-11,15:12:07,00,\";";
String payload;

//
// String Parser function
// Input: Str Source String
//        Arg1 - Output start position
//        Arg2 - Output end position
void GetNoData(int number, int *start, int *stop) {
  
  int Index=0;
  *start=0;
  *stop=0;
  // Find first '"'
  while ((Index<payload.length())&&(payload[Index]!='"'))
    {Index++;}
  // if current position is not '"', this means didn't find '"'
  if (payload[Index]!='"')  {return ;}
  // Look for the number string
  while (number>0) {
    *start=Index; *stop=Index;
    while ((Index<payload.length())&&(payload[Index]!=',')) {Index++;}
    *stop=Index;  
    Index++;
    number--;
  }     
}

void loop() {
  //USE_SERIAL.print("[HTTP] begin...\n");


    // wait for WiFi connection
    if((wifiMulti.run() == WL_CONNECTED)) {

        HTTPClient http;

        USE_SERIAL.print("[HTTP] begin...\n");
        // configure traged server and url
        //http.begin("https://www.howsmyssl.com/a/check", ca); //HTTPS
        http.begin("http://hq.sinajs.cn/list=sh000001"); //HTTP

        USE_SERIAL.print("[HTTP] GET...\n");
        // start connection and send HTTP header
        int httpCode = http.GET();

        // httpCode will be negative on error
        if(httpCode > 0) {
            // HTTP header has been send and Server response header has been handled
            USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);

            // file found at server
            if(httpCode == HTTP_CODE_OK) {
                payload = http.getString();
                USE_SERIAL.println(payload);
                int a,b,i;
                String CurrentHi,CurrentLow;
                long v;
                
                //时间
                GetNoData(32,&a,&b);
                for (int i=a;i<b;i++) { USE_SERIAL.print(payload[i]); } USE_SERIAL.print("\n");
               
                //A5 5A 12 82 04 0b 30 33 31 36 20 32 32 3A 32 39 3A 31 32 FF FF 
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(3+b-a+2);
                Serial2.write(0x82);
                Serial2.write(0x04);
                Serial2.write(0x0B);  
                for (int i=a;i<b;i++) { Serial2.write(payload[i]); } 
                Serial2.write(0xFF);
                Serial2.write(0xFF);
                
                //大盘
                GetNoData(4,&a,&b);
                for ( i=a;i<b;i++) { USE_SERIAL.print(payload[i]); } USE_SERIAL.print("\n");
                //A5 5A 0E 82 04 86 30 33 31 36 20 34 33 32 32 FF FF
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(3+b-a+2);
                Serial2.write(0x82);
                Serial2.write(0x04);
                Serial2.write(0x86);  
                for (int i=a;i<b;i++) { Serial2.write(payload[i]); } 
                Serial2.write(0xFF);
                Serial2.write(0xFF);
                
                //大盘整数
                for ( i=a;payload[i]!='.';i++) {CurrentHi=CurrentHi+payload[i];}
                //Serial.print(CurrentHi);Serial.print("\n");
                USE_SERIAL.print(CurrentHi.toInt());USE_SERIAL.print("\n");    
                //大盘小数
                for (i=i+1;i!=b;i++) {CurrentLow=CurrentLow+payload[i];}
                //Serial.print(CurrentHi);Serial.print("\n");
                USE_SERIAL.print(CurrentLow.toInt());USE_SERIAL.print("\n");  
                v= CurrentHi.toInt()*10000+CurrentLow.toInt();
                v=(v-27500000)/1000+200;
                USE_SERIAL.print(v);  USE_SERIAL.print("\n");  
                //A5 5A 04 84 01 00 00 
                Serial2.write(0xA5);
                Serial2.write(0x5A);
                Serial2.write(4);
                Serial2.write(0x84);
                Serial2.write(0x01);
                //Serial2.write(((CurrentHi.toInt()-2600)&0xFF00)>>8);  
                //Serial2.write((CurrentHi.toInt()-2600)&0xFF);
                Serial2.write((v>>8)&0xFF);  
                Serial2.write(v&0xFF);

            }
        } else {
            USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
        }

        http.end();
    }

    delay(5000);
}

找一个纸盒,将屏幕固定在外面,因为除了供电没有其他线路,所以内部使用面包板插接即可:

工作的视频(因为这个屏幕支持触摸,所以看起来外面还有一层膜):

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注