开发板的外设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;
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);
SSD1306_sendCommand(0xA6);
SSD1306_sendCommand(0xAE);
SSD1306_sendCommand(0xD5);
SSD1306_sendCommand(0x80);
SSD1306_sendCommand(0xA8);
SSD1306_sendCommand(0x3F);
SSD1306_sendCommand(0xD3);
SSD1306_sendCommand(0x0);
SSD1306_sendCommand(0x40|0x0);
SSD1306_sendCommand(0x8D);
SSD1306_sendCommand(0x14);
SSD1306_sendCommand(0x20);
SSD1306_sendCommand(0x00);
SSD1306_sendCommand(0xA1);
SSD1306_sendCommand(0xC8);
SSD1306_sendCommand(0xDA);
SSD1306_sendCommand(0x12);
SSD1306_sendCommand(0x81);
SSD1306_sendCommand(0xCF);
SSD1306_sendCommand(0xd9);
SSD1306_sendCommand(0xF1);
SSD1306_sendCommand(0xDB);
SSD1306_sendCommand(0x40);
SSD1306_sendCommand(0xA4);
SSD1306_sendCommand(0xA6);
SSD1306_clearDisplay();
SSD1306_sendCommand(0x2E);
SSD1306_sendCommand(0x20);
SSD1306_sendCommand(0x00);
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);
SSD1306_sendCommand(0x00);
}
void SSD1306_setPageMode()
{
addressingMode = PAGE_MODE;
SSD1306_sendCommand(0x20);
SSD1306_sendCommand(0x02);
}
void SSD1306_setTextXY(unsigned char row, unsigned char col)
{
SSD1306_sendCommand(0xB0 + row);
SSD1306_sendCommand(0x00 + (m_font_width*col & 0x0F));
SSD1306_sendCommand(0x10 + ((m_font_width*col>>4)&0x0F));
}
void SSD1306_clearDisplay()
{
unsigned char i,j;
SSD1306_sendCommand(SSD1306_Display_Off_Cmd);
for(j=0;j<8;j++)
{
SSD1306_setTextXY(j,0);
{
for(i=0;i<16;i++)
{
SSD1306_putChar(' ');
}
}
}
SSD1306_sendCommand(SSD1306_Display_On_Cmd);
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;
if(ch < 32 || ch > 127)
{
ch = ' ';
}
unsigned char i = 0;
for(i=0;i<m_font_width;i++)
{
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;
for(i=0;i<decimal;i++)
{
decy *=10;
temp = decy;
SSD1306_putNumber(temp);
decy -= temp;
}
f +=decimal;
return f;
}
void SSD1306_drawBitmap(unsigned char *bitmaparray,int bytes)
{
char localAddressMode = addressingMode;
if(addressingMode != HORIZONTAL_MODE)
{
SSD1306_setHorizontalMode();
}
int i=0;
for(i=0;i<bytes;i++)
{
SSD1306_sendData(pgm_read_byte(&bitmaparray[i]));
}
if(localAddressMode == PAGE_MODE)
{
SSD1306_setPageMode();
}
}
void SSD1306_setHorizontalScrollProperties(int direction,unsigned char startPage, unsigned char endPage, unsigned char scrollSpeed)
{
if(Scroll_Right == direction)
{
SSD1306_sendCommand(0x26);
}
else
{
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
#define SSD1306_Max_Y 63
#define PAGE_MODE 01
#define HORIZONTAL_MODE 02
#define SSD1306_Address 0x3C
#define SSD1306_Command_Mode 0x00
#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
#define SSD1306_I2C_DEVFILE "/dev/i2c-1"
#define SSD1306_I2C_ADDR 0x3c
static int ssd1306_i2c_devfd = 0;
const uint8_t* m_font;
static uint8_t m_font_offset = 2;
static uint8_t m_font_width;
static uint8_t m_col;
static uint8_t m_row;
static char addressingMode;
void SSD1306_init(void);
void SSD1306_setNormalDisplay();
void SSD1306_setInverseDisplay();
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
OLEDFONT(font8x8) =
{
0x08,
0x08,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
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,
0x44,0x42,0x7E,0x40,0x40,0x00,0x00,0x00,
0x64,0x52,0x52,0x52,0x52,0x4C,0x00,0x00,
0x24,0x42,0x42,0x4A,0x4A,0x34,0x00,0x00,
0x30,0x28,0x24,0x7E,0x20,0x20,0x00,0x00,
0x2E,0x4A,0x4A,0x4A,0x4A,0x32,0x00,0x00,
0x3C,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00,
0x02,0x02,0x62,0x12,0x0A,0x06,0x00,0x00,
0x34,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00,
0x0C,0x52,0x52,0x52,0x52,0x3C,0x00,0x00,
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,
0x7E,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00,
0x3C,0x42,0x42,0x42,0x42,0x24,0x00,0x00,
0x7E,0x42,0x42,0x42,0x24,0x18,0x00,0x00,
0x7E,0x4A,0x4A,0x4A,0x4A,0x42,0x00,0x00,
0x7E,0x0A,0x0A,0x0A,0x0A,0x02,0x00,0x00,
0x3C,0x42,0x42,0x52,0x52,0x34,0x00,0x00,
0x7E,0x08,0x08,0x08,0x08,0x7E,0x00,0x00,
0x00,0x42,0x42,0x7E,0x42,0x42,0x00,0x00,
0x30,0x40,0x40,0x40,0x40,0x3E,0x00,0x00,
0x7E,0x08,0x08,0x14,0x22,0x40,0x00,0x00,
0x7E,0x40,0x40,0x40,0x40,0x40,0x00,0x00,
0x7E,0x04,0x08,0x08,0x04,0x7E,0x00,0x00,
0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,0x00,
0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00,
0x7E,0x12,0x12,0x12,0x12,0x0C,0x00,0x00,
0x3C,0x42,0x52,0x62,0x42,0x3C,0x00,0x00,
0x7E,0x12,0x12,0x12,0x32,0x4C,0x00,0x00,
0x24,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00,
0x02,0x02,0x02,0x7E,0x02,0x02,0x02,0x00,
0x3E,0x40,0x40,0x40,0x40,0x3E,0x00,0x00,
0x1E,0x20,0x40,0x40,0x20,0x1E,0x00,0x00,
0x3E,0x40,0x20,0x20,0x40,0x3E,0x00,0x00,
0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00,
0x02,0x04,0x08,0x70,0x08,0x04,0x02,0x00,
0x42,0x62,0x52,0x4A,0x46,0x42,0x00,0x00,
0x00,0x00,0x7E,0x42,0x42,0x00,0x00,0x00,
0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
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,
0x00,0x7E,0x48,0x48,0x48,0x30,0x00,0x00,
0x00,0x00,0x38,0x44,0x44,0x44,0x00,0x00,
0x00,0x30,0x48,0x48,0x48,0x7E,0x00,0x00,
0x00,0x38,0x54,0x54,0x54,0x48,0x00,0x00,
0x00,0x00,0x00,0x7C,0x0A,0x02,0x00,0x00,
0x00,0x18,0xA4,0xA4,0xA4,0xA4,0x7C,0x00,
0x00,0x7E,0x08,0x08,0x08,0x70,0x00,0x00,
0x00,0x00,0x00,0x48,0x7A,0x40,0x00,0x00,
0x00,0x00,0x40,0x80,0x80,0x7A,0x00,0x00,
0x00,0x7E,0x18,0x24,0x40,0x00,0x00,0x00,
0x00,0x00,0x00,0x3E,0x40,0x40,0x00,0x00,
0x00,0x7C,0x04,0x78,0x04,0x78,0x00,0x00,
0x00,0x7C,0x04,0x04,0x04,0x78,0x00,0x00,
0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00,
0x00,0xFC,0x24,0x24,0x24,0x18,0x00,0x00,
0x00,0x18,0x24,0x24,0x24,0xFC,0x80,0x00,
0x00,0x00,0x78,0x04,0x04,0x04,0x00,0x00,
0x00,0x48,0x54,0x54,0x54,0x20,0x00,0x00,
0x00,0x00,0x04,0x3E,0x44,0x40,0x00,0x00,
0x00,0x3C,0x40,0x40,0x40,0x3C,0x00,0x00,
0x00,0x0C,0x30,0x40,0x30,0x0C,0x00,0x00,
0x00,0x3C,0x40,0x38,0x40,0x3C,0x00,0x00,
0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,
0x00,0x1C,0xA0,0xA0,0xA0,0x7C,0x00,0x00,
0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,
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
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
$(CC) -c -Wall $(D_INC) $< -o $@
.PHONY: clean
clean:
rm -f $(D_OBJ)/* $(TATGET) $(D_MK)/*
编译后上传给开发板,执行后就顺利驱动了OLED ssd1306了。