天天看點

樹莓派oled IP顯示

1 實作效果

樹莓派oled IP顯示

2 說明

問題: 在嵌入式開發中,經常遇到一些問題,比如收到一塊開發闆,沒有螢幕,沒有序列槽,需要調試,隻能使用網口連接配接。

可是如果公式内網不是你管理,無法設定固定IP,那麼怎麼搞?我開發闆IP都不知道怎麼連接配接調試或者寫代碼?

為了解決這個問題,這便是我此次創作的目的!

看了網上很多方法,其中有的使用揚聲器開機播報IP,确實也是可以,不過我最終選擇的還是使用OLED螢幕顯示IP,其中還可以顯示cpu溫度、MAC位址、時間等其他資訊。

這裡我是用的開發環境是用qt開發(雖然這個項目沒有ui界面),iic驅動使用樹莓派的wiringpi IO驅動庫。

oled螢幕淘寶買的,8元包郵!!!(圖檔無賣家資訊)

樹莓派oled IP顯示

3 設計思路

軟體整體包含三個部分,一個是oled的顯示驅動,一個是樹莓派需要顯示的資訊擷取,最後就是軟體開機運作的設定。

整體思路就是,使用一個定時器,1s 驅動一次,每次顯示都需要重新整理時間,每30s重新整理一次cpu溫度、IP位址、MAC位址資訊。

我是用的oled顯示屏是12832,即128 * 32個像素點,顯示字元用的8*8大小的,是以能顯示4行資訊,最長顯示16個字元,是以mac位址會将中間的“:”符号去掉顯示。

顯示的資訊排布:

行号 顯示内容 重新整理間隔
第一行 系統時間 1s
第二行 cpu溫度 30s
第三行 IP位址 30s
第四行 MAC位址(eth0) 30s

4 硬體連接配接

随便畫的,繪制比較簡單,樹莓派的3、5引腳為IIC_1的SDA(資料)和SCL(時鐘)腳,我們使用的wiringpi庫也是使用的這個IIC外設,是以我們的iic螢幕也是挂在這上面。

樹莓派oled IP顯示

5 代碼設計

5.1 資訊擷取

(1)時間擷取

擷取時間是最簡單的,使用QTime或者QDateTime類即可擷取,代碼如下:

#include <QTime>
 QString timeStr = QTime::currentTime().toString("    hh:mm:ss    ");
           

上面代碼為什麼隻使用QTime擷取時間,因為螢幕寬度有線,無法顯示日期+時間,是以把日期去掉了。

“hh:mm:ss” 為顯示 “ 時:分:秒 ”

如果需要顯示日期,則使用QDateTime類,代碼如下:

#include <QDateTime>
     QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
           

(2)cpu溫度擷取

#include <QFile>
#define TEMP_PATH "/sys/class/thermal/thermal_zone0/temp"
QString OledIP::getCpuTemp()
{
    char buf[20];
    QFile tempFile(TEMP_PATH);
    if(tempFile.open(QFile::ReadOnly))
    {
        tempFile.read(buf,20);
        float temp = atoi(buf) / 1000.0;
        return QString::number(temp);
    }
    return "";
}
           

(3)IP位址擷取

QString OledIP::getLocalIp()
{
    QString myIp;
    QList<QHostAddress> ipList = QNetworkInterface::allAddresses();
    for (int i = 0; i < ipList.size(); ++i)	 // 擷取第一個本主機的IPv4位址
    {
           if (ipList.at(i) != QHostAddress::LocalHost && ipList.at(i).toIPv4Address())
           {
               myIp= ipList.at(i).toString();
               break;
           }
     }
     if (myIp.isEmpty())	 // 如果沒有找到,則使用本地IP
        myIp= QHostAddress(QHostAddress::LocalHost).toString();
     return myIp;
}
           

(4)MAC位址擷取

QString OledIP::getMAC(Qstring card = "eth0")
{
    QString myMAC;
    auto interfaces = QNetworkInterface::allInterfaces();

    for (int i = 0; i < interfaces.size(); i++)
    {
        if(interfaces.at(i).name().contains(card))
            if (interfaces.at(i).isValid())
            {
                myMAC= interfaces.at(i).hardwareAddress().replace(":","");
                break;
            }
    }
    return myMAC;
}
           

輸入參數為網卡名字,不同的網卡存在不同的MAC位址,該參數一般傳入 “eth0”。

5.2 驅動12832螢幕

(1)寫入指令和資料

void oled12832::writeCmd(int fd,unsigned char I2C_Command)//寫指令
{
    wiringPiI2CWriteReg8(fd,0x00, I2C_Command);
}
void oled12832::writeData(int fd,unsigned char I2C_Data)//寫資料
{
    wiringPiI2CWriteReg8(fd,0x40, I2C_Data);
}
           

(2)初始化寄存器

