0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C++ の勉強 ⑦ まとめ。sht45の測定結果の温度と湿度を7セグメントLEDに表示する

Posted at

 前回のプログラムでは、二つの7セグメントLEDを利用できるには中途半端になっていました。最初に、二つとも表示ができるように修正します。
 具体的には、アドレスを引数に追加しました。
 その後、sht45その湿度と温度を表示します。

ex129.cpp
#include <iostream>
#include <string>
#include <iomanip>
#include <map>
#include <cstdint>
#include <array>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <unistd.h>
#include <string>

#define white_ht16k33Adr 0x71
#define red_ht16k33Adr 0x70
#define HT16K33_GENERIC_SYSTEM_ON 0x21
#define HT16K33_GENERIC_DISPLAY_ON 0x81
#define HT16K33_GENERIC_CMD_BRIGHTNESS 0xe0

int fd;
uint8_t address, data, segment, resister, level;
int systemOn(uint8_t address);
int displayOn(uint8_t address);
int brightnessSet(uint8_t address,int level);
int one_byte_write(uint8_t address, uint8_t resisterAdr, uint8_t setData);
int clearDisplay(uint8_t address);
int display(uint8_t address, uint8_t dispSegment, uint8_t dispData);
int s, i;
int convertDispData(uint8_t address, float measurementData);
std::array<uint8_t, 4> segmentDispData = {0, 0, 0, 0};

int main(){
   std::cout << "start display HT16K33\n";
   fd = open("/dev/i2c-1", O_RDWR);
   systemOn(white_ht16k33Adr); systemOn(red_ht16k33Adr);
   usleep(1000);
   displayOn(white_ht16k33Adr); displayOn(red_ht16k33Adr);
   usleep(1000);
   brightnessSet(white_ht16k33Adr, 8); brightnessSet(red_ht16k33Adr, 8);
   usleep(1000);
   clearDisplay(white_ht16k33Adr); clearDisplay(red_ht16k33Adr);
   usleep(1000);

   float temp = -9.06;
   convertDispData(white_ht16k33Adr, temp);
   float humi = 98;
   convertDispData(red_ht16k33Adr, humi);

   return 0;
}

int convertDispData(uint8_t address, float measurementData){
   std::array<uint8_t, 4> segmentDispData;
   std::string measurementDataString = std::to_string(measurementData);
   std::string measurementDataStringSlim = measurementDataString.erase(measurementDataString.find("00"));
   std::cout << "input measurementData(string): " << measurementDataStringSlim << "\n";
   int size = measurementDataStringSlim.size();

   std::map<unsigned char, uint8_t> figData{
           {'0', 0x3f}, {'1', 0x06}, {'2', 0x5b}, {'3', 0x4f}, {'4', 0x66}, {'5', 0x6d},
           {'6', 0x7d}, {'7', 0x07}, {'8', 0x7f}, {'9', 0x67}, {'-', 0x40} ,{'.', 0x80}};

   std::map<uint8_t, uint8_t> segmentData{{1, 0}, {2, 2}, {3, 6}, {4, 8}};

   s = 4;
   for (i = 1; i < size + 1; i++){
       if (measurementDataStringSlim[size-i] == '.'){
           i++;
           segmentDispData[s] = figData.at(measurementDataStringSlim[size-i]) | 0x80;
       }else{
           segmentDispData[s] = figData.at(measurementDataStringSlim[size-i]);
       }
   std::cout << "segment" << s << ": " <<  measurementDataString[size-i]
             << " 0x" << std::hex << (int)segmentDispData[s] << "\n";

   display(address, segmentData[s], (int)segmentDispData[s]);
   s--;
   }
    return 0;
}

int systemOn(uint8_t address){
   one_byte_write(address, HT16K33_GENERIC_SYSTEM_ON, 0);
   return 0;
}

int displayOn(uint8_t address){
   one_byte_write(address, HT16K33_GENERIC_DISPLAY_ON, 0);
   return 0;
}

int brightnessSet(uint8_t address, int level){
   one_byte_write(address, HT16K33_GENERIC_CMD_BRIGHTNESS, level);
   return 0;
}

int one_byte_write(uint8_t address, uint8_t resisterAdr, uint8_t setData){
   struct i2c_msg msg[1];  // /usr/include/linux/i2c.h
   struct i2c_rdwr_ioctl_data packets;  // /usr/include/linux/i2c-dev.h
   uint8_t data[2];

   msg[0].addr =  address;  // device address
   msg[0].flags = 0;   // read、writeやアドレス長の指定
   msg[0].len = 1;     // bufに指定するdataのサイズ
   msg[0].buf = data;

   data[0] = resisterAdr;
   data[1] = setData;
   packets.msgs = msg;
   packets.nmsgs = 1;  //  msgのサイズ指定

   int ret = ioctl(fd, I2C_RDWR, &packets);

   return 0;
}

