米尔电子
直播中

华仔stm32

3年用户 2961经验值
擅长:嵌入式技术
私信 关注
[技术]

【米尔王牌产品MYD-Y6ULX-V2开发板试用体验】驱动OLED SSD1306

开发板的外设I2C是常用的外设之一,温湿度传感器、OLED等都是经过i2c的总线驱动,今天驱动常用的OLED ssd1306。
1、硬件接线如下图,J14的19脚为SDA,20脚为SCL:
image.png
(备注)手册上有误,手册上写的是i2c2,但是在设备管理器里面是i2c1。
image.png

2、在ubuntu上创建ssd1306.c、ssd1306.h、main.c,以及字库

image.png
ssd1306.c:

#include "ssd1306.h"

void SSD1306_init(void)
{
	m_font_offset = 2;
	//I2C init
	ssd1306_i2c_devfd = open(SSD1306_I2C_DEVFILE, O_RDWR);
	if(ioctl(ssd1306_i2c_devfd, I2C_SLAVE, SSD1306_I2C_ADDR)<0 )
	{
		printf("SSD1306 ioctl error : %s\r\n", strerror(errno));
	}

	SSD1306_sendCommand(0xAE);            //display off
	SSD1306_sendCommand(0xA6);            //Set Normal Display (default)
	SSD1306_sendCommand(0xAE);            //DISPLAYOFF
	SSD1306_sendCommand(0xD5);            //SETDISPLAYCLOCKDIV
	SSD1306_sendCommand(0x80);            // the suggested ratio 0x80
	SSD1306_sendCommand(0xA8);            //SSD1306_SETMULTIPLEX
	SSD1306_sendCommand(0x3F);
	SSD1306_sendCommand(0xD3);            //SETDISPLAYOFFSET
	SSD1306_sendCommand(0x0);             //no offset
	SSD1306_sendCommand(0x40|0x0);        //SETSTARTLINE
	SSD1306_sendCommand(0x8D);            //CHARGEPUMP
	SSD1306_sendCommand(0x14);
	SSD1306_sendCommand(0x20);            //MEMORYMODE
	SSD1306_sendCommand(0x00);            //0x0 act like ks0108
	SSD1306_sendCommand(0xA1);            //SEGREMAP   Mirror screen horizontally (A0)
	SSD1306_sendCommand(0xC8);            //COMSCANDEC Rotate screen vertically (C0)
	SSD1306_sendCommand(0xDA);            //0xDA
	SSD1306_sendCommand(0x12);            //COMSCANDEC
	SSD1306_sendCommand(0x81);            //SETCONTRAST
	SSD1306_sendCommand(0xCF);            //
	SSD1306_sendCommand(0xd9);            //SETPRECHARGE 
	SSD1306_sendCommand(0xF1); 
	SSD1306_sendCommand(0xDB);            //SETVCOMDETECT                
	SSD1306_sendCommand(0x40);
	SSD1306_sendCommand(0xA4);            //DISPLAYALLON_RESUME        
	SSD1306_sendCommand(0xA6);            //NORMALDISPLAY             
	SSD1306_clearDisplay();
	SSD1306_sendCommand(0x2E);            //Stop scroll
	SSD1306_sendCommand(0x20);            //Set Memory Addressing Mode
	SSD1306_sendCommand(0x00);            //Set Memory Addressing Mode ab Horizontal addressing mode
	SSD1306_setFont(font8x8);
}

void SSD1306_setFont(const uint8_t* font)
{
  m_font = font;
  m_font_width = pgm_read_byte(&m_font[0]);
}

void SSD1306_sendCommand(unsigned char command)
{
	uint8_t val[2];
  val[0] = SSD1306_Command_Mode;
  val[1] = command;
	if( write(ssd1306_i2c_devfd, &val, 2) < 0 )
	{
		printf("I2C write error\n");
	}
}

void SSD1306_setBrightness(unsigned char Brightness)
{
   SSD1306_sendCommand(SSD1306_Set_Brightness_Cmd);
   SSD1306_sendCommand(Brightness);
}

void SSD1306_setHorizontalMode()
{
    addressingMode = HORIZONTAL_MODE;
    SSD1306_sendCommand(0x20);                      //set addressing mode
    SSD1306_sendCommand(0x00);                      //set horizontal addressing mode
}

void SSD1306_setPageMode()
{
    addressingMode = PAGE_MODE;
    SSD1306_sendCommand(0x20);                      //set addressing mode
    SSD1306_sendCommand(0x02);                      //set page addressing mode
}

