精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux驅動開發-編寫OLED顯示屏驅動

DS小龍哥-嵌入式技術 ? 2022-09-17 15:19 ? 次閱讀

【摘要】 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. 硬件接線效果


image-20220104161740431image-20220104161800291image-20220104161852986image-20220104161906616

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
    +關注

    關注

    119

    文章

    6183

    瀏覽量

    223861
  • 顯示屏
    +關注

    關注

    28

    文章

    4462

    瀏覽量

    74141
  • Linux
    +關注

    關注

    87

    文章

    11232

    瀏覽量

    208961
收藏 人收藏

    評論

    相關推薦

    oled是什么顯示屏 OLED與LCD的區別

    OLED是什么顯示屏 OLED(Organic Light-Emitting Diode),即有機發光二極管,是一種電流型的有機發光器件。其工作原理是通過載流子的注入和復合而致發光,發光強度與注入
    的頭像 發表于 10-21 16:40 ?879次閱讀

    oled顯示屏的優缺點有哪些

    OLED(有機發光二極管)顯示屏作為一種先進的顯示技術,近年來在電子產品領域得到了廣泛的應用。其獨特的發光原理和構造使其具有一系列顯著的優點,但同時也存在一些不容忽視的缺點。以下是對OLED
    的頭像 發表于 10-21 16:37 ?762次閱讀

    LED顯示屏驅動電源:恒流與恒壓,誰更勝一籌?

    。然而,在這背后,有一個不可或缺的元素在默默支撐著這一切——那就是LED顯示屏驅動電源。 LED顯示屏驅動電源,主要分為恒壓驅動和恒流
    的頭像 發表于 09-24 01:50 ?317次閱讀
    LED<b class='flag-5'>顯示屏</b><b class='flag-5'>驅動</b>電源:恒流與恒壓,誰更勝一籌?

    linux驅動程序如何加載進內核

    Linux系統中,驅動程序是內核與硬件設備之間的橋梁。它們允許內核與硬件設備進行通信,從而實現對硬件設備的控制和管理。 驅動程序的編寫 驅動
    的頭像 發表于 08-30 15:02 ?388次閱讀

    Linux 驅動開發與應用開發,你知道多少?

    一、Linux驅動開發與應用開發的區別開發層次不同:Linux
    的頭像 發表于 08-30 12:16 ?632次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>驅動</b><b class='flag-5'>開發</b>與應用<b class='flag-5'>開發</b>,你知道多少?

    【xG24 Matter開發套件試用體驗】物聯網密碼柜之驅動矩陣鍵盤和OLED顯示

    +circuitpython進行開發,矩陣鍵盤驅動為自行編寫Oled驅動基于Adafruit SSD_1306庫。 到本階段為止已實現的功
    發表于 08-04 23:04

    OLED柔性顯示屏的金線封裝膠

    OLED柔性顯示屏的金線封裝膠是確保柔性顯示屏中金線連接穩定、防止外界環境侵害的關鍵材料。OLED柔性顯示屏在使用金線進行連接時,需要一種能
    的頭像 發表于 07-12 09:46 ?588次閱讀
    <b class='flag-5'>OLED</b>柔性<b class='flag-5'>顯示屏</b>的金線封裝膠

    LED顯示屏中什么是靜態驅動?什么是掃描驅動?兩者的區別是什么?

    LED顯示屏技術的不斷進步,不僅提升了我們的視覺體驗,也為廣告、娛樂、教育等多個領域帶來了革命性的變化。無論是靜態驅動的精準呈現,還是動態掃描驅動的高效表現,都體現了LED技術的無限可能。未來,隨著
    的頭像 發表于 06-25 17:25 ?493次閱讀

    LED顯示屏設計方案

    1、LED顯示屏基礎知識2、LED顯示屏設計要素3、LED顯示屏驅動方案4、LED顯示屏控制系統5、LED
    發表于 04-03 17:21 ?9次下載

    OLED透明與雙面顯示屏結合會有怎樣的效果呢

    OLED透明與雙面顯示屏的結合,無疑為顯示技術領域帶來了全新的可能性。這種結合不僅將拓寬顯示技術的應用領域,更將改變我們與數字信息的交互方
    的頭像 發表于 04-03 14:31 ?460次閱讀

    0.96寸 OLED 顯示屏使用手冊

    電子發燒友網站提供《0.96寸 OLED 顯示屏使用手冊.pdf》資料免費下載
    發表于 03-19 11:02 ?28次下載

    新款iPad Pro采用OLED顯示屏及三星顯示驅動IC

    網站消息指出,11英寸及12.9英寸iPad Pro新品的獨家顯示驅動IC (DDI) 供應商將定為三星System LSI。此外,配備LG顯示OLED
    的頭像 發表于 03-18 15:56 ?666次閱讀

    stm32f407vet6驅動0.96寸oled顯示屏無法顯示怎么解決?

    stm32f407vet6驅動0.96寸oled——iic協議代碼無報錯時鐘正確顯示屏無法顯示
    發表于 03-14 06:49

    LED顯示屏模組邏輯驅動芯片:SM245的功能和應用

    LED顯示屏模組邏輯驅動芯片是LED顯示屏中的重要部件,它負責控制LED燈珠的亮度和顏色,從而實現圖像和視頻的顯示。隨著LED顯示屏應用范圍
    的頭像 發表于 02-25 10:37 ?1055次閱讀
    LED<b class='flag-5'>顯示屏</b>模組邏輯<b class='flag-5'>驅動</b>芯片:SM245的功能和應用

    LCD顯示屏、LED顯示屏OLED顯示屏有什么區別?

    LCD顯示屏、LED顯示屏OLED顯示屏有什么區別? LCD顯示屏、LED顯示屏
    的頭像 發表于 12-11 14:29 ?1.7w次閱讀