admin管理员组文章数量:1122850
1 实现效果
2 说明
问题: 在嵌入式开发中,经常遇到一些问题,比如收到一块开发板,没有屏幕,没有串口,需要调试,只能使用网口连接。
可是如果公式内网不是你管理,无法设置固定IP,那么怎么搞?我开发板IP都不知道怎么连接调试或者写代码?
为了解决这个问题,这便是我此次创作的目的!
看了网上很多方法,其中有的使用扬声器开机播报IP,确实也是可以,不过我最终选择的还是使用OLED屏幕显示IP,其中还可以显示cpu温度、MAC地址、时间等其他信息。
这里我是用的开发环境是用qt开发(虽然这个项目没有ui界面),iic驱动使用树莓派的wiringpi IO驱动库。
oled屏幕淘宝买的,8元包邮!!!(图片无卖家信息)
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屏幕也是挂在这上面。
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/jiangtao008/raspi-oledip
版权声明:本文标题:树莓派oled IP显示 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1726436450a1096431.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论