void SSD1306_setTextXY(unsigned char row, unsigned char col)
{
    SSD1306_sendCommand(0xB0 + row);                          //set page address
    SSD1306_sendCommand(0x00 + (m_font_width*col & 0x0F));    //set column lower addr
    SSD1306_sendCommand(0x10 + ((m_font_width*col>>4)&0x0F)); //set column higher addr
}

void SSD1306_clearDisplay()
{
  unsigned char i,j;
  SSD1306_sendCommand(SSD1306_Display_Off_Cmd);     //display off
  for(j=0;j<8;j++)
  {    
    SSD1306_setTextXY(j,0);    
    {
      for(i=0;i<16;i++)  //clear all columns
      {
        SSD1306_putChar(' ');    
      }
    }
  }
  SSD1306_sendCommand(SSD1306_Display_On_Cmd);     //display on
  SSD1306_setTextXY(0,0);    
}

void SSD1306_sendData(unsigned char Data)
{
  uint8_t val[2];
  val[0] = SSD1306_Data_Mode;
  val[1] = Data;
  if( write(ssd1306_i2c_devfd, &val, 2) < 0 )
  {
    printf("I2C write error\n");
  }
}

int SSD1306_putChar(unsigned char ch)
{
    if (!m_font) return 0;
    //Ignore non-printable ASCII characters. This can be modified for
    //multilingual font.  
    if(ch < 32 || ch > 127) 
    {
        ch = ' ';
    }
    unsigned char i = 0;
    for(i=0;i<m_font_width;i++)
    {
       // Font array starts at 0, ASCII starts at 32
       SSD1306_sendData(pgm_read_byte(&m_font[(ch-32)*m_font_width+m_font_offset+i])); 
    }
}

void SSD1306_putString(const char *string)
{
    unsigned char i=0;
    while(string[i])
    {
        SSD1306_putChar(string[i]);     
        i++;
    }
}

unsigned char SSD1306_putNumber(long long_num)
{
  unsigned char char_buffer[10]="";
  unsigned char i = 0;
  unsigned char f = 0;

  if (long_num < 0) 
  {
    f=1;
    SSD1306_putChar('-');
    long_num = -long_num;
  } 
  else if (long_num == 0) 
  {
    f=1;
    SSD1306_putChar('0');
    return f;
  } 

  while (long_num > 0) 
  {
    char_buffer[i++] = long_num % 10;
    long_num /= 10;
  }

  f=f+i;
  for(; i > 0; i--)
  {
    SSD1306_putChar('0'+ char_buffer[i - 1]);
  }
  return f;

}

unsigned char SSD1306_putFloat(float floatNumber,unsigned char decimal)
{
  unsigned int temp=0;
  float decy=0.0;
  float rounding = 0.5;
  unsigned char f=0;
  if(floatNumber<0.0)
  {
    SSD1306_putString("-");
    floatNumber = -floatNumber;
    f +=1;
  }
  unsigned char i=0;
  for (i=0; i<decimal; ++i)
  {
    rounding /= 10.0;
  }
    floatNumber += rounding;
  
  temp = floatNumber;
  f += SSD1306_putNumber(temp);
  if(decimal>0)
  {
    SSD1306_putChar('.');
    f +=1;
 }
  decy = floatNumber-temp;//decimal part, 
  for(i=0;i<decimal;i++)//4 
  {
    decy *=10;// for the next decimal
    temp = decy;//get the decimal
    SSD1306_putNumber(temp);
    decy -= temp;
  }
  f +=decimal;
  return f;
}

void SSD1306_drawBitmap(unsigned char *bitmaparray,int bytes)
{
  char localAddressMode = addressingMode;
  if(addressingMode != HORIZONTAL_MODE)
  {
      //Bitmap is drawn in horizontal mode     
      SSD1306_setHorizontalMode();
  }
  int i=0;
  for(i=0;i<bytes;i++)
  {
      SSD1306_sendData(pgm_read_byte(&bitmaparray[i]));
  }

  if(localAddressMode == PAGE_MODE)
  {
     //If pageMode was used earlier, restore it.
     SSD1306_setPageMode(); 
  }
  
}