int clearDisplay(uint8_t address){
   struct i2c_msg msg[1];
   struct i2c_rdwr_ioctl_data packets;
   uint8_t data[11];

   msg[0].addr = address;  // device address
   msg[0].flags = 0;    // read、writeやアドレス長の指定
   msg[0].len = 11;     // bufに指定するdataのサイズ
   msg[0].buf = data;

   data[0] = 0;
   data[1] = 0x00;
   data[2] = 0x00;
   data[3] = 0x00;
   data[4] = 0x00;
   data[5] = 0x00;
   data[6] = 0x00;
   data[7] = 0x00;
   data[8] = 0x00;
   data[9] = 0x00;
   data[10] = 0x00;
   packets.msgs = msg;
   packets.nmsgs = 1;  //  msgのサイズ指定

   int retclear = ioctl(fd, I2C_RDWR, &packets);

   return 0;
}

int display(uint8_t address, uint8_t dispSegment, uint8_t dispData){
   struct i2c_msg msgP[1];
   struct i2c_rdwr_ioctl_data packetsP;
   unsigned char data[2];

   msgP[0].addr =  address;
   msgP[0].flags = 0;
   msgP[0].len = 2;
   msgP[0].buf = data;

   data[0] = dispSegment;
   data[1] = dispData;
   packetsP.msgs = msgP;
   packetsP.nmsgs = 1;        // データ書き込みでmsgは1
   int retP = ioctl(fd, I2C_RDWR, &packetsP);

   return 0;
}

 実行します。赤色と白色の7セグメントLEDの両方を制御できるようになりました。

$ g++ ex129.cpp
yoshi@yoshi:~/book$ ./a.out
start display HT16K33
input measurementData(string): -9.06
segment4: 6 0x7d
segment3: 0 0x3f
segment2: 9 0xe7
segment1: - 0x40
input measurementData(string): 98.
segment4: 8 0xff
segment3: 9 0x67

sht45の測定結果を表示する

 sht45の測定結果である温度と湿度を、7セグメントLEDに表示します。
 たくさんあった、初期設定類は、init_ht16k33()init_sht45()に集約しました。

ex130.cpp
#include <iostream>
#include <string>
#include <iomanip>
#include <map>
#include <cstdint>
#include <array>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <unistd.h>
#include <string>
#include <tuple>

#define white_ht16k33Adr 0x71
#define red_ht16k33Adr 0x70
#define HT16K33_GENERIC_SYSTEM_ON 0x21
#define HT16K33_GENERIC_DISPLAY_ON 0x81
#define HT16K33_GENERIC_CMD_BRIGHTNESS 0xe0
#define sht45Adr 0x44

int fd;
uint8_t address, data, segment, resister, level, i, s;
int systemOn(uint8_t address);
int displayOn(uint8_t address);
int brightnessSet(uint8_t address,int level);
int one_byte_write(uint8_t address, uint8_t resisterAdr, uint8_t setData);
int one_byte_write_noaddress(uint8_t address, uint8_t setData);
int clearDisplay(uint8_t address);
int display(uint8_t address, uint8_t dispSegment, uint8_t dispData);
int convertDispData(uint8_t address, float measurementData);
std::array<uint8_t, 4> segmentDispData = {0, 0, 0, 0};
std::tuple<float, float> readSht45_data();
uint8_t CalcCrc(const uint8_t * crcdata, uint8_t size);
uint8_t reflect(uint8_t c);

float temp;
float humi;
int init_sht45();
int init_ht16k33();

int main(){
    std::cout << "start display HT16K33\n";
    fd = open("/dev/i2c-1", O_RDWR);
    init_ht16k33();
    init_sht45();

    auto [temp, humi] = readSht45_data();
    std::cout << "\ntemp is "  << std::fixed << std::setprecision(2) << temp << "`C\n";
    std::cout << "humi is "  << std::fixed << std::setprecision(1) << humi << "%\n";
    int temp_10 = int(10.0 * temp); temp = float(temp_10) /10.0;
    int humi_1 = int(humi); humi = float(humi_1) /1.0;
    convertDispData(white_ht16k33Adr, temp);
    convertDispData(red_ht16k33Adr, humi);

 return 0;
}

int init_ht16k33(){
    systemOn(white_ht16k33Adr); systemOn(red_ht16k33Adr);
    usleep(1000);
    displayOn(white_ht16k33Adr); displayOn(red_ht16k33Adr);
    usleep(1000);
    brightnessSet(white_ht16k33Adr, 8); brightnessSet(red_ht16k33Adr, 8);
    usleep(1000);
    clearDisplay(white_ht16k33Adr); clearDisplay(red_ht16k33Adr);
    usleep(1000);
    std::cout << "\ninit ht16k33  \n";
    return 0;
}

