前回のプログラムでは、二つの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というのもおかしい。変化途中でミスってるような気もします。