void oled12832::regInit(int fd)
{
    writeCmd(fd,0xAE); //display off
    writeCmd(fd, 0x20);	//Set Memory Addressing Mode
    writeCmd(fd, 0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
    writeCmd(fd, 0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
    writeCmd(fd, 0xc8);	//Set COM Output Scan Direction
    writeCmd(fd, 0x00); //---set low column address
    writeCmd(fd, 0x10); //---set high column address
    writeCmd(fd, 0x40); //--set start line address
    writeCmd(fd, 0x81); //--set contrast control register
    writeCmd(fd, 0xff); //亮度調節 0x00~0xff
    writeCmd(fd, 0xa1); //--set segment re-map 0 to 127
    writeCmd(fd, 0xa6); //--set normal display
    writeCmd(fd, 0xa8); //--set multiplex ratio(1 to 64)
    writeCmd(fd, 0x3F); //
    writeCmd(fd, 0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
    writeCmd(fd, 0xd3); //-set display offset
    writeCmd(fd, 0x00); //-not offset
    writeCmd(fd, 0xd5); //--set display clock divide ratio/oscillator frequency
    writeCmd(fd, 0xf0); //--set divide ratio
    writeCmd(fd, 0xd9); //--set pre-charge period
    writeCmd(fd, 0x22); //
    writeCmd(fd, 0xda); //--set com pins hardware configuration
    writeCmd(fd, 0x12);
    writeCmd(fd, 0xdb); //--set vcomh
    writeCmd(fd, 0x20); //0x20,0.77xVcc
    writeCmd(fd, 0x8d); //--set DC-DC enable
    writeCmd(fd, 0x14); //
    writeCmd(fd, 0xaf); //--turn on oled panel
}
           

(3)設定寫入位置

void oled12832::oledSetPos(int fd,unsigned char x, unsigned char y) //設定起始點坐标
{
    writeCmd(fd, 0xb0 + x);
    writeCmd(fd,((y & 0x0f) | 0x00));//LOW
    writeCmd(fd,(((y & 0xf0) >> 4) | 0x10));//HIGHT
}
           

(4) 螢幕填充和清空

void oled12832::oledFill(unsigned char data)//全屏填充
{
    for (unsigned char i = 0; i < 8; i++)
    {
        oledSetPos(mOledHard, i, 0); //設定起始點坐标
        for (int j = 0; j < 128; j++)
            writeData(mOledHard, data);//寫資料
    }
}
void oled12832::oledClear()//清屏
{
    unsigned char i, j;
    for (i = 0; i < 8; i++)
    {
        oledSetPos(mOledHard, i, 0); //設定起始點坐标
        for (j = 0; j < 128; j++)
            writeData(mOledHard, 0x00);//寫資料
    }
}
           

(5)清空某行(0-3,一共4行)

void oled12832::clearLine(int row)
{
    oledSetPos(mOledHard,row*2, 0); //設定起始點坐标
    for (int j = 0; j < 128; j++)
        writeData(mOledHard, 0x00);//寫資料
    oledSetPos(mOledHard,row*2+1, 0); //設定起始點坐标
    for (int j = 0; j < 128; j++)
        writeData(mOledHard, 0x00);//寫資料
}
           

(6)顯示字元

//顯示字元
void oled12832::showASCLL(unsigned char row, unsigned char col, unsigned char ascii_char)
{
    unsigned char  i,j;
    i = ascii_char - ' ';	//擷取字元偏移量,這是因為字庫跟标準ASCII碼表相差32,即一個空格
    writeCmd(mOledHard ,0xb0+row);	//設定頁位址
    writeCmd(mOledHard ,col&0x0F);			//設定列位址
    writeCmd(mOledHard ,((col&0xF0)>>4)|0x10);

    for(j=0;j<8;j++)
        writeData(mOledHard ,oled_fonts1608[i][j]);

    writeCmd(mOledHard ,0xB0+(row&0x07)+1);	//設定下一頁位址
    writeCmd(mOledHard ,col&0x0F);			//設定列位址
    writeCmd(mOledHard ,((col&0xF0)>>4)|0x10);
    for(j=0;j<8;j++)
        writeData(mOledHard ,oled_fonts1608[i][j+8]);
}
           

(7)顯示字元串

//顯示字元串
void oled12832::showString(unsigned char row, unsigned char col, unsigned char *ascii_string)
{
    row = row*2;
    while(*ascii_string != '\0')
    {
        if(col == 128)	//防止出現長度大于16的字元串在同一行顯示的情況
        {
            col = 0;
            row += 2;
        }
        showASCLL(row, col, *ascii_string);
        col += 8;
        ascii_string++;
    }
}
void oled12832::showString(unsigned char row, unsigned char col, QString str)
{
    QByteArray buff = str.toLatin1();
    unsigned char *ptr = (unsigned char *)buff.data();
    showString(row,col,ptr);
}

           

5.3 開機啟動腳本(保證該程式隻運作在一個程序)

為什麼還需要腳本啟動,而不是直接運作oledIP可執行檔案,因為我是将啟動方式放在profile中,樹莓派開機過程中,好像是會多次運作到此檔案,是以會導緻多個oledIP程序運作,是以運作該程序之前使用pgrep查詢一下是否有oledIP程序,如果沒有才執行,腳本内容如下:

if [ $(pgrep -f oledIP | wc -l) -eq 0 ];then
cd /home/pi/mApp
./oledIP &
fi
           

樹莓派自定義程序開機啟動的方式很多,可參考其他文章,個人做嵌入式linux開發習慣修改profile檔案,其實不推薦此方法。

5.4整體代碼

整體代碼已經上傳至gitee并開源,其中包含編譯好的可執行檔案,樹莓派的ubuntu系統可直接運作。

項目連結: https://gitee.com/jiangtao008/raspi-oledip

繼續閱讀