【摘要】 OLED顯示屏在是智能手環,智能手表上用的非常的多,功耗低,不刺眼,優點特別多。本篇文章就介紹,在Linux系統里如何使用OLED顯示屏,要使用OLED顯示屏,大致分為兩步: (1) 針對OLED顯示屏編寫一個驅動 (2) 編寫應用層程序進行測試。
1. 前言
OLED顯示屏在是智能手環,智能手表上用的非常的多,功耗低,不刺眼,優點特別多。本篇文章就介紹,在Linux系統里如何使用OLED顯示屏,要使用OLED顯示屏,大致分為兩步: (1) 針對OLED顯示屏編寫一個驅動 (2) 編寫應用層程序進行測試。
采用的OLED顯示屏是0.96寸SPI接口顯示屏,分辨率是128*64,比較便宜,淘寶上非常多。
測試開發板采用友善之臂Tiny4412,三星的EXYNOS-4412芯片,4核1.5GHZ,板載8G-EMMC,2G-DDR。
2. 硬件接線效果




3. 驅動代碼
Linux內核提供了標準SPI子系統框架,和前面介紹的IIC子系統框架使用類似,代碼分為設備端和驅動端,Linux內核提供子系統的目的就是為了統一驅動編寫標準,提高驅動代碼的移植性。
本篇文章代碼沒有采用SPI子系統框架,采用單片機慣用的模擬SPI時序,對入門而言,代碼更容易理解。
3.1 oled.c 驅動示例代碼
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
定義OLED需要使用的寄存器
*/
static volatile unsigned int *GPB_CON=NULL;
static volatile unsigned int *GPB_DAT=NULL;
//OLED屏幕底層接口
#define OLED_SCK(x) if(x){*GPB_DAT|=1<<0;}else{*GPB_DAT&=~(1<<0);}
#define OLED_MOSI(x) if(x){*GPB_DAT|=1<<3;}else{*GPB_DAT&=~(1<<3);}
#define OLED_RES(x) if(x){*GPB_DAT|=1<<4;}else{*GPB_DAT&=~(1<<4);}
#define OLED_DC(x) if(x){*GPB_DAT|=1<<5;}else{*GPB_DAT&=~(1<<5);}
#define OLED_CS(x) if(x){*GPB_DAT|=1<<1;}else{*GPB_DAT&=~(1<<1);}
//命令與數據區分
#define OLED_CMD 0
#define OLED_DAT 1
//函數聲明區域
static void OLED_WriteOneByte(u8 data,u8 cmd);
static u8 OLED_GPIO_Init(void);
static void OLED_Init(void);
static void OLED_Clear(u8 data);
static void OLED_DrawPoint(u8 x,u8 y,u8 c);
static void OLED_RefreshGRAM(void);
/*
函數功能: OLED對應的GPIO口初始化
硬件連接:
OLED模塊---Tiny4412開發板
GND--------GND
VCC--------VCC(5V)
D0---------SCL--------------GPB_0
D1---------MOSI-------------GPB_3
RES--------復位-------------GPB_4
DC---------數據/命令--------GPB_5
CS---------CS片選-----------GPB_1
*/
static u8 OLED_GPIO_Init(void)
{
/*1. 將物理地址轉換為虛擬地址*/
GPB_CON=ioremap(0x11400040,4);
GPB_DAT=ioremap(0x11400044,4);
if(GPB_CON==NULL||GPB_DAT==NULL)
{
printk("物理地址轉換為虛擬地址出現問題!\n");
return -1;
}
/*2. 配置GPIO口模式*/
*GPB_CON&=0xFF000F00;
*GPB_CON|=0x00111011;
/*3. 上拉GPIO口*/
OLED_CS(1);
OLED_DC(1);
OLED_MOSI(1);
OLED_RES(1);
OLED_SCK(1);
}
/*
函數功能: OLED屏幕初始化
*/
static void OLED_Init(void)
{
/*1. 初始化配置GPIO口*/
OLED_GPIO_Init();
/*2. 執行OLED屏幕的初始化配置*/
OLED_RES(1);
udelay(2000);
OLED_RES(0);
udelay(2000);
OLED_RES(1);
udelay(2000);
OLED_WriteOneByte(0xAE,OLED_CMD); //0xAE表示關顯示,0xAF表示開顯示
OLED_WriteOneByte(0x00,OLED_CMD);
OLED_WriteOneByte(0x10,OLED_CMD);
OLED_WriteOneByte(0x40,OLED_CMD);
OLED_WriteOneByte(0xB0,OLED_CMD);
OLED_WriteOneByte(0x81,OLED_CMD);
OLED_WriteOneByte(0xCF,OLED_CMD);
OLED_WriteOneByte(0xA1,OLED_CMD);
OLED_WriteOneByte(0xA6,OLED_CMD);
OLED_WriteOneByte(0xA8,OLED_CMD);
OLED_WriteOneByte(0x3F,OLED_CMD);
OLED_WriteOneByte(0xC8,OLED_CMD);
OLED_WriteOneByte(0xD3,OLED_CMD);
OLED_WriteOneByte(0x00,OLED_CMD);
OLED_WriteOneByte(0xD5,OLED_CMD);
OLED_WriteOneByte(0x80,OLED_CMD);
OLED_WriteOneByte(0xD9,OLED_CMD);
OLED_WriteOneByte(0xF1,OLED_CMD);
OLED_WriteOneByte(0xDA,OLED_CMD);
OLED_WriteOneByte(0x12,OLED_CMD);
OLED_WriteOneByte(0xDB,OLED_CMD);
OLED_WriteOneByte(0x30,OLED_CMD);
OLED_WriteOneByte(0x8D,OLED_CMD);
OLED_WriteOneByte(0x14,OLED_CMD);
OLED_WriteOneByte(0xAF,OLED_CMD); //正常模式
}
/*
函數功能: 寫一個字節
函數參數:
cmd=0表示命令,cmd=1表示數據
*/
static void OLED_WriteOneByte(u8 data,u8 cmd)
{
u8 i;
/*1. 區分發送數據是命令還是屏幕數據*/
if(cmd){OLED_DC(1);}
else {OLED_DC(0);}
udelay(2);
/*2. 發送實際的數據*/
OLED_CS(0); //選中OLED
for(i=0;i<8;i++)
{
udelay(2);
OLED_SCK(0); //告訴從機,主機將要發送數據
if(data&0x80){OLED_MOSI(1);} //發送數據
else {OLED_MOSI(0);}
udelay(2);
OLED_SCK(1); //告訴從機,主機數據發送完畢
data<<=1; //繼續發送下一位數據
}
OLED_CS(1); //取消選中OLED
OLED_SCK(1); //上拉時鐘線,恢復空閑電平
}
/*
函數功能: 清屏 (開全部燈、關全部燈)
*/
static void OLED_Clear(u8 data)
{
u8 i,j;
for(i=0;i<8;i++)
{
OLED_WriteOneByte(0xB0+i,OLED_CMD); //設置頁地址
OLED_WriteOneByte(0x10,OLED_CMD); //設置列高起始地址(半字節)
OLED_WriteOneByte(0x00,OLED_CMD); //設置列低起始地址(半字節)
for(j=0;j<128;j++)
{
OLED_WriteOneByte(data,OLED_DAT); //寫數據
}
}
}
/*
定義顯存數組: 8行,每行128列,與OLED屏幕對應
*/
static u8 OLED_GRAM[8][128];
/*
函數功能: 畫點函數
x: 橫向坐標0~128
y: 縱坐標0~64
c: 1表示亮、0表示滅
*/
static void OLED_DrawPoint(u8 x,u8 y,u8 c)
{
u8 page;
page=y/8; //得到當前點的頁數0/8=0 1/8=0
y=y%8; //得到一列中點的位置。(0~7)
//0%8=0 1%8=1 .....7%8=7 8%8=0 9%8=1 ......
if(c) OLED_GRAM[page][x]|=1vm_flags |= VM_RESERVED;//標志該內存區不能被換出,在設備驅動中虛擬頁和物理頁的關系應該是長期的,應該保留起來,不能隨便被別的虛擬頁換出
if(remap_pfn_range(vma,//虛擬內存區域,即設備地址將要映射到這里
vma->vm_start,//虛擬空間的起始地址
virt_to_phys(mmap_buffer)>>PAGE_SHIFT,//與物理內存對應的頁幀號,物理地址右移 12 位
vma->vm_end - vma->vm_start,//映射區域大小,一般是頁大小的整數倍
vma->vm_page_prot))//保護屬性,
{
return -EAGAIN;
}
printk("(drv)映射的長度:%d\n",vma->vm_end - vma->vm_start);
printk("物理地址:0x%X\n",virt_to_phys(mmap_buffer));
/*
開發板的DDR容量: 1G
0x40000000 ~ 0x80000000
0x10000000=256M
*/
return 0;
}
#define _OLED_RefreshGRAM 0x12345 /*將應用層的數據刷新到OLED屏幕上*/
#define _OLED_ClearGRAM 0x45678 /*將應用層的數據刷新到OLED屏幕上*/
static int lcd_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
{
switch(cmd)
{
case _OLED_RefreshGRAM:
memcpy(OLED_GRAM,mmap_buffer,1024); //拷貝數據
OLED_RefreshGRAM(); /*刷新*/
break;
case _OLED_ClearGRAM: /*清屏*/
OLED_Clear(0);
break;
}
return 0;
}
static int lcd_release(struct fb_info *info, int user)
{
if(mmap_buffer!=NULL)
{
kfree(mmap_buffer);
}
printk("lcd_release調用成功\n");
return 0;
}
/*幀緩沖設備專用的文件操作接口*/
static struct fb_ops fbops=
{
.fb_open=lcd_open,
.fb_release=lcd_release,
.fb_mmap=lcd_mmap,
.fb_ioctl=lcd_ioctl
};
/*幀緩沖的設備結構體*/
static struct fb_info lcd_info=
{
.var= /*可變形參*/
{
.xres=128,
.yres=64,
.bits_per_pixel=1
},
.fix=
{
.smem_len=4096,
.line_length=128
},
.fbops=&fbops
};
static int __init tiny4412_oled_init(void)
{
/*1. 初始化OLED屏幕*/
OLED_Init();
OLED_Clear(0);//清屏為黑色
/*2. 幀緩沖驅動注冊*/
if(register_framebuffer(&lcd_info)!=0)
{
printk("提示: lcd驅動安裝失敗!\n");
return -1;
}
else
{
printk("提示: lcd驅動安裝成功!\n");
}
return 0;
}
static void __exit tiny4412_oled_exit(void)
{
/*1. 幀緩沖驅動注銷*/
if(unregister_framebuffer(&lcd_info)!=0)
{
printk("提示: lcd驅動卸載失敗!\n");
return -1;
}
else
{
printk("提示: lcd驅動卸載成功!\n");
}
/*2. 解除虛擬地址映射關系*/
iounmap(GPB_CON);
iounmap(GPB_DAT);
}
module_init(tiny4412_oled_init); /*指定驅動的入口函數*/
module_exit(tiny4412_oled_exit); /*指定驅動的出口函數*/
MODULE_LICENSE("GPL"); /*指定驅動許可證*/
;>
3.2 app.c 應用層代碼
#include
#include
#include
#include
#include
#include
#include
unsigned char *lcd_mem=NULL; /*LCD的內存地址*/
struct fb_fix_screeninfo finfo; /*固定形參*/
struct fb_var_screeninfo vinfo; /*可變形參*/
unsigned char font[]=
{
/*-- 文字: 國 --*/
/*-- 宋體42; 此字體下對應的點陣為:寬x高=56x56 寬/8*高*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0x00,0x00,0x00,0x07,0x00,0x01,0xFF,0xFF,0xFF,
0xFF,0xFF,0xC0,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x01,0xF0,0x00,0x00,0x00,0x07,
0xC0,0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,
0xF0,0x00,0x00,0x01,0x87,0x80,0x01,0xF0,0x00,0x00,0x03,0xC7,0x80,0x01,0xF7,0xFF,
0xFF,0xFF,0xE7,0x80,0x01,0xF3,0xFF,0xFF,0xFF,0xF7,0x80,0x01,0xF1,0xC0,0x7C,0x00,
0x07,0x80,0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,
0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,
0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,
0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,0x06,0x07,0x80,0x01,0xF0,0x00,0x7C,0x0F,0x07,
0x80,0x01,0xF1,0xFF,0xFF,0xFF,0x87,0x80,0x01,0xF1,0xFF,0xFF,0xFF,0xC7,0x80,0x01,
0xF0,0xF0,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,0x7C,0x00,0x07,0x80,0x01,0xF0,0x00,
0x7F,0xC0,0x07,0x80,0x01,0xF0,0x00,0x7D,0xF0,0x07,0x80,0x01,0xF0,0x00,0x7C,0xFC,
0x07,0x80,0x01,0xF0,0x00,0x7C,0x7E,0x07,0x80,0x01,0xF0,0x00,0x7C,0x3F,0x07,0x80,
0x01,0xF0,0x00,0x7C,0x3F,0x07,0x80,0x01,0xF0,0x00,0x7C,0x1F,0x07,0x80,0x01,0xF0,
0x00,0x7C,0x0F,0x07,0x80,0x01,0xF0,0x00,0x7C,0x0E,0x07,0x80,0x01,0xF0,0x00,0x7C,
0x07,0x87,0x80,0x01,0xF0,0x00,0x7C,0x03,0xC7,0x80,0x01,0xF0,0x00,0x7C,0x07,0xE7,
0x80,0x01,0xFF,0xFF,0xFF,0xFF,0xF7,0x80,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x01,
0xF7,0x80,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,
0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,
0x07,0x80,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,
0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,0x07,0x80,0x01,0xF0,
0x00,0x00,0x00,0x07,0x80,0x01,0xF0,0x00,0x00,0x00,0x07,0x00,0x01,0xC0,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
/*
定義顯存數組: 8行,每行128列,與OLED屏幕對應
*/
static unsigned char OLED_GRAM[8][128];
/*
函數功能: 畫點函數
x: 橫向坐標0~128
y: 縱坐標0~64
c: 1表示亮、0表示滅
*/
static void OLED_DrawPoint(unsigned char x,unsigned char y,unsigned char c)
{
unsigned char page;
page=y/8; //得到當前點的頁數0/8=0 1/8=0
y=y%8; //得到一列中點的位置。(0~7)
//0%8=0 1%8=1 .....7%8=7 8%8=0 9%8=1 ......
if(c) OLED_GRAM[page][x]|=1<;>
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
OLED
+關注
關注
121文章
6367瀏覽量
234115 -
顯示屏
+關注
關注
30文章
4705瀏覽量
79748 -
Linux
+關注
關注
88文章
11790瀏覽量
219385
發布評論請先 登錄
相關推薦
熱點推薦
深入剖析LM3509:高效白光LED與OLED顯示驅動器
深入剖析LM3509:高效白光LED與OLED顯示驅動器 在當今的電子設備中,顯示屏的質量和性能至關重要。無論是智能手機、平板電腦還是其他便攜式設備,都需要高效穩定的LED和
MAX20056B:汽車顯示屏高亮度LED驅動的理想之選
MAX20056B:汽車顯示屏高亮度LED驅動的理想之選 在汽車顯示屏應用中,高亮度LED驅動的性能至關重要。今天我們要介紹的MAX20056B,是一款集成了DC - DC開關升壓/S
使用硬件SPI1輪詢模式來實現驅動OLED顯示屏
此篇介紹使用硬件SPI1輪詢模式來實現驅動OLED顯示屏硬件連接
GND ——GND
VCC ——3.3V
DO——PA5
DI——PA7
RES ——PB1
DC——PB0
CS——PA4
軟件
發表于 01-27 12:36
【免費送書】成為硬核Linux開發者:《Linux 設備驅動開發(第 2 版)》
Linux系統的設備驅動開發,一直給人門檻較高的印象,主要因內核機制抽象、需深度理解硬件原理、開發調試難度大所致。2021年,一本講解驅動
蜂鳥E203驅動OLED顯示
利用GPIO模擬IIC驅動4pin的OLED顯示字符,開發平臺為芯來官方IDE。
不想寫過程,上傳整個工程文件,主要代碼如下:
下載:led
發表于 10-31 06:08
力芯微矩陣型恒壓LED驅動芯片為車載顯示屏帶來“智”變
在汽車智能化飛速發展的今天,車載顯示屏作為人車交互的重要窗口,其顯示效果和性能直接影響到用戶的駕駛體驗和行車安全。力芯微矩陣型恒壓LED驅動芯片,憑借其卓越的性能和創新的技術,為車載顯示屏
【RA4M2-SENSOR】+OLED屏顯示驅動
RA4M2-SENSOR開發板是一款近于最小系統的開發板,通過添加相應的外設,可豐富其功能。
這里就為它配置一個I2C接口的OLED屏,驅動
發表于 09-02 18:28
【Milk-V Duo S 開發板免費體驗】DuoS 超聲波測距 OLED 顯示
上篇搭建開發環境并點亮了 OLED 顯示屏,詳見:
https://bbs.elecfans.com/jishu_2498771_1_1.html
本篇使用 DuoS 驅動超聲
發表于 08-22 03:55
【RA-Eco-RA6M4開發板評測】+OLED屏顯示驅動
SDIN------P209
在使用I2C進行硬件驅動前,先以模擬的方式來驅動該顯示屏。
在程序設計前,需使用RASC對所用引腳加以配置,以是其作為GPIO口來使用。
然后,在回到KEIL中進
發表于 07-23 17:33
液晶顯示屏背光驅動設計的核心要點
在液晶顯示屏的世界里,無論是信息清晰的單色屏還是色彩絢麗的彩色屏,背光都是其視覺呈現的靈魂。然而,背光驅動絕非簡單的“通電即亮”。忽視設計細節,輕則導致亮度不均、用戶體驗打折,重則縮短
冠顯光電0.6"HDMI 單目驅動板方案,加速微顯示方案落地
該方案主要包括0.6”硅基顯示屏,HDMI單目顯示屏驅動板。驅動板以 Micro HDMI 接口為視頻數據傳輸接口,可用于 TDO 硅基產品的 demo 展示、產品特性評估以及基于該
基于Linux的液晶顯示屏驅動技術的研究與應用
液 晶 屏在我們 日 常 的 生產和 生活 中 應用 廣泛 。 本文所描述 的液 晶 屏 的驅動 與 應用 是基于 電解鋁廠 中 實 際 的 生產 需 要設計而成 , 并且可將其移植到其它 相關 系 統 。?
發表于 05-06 16:22
?0次下載
Linux驅動開發-編寫OLED顯示屏驅動
評論