void SSD1306_setHorizontalScrollProperties(int direction,unsigned char startPage, unsigned char endPage, unsigned char scrollSpeed)
{
   if(Scroll_Right == direction)
   {
        //Scroll right
        SSD1306_sendCommand(0x26);
   }
   else
   {
        //Scroll left  
        SSD1306_sendCommand(0x27);

   }
    SSD1306_sendCommand(0x00);
    SSD1306_sendCommand(startPage);
    SSD1306_sendCommand(scrollSpeed);
    SSD1306_sendCommand(endPage);
    SSD1306_sendCommand(0x00);
    SSD1306_sendCommand(0xFF);
}

void SSD1306_activateScroll()
{
    SSD1306_sendCommand(SSD1306_Activate_Scroll_Cmd);
}

void SSD1306_deactivateScroll()
{
    SSD1306_sendCommand(SSD1306_Dectivate_Scroll_Cmd);
}

void SSD1306_setNormalDisplay()
{
    SSD1306_sendCommand(SSD1306_Normal_Display_Cmd);
}

void SSD1306_setInverseDisplay()
{
    SSD1306_sendCommand(SSD1306_Inverse_Display_Cmd);
}

ssd1306.h:

#ifndef SSD1306_H
#define SSD1306_H

#define pgm_read_byte(addr) (*(unsigned char *)(addr))
#define OLEDFONT(name) static const uint8_t name[]

#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <errno.h>

#include "font8x8.h"
#include "font5x7.h"

#define SSD1306_Max_X                 127    //128 Pixels
#define SSD1306_Max_Y                 63     //64  Pixels

#define PAGE_MODE                     01
#define HORIZONTAL_MODE               02

#define SSD1306_Address               0x3C
#define SSD1306_Command_Mode          0x00//0x80
#define SSD1306_Data_Mode             0x40
#define SSD1306_Display_Off_Cmd       0xAE
#define SSD1306_Display_On_Cmd        0xAF
#define SSD1306_Normal_Display_Cmd    0xA6
#define SSD1306_Inverse_Display_Cmd   0xA7
#define SSD1306_Activate_Scroll_Cmd   0x2F
#define SSD1306_Dectivate_Scroll_Cmd  0x2E
#define SSD1306_Set_Brightness_Cmd    0x81

#define Scroll_Left                   0x00
#define Scroll_Right                  0x01

#define Scroll_2Frames                0x7
#define Scroll_3Frames                0x4
#define Scroll_4Frames                0x5
#define Scroll_5Frames                0x0
#define Scroll_25Frames               0x6
#define Scroll_64Frames               0x1
#define Scroll_128Frames              0x2
#define Scroll_256Frames              0x3

///////////////////////////////////////////
// modify this for platform-compatibility
//  I2C device args
///////////////////////////////////////////
#define SSD1306_I2C_DEVFILE "/dev/i2c-1" // Raspberry Pi (Pin 3 5)
//#define SSD1306_I2C_DEVFILE "/dev/i2c-0" // Galileo Gen1

#define SSD1306_I2C_ADDR 0x3c // ==(SSD1306_Address)
static int ssd1306_i2c_devfd = 0;

const uint8_t* m_font;      // Current font.
static uint8_t m_font_offset = 2;  // Font bytes for meta data.
static uint8_t m_font_width;       // Font witdth.
static uint8_t m_col;              // Cursor column.
static uint8_t m_row;              // Cursor row (RAM). 
static char addressingMode;

void SSD1306_init(void);

void SSD1306_setNormalDisplay();
void SSD1306_setInverseDisplay();

// modified
void SSD1306_sendCommand(unsigned char command);
void SSD1306_sendData(unsigned char Data);

void SSD1306_setPageMode();
void SSD1306_setHorizontalMode();

void SSD1306_setTextXY(unsigned char Row, unsigned char Column);
void SSD1306_clearDisplay();
void SSD1306_setBrightness(unsigned char Brightness);
int SSD1306_putChar(unsigned char c);
void SSD1306_putString(const char *string);
unsigned char SSD1306_putNumber(long n);
unsigned char SSD1306_putFloat(float floatNumber,unsigned char decimal);
void SSD1306_drawBitmap(unsigned char *bitmaparray,int bytes);

void SSD1306_setHorizontalScrollProperties(
    int direction,
    unsigned char startPage, 
    unsigned char endPage, 
    unsigned char scrollSpeed);
void SSD1306_activateScroll();
void SSD1306_deactivateScroll();

void SSD1306_setFont(const uint8_t* font);

#endif

字库:

#ifndef FONT8x8_H
#define FONT8x8_H

// 8x8 Font ASCII 32 - 127 Implemented
// Users can modify this to support more characters (glyphs)

