• FPGA之旅设计99例之第九例-----驱动0.96寸OLED屏


    一. 简介

    这是FPGA之旅设计的第九例啦!!!本例将介绍如何使用FPGA驱动OLED屏幕,并在接下来的几例中,配合其它模块,进行一些有趣的综合实验。由于使用的OLED屏是IIC接口的,对IIC接口不是很清楚的,可以参考第五例的设计,同时使用第五例写好的IIC模块,驱动OLED屏。Let’s do it!

    二. 0.96寸OLED屏介绍

    这里就只介绍最常用的0.96寸屏,其它的一样。OLED共支持8080并口、SPI和IIC三种接口,同样也只介绍IIC接口的用法。0.96寸OLED屏幕的分辨率为128×64,内部有一块GRAM用来存储显示的数据。

    (一).OLED的存储区域

    这块存储区域分为8个page,每个page下面共有128bit,如下图所示

    在这里插入图片描述

    这就难免会有些疑问了,128×8,不应该是128×64嘛? 8个page,为什么是64行呢?数据写入的呢?

    每一个page包括8行,所以说8个page共有64行。IIC每次发送数据的时候,是发送一个byte的,也就是8bit,这8bit数据会存储到某一列的八行中,例如图中SEG0区域,是第一列的头八行。这样GRAM的存储区域就弄懂了。

    (二).OLED的数据存储模式

    当我们向OLED的GRAM发送显示数据的过程中,OLED内部共有三种处理模式。

    模式一: 当我们指定了一个page和某一列的时候,每写一个数据,列会自动加一,当写到page的最后一列的时候,列数,会自动跳转到第零列,需要手动的切换page。

    在这里插入图片描述

    模式二:与模式一不同的时候,当写达到page的最后一列的时候,列数跳转到第零列的同时,page数也会加一。

    在这里插入图片描述

    模式三: 与前两个模式不同,模式三,是一列一列的写,每写完一个数据,page数加一,当加到最后一个page的时候,列数加一,page跳转到第一个page。

    在这里插入图片描述

    在实际的使用中,具体使用那一种模式,可以根据自己的子模软件或者项目来,怎么方便怎么来!

    了解了上面两个部分后,基本就可以编写驱动程序啦,不要问为什么,(#.#),初始化OLED就是配置一些列命令的过程,而这些寄存器和配置的值一般都是copy现成的。然后了解一下关键的一两个命令就可以啦。想要深入的了解OLED的功能的话,可以阅读对应的芯片手册哦!在后面的例程中也会介绍部分功能强大的命令。

    三. OLED关键命令介绍

    • 0xAE/0xAF: 对应着开启OLED显示和关闭OLED显示
    • 0x20-0x22: 对应着上面的三种OLED数据存储模式,默认为0x22,模式一
    • 0x00-0x0F: 设置列地址的低四位,默认为0x00,
    • 0x10-0x1F: 设置列地址的高四位,默认为0x10,
    • 0xB0-0xB7: 设置page,第四位表示page。

    暂时差不多只需要了解上面的这些寄存器。

    四. IIC驱动OLED数据格式

    驱动OLED分为写数据和写命令(读暂时不考虑)。写命令就是配置的过程,写数据就是写入GRAM中进行显示的过程。

    IIC数据格式 :OLED地址 + 命令 / 数据 + 值。

    OLED地址,就是IIC协议中的从机地址,我这里是0x78。

    命令/数据中,0x00表示接下来的值代表命令,0x40表示接下的值表示数据,存入GRMA。

    ,具体的命令或者数据

    也就是说每一次IIC需要传输24bit,3个字节的数据,和第五例的IIC模块完美对应,那事情就好办啦!

    五. OLED初始化

    直接copy某例程提供的配置参数,共需要配置26个命令,第一个是上面介绍的0xAE命令,关闭OLED显示。最后一个也是介绍的0xAF命令,开启OLED显示,没有配置模式,直接使用的默认的模式一,配置完成后,可以看到OLED屏被点亮,内容是杂乱的。

    always@(*)
    begin
    	case(Init_index)
            'd0:		Init_data_reg <= {8'h78,8'h00,8'hAE};  //OLED地址 + 命令  +  值。**
    		'd1:		Init_data_reg <= {8'h78,8'h00,8'h00};
    		'd2:		Init_data_reg <= {8'h78,8'h00,8'h10};
    		'd3:		Init_data_reg <= {8'h78,8'h00,8'h40};
    		'd4:		Init_data_reg <= {8'h78,8'h00,8'hB0};
    		'd5:		Init_data_reg <= {8'h78,8'h00,8'h81};
    		'd6:		Init_data_reg <= {8'h78,8'h00,8'hFF};
    		'd7:		Init_data_reg <= {8'h78,8'h00,8'hA1};
    		'd8:		Init_data_reg <= {8'h78,8'h00,8'hA6};
    		'd9:		Init_data_reg <= {8'h78,8'h00,8'hA8};
    		'd10:		Init_data_reg <= {8'h78,8'h00,8'h3F};
    		'd11:		Init_data_reg <= {8'h78,8'h00,8'hC8};
    		'd12:		Init_data_reg <= {8'h78,8'h00,8'hD3};
    		'd13:		Init_data_reg <= {8'h78,8'h00,8'h00};
    		'd14:		Init_data_reg <= {8'h78,8'h00,8'hD5};
    		'd15:		Init_data_reg <= {8'h78,8'h00,8'h80};
    		'd16:		Init_data_reg <= {8'h78,8'h00,8'hD8};
    		'd17:		Init_data_reg <= {8'h78,8'h00,8'h05};
    		'd18:		Init_data_reg <= {8'h78,8'h00,8'hD9};
    		'd19:		Init_data_reg <= {8'h78,8'h00,8'hF1};
    		'd20:		Init_data_reg <= {8'h78,8'h00,8'hDA};
    		'd21:		Init_data_reg <= {8'h78,8'h00,8'h12};
    		'd22:		Init_data_reg <= {8'h78,8'h00,8'hDB};
    		'd23:		Init_data_reg <= {8'h78,8'h00,8'h30};
    		'd24:		Init_data_reg <= {8'h78,8'h00,8'h8D};
    		'd25:		Init_data_reg <= {8'h78,8'h00,8'h14};
    		'd26:		Init_data_reg <= {8'h78,8'h00,8'hAF};
    		default:
    			Init_data_reg <= {8'h78,8'h00,8'hAE};
    		endcase
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    六. 向GRAM中写入数据

    初始化后,就可以显示内容啦,仅仅只需要配置page和起始列三个命令,然后写入数据即可,配置页和列地址,只有在模式一有效,也就是上电默认的模式

    这样就可以显示数据啦,亲测可用哦!

    'd0:show_data_reg <= {8'h78,8'h00,8'hb0 + show_pag};        //配置页
    'd1:show_data_reg <= {8'h78,8'h00,8'h00 +start_x[3:0]};     //配置列的低四位
    'd2:show_data_reg <= {8'h78,8'h00,8'h10 + start_x[6:4]};    //配置列的高四位,128列只需要配置高三位即可。
    'd3:show_data_reg <= {8'h78,8'h40, data};  					//向配置的地址中,写入显示的数据
    
    • 1
    • 2
    • 3
    • 4

    其实驱动OLED也没有那么复杂嘛。

    七. 上板验证

    先来编写个简单的模块,用来初始化OLED。下载程序后,我的OLED是亮起来了,你的呢!

    //OLED顶层模块
    module OLED_Top(
    
    	input			sys_clk,
    	input			rst_n,
    
    	//OLED IIC
    	output		OLED_SCL,
    	inout			OLED_SDA
    );
    localparam	OLED_INIT = 'd0;			//初始化
    localparam	OLED_IDLE = 'd1;			//空闲
    reg[4:0]	state , next_state;
    wire			init_finish;
    wire[23:0]  Init_data;
    wire 			init_req;
    wire			IICWriteDone;
    assign init_req = (state == OLED_INIT) ? 1'b1 : 1'b0;
    always@(posedge sys_clk or negedge rst_n)
    begin
    	if(rst_n == 1'b0)
    		state <= OLED_INIT;
    	else
    		state <= next_state;
    end
    always@(*)
    begin
    	case(state)
    	OLED_INIT:
    		if(init_finish == 1'b1)
    			next_state <= OLED_IDLE;
    		else
    			next_state <= OLED_INIT;
    	OLED_IDLE:
    		next_state <= OLED_IDLE;
    	default: next_state <= OLED_INIT;
    	endcase
    end
    OLED_Init OLED_Init(
    	
    	.sys_clk				(sys_clk),
    	.rst_n				(rst_n),
    	
    	.init_req			(init_req),				//初始化请求
    	.write_done			(IICWriteDone),			//一组初始化数据完成信号
    	
    	.init_finish		(init_finish),			//初始化完成输出
    
    	.Init_data			(Init_data)//初始化的数据
    );
    IIC_Driver IIC_DriverHP_OLED(
       .sys_clk				(sys_clk),           /*系统时钟*/
       .rst_n				(rst_n),             /*系统复位*/
    
        .IICSCL				(OLED_SCL),            /*IIC 时钟输出*/
        .IICSDA				(OLED_SDA),             /*IIC 数据线*/
    
    
        .IICSlave			({Init_data[15:8],Init_data[23:16]}),           /*从机 8bit的寄存器地址 + 8bit的从机地址*/
    
        .IICWriteReq		(init_req),       /*IIC写寄存器请求*/
        .IICWriteDone		(IICWriteDone),      /*IIC写寄存器完成*/
        .IICWriteData		(Init_data[7:0]),       /*IIC发送数据  8bit的数据*/
    
        .IICReadReq			(1'b0),        /*IIC读寄存器请求*/
        .IICReadDone			(),       /*IIC读寄存器完成*/
        .IICReadData    		()    /*IIC读取数据*/
    );
    endmodule 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    FPGA驱动OLED就结束啦!

    gzh回复 FPGA之旅设计99例之第九例 获取工程文件

  • 相关阅读:
    Rocky Linux 9 安装 Gitelab-ee(15.6.0-ee)
    Android studio的Bumblebee版本Gradle7.2降到Gradle4.2.0详细步骤记录(项目已上传)
    【Windows无法修复问题】“启动修复”无法修复你的电脑解决方法
    国家强制性灯具安全标准GB7000.1-2015
    使用randn实现randm的通用方法
    移动端表格分页uni-app
    sudo+vim+g++/gcc+makefile+进度条
    群晖(Synology)NAS 后台安装 Docker 后配置 Activemq Artemis
    多线程详解(三)
    【gcc】RtpTransportControllerSend学习笔记 1
  • 原文地址:https://blog.csdn.net/weixin_44678052/article/details/126675726