开发板的外设I2C是常用的外设之一,温湿度传感器、OLED等都是经过i2c的总线驱动,今天驱动常用的OLED ssd1306。
1、硬件接线如下图,J14的19脚为SDA,20脚为SCL:
(备注)手册上有误,手册上写的是i2c2,但是在设备管理器里面是i2c1。
2、在ubuntu上创建ssd1306.c、ssd1306.h、main.c,以及字库
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了。
更多回帖