int init_sht45(){
    one_byte_write_noaddress(sht45Adr,0x94);  // reset
    usleep(1000);
    one_byte_write_noaddress(sht45Adr,0xfd);  // high precision
    usleep(10000);
    std::cout << "\ninit sht45  \n";
    return 0;
}

int convertDispData(uint8_t address, float measurementData){
    std::string measurementDataString;
    std::string measurementDataStringSlim;
    std::cout << "input measurementData(float): "<< std::fixed << std::setprecision(3) << measurementData << "\n";
    std::array<uint8_t, 4> segmentDispData;
    measurementDataString = std::to_string(measurementData);
    std::cout << "measurementDataString (to_string) " << measurementDataString << "\n";
    if (measurementDataString.find("00") != std::string::npos){
        std::cout << "00\n";
        measurementDataStringSlim = measurementDataString.erase(measurementDataString.find("00"));
    }

    if (measurementDataString.find("99") != std::string::npos){
        std::cout << "99\n";
        measurementDataStringSlim = measurementDataString.erase(measurementDataString.find("99"));
    }
        std::cout << "input measurementData(string): " << measurementDataStringSlim << "\n";
        int size = measurementDataStringSlim.size();
//        std::cout << "measurementData(string) length" << size << "\n";

    std::map<unsigned char, uint8_t> figData{
            {'0', 0x3f}, {'1', 0x06}, {'2', 0x5b}, {'3', 0x4f}, {'4', 0x66}, {'5', 0x6d},
            {'6', 0x7d}, {'7', 0x07}, {'8', 0x7f}, {'9', 0x67}, {'-', 0x40} ,{'.', 0x80}};

    std::map<uint8_t, uint8_t> segmentData{{1, 0}, {2, 2}, {3, 6}, {4, 8}};

    s = 4;
    for (i = 1; i < size + 1; i++){
        if (measurementDataStringSlim[size-i] == '.'){
            i++;
            segmentDispData[s] = figData.at(measurementDataStringSlim[size-i]) | 0x80;
        }else{
            segmentDispData[s] = figData.at(measurementDataStringSlim[size-i]);
        }
    std::cout << "segment" << (int)s << ": " <<  measurementDataString[size-i]
              << " 0x" << std::hex << (int)segmentDispData[s] << "\n";

    display(address, segmentData[s], (int)segmentDispData[s]);
    s--;
    }
     return 0;
}

int systemOn(uint8_t address){
    one_byte_write(address, HT16K33_GENERIC_SYSTEM_ON, 0);
    return 0;
}

int displayOn(uint8_t address){
    one_byte_write(address, HT16K33_GENERIC_DISPLAY_ON, 0);
    return 0;
}

int brightnessSet(uint8_t address, int level){
    one_byte_write(address, HT16K33_GENERIC_CMD_BRIGHTNESS, level);
    return 0;
}

int one_byte_write(uint8_t address, uint8_t resisterAdr, uint8_t setData){
    struct i2c_msg msg[1];  // /usr/include/linux/i2c.h
    struct i2c_rdwr_ioctl_data packets;  // /usr/include/linux/i2c-dev.h
    uint8_t data[2];

    msg[0].addr =  address;  // device address
    msg[0].flags = 0;   // read、writeやアドレス長の指定
    msg[0].len = 1;     // bufに指定するdataのサイズ
    msg[0].buf = data;

    data[0] = resisterAdr;
    data[1] = setData;
    packets.msgs = msg;
    packets.nmsgs = 1;  //  msgのサイズ指定

    int ret = ioctl(fd, I2C_RDWR, &packets);

    return 0;
}

int one_byte_write_noaddress(uint8_t address, uint8_t setData){
    struct i2c_msg msg[1];  // /usr/include/linux/i2c.h
    struct i2c_rdwr_ioctl_data packets;  // /usr/include/linux/i2c-dev.h
    uint8_t data[1];

    msg[0].addr =  address;  // device address
    msg[0].flags = 0;   // read、writeやアドレス長の指定
    msg[0].len = 1;     // bufに指定するdataのサイズ
    msg[0].buf = data;

    data[0] = setData;
    packets.msgs = msg;
    packets.nmsgs = 1;  //  msgのサイズ指定

    int ret = ioctl(fd, I2C_RDWR, &packets);

    return 0;
}