OLEDFONT(font8x8) =
{
  0x08,                                     // width
  0x08,                                     // height

  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // <space>
  0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,  // !
  0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,  // "
  0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00,  // #
  0x00,0x2E,0x2A,0x7F,0x2A,0x3A,0x00,0x00,  // $
  0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00,  // %
  0x00,0x20,0x54,0x4A,0x54,0x20,0x50,0x00,  // &
  0x00,0x00,0x00,0x04,0x02,0x00,0x00,0x00,  // '
  0x00,0x00,0x00,0x3C,0x42,0x00,0x00,0x00,  // (
  0x00,0x00,0x00,0x42,0x3C,0x00,0x00,0x00,  // )
  0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00,  // *
  0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,  // +
  0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,  // ,
  0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00,  // -
  0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,  // .
  0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00,  // /

  0x3C,0x62,0x52,0x4A,0x46,0x3C,0x00,0x00,  // 0
  0x44,0x42,0x7E,0x40,0x40,0x00,0x00,0x00,  // 1
  0x64,0x52,0x52,0x52,0x52,0x4C,0x00,0x00,  // 2
  0x24,0x42,0x42,0x4A,0x4A,0x34,0x00,0x00,  // 3
  0x30,0x28,0x24,0x7E,0x20,0x20,0x00,0x00,  // 4
  0x2E,0x4A,0x4A,0x4A,0x4A,0x32,0x00,0x00,  // 5
  0x3C,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00,  // 6
  0x02,0x02,0x62,0x12,0x0A,0x06,0x00,0x00,  // 7
  0x34,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00,  // 8
  0x0C,0x52,0x52,0x52,0x52,0x3C,0x00,0x00,  // 9
  0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,  // :
  0x00,0x00,0x80,0x64,0x00,0x00,0x00,0x00,  // ;
  0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00,  // <
  0x00,0x28,0x28,0x28,0x28,0x28,0x00,0x00,  // =
  0x00,0x00,0x44,0x28,0x10,0x00,0x00,0x00,  // >
  0x00,0x04,0x02,0x02,0x52,0x0A,0x04,0x00,  // ?

  0x00,0x3C,0x42,0x5A,0x56,0x5A,0x1C,0x00,  // @
  0x7C,0x12,0x12,0x12,0x12,0x7C,0x00,0x00,  // A
  0x7E,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00,  // B
  0x3C,0x42,0x42,0x42,0x42,0x24,0x00,0x00,  // C
  0x7E,0x42,0x42,0x42,0x24,0x18,0x00,0x00,  // D
  0x7E,0x4A,0x4A,0x4A,0x4A,0x42,0x00,0x00,  // E
  0x7E,0x0A,0x0A,0x0A,0x0A,0x02,0x00,0x00,  // F
  0x3C,0x42,0x42,0x52,0x52,0x34,0x00,0x00,  // G
  0x7E,0x08,0x08,0x08,0x08,0x7E,0x00,0x00,  // H
  0x00,0x42,0x42,0x7E,0x42,0x42,0x00,0x00,  // I
  0x30,0x40,0x40,0x40,0x40,0x3E,0x00,0x00,  // J
  0x7E,0x08,0x08,0x14,0x22,0x40,0x00,0x00,  // K
  0x7E,0x40,0x40,0x40,0x40,0x40,0x00,0x00,  // L
  0x7E,0x04,0x08,0x08,0x04,0x7E,0x00,0x00,  // M
  0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,0x00,  // N
  0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,  // O

  0x7E,0x12,0x12,0x12,0x12,0x0C,0x00,0x00,  // P
  0x3C,0x42,0x52,0x62,0x42,0x3C,0x00,0x00,  // Q
  0x7E,0x12,0x12,0x12,0x32,0x4C,0x00,0x00,  // R
  0x24,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00,  // S
  0x02,0x02,0x02,0x7E,0x02,0x02,0x02,0x00,  // T
  0x3E,0x40,0x40,0x40,0x40,0x3E,0x00,0x00,  // U
  0x1E,0x20,0x40,0x40,0x20,0x1E,0x00,0x00,  // V
  0x3E,0x40,0x20,0x20,0x40,0x3E,0x00,0x00,  // W
  0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00,  // X
  0x02,0x04,0x08,0x70,0x08,0x04,0x02,0x00,  // Y
  0x42,0x62,0x52,0x4A,0x46,0x42,0x00,0x00,  // Z
  0x00,0x00,0x7E,0x42,0x42,0x00,0x00,0x00,  // [
  0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,  // <backslash>
  0x00,0x00,0x42,0x42,0x7E,0x00,0x00,0x00,  // ]
  0x00,0x08,0x04,0x7E,0x04,0x08,0x00,0x00,  // ^
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,  // _

  0x3C,0x42,0x99,0xA5,0xA5,0x81,0x42,0x3C,  // `
  0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00,  // a
  0x00,0x7E,0x48,0x48,0x48,0x30,0x00,0x00,  // b
  0x00,0x00,0x38,0x44,0x44,0x44,0x00,0x00,  // c
  0x00,0x30,0x48,0x48,0x48,0x7E,0x00,0x00,  // d
  0x00,0x38,0x54,0x54,0x54,0x48,0x00,0x00,  // e
  0x00,0x00,0x00,0x7C,0x0A,0x02,0x00,0x00,  // f
  0x00,0x18,0xA4,0xA4,0xA4,0xA4,0x7C,0x00,  // g
  0x00,0x7E,0x08,0x08,0x08,0x70,0x00,0x00,  // h
  0x00,0x00,0x00,0x48,0x7A,0x40,0x00,0x00,  // i
  0x00,0x00,0x40,0x80,0x80,0x7A,0x00,0x00,  // j
  0x00,0x7E,0x18,0x24,0x40,0x00,0x00,0x00,  // k
  0x00,0x00,0x00,0x3E,0x40,0x40,0x00,0x00,  // l
  0x00,0x7C,0x04,0x78,0x04,0x78,0x00,0x00,  // m
  0x00,0x7C,0x04,0x04,0x04,0x78,0x00,0x00,  // n
  0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,  // o

  0x00,0xFC,0x24,0x24,0x24,0x18,0x00,0x00,  // p
  0x00,0x18,0x24,0x24,0x24,0xFC,0x80,0x00,  // q
  0x00,0x00,0x78,0x04,0x04,0x04,0x00,0x00,  // r
  0x00,0x48,0x54,0x54,0x54,0x20,0x00,0x00,  // s
  0x00,0x00,0x04,0x3E,0x44,0x40,0x00,0x00,  // t
  0x00,0x3C,0x40,0x40,0x40,0x3C,0x00,0x00,  // u
  0x00,0x0C,0x30,0x40,0x30,0x0C,0x00,0x00,  // v
  0x00,0x3C,0x40,0x38,0x40,0x3C,0x00,0x00,  // w
  0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,  // x
  0x00,0x1C,0xA0,0xA0,0xA0,0x7C,0x00,0x00,  // y
  0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,  // z
  0x00,0x08,0x08,0x76,0x42,0x42,0x00,0x00,  // {
  0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,  // |
  0x00,0x42,0x42,0x76,0x08,0x08,0x00,0x00,  // }
  0x00,0x00,0x04,0x02,0x04,0x02,0x00,0x00,  // ~
};

