问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

基于单片机OLED简易图形库开发指南(附源代码)

创作时间:
作者:
@小白创作中心

基于单片机OLED简易图形库开发指南(附源代码)

引用
CSDN
1.
https://m.blog.csdn.net/ybhuangfugui/article/details/140704708

本文将介绍如何使用基于SSD1306驱动器的128x64 OLED显示屏进行温度显示界面的开发。通过详细讲解硬件连接、基本概念、API函数说明以及完整的代码示例,帮助读者快速掌握OLED显示屏的使用方法。

硬件介绍

该128x64 OLED为单色显示屏,基于SSD1306驱动器芯片。常见的尺寸有0.96寸和1.3寸,其中1.3寸屏幕虽然显示效果更好,但价格略贵。

这种显示屏支持I2C和SPI两种通信方式,具体选择取决于实际需求。

显示大小和坐标

128x64显示屏的坐标系统如下:

  • 横坐标范围:0-127
  • 纵坐标范围:0-63
  • 原点(0,0)位于左下角

显示屏分为八个8像素高频段,称为页面,一个字节对应于8像素的垂直列,其位顺序如下图所示:

图形库API说明

初始化和清除显示

void InitDisplay () {
  Wire.beginTransmission(address);
  Wire.write(commands);
  Wire.write(0xA1); 
  Wire.write(0xAF); 
  Wire.endTransmission();
}

void ClearDisplay () {
  for (int p = 0 ; p < 8; p++) {
    Wire.beginTransmission(address);
    Single(0xB0 + p);
    Wire.endTransmission();
    for (int q = 0 ; q < 8; q++) {
      Wire.beginTransmission(address);
      Wire.write(data);
      for (int i = 0 ; i < 20; i++) Wire.write(0);
      Wire.endTransmission();
    }
  }
}

绘制点和线

void PlotPoint (int x, int y) {
  Wire.beginTransmission(address);        //地址
  Single(0x00 + ((x + 2) & 0x0F));
  Single(0x10 + ((x + 2)>>4));
  Single(0xB0 + (y >> 3));
  Single(0xE0);                      //读取并修改写入
  Wire.write(onedata);
  Wire.endTransmission();
  Wire.requestFrom(address, 2);
  Wire.read(); 
  
  int j = Wire.read();
  Wire.beginTransmission(address);
  Wire.write(onedata);
  Wire.write((1<<(y & 0x07)) | j);
  Single(0xEE);                           // Cancel read modify write
  Wire.endTransmission();
}

void DrawTo (int x, int y) {
  int sx, sy, e2, err;
  int dx = abs(x - x0);
  int dy = abs(y - y0);
  if (x0 < x) sx = 1; else sx = -1;
  if (y0 < y) sy = 1; else sy = -1;
  err = dx - dy;
  for (;;) {
    PlotPoint(x0, y0);
    if (x0==x && y0==y) return;
    e2 = err<<1;
    if (e2 > -dy) { err = err - dy; x0 = x0 + sx; }
    if (e2 < dx) { err = err + dx; y0 = y0 + sy; }
  }
}

绘制字符和文本

void PlotChar (int c, int x, int y) {
  int h = y & 0x07;
  for (int p = 0; p < 2; p++) {
    Wire.beginTransmission(address);
    Single(0xB0 + (y >> 3) + p);          // Page
    for (int col=0; col<6; col++) {
      Single(0x00 + ((x+2+col) & 0x0F));  // Column low nibble
      Single(0x10 + ((x+2+col)>>4));      // Column high nibble
      Single(0xE0);                       // Read modify write
      Wire.write(onedata);
      Wire.endTransmission();
      Wire.requestFrom(address, 2);
      Wire.read();                        // Dummy read
      int j = Wire.read();
      Wire.beginTransmission(address);
      Wire.write(onedata);
      int bits = ReverseByte(pgm_read_byte(&CharMap[c-32][col]));
      Wire.write((bits<<h)>>(p<<3) | j);
      Single(0xEE);                       // Cancel read modify write
    }
    Wire.endTransmission();
  }
}

void PlotText(PGM_P s) {
  int p = (int)s;
  while (1) {
    char c = pgm_read_byte(p++);
    if (c == 0) return;
    PlotChar(c, x0, y0);
    x0 = x0 + 6;
  }
}

实例:温度显示界面

本例程为简单Demo:15分钟记录一次温度,并将其绘制在显示屏上,精度为0.5°C。

电路连接

Demo程序

const int Now = 1547;                   // 比如设置时间为:15:47
unsigned long StartMins = (unsigned long)((Now/100)*60 + (Now%100));
void loop () {
  unsigned int SampleNo = StartMins/15;
  
  // 绘制温度图
  int x1 = 16, y1 = 11;
  int yscale = 2;
  MoveTo(26, 56); PlotText(PSTR("Temperature ~C"));
 
  //横轴
  MoveTo(x1, y1); DrawTo(x1+96, y1);
  for (int i=0; i<=24; i=i+4) {
    int mark = x1+i*4;
    MoveTo(mark, y1); DrawTo(mark, y1-2);
    int tens = i/10;
    if (tens != 0) {
      PlotChar(tens+'0', mark-6, y1-12);
      PlotChar(i%10+'0', mark, y1-12);
    } else PlotChar(i%10+'0', mark-3, y1-12);
  }
 
  //纵轴
  MoveTo(x1, y1); DrawTo(x1, y1+50);
  for (int i=5; i<=25; i=i+5) {
    int mark = y1+i*yscale-10;
    MoveTo(x1, mark); DrawTo(x1-2, mark);
    int tens = i/10;
    if (tens != 0) PlotChar(tens+'0', x1-15, mark-3);
    PlotChar(i%10+'0', x1-9, mark-3);
  }
  for (;;) {
    //每15分钟更新一下
    while ((unsigned long) ((StartMins + millis()/60000)/15)%96 == SampleNo);
    // Time to take a new reading
    SampleNo = (SampleNo+1)%96;
    int Temperature = (analogRead(A2)*25)/233;
    PlotPoint(SampleNo+x1, Temperature-10+y1);
  }
}

通过这个实例,我们可以看到如何使用上述API函数来实现一个简单的温度显示界面。希望这篇文章能为大家提供一些设计思路,帮助大家在开发类似项目时少走弯路。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号