int clearDisplay(uint8_t address){
    struct i2c_msg msg[1];
    struct i2c_rdwr_ioctl_data packets;
    uint8_t data[11];

    msg[0].addr = address;  // device address
    msg[0].flags = 0;    // read、writeやアドレス長の指定
    msg[0].len = 11;     // bufに指定するdataのサイズ
    msg[0].buf = data;

    data[0] = 0;
    data[1] = 0x00;
    data[2] = 0x00;
    data[3] = 0x00;
    data[4] = 0x00;
    data[5] = 0x00;
    data[6] = 0x00;
    data[7] = 0x00;
    data[8] = 0x00;
    data[9] = 0x00;
    data[10] = 0x00;
    packets.msgs = msg;
    packets.nmsgs = 1;  //  msgのサイズ指定

    int retclear = ioctl(fd, I2C_RDWR, &packets);

    return 0;
}

int display(uint8_t address, uint8_t dispSegment, uint8_t dispData){
    struct i2c_msg msgP[1];
    struct i2c_rdwr_ioctl_data packetsP;
    unsigned char data[2];

    msgP[0].addr =  address;
    msgP[0].flags = 0;
    msgP[0].len = 2;
    msgP[0].buf = data;

    data[0] = dispSegment;
    data[1] = dispData;
    packetsP.msgs = msgP;
    packetsP.nmsgs = 1;        // データ書き込みでmsgは1
    int retP = ioctl(fd, I2C_RDWR, &packetsP);

    return 0;
}

std::tuple<float, float> readSht45_data(){
    // read 6 data
    struct i2c_msg msgP[1];
    struct i2c_rdwr_ioctl_data packetsP;
    unsigned char data1[1], data2[6];

    msgP[0].addr =  sht45Adr;
    msgP[0].flags = I2C_M_RD;   // アドレスを書き込み
    msgP[0].len = 6;
    msgP[0].buf = &data2[0];

    packetsP.msgs = msgP;
    packetsP.nmsgs = 1;        // データ読み出しでmsgは1
    int retP = ioctl(fd, I2C_RDWR, &packetsP);

//    std::cout << "read all data " << (int)data2[0] << " " << (int)data2[1] << " " << (int)data2[2] << " " << (int)data2[3] << " " << (int)data2[4] << " " << (int)data2[5] << "\n";

    int tempCrc = CalcCrc(data2, 2);
    if (data2[2] == tempCrc) {

//        std::cout << " temp crc is 0x" << std::hex << (int)data2[2] << " calcedCRC is 0x" << std::hex << tempCrc << "\n";

        int Stemp = data2[0] << 8 | data2[1];
        temp = -45 + (float)Stemp * 175.0 / 65535.0;
    }
    int humiCrc = CalcCrc(data2+3, 2);
    if (data2[5] == humiCrc) {

//        std::cout << " humi crc is 0x" << std::hex << (int)data2[5] << " calcedCRC is 0x" << std::hex << humiCrc << "\n";

        int SRH = data2[3] << 8 | data2[4];
        humi = 100.0 * (float)SRH / 65535.0;
    }

    return  std::make_tuple(temp, humi);
}

uint8_t table[256] ={
   0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,35, 125, 159,193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53
};

uint8_t CalcCrc(const uint8_t * crcdata, uint8_t length){

//    std::cout << "in function \n new data 0x" << std::hex << (int)crcdata[0] << std::hex << (int)crcdata[1]
//              << " 0b" << ((std::bitset<8>(*crcdata)).to_string()).insert(4, " ")
//              << "\n data size is " << (int)length << "\n";

    uint8_t crc = 0xff;
    crc = table[reflect(crcdata[0]) ^ crc];
    crc = table[reflect(crcdata[1]) ^ crc];

    return reflect(crc);
}

uint8_t reflect( uint8_t c ){
  c = ((c & 0x55) <<  1) | (c >>  1) & 0x55;
  c = ((c & 0x33) <<  2) | (c >>  2) & 0x33;
  c = ((c & 0x0f) <<  4) | (c >>  4) & 0x0f;
  return c;
}

 実行します。

$ g++ ex130.cpp
yoshi@yoshi:~/book$ ./a.out
start display HT16K33

init ht16k33

init sht45

temp is 27.89`C
humi is 58.6%
input measurementData(float): 27.800
measurementDataString (to_string) 27.799999
99
input measurementData(string): 27.7
segment4: 7 0x7
segment3: 7 0x87
segment2: 2 0x5b
input measurementData(float): 58.000
measurementDataString (to_string) 58.000000
00
input measurementData(string): 58.
segment4: 8 0xff
segment3: 5 0x6d

 少し冗長な出力になっています。
 前回、実数-12.3をto_stringしたら、-12.300000になったという話を書きました。それだけではなかったのです。-12.299999という出力も出るのです。実数は実に恐ろしやです。ほかの事例も出てくるかもしれないので、その経過を出力させています。

 さらに、計測値が27.89℃なのに、表示は27.7というのもおかしい。変化途中でミスってるような気もします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?