#endif

main.c:

#include "ssd1306.h"

int main()
{
	SSD1306_init();
	SSD1306_clearDisplay();
  SSD1306_setBrightness(255);

  SSD1306_setPageMode();
	SSD1306_setTextXY(0,0);
	SSD1306_putString("HELLO MYD-Y6ULX!");
  SSD1306_setTextXY(1,0);
  SSD1306_putString("SSD1306 DEMO");
  SSD1306_setTextXY(2,0);
  SSD1306_putString("2022-11-07");
	close(ssd1306_i2c_devfd);
	return 0;
}

makefile:

vpath %.c src #查找依赖时如果遇到%.c,则自动到src目录下寻找
D_SRC = src
CC=arm-linux-gnueabihf-gcc 
D_INC = -I./inc
D_OBJ = obj
D_MK  = build
TATGET = ssd1306test
 
SRC_C   = $(foreach dir, $(D_SRC), $(wildcard $(dir)/*.c))
OBJ_C   = $(addprefix $(D_OBJ)/,$(patsubst %.c,%.o,$(notdir $(SRC_C))))

 

$(TATGET):$(OBJ_C)
	$(CC) -o $(D_MK)/$@ $^
 
$(D_OBJ)/%.o:%.c  #自动去src目录下找.c结尾的文件。
	$(CC) -c -Wall $(D_INC) $< -o $@
 

 
.PHONY: clean
clean:
	rm -f $(D_OBJ)/* $(TATGET) $(D_MK)/*

编译后上传给开发板,执行后就顺利驱动了OLED ssd1306了。

更多回帖

发帖
×
20
完善资料,
赚取积分