跳转至

本次使用开发环境:

软件:Quartus II 64-Bit

开发板及芯片型号:至芯--EP4CE6E22C8N 1.2V

协议核心概述

  1. 物理层特性
  2. 双线制:仅需SCL(时钟线)和SDA(数据线)两根线,均需外接上拉电阻,空闲时保持高电平
  3. 多主多从:支持多个主机和从机,通过设备地址(通常7位)区分不同外设,地址后接1位读写标志位(0写/1读)
  4. 半双工通信:数据线SDA同一时刻只能单向传输,由主机控制时序
  5. 关键时序状态
  6. 起始条件(Start):SCL高电平时,SDA由高→低跳变,标志通信开始
  7. 停止条件(Stop):SCL高电平时,SDA由低→高跳变,标志通信结束
  8. 数据传输:SCL低电平时更新SDA数据,SCL高电平时保持稳定,数据按高位优先传输
  9. 应答机制(ACK/NACK):每传输8位数据后,接收方在第9个SCL周期拉低SDA(ACK)或保持高电平(NACK)

  10. 状态机驱动

  11. 通过状态机划分IIC操作阶段,典型状态包括:

    空闲态(IDLE)、起始态(START)、写数据(WR_DATA)、读数据(RD_DATA)、应答(ACK)、停止态(STOP)

  12. 示例状态机跳转逻辑:

    Verilogcase(state) IDLE: 检测到读写请求→跳转START; START: 生成起始信号→跳转WR_DATA; WR_DATA: 发送8位数据→跳转ACK; ACK: 检测应答→根据操作类型跳转STOP或继续传输; STOP: 结束通信→返回IDLE; endcase

  13. 时钟分频与时序控制

  14. 将FPGA系统时钟(如50MHz)分频至IIC速率(如100kHz或400kHz),需计算分频参数(例如50MHz/100kHz=500分频)

  15. 在SCL低电平中点(如分频计数器的65/250位置)更新SDA数据,确保时序稳定

  16. 数据收发逻辑及数据帧结构

  • 写操作:主机依次发送设备地址(+写标志)、寄存器地址、数据,每字节后检测ACK
  • 读操作:主机发送设备地址(+写标志)→寄存器地址→重新发送起始信号→设备地址(+读标志)→接收数据并发送ACK/NACK

1. 基础知识

1. I2C(IIC)通讯协议

I2C通讯协议(Inter - Intergrated Circuit)是由Philips公司开发的一种简单、双向二线同步串行总线,只需要两根先就可以在连接于总线上的器件之间传送信息。

I2C通讯协议和通信接口在很多工程中与广泛的应用,如数据采集领域的串行AD,图像处理领域的摄像头配置,工业控制领域的X射线管配置等等。除此之外,由于I2C协议占用的引脚特别少,硬件实现简单,可扩展性强,现在被广泛使用在系统内多个集成电路(IC)间的通讯。同时也通常用于连接低速设备,如传感器、存储器和其他外设。它使用两根线(SCL和SDA)来实现双向通信,具有地址定向性和主从模式。

优点:

  • 多设备支持:I2C支持多个设备连接到同一总线上,每个设备都有唯一的地址。
  • 简单:I2C协议相对简单,易于实现和调试。
  • 低功耗:在空闲状态时,显示高阻态,I2C总线上的器件可以进入低功耗模式,节省能量。(空闲状态下,IIC设备端口处于高阻态,所以IIC总线空闲时刻也就是高电平
  • 仲裁:总线上可以连接多个从机,也可以连接多个主机,当多个主机同时使用总线时,为了防止数据发生冲突,会使用仲裁的方式来决定哪个设备使用总线
  • 速度:IIC具有3个传输模式,在标准模式下,传输速度为100kb/s。在快速模式下,速度为400kb/s。最后是高速模式,速度可以达到3.4MB/s。当前的大多数IIC设备仅支持标准模式和快速模式。

缺点:

  • 速度较慢:I2C通信速度较低,适用于低速设备。
  • 受限制:I2C的总线长度和设备数量受到限制,过长的总线可能导致通信问题。
  • 冲突:当多个设备尝试同时发送数据时,可能会发生冲突,需要额外的冲突检测和处理机制。

应用案例:

就其应用而言,连接方面,I2C在需要简单且经济的通信环境中表现出色。它尤其擅长在小型传感器、LCD 屏幕和 RTC(实时时钟)模块中使用。此外,I2C 由于其在紧凑电路中的效率,在温度控制设备、电池管理系统和 LED 控制器中很有用。但是,在需要快速或长距离数据传输的项目中,最好选择其他协议。

读写等详细的通信过程可参考下文:

老宇哥带你玩转 ESP32:07 I2C协议,看这一篇就够了 (点击阅读)

### 2. I2C物理层

I2C_SCL:串行时钟线,用于同步通讯数据;

I2C_SDA: 双向串行数据线,传输通讯数据;

3. I2C协议层

在这个示意图中,包含4个状态:

1: 总线空闲状态

2: 起始信号

3: 数据读写状态

4: 停止信号

在SCL为高电平的时候,进行数据的写入,低电平的时候,进行数据的更新。

当我们的从机设备正确接受到我们发送的信号的时候,会把SDA数据线拉低,称为响应位,表示向主机发送一个单比特的应答信号。

关于器件的地址的内容

器件地址被定义为7Bit的数据,器件厂商在出厂的时候就将地址设置好了,用户不能进行自己更改,但是有的厂商如上图所示,其中高4位是固定的,但是后3位没有被写入,这样的情况是允许用户自行设置的。

可以在这里看到,根据上面的两行图像,可以确定这个芯片的I2C地址为10100_000,因为A0、A1、A2都是低电平。

最后一位为读写控制位,0表示写入,1表示读取。

举例:如果要让这个芯片处于读取状态,使用I2C协议的地址则为:10100_000_1

4. 数据传输流程

I²C协议中判断数据接收设备的基本步骤:

  1. 地址分配:每个连接到I²C总线的设备都有一个唯一的地址。这个地址在设备制造时被设定,并且通常通过硬件方式设置。
  2. 开始条件:在数据传输开始之前,主机设备会发送一个开始条件,这通常涉及到SDA(数据线)和SCL(时钟线)的特定电平变化。
  3. 发送地址:主机设备随后会在SDA线上发送目标设备的7位地址,加上一个额外的读/写位(R/W位)。这个位指示了接下来的操作是读取(1)还是写入(0)。
  4. 确认应答:当地址和R/W位被发送后,目标设备需要在下一个时钟脉冲的开始时将SDA线拉低,以表示它已经接收到了地址并且准备好进行通信。这个过程称为应答(ACK)。
  5. 数据传输:一旦接收到应答,主机设备就会开始发送数据。如果是写入操作,主机发送数据;如果是读取操作,从设备发送数据。
  6. 非应答(NACK):如果目标设备不是预期的接收者,或者由于其他原因无法接收数据,它会在下一个时钟脉冲的开始时不拉低SDA线,表示非应答。
  7. 停止条件:数据传输完成后,主机设备会发送一个停止条件,这涉及到SDA和SCL线的特定电平变化,以结束数据传输。
  8. 多主机环境:在多主机环境中,如果有多个主机尝试同时控制总线,它们会使用仲裁机制来决定哪个主机获得控制权。仲裁是基于发送的数据位,如果两个主机尝试发送不同的位,发送0的主机会放弃控制权。

2. IIC驱动7Pin 0.96寸 OLED显示屏实例

1. 硬件修改

在驱动显示屏时,显示屏默认使用SPI协议驱动,要改为IIC协议驱动需要将硬件电路进行简单的修改,具体就是:

  1. 将背面R3电阻移动到R4的 位置

  2. 短接R8电阻

改造好之后,不能象原生的IIC屏幕那样接4根线即可,必须将7个管脚都要接线,否则可能没有任何显示。管脚处理:

1、CS 脚接地。

2、DC 脚的处理:在 IIC 通信中 DC 的高低电平是用来选择 IIC 通信地址的;当 DC 接地时 IIC从机地址为:0x78,当 DC 接高电平时 IIC 地址为 0x7A;测试程序中所用的为 0x78; 通常直接将 DC 接地

3、关于 RES 的处理。RES 这个脚是 OLED 屏的复位脚;大家在用 OLED 屏的时候会发现;所

有 OLED 本身都会有一个复位脚;因为 OLED 在被操作之前需要在将寄存作一次复位;然后才能对期进行初始货操作;否则 OLED 可能会出现水稳定的情况。RES 处理方案:  

1> 简单的验证办法:将RES接电源正;这样可以把屏点亮;但是会不稳定,在快速测试时可以这么操作

2> 将RES脚与开发板的复位脚连接;通过开发板的复位来对OLED进行复位

3> 通过一个IO脚来对OLED进行复位,这个操作放在对屏初始化之前;先将RES拉低延迟 200ms 左右;然后再拉高一直处于高电平状态

4> 通过一个RC复位电路来控制RES

4、D0 为 IIC 时钟线或者SCK为时钟线,

5、D1 为 IIC 数据线或者SDA为数据线;

6、GND 为接地线,

7、VDD 为电源线;

2.OLED上的驱动部分:

OLED屏幕有三种刷新方式分别为页地址模式, 水平地址模式和垂直地址模式,。 水平地址模式和垂直地址模式可以在一页(一列)写完后自动换页(列) 所以在水平地址寻址或者垂直地址寻址模式下,只要源源不断的发送数据即可

页地址模式

水平地址模式

垂直地址模式

3. OLED关键命令介绍

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

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

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

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

,具体的命令或者数据

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

3. IIC驱动4Pin OLED显示器显示DHT11温湿度数据

3.1 字模设计

3.2 程序设计

```verilog main.v

module main(

input           sys_clk,
input           rst_n,

inout           dht11,

output      OLED_SCL,
inout           OLED_SDA

);

wire dht11_done; reg dht11_req; wire[7:0] tempH; wire[7:0] tempL;
wire[7:0] humidityH; wire[7:0] humidityL;

localparam S_DELAY = 'd55_000_000; reg[35:0] delay;

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) delay <= 'd0; else if(dht11_done == 1'b1) delay <= 'd0; else if(delay == S_DELAY) delay <= delay; else delay <= delay + 1'b1; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0)
dht11_req <= 1'b0; else if(delay == S_DELAY) dht11_req <= 1'b1; else dht11_req <= 1'b0;

end

DHT11 DHT11HP(

.sys_clk            (sys_clk),
.rst_n          (rst_n),

.dht11_req      (dht11_req),   //dht11数据采集请求
.dht11_done     (dht11_done),    //dht11数据采集结束
.dht11_error    (), //dht11数据采集正确与否判断   1为错误

.tempH          (tempH),            //温度数据整数
.tempL          (tempL),            //温度数据小数
.humidityH      (humidityH),        //温度数据整数
.humidityL      (humidityL),        //温度数据小数


.dht11          (dht11)

);

OLED_Top OLED_TopHP(

.sys_clk        (sys_clk),
.rst_n      (rst_n),

.dht11_done     (dht11_done),
.tempH          (tempH),            //温度数据整数
.tempL          (tempL),            //温度数据小数
.humidityH      (humidityH),        //温度数据整数
.humidityL      (humidityL),        //温度数据小数

//OLED IIC
.OLED_SCL   (OLED_SCL),
.OLED_SDA   (OLED_SDA)

);

endmodule




```verilog iic.v
`timescale 1ns/1ps


module  IIC_Driver(
    input       sys_clk,           /*系统时钟*/
    input       rst_n,             /*系统复位*/

    output      IICSCL,            /*IIC 时钟输出*/
    inout       IICSDA,             /*IIC 数据线*/


    input[15:0] IICSlave,           /*从机 8bit的寄存器地址 + 8bit的从机地址*/

    input       IICWriteReq,       /*IIC写寄存器请求*/
    output      IICWriteDone,      /*IIC写寄存器完成*/
    input[7:0]  IICWriteData,       /*IIC发送数据  8bit的数据*/

    input       IICReadReq,        /*IIC读寄存器请求*/
    output      IICReadDone,       /*IIC读寄存器完成*/
    output[7:0] IICReadData        /*IIC读取数据*/
);


/*IIC 状态*/
localparam IIC_IDLE       =   6'b000_001;  /*空闲态*/
localparam IIC_START      =   6'b000_010;  /*起始态*/
localparam IIC_WRDATA     =   6'b000_100;  /*写数据态*/
localparam IIC_RDDATA     =   6'b001_000;  /*读数据态*/
localparam IIC_ACK        =   6'b010_000;  /*应答态*/
localparam IIC_STOP       =   6'b100_000;  /*停止态*/



localparam  IIC_Pre       =   'd100;     /*iiC分频*/

reg[5:0]   state , next_state;
reg[21:0]  IICCnt;              /*IIC计数器*/
reg[3:0]   IICBitCnt;           /*IIC数据发送个数计数*/
reg[1:0]   IICACKStopCnt;       /*IIC ack stop应答计数*/
reg[2:0]   IICSendBytes;        /*IIC 发送字节计数*/ 


reg[15:0]   IICSlaveReg;           /*从机地址+寄存器数据*/
reg[7:0]   IICReadDataReg;         /*读取到的数据*/


reg     IICWriteReqReg;

reg   iictx;     /*iic发送数据引脚*/
reg   iicCLK;    /*iic时钟信号引脚*/

assign IICSDA = (state == IIC_RDDATA || (state == IIC_ACK)) ? 1'bz : iictx;  /*iic为读数据或者应答的时候,输出为高阻态*/
assign IICSCL =  iicCLK;

assign IICReadData = IICReadDataReg;

assign IICReadDone  = (state != next_state && state == IIC_STOP) ? 1'b1 : 1'b0;
assign IICWriteDone = (state != next_state && state == IIC_STOP) ? 1'b1 : 1'b0;



always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICWriteReqReg <= 1'b0;
    else if(IICWriteDone == 1'b1)
        IICWriteReqReg <= 1'b0;
    else if(IICWriteReq == 1'b1)
       IICWriteReqReg <= 1'b1;
    else
        IICWriteReqReg <= IICWriteReqReg;

end

always @(posedge sys_clk or negedge rst_n) 
begin
    if(rst_n == 1'b0)
        state <= IIC_IDLE;
    else
        state <= next_state;   
end

/*状态机*/
always @(*)
begin
    case(state)
    IIC_IDLE: 
        if(IICWriteReq == 1'b1 || IICReadReq == 1'b1)
            next_state <= IIC_START;
        else
            next_state <= IIC_IDLE;
    IIC_START:
        if(IICCnt == (IIC_Pre * 'd2))
            next_state <= IIC_WRDATA;
        else
            next_state <= IIC_START;
    IIC_WRDATA:
        if(IICBitCnt == 'd8 /*&& IICCnt == IIC_Pre /4 */&& iicCLK == 1'b0)
            next_state <= IIC_ACK;
        else
            next_state <= IIC_WRDATA;
    IIC_RDDATA:
        if(IICBitCnt == 'd8 && IICCnt == IIC_Pre /4 && iicCLK == 1'b0)
            next_state <= IIC_ACK;
        else
            next_state <= IIC_RDDATA;
    IIC_ACK:
        if(IICACKStopCnt == 'd1 /*&& IICCnt == IIC_Pre /4 */&& iicCLK == 1'b0)
            if(IICSendBytes == 'd2) 
                if(/*IICWriteReq*/IICWriteReqReg == 1'b1)             /*三个字节发送完成,进入停止态*/
                    next_state <= IIC_STOP;
                else 
                    next_state <= IIC_RDDATA;
            else if(IICSendBytes == 'd2 && IICReadReq == 1'b1)
                next_state <= IIC_START;
            else if(IICSendBytes == 'd4)
                next_state <= IIC_STOP;
            else
                next_state <= IIC_WRDATA;
        else
            next_state <= IIC_ACK;
    IIC_STOP:
        if(IICACKStopCnt == 'd1 && IICCnt == IIC_Pre/4 && iicCLK == 1'b1)
            next_state <= IIC_IDLE;
        else
            next_state <= IIC_STOP;
    default:  next_state <= IIC_IDLE;
    endcase
end



/*IIC 发送字节计数*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICSendBytes <= 'd0;
    else if(state == IIC_IDLE)
        IICSendBytes <= 'd0;
    else if(state == IIC_ACK)
        if(next_state != state)
            IICSendBytes <= IICSendBytes + 1'b1;
        else
            IICSendBytes <= IICSendBytes;
    else
        IICSendBytes <= IICSendBytes;

end

/*IIC分频计数*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICCnt <= 'd0;
    else if(IICCnt == IIC_Pre && state != IIC_START)
        IICCnt <= 'd0;
    else if(IICCnt == (IIC_Pre *'d2) && state != IIC_START)
        IICCnt <= 'd0;
    else if(state != next_state)
        IICCnt <= 'd0;
    else if(state == IIC_START)
        IICCnt <= IICCnt + 1'b1;
    else if(state == IIC_WRDATA )
        IICCnt <= IICCnt + 1'b1;
    else if(state == IIC_RDDATA)
        IICCnt <= IICCnt + 1'b1;
    else if(state == IIC_ACK)
        IICCnt <= IICCnt + 1'b1;
    else if(state == IIC_STOP)
        IICCnt <= IICCnt + 1'b1;
end

/*IIC发送bit计数*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICBitCnt <= 'd0;
    else if(state == IIC_IDLE || state == IIC_ACK)
        IICBitCnt <= 'd0;
    else if(state == IIC_WRDATA && IICCnt == (IIC_Pre /2))
        if(iicCLK == 1'b1)
            IICBitCnt <= IICBitCnt + 1'b1;
        else
            IICBitCnt <= IICBitCnt;
    else if(state == IIC_RDDATA && IICCnt == (IIC_Pre /2))
        if(iicCLK == 1'b1)
            IICBitCnt <= IICBitCnt + 1'b1;
        else
            IICBitCnt <= IICBitCnt;
    else
        IICBitCnt <= IICBitCnt;
end


/*IIC ack stop应答计数*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICACKStopCnt <= 'd0;
    else if(state != next_state)
        IICACKStopCnt <= 'd0;
    else if((state == IIC_ACK || state == IIC_STOP) && IICCnt == (IIC_Pre /2))
        if(iicCLK == 1'b1)
            IICACKStopCnt <= IICACKStopCnt + 1'b1;
        else
            IICACKStopCnt <= IICACKStopCnt;
    else if(state == IIC_ACK || state == IIC_STOP)
        IICACKStopCnt <= IICACKStopCnt;
    else
        IICACKStopCnt <= 'd0;
end

/*IIC从机信息控制*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICSlaveReg <= 'd0;
    else if((IICWriteReq == 1'b1 || IICReadReq == 1'b1) && state == IIC_IDLE)  /*请求来时,保存信息*/
        IICSlaveReg <= IICSlave;
    else if(state == IIC_ACK && state != next_state)   /*每发送完成一字节,就调换数据,始终发送的是低8位*/
        if(IICSendBytes == 'd2)
            IICSlaveReg <= {IICSlaveReg[7:0],IICSlaveReg[15:8]} + 1'b1;
        else
            IICSlaveReg <= {IICSlaveReg[7:0],IICSlaveReg[15:8]};
    else
        IICSlaveReg <= IICSlaveReg;
end


/*IIC 时钟控制*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        iicCLK <= 1'b1;
    else if(state == IIC_START && IICCnt == (IIC_Pre*2))      /*开始结束时,拉低时钟线*/
        iicCLK <= 1'b0;
    else if(state == IIC_START && IICCnt > IIC_Pre)
        iicCLK <= 1'b1;
    else if(state == IIC_START && IICCnt == IIC_Pre)
        iicCLK <= iicCLK;
    else if(state == IIC_WRDATA && IICCnt == IIC_Pre)     /*发送数据,依次取反时钟线*/
        iicCLK <= ~iicCLK;
    else if(state == IIC_RDDATA && IICCnt == IIC_Pre)     /*接收数据,依次取反时钟线*/
        iicCLK <= ~iicCLK;
    else if(state == IIC_ACK && IICCnt == IIC_Pre)
        iicCLK <= ~iicCLK;
    else if(state == IIC_STOP && IICCnt == IIC_Pre)  /*在停止态时,IICCnt时,直接拉高iicCLK*/
        iicCLK <= 1'b1;
end


/*iic 发送控制*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)   
        iictx <= 1'b1;
    else if(state == IIC_START && IICCnt == (IIC_Pre/2))      /*开始,iic数据线拉低*/
        iictx <= 1'b0;
    else if(state == IIC_START && IICCnt == IIC_Pre/4)      /*开始,iic数据线拉低*/
        iictx <= 1'b1;
    else if(state == IIC_WRDATA && IICCnt == IIC_Pre / 2)     /*iic发送数据*/
        if(iicCLK == 1'b0 && IICSendBytes == 'd2 && (IICWriteReq == 1'b1 || IICWriteReqReg == 1'b1))
            iictx <= IICWriteData['d7-IICBitCnt];
        else if(iicCLK == 1'b0)
            iictx <= IICSlaveReg['d7-IICBitCnt];
        else
            iictx <= iictx;
    else if(state == IIC_ACK)
        iictx <= 1'b0;

    else if(state == IIC_STOP && IICCnt == (IIC_Pre))
        if(iicCLK == 1'b1)
            iictx <= 1'b1;
        else
            iictx <= iictx;
    else if(state == IIC_IDLE)
        iictx <= 1'b1;
end


/*iic 读取数据控制*/
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        IICReadDataReg <= 'd0;
    else if(state == IIC_RDDATA && IICCnt == IIC_Pre / 2)
        if(iicCLK == 1'b1)
            IICReadDataReg <= {IICReadDataReg[6:0],IICSDA};
        else
            IICReadDataReg <= IICReadDataReg;
    else
        IICReadDataReg <= IICReadDataReg;
end


endmodule


```verilog dht11.v

/dht11温湿度数据获取模块/ module DHT11(

input               sys_clk,
input               rst_n,

input               dht11_req,   //dht11数据采集请求
output          dht11_done,  //dht11数据采集结束
output          dht11_error, //dht11数据采集正确与否判断   1为错误

output[7:0]     tempH,          //温度数据整数
output[7:0]     tempL,          //温度数据小数
output[7:0]     humidityH,      //温度数据整数
output[7:0]     humidityL,      //温度数据小数


inout               dht11

);

//时钟为50MHZ,20ns localparam TIME18ms = 'd1000_099; //开始态的拉低18ms,900_000个时钟周期,这里适当的延长了拉低时间。 localparam TIME35us = 'd1_750; //数据传输过程中,数据0拉高的出现

localparam S_IDLE = 'd0; //空闲态 localparam S_START_FPGA = 'd1; //FPGA请求采集数据开始 localparam S_START_DHT11 = 'd2; //DHT11开始请求应答 localparam S_DATA = 'd3; //数据传输 localparam S_STOP = 'd4; //数据结束 localparam S_DOEN = 'd5; //数据采集完成

reg[2:0] state , next_state;

reg[22:0] DHT11_Cnt; //计时器 reg[5:0] DHT11Bit_Cnt; // 接收dht11传输bit数计数

reg[39:0] dht11_data;

reg dht11_d0 , dht11_d1; wire dht11_negedge;

//检测dht11的上下边沿
assign dht11_negedge = (~dht11_d0) & dht11_d1;

assign dht11 = (state == S_START_FPGA && (DHT11_Cnt <= TIME18ms)) ? 1'b0 : 1'bz; assign dht11_done = (state == S_DOEN) ? 1'b1 : 1'b0;

assign tempH = dht11_data[23:16]; assign tempL = dht11_data[15:8];

assign humidityH = dht11_data[39:32]; assign humidityL = dht11_data[31:24];

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) begin dht11_d0 <= 1'b1; dht11_d1 <= 1'b1; end else begin dht11_d0 <= dht11; dht11_d1 <= dht11_d0; end end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) state <= S_IDLE; else state <= next_state; end

always@(*) begin case(state) S_IDLE: if(dht11_req == 1'b1) //数据采集请求过来进入开始态 next_state <= S_START_FPGA; else next_state <= S_IDLE; S_START_FPGA:
if((DHT11_Cnt >= TIME18ms) && dht11_negedge == 1'b1) //FPGA请求结束结束 next_state <= S_START_DHT11; else next_state <= S_START_FPGA; S_START_DHT11: if((DHT11_Cnt > TIME35us) && dht11_negedge == 1'b1) //延时一段时间后,通过判断dht11总线的下降沿,是否结束响应 next_state <= S_DATA; else next_state <= S_START_DHT11; S_DATA: if(DHT11Bit_Cnt == 'd39 && dht11_negedge == 1'b1) //接收到40bit数据后,进入停止态 next_state <= S_STOP; else next_state <= S_DATA; S_STOP: if(DHT11_Cnt == TIME35us + TIME35us) //数据传输完成后,等待总线拉低50us,这里是70us next_state <= S_DOEN; else next_state <= S_STOP; S_DOEN: next_state <= S_IDLE;

default: next_state <= S_IDLE;
endcase

end

/计数模块/ always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) DHT11_Cnt <= 'd0; else if(state != next_state) //状态变换的时候,计时器置0 DHT11_Cnt <= 'd0; else if(state == S_START_FPGA)
DHT11_Cnt <= DHT11_Cnt + 1'b1; else if(state == S_START_DHT11) DHT11_Cnt <= DHT11_Cnt + 1'b1; else if(state == S_DATA && dht11_negedge == 1'b0) //数据的时候,只需要在高电平的时候计数 DHT11_Cnt <= DHT11_Cnt + 1'b1; else if(state == S_STOP) DHT11_Cnt <= DHT11_Cnt + 1'b1; else DHT11_Cnt <= 'd0;
end

/接收数据存储/ always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) dht11_data <= 'd0; else if(state == S_DATA) if((DHT11_Cnt <= (TIME35us + 'd2500)) && dht11_negedge == 1'b1) //'d3000为低电平时间,高电平持续时间低于35us认为是数据0 dht11_data <= {dht11_data[38:0],1'b0}; else if(dht11_negedge == 1'b1) dht11_data <= {dht11_data[38:0],1'b1}; else dht11_data <= dht11_data; else dht11_data <= dht11_data; end

/接收bit计数/ always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) DHT11Bit_Cnt <= 'd0; else if(state == S_DATA && dht11_negedge == 1'b1) DHT11Bit_Cnt <= DHT11Bit_Cnt + 1'b1; else if(state == S_DOEN) //结束后,bit计数清零 DHT11Bit_Cnt <= 'd0; else DHT11Bit_Cnt <= DHT11Bit_Cnt; end

endmodule


下面是oled的程序



```verilog OLED_FontData.v




//中文16*16 数字和字母8*16
module OLED_FontData(

    input           sys_clk,
    input           rst_n,

    input           font_row,
    input[5:0]  font_sel,
    input[8:0]  index,

    output reg[7:0]  data
);


reg[7:0] data0[15:0];   //F
reg[7:0] data1[15:0];   //G
reg[7:0] data2[15:0];   //P
reg[7:0] data3[15:0];   //A
reg[7:0] data4[31:0];   //之
reg[7:0] data5[31:0];   //旅

reg[7:0] data6[31:0];   //温
reg[7:0] data7[31:0];   //度
reg[7:0] data8[31:0];   //湿
reg[7:0] data9[31:0];   //度
reg[7:0] data10[15:0];   //.
reg[7:0] data11[31:0];   //℃
reg[7:0] data12[15:0];   //R
reg[7:0] data13[15:0];   //H

always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 'd0)
        data <= 'd0;
    else if(font_sel == 'd0)
        data <= data0[index + 'd8 * font_row];
    else if(font_sel == 'd1)
        data <= data1[index + 'd8 * font_row];
    else if(font_sel == 'd2)
        data <= data2[index + 'd8 * font_row];
    else if(font_sel == 'd3)
        data <= data3[index + 'd8 * font_row];
    else if(font_sel == 'd4)
        data <= data4[index + 'd16 * font_row];
    else if(font_sel == 'd5)
        data <= data5[index + 'd16 * font_row];
    else if(font_sel == 'd6)
        data <= data6[index + 'd16 * font_row];
    else if(font_sel == 'd7)
        data <= data7[index + 'd16 * font_row];
    else if(font_sel == 'd8)
        data <= data8[index + 'd16 * font_row];
    else if(font_sel == 'd9)
        data <= data9[index + 'd16 * font_row];
    else if(font_sel == 'd10)
        data <= data10[index + 'd8 * font_row];
    else if(font_sel == 'd11)
        data <= data11[index + 'd16 * font_row];
    else if(font_sel == 'd12)
        data <= data12[index + 'd8 * font_row];
    else if(font_sel == 'd13)
        data <= data13[index + 'd8 * font_row];
    else if(font_sel == 'd14)
        data <= data10[index + 'd8 * font_row];
    else
        data <= data;
end

always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data0[0] = 8'h08;
        data0[1] = 8'hF8;
        data0[2] = 8'h88;
        data0[3] = 8'h88;
        data0[4] = 8'hE8;
        data0[5] = 8'h08;
        data0[6] = 8'h10;
        data0[7] = 8'h00;
        data0[8] = 8'h20;
        data0[9] = 8'h3F;
        data0[10] = 8'h20;
        data0[11] = 8'h00;
        data0[12] = 8'h03;
        data0[13] = 8'h00;
        data0[14] = 8'h00;
        data0[15] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data1[0] = 8'h08;
        data1[1] = 8'hF8;
        data1[2] = 8'h08;
        data1[3] = 8'h08;
        data1[4] = 8'h08;
        data1[5] = 8'h08;
        data1[6] = 8'hF0;
        data1[7] = 8'h00;
        data1[8] = 8'h20;
        data1[9] = 8'h3F;
        data1[10] = 8'h21;
        data1[11] = 8'h01;
        data1[12] = 8'h01;
        data1[13] = 8'h01;
        data1[14] = 8'h00;
        data1[15] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data2[0] = 8'hC0;
        data2[1] = 8'h30;
        data2[2] = 8'h08;
        data2[3] = 8'h08;
        data2[4] = 8'h08;
        data2[5] = 8'h38;
        data2[6] = 8'h00;
        data2[7] = 8'h00;
        data2[8] = 8'h07;
        data2[9] = 8'h18;
        data2[10] = 8'h20;
        data2[11] = 8'h20;
        data2[12] = 8'h22;
        data2[13] = 8'h1E;
        data2[14] = 8'h02;
        data2[15] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data3[0] = 8'h00;
        data3[1] = 8'h00;
        data3[2] = 8'hC0;
        data3[3] = 8'h38;
        data3[4] = 8'hE0;
        data3[5] = 8'h00;
        data3[6] = 8'h00;
        data3[7] = 8'h00;
        data3[8] = 8'h20;
        data3[9] = 8'h3C;
        data3[10] = 8'h23;
        data3[11] = 8'h02;
        data3[12] = 8'h02;
        data3[13] = 8'h27;
        data3[14] = 8'h38;
        data3[15] = 8'h20;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data4[0] = 8'h10;
        data4[1] = 8'h0C;
        data4[2] = 8'h04;
        data4[3] = 8'h84;
        data4[4] = 8'h14;
        data4[5] = 8'h64;
        data4[6] = 8'h05;
        data4[7] = 8'h06;
        data4[8] = 8'hF4;
        data4[9] = 8'h04;
        data4[10] = 8'h04;
        data4[11] = 8'h04;
        data4[12] = 8'h04;
        data4[13] = 8'h14;
        data4[14] = 8'h0C;
        data4[15] = 8'h00;
        data4[16] = 8'h04;
        data4[17] = 8'h84;
        data4[18] = 8'h84;
        data4[19] = 8'h44;
        data4[20] = 8'h47;
        data4[21] = 8'h24;
        data4[22] = 8'h14;
        data4[23] = 8'h0C;
        data4[24] = 8'h07;
        data4[25] = 8'h0C;
        data4[26] = 8'h14;
        data4[27] = 8'h24;
        data4[28] = 8'h44;
        data4[29] = 8'h84;
        data4[30] = 8'h04;
        data4[31] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data5[0] = 8'h02;
        data5[1] = 8'hFA;
        data5[2] = 8'h82;
        data5[3] = 8'h82;
        data5[4] = 8'hFE;
        data5[5] = 8'h80;
        data5[6] = 8'h40;
        data5[7] = 8'h20;
        data5[8] = 8'h50;
        data5[9] = 8'h4C;
        data5[10] = 8'h43;
        data5[11] = 8'h4C;
        data5[12] = 8'h50;
        data5[13] = 8'h20;
        data5[14] = 8'h40;
        data5[15] = 8'h00;
        data5[16] = 8'h08;
        data5[17] = 8'h18;
        data5[18] = 8'h48;
        data5[19] = 8'h84;
        data5[20] = 8'h44;
        data5[21] = 8'h3F;
        data5[22] = 8'h40;
        data5[23] = 8'h44;
        data5[24] = 8'h58;
        data5[25] = 8'h41;
        data5[26] = 8'h4E;
        data5[27] = 8'h60;
        data5[28] = 8'h58;
        data5[29] = 8'h47;
        data5[30] = 8'h40;
        data5[31] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data6[0] = 8'h10;
        data6[1] = 8'h60;
        data6[2] = 8'h02;
        data6[3] = 8'h8C;
        data6[4] = 8'h00;
        data6[5] = 8'h00;
        data6[6] = 8'hFE;
        data6[7] = 8'h92;
        data6[8] = 8'h92;
        data6[9] = 8'h92;
        data6[10] = 8'h92;
        data6[11] = 8'h92;
        data6[12] = 8'hFE;
        data6[13] = 8'h00;
        data6[14] = 8'h00;
        data6[15] = 8'h00;
        data6[16] = 8'h04;
        data6[17] = 8'h04;
        data6[18] = 8'h7E;
        data6[19] = 8'h01;
        data6[20] = 8'h40;
        data6[21] = 8'h7E;
        data6[22] = 8'h42;
        data6[23] = 8'h42;
        data6[24] = 8'h7E;
        data6[25] = 8'h42;
        data6[26] = 8'h7E;
        data6[27] = 8'h42;
        data6[28] = 8'h42;
        data6[29] = 8'h7E;
        data6[30] = 8'h40;
        data6[31] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data7[0] = 8'h00;
        data7[1] = 8'h00;
        data7[2] = 8'hFC;
        data7[3] = 8'h24;
        data7[4] = 8'h24;
        data7[5] = 8'h24;
        data7[6] = 8'hFC;
        data7[7] = 8'h25;
        data7[8] = 8'h26;
        data7[9] = 8'h24;
        data7[10] = 8'hFC;
        data7[11] = 8'h24;
        data7[12] = 8'h24;
        data7[13] = 8'h24;
        data7[14] = 8'h04;
        data7[15] = 8'h00;
        data7[16] = 8'h40;
        data7[17] = 8'h30;
        data7[18] = 8'h8F;
        data7[19] = 8'h80;
        data7[20] = 8'h84;
        data7[21] = 8'h4C;
        data7[22] = 8'h55;
        data7[23] = 8'h25;
        data7[24] = 8'h25;
        data7[25] = 8'h25;
        data7[26] = 8'h55;
        data7[27] = 8'h4C;
        data7[28] = 8'h80;
        data7[29] = 8'h80;
        data7[30] = 8'h80;
        data7[31] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data8[0] = 8'h10;
        data8[1] = 8'h60;
        data8[2] = 8'h02;
        data8[3] = 8'h8C;
        data8[4] = 8'h00;
        data8[5] = 8'hFE;
        data8[6] = 8'h92;
        data8[7] = 8'h92;
        data8[8] = 8'h92;
        data8[9] = 8'h92;
        data8[10] = 8'h92;
        data8[11] = 8'h92;
        data8[12] = 8'hFE;
        data8[13] = 8'h00;
        data8[14] = 8'h00;
        data8[15] = 8'h00;
        data8[16] = 8'h04;
        data8[17] = 8'h04;
        data8[18] = 8'h7E;
        data8[19] = 8'h01;
        data8[20] = 8'h44;
        data8[21] = 8'h48;
        data8[22] = 8'h50;
        data8[23] = 8'h7F;
        data8[24] = 8'h40;
        data8[25] = 8'h40;
        data8[26] = 8'h7F;
        data8[27] = 8'h50;
        data8[28] = 8'h48;
        data8[29] = 8'h44;
        data8[30] = 8'h40;
        data8[31] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data9[0] = 8'h00;
        data9[1] = 8'h00;
        data9[2] = 8'hFC;
        data9[3] = 8'h24;
        data9[4] = 8'h24;
        data9[5] = 8'h24;
        data9[6] = 8'hFC;
        data9[7] = 8'h25;
        data9[8] = 8'h26;
        data9[9] = 8'h24;
        data9[10] = 8'hFC;
        data9[11] = 8'h24;
        data9[12] = 8'h24;
        data9[13] = 8'h24;
        data9[14] = 8'h04;
        data9[15] = 8'h00;
        data9[16] = 8'h40;
        data9[17] = 8'h30;
        data9[18] = 8'h8F;
        data9[19] = 8'h80;
        data9[20] = 8'h84;
        data9[21] = 8'h4C;
        data9[22] = 8'h55;
        data9[23] = 8'h25;
        data9[24] = 8'h25;
        data9[25] = 8'h25;
        data9[26] = 8'h55;
        data9[27] = 8'h4C;
        data9[28] = 8'h80;
        data9[29] = 8'h80;
        data9[30] = 8'h80;
        data9[31] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data10[0] = 8'h00;
        data10[1] = 8'h00;
        data10[2] = 8'h00;
        data10[3] = 8'h00;
        data10[4] = 8'h00;
        data10[5] = 8'h00;
        data10[6] = 8'h00;
        data10[7] = 8'h00;
        data10[8] = 8'h00;
        data10[9] = 8'h30;
        data10[10] = 8'h30;
        data10[11] = 8'h00;
        data10[12] = 8'h00;
        data10[13] = 8'h00;
        data10[14] = 8'h00;
        data10[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data11[0] = 8'h06;
        data11[1] = 8'h09;
        data11[2] = 8'h09;
        data11[3] = 8'hE6;
        data11[4] = 8'hF8;
        data11[5] = 8'h0C;
        data11[6] = 8'h04;
        data11[7] = 8'h02;
        data11[8] = 8'h02;
        data11[9] = 8'h02;
        data11[10] = 8'h02;
        data11[11] = 8'h02;
        data11[12] = 8'h04;
        data11[13] = 8'h1E;
        data11[14] = 8'h00;
        data11[15] = 8'h00;
        data11[16] = 8'h00;
        data11[17] = 8'h00;
        data11[18] = 8'h00;
        data11[19] = 8'h07;
        data11[20] = 8'h1F;
        data11[21] = 8'h30;
        data11[22] = 8'h20;
        data11[23] = 8'h40;
        data11[24] = 8'h40;
        data11[25] = 8'h40;
        data11[26] = 8'h40;
        data11[27] = 8'h40;
        data11[28] = 8'h20;
        data11[29] = 8'h10;
        data11[30] = 8'h00;
        data11[31] = 8'h00;
    end
end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data12[0] = 8'h08;
        data12[1] = 8'hF8;
        data12[2] = 8'h88;
        data12[3] = 8'h88;
        data12[4] = 8'h88;
        data12[5] = 8'h88;
        data12[6] = 8'h70;
        data12[7] = 8'h00;
        data12[8] = 8'h20;
        data12[9] = 8'h3F;
        data12[10] = 8'h20;
        data12[11] = 8'h00;
        data12[12] = 8'h03;
        data12[13] = 8'h0C;
        data12[14] = 8'h30;
        data12[15] = 8'h20;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data13[0] = 8'h08;
        data13[1] = 8'hF8;
        data13[2] = 8'h08;
        data13[3] = 8'h00;
        data13[4] = 8'h00;
        data13[5] = 8'h08;
        data13[6] = 8'hF8;
        data13[7] = 8'h08;
        data13[8] = 8'h20;
        data13[9] = 8'h3F;
        data13[10] = 8'h21;
        data13[11] = 8'h01;
        data13[12] = 8'h01;
        data13[13] = 8'h21;
        data13[14] = 8'h3F;
        data13[15] = 8'h20;
    end

end

endmodule 

```verilog OLED_Init.v

//oled_init 初始化模块 module OLED_Init(

input                   sys_clk,
input                   rst_n,

input                   init_req,               //初始化请求
input                   write_done,             //一组初始化数据完成信号

output              init_finish,            //初始化完成输出

output[23:0]        Init_data       //初始化的数据

);

localparam RST_T = 1'b0; //复位有效

reg[23:0] Init_data_reg; reg[4:0] Init_index;

assign Init_data = Init_data_reg; assign init_finish = (Init_index >= 'd26 && write_done == 1'b1) ? 1'b1 : 1'b0;//初始化完成信号

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == RST_T) Init_index <= 'd0; else if(Init_index == 'd26 && write_done == 1'b1 ) Init_index <= 'd0; else if(write_done == 1'b1 && init_req == 1'b1) Init_index <= Init_index + 1'b1; else Init_index <= Init_index; end

always@(*) begin case(Init_index) 'd0: Init_data_reg <= {8'h78,8'h00,8'hAE}; '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

endmodule


```verilog OLED_NumData.v





/*数字数据0-9*/
module  OLED_NumData(

    input           sys_clk,
    input           rst_n,

    input           font_row,
    input[4:0]  font_sel,
    input[4:0]  index,

    output reg[7:0]  data

);




/*0-9*/
reg[7:0]    data0[15:0];
reg[7:0]    data1[15:0];
reg[7:0]    data2[15:0];
reg[7:0]    data3[15:0];
reg[7:0]    data4[15:0];
reg[7:0]    data5[15:0];
reg[7:0]    data6[15:0];
reg[7:0]    data7[15:0];
reg[7:0]    data8[15:0];
reg[7:0]    data9[15:0];


always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        data <= 'd0;
    else if(font_sel == 'd0)
        data <= data0[index + 'd8 * font_row];
    else if(font_sel == 'd1)
        data <= data1[index + 'd8 * font_row];
    else if(font_sel == 'd2)
        data <= data2[index + 'd8 * font_row];
    else if(font_sel == 'd3)
        data <= data3[index + 'd8 * font_row];
    else if(font_sel == 'd4)
        data <= data4[index + 'd8 * font_row];
    else if(font_sel == 'd5)
        data <= data5[index + 'd8 * font_row];
    else if(font_sel == 'd6)
        data <= data6[index + 'd8 * font_row];
    else if(font_sel == 'd7)
        data <= data7[index + 'd8 * font_row];
    else if(font_sel == 'd8)
        data <= data8[index + 'd8 * font_row];
    else if(font_sel == 'd9)
        data <= data9[index + 'd8 * font_row];
end


always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data0[0] = 8'h00;
        data0[1] = 8'hE0;
        data0[2] = 8'h10;
        data0[3] = 8'h08;
        data0[4] = 8'h08;
        data0[5] = 8'h10;
        data0[6] = 8'hE0;
        data0[7] = 8'h00;
        data0[8] = 8'h00;
        data0[9] = 8'h0F;
        data0[10] = 8'h10;
        data0[11] = 8'h20;
        data0[12] = 8'h20;
        data0[13] = 8'h10;
        data0[14] = 8'h0F;
        data0[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data1[0] = 8'h00;
        data1[1] = 8'h00;
        data1[2] = 8'h10;
        data1[3] = 8'h10;
        data1[4] = 8'hF8;
        data1[5] = 8'h00;
        data1[6] = 8'h00;
        data1[7] = 8'h00;
        data1[8] = 8'h00;
        data1[9] = 8'h00;
        data1[10] = 8'h20;
        data1[11] = 8'h20;
        data1[12] = 8'h3F;
        data1[13] = 8'h20;
        data1[14] = 8'h20;
        data1[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data2[0] = 8'h00;
        data2[1] = 8'h70;
        data2[2] = 8'h08;
        data2[3] = 8'h08;
        data2[4] = 8'h08;
        data2[5] = 8'h08;
        data2[6] = 8'hF0;
        data2[7] = 8'h00;
        data2[8] = 8'h00;
        data2[9] = 8'h30;
        data2[10] = 8'h28;
        data2[11] = 8'h24;
        data2[12] = 8'h22;
        data2[13] = 8'h21;
        data2[14] = 8'h30;
        data2[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data3[0] = 8'h00;
        data3[1] = 8'h30;
        data3[2] = 8'h08;
        data3[3] = 8'h08;
        data3[4] = 8'h08;
        data3[5] = 8'h88;
        data3[6] = 8'h70;
        data3[7] = 8'h00;
        data3[8] = 8'h00;
        data3[9] = 8'h18;
        data3[10] = 8'h20;
        data3[11] = 8'h21;
        data3[12] = 8'h21;
        data3[13] = 8'h22;
        data3[14] = 8'h1C;
        data3[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data4[0] = 8'h00;
        data4[1] = 8'h00;
        data4[2] = 8'h80;
        data4[3] = 8'h40;
        data4[4] = 8'h30;
        data4[5] = 8'hF8;
        data4[6] = 8'h00;
        data4[7] = 8'h00;
        data4[8] = 8'h00;
        data4[9] = 8'h06;
        data4[10] = 8'h05;
        data4[11] = 8'h24;
        data4[12] = 8'h24;
        data4[13] = 8'h3F;
        data4[14] = 8'h24;
        data4[15] = 8'h24;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data5[0] = 8'h00;
        data5[1] = 8'hF8;
        data5[2] = 8'h88;
        data5[3] = 8'h88;
        data5[4] = 8'h88;
        data5[5] = 8'h08;
        data5[6] = 8'h08;
        data5[7] = 8'h00;
        data5[8] = 8'h00;
        data5[9] = 8'h19;
        data5[10] = 8'h20;
        data5[11] = 8'h20;
        data5[12] = 8'h20;
        data5[13] = 8'h11;
        data5[14] = 8'h0E;
        data5[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data6[0] = 8'h00;
        data6[1] = 8'hE0;
        data6[2] = 8'h10;
        data6[3] = 8'h88;
        data6[4] = 8'h88;
        data6[5] = 8'h90;
        data6[6] = 8'h00;
        data6[7] = 8'h00;
        data6[8] = 8'h00;
        data6[9] = 8'h0F;
        data6[10] = 8'h11;
        data6[11] = 8'h20;
        data6[12] = 8'h20;
        data6[13] = 8'h20;
        data6[14] = 8'h1F;
        data6[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data7[0] = 8'h00;
        data7[1] = 8'h18;
        data7[2] = 8'h08;
        data7[3] = 8'h08;
        data7[4] = 8'h88;
        data7[5] = 8'h68;
        data7[6] = 8'h18;
        data7[7] = 8'h00;
        data7[8] = 8'h00;
        data7[9] = 8'h00;
        data7[10] = 8'h00;
        data7[11] = 8'h3E;
        data7[12] = 8'h01;
        data7[13] = 8'h00;
        data7[14] = 8'h00;
        data7[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data8[0] = 8'h00;
        data8[1] = 8'h70;
        data8[2] = 8'h88;
        data8[3] = 8'h08;
        data8[4] = 8'h08;
        data8[5] = 8'h88;
        data8[6] = 8'h70;
        data8[7] = 8'h00;
        data8[8] = 8'h00;
        data8[9] = 8'h1C;
        data8[10] = 8'h22;
        data8[11] = 8'h21;
        data8[12] = 8'h21;
        data8[13] = 8'h22;
        data8[14] = 8'h1C;
        data8[15] = 8'h00;
    end


end
always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        data9[0] = 8'h00;
        data9[1] = 8'hF0;
        data9[2] = 8'h08;
        data9[3] = 8'h08;
        data9[4] = 8'h08;
        data9[5] = 8'h10;
        data9[6] = 8'hE0;
        data9[7] = 8'h00;
        data9[8] = 8'h00;
        data9[9] = 8'h01;
        data9[10] = 8'h12;
        data9[11] = 8'h22;
        data9[12] = 8'h22;
        data9[13] = 8'h11;
        data9[14] = 8'h0F;
        data9[15] = 8'h00;
    end


end
endmodule 

```verilog OLED_Refresh.v

//刷新模块,将oled屏幕全部变为黑色 module OLED_Refresh( input sys_clk, input rst_n,

input                   refresh_req,                //初始化请求
input                   write_done,             //一组初始化数据完成信号

output              refresh_finish,         //初始化完成输出

output[23:0]        refresh_data        //初始化的数据

);

reg[23:0] refresh_data_reg; reg[10:0] refresh_index; reg[2:0] page; assign refresh_data = refresh_data_reg; assign refresh_finish = (page == 'd7 && refresh_index == 'd130 && write_done == 1'b1) ? 1'b1 : 1'b0;

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) refresh_index <= 'd0; else if(refresh_index == 'd130 && write_done == 1'b1) refresh_index <= 'd0; else if(write_done == 1'b1) refresh_index <= refresh_index + 1'b1; else refresh_index <= refresh_index; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) page <= 'd0; else if(refresh_index == 'd130 && write_done == 1'b1) page <= page + 1'b1; else page <= page; end

always@(*) begin case(refresh_index) 'd0: refresh_data_reg <= {8'h78,8'h00,8'hB0 + page}; 'd1: refresh_data_reg <= {8'h78,8'h00,8'h00}; 'd2: refresh_data_reg <= {8'h78,8'h00,8'h10}; default: refresh_data_reg <= {8'h78,8'h40,8'h00}; endcase end

endmodule


```verilog OLED_SelData.v






module OLED_SelData(

    input               sys_clk,
    input               rst_n,


    input               init_req,
    input[23:0]     init_data,

    input               refresh_req,
    input[23:0]     refresh_data,

    input               showfont_req,
    input[23:0]    showfont_data,

    input               showdata_req,
    input[23:0]     showdata_data, 

    output          IICWriteReq,
    output[23:0]    IICWriteData
);

reg       IICWriteReqReg;
reg[23:0] IICWriteDataReg; 

assign IICWriteReq  = init_req | showfont_req | refresh_req | showdata_req;
assign IICWriteData = (init_req == 1'b1) ? init_data : (refresh_req == 1'b1) ? refresh_data : (showfont_req == 1'b1) ? showfont_data : showdata_data;


endmodule 

```verilog OLED_ShowData.v

module OLED_ShowData(

input               sys_clk,
input               rst_n,


input               dht11_done,
input[7:0]     tempH,   
input[7:0]     tempL,
input[7:0]     humidityH,
input[7:0]     humidityL,


input               ShowData_req,        //字符显示请求
input               write_done,          //iic一组数据写完成

output[23:0]    ShowData_Data,       //字符显示数据

output          ShowData_finish   //字符显示完成

);

// //reg[3:0] tempHH; //tempH的高位 //reg[3:0] tempHL; //tempH的低位 //reg[3:0] tempLH; //reg[3:0] tempLL; // //reg[3:0] humidityHH; //reg[3:0] humidityHL; //reg[3:0] humidityLH; //reg[3:0] humidityLL;

reg[7:0] tempHREG; reg[7:0] tempLREG; reg[7:0] humidityHREG; reg[7:0] humidityLREG;

reg[4:0] font;

reg[4:0] font_sel; reg[4:0] font_index; reg font_row;

reg[7:0] show_x; reg[3:0] show_y; reg[23:0] showfont_data_reg; wire onefont_finish; wire[7:0] fontdata;

assign onefont_finish = (font_row == 1'b1 && font_index == 'd10 && write_done == 1'b1) ? 1'b1 : 1'b0; assign ShowData_finish = (onefont_finish == 1'b1 && font_sel == 'd7) ? 1'b1 : 1'b0; assign ShowData_Data = showfont_data_reg;

always@(*) begin case(font_index) 'd0: showfont_data_reg <= {8'h78,8'h00,8'hB0 + show_y + font_row}; 'd1: showfont_data_reg <= {8'h78,8'h00,8'h00 + show_x[3:0]}; 'd2: showfont_data_reg <= {8'h78,8'h00,8'h10 + show_x[7:4]}; default: showfont_data_reg <= {8'h78,8'h40,fontdata}; //fontdata endcase end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) font_index <= 'd0; else if(write_done == 1'b1 && font_index == 'd10) font_index <= 'd0; else if(write_done == 1'b1 && ShowData_req == 1'b1) font_index <= font_index + 1'b1; else font_index <= font_index; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) font_row <= 1'b0; else if(onefont_finish == 1'b1) font_row <= 1'b0; else if(write_done == 1'b1 && font_index == 'd10) font_row <= 1'b1; else font_row <= font_row; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) font_sel <= 'd0; else if(ShowData_finish == 1'b1) font_sel <= 'd0; else if(onefont_finish == 1'b1) font_sel <= font_sel + 1'b1; else font_sel <= font_sel; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) begin show_x <= 'd0; show_y <= 'd0; end else if(font_sel == 'd0) begin show_x <= 'd54; show_y <= 'd3; end else if(font_sel == 'd1) begin show_x <= 'd62; show_y <= 'd3; end else if(font_sel == 'd2) begin show_x <= 'd79; show_y <= 'd3; end else if(font_sel == 'd3) begin show_x <= 'd88; show_y <= 'd3; end

else if(font_sel == 'd4)
begin
    show_x <= 'd54;
    show_y <= 'd5;
end
else if(font_sel == 'd5)
begin
    show_x <= 'd62;
    show_y <= 'd5;
end
else if(font_sel == 'd6)
begin
    show_x <= 'd79;
    show_y <= 'd5;
end
else if(font_sel == 'd7)
begin
    show_x <= 'd88;
    show_y <= 'd5;
end

else
begin
    show_x <= 'd0;
    show_y <= 'd0;
end

end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) font <= 'd0; else if(font_sel == 'd0) font <= tempHREG / 10; else if(font_sel == 'd1) font <= tempHREG % 10; else if(font_sel == 'd2) font <= tempLREG / 10; else if(font_sel == 'd3) font <= tempLREG % 10;

else if(font_sel == 'd4)
    font <= humidityHREG / 10;
else if(font_sel == 'd5)
    font <= humidityHREG % 10;
else if(font_sel == 'd6)
    font <= humidityLREG / 10;
else if(font_sel == 'd7)
    font <= humidityLREG % 10;
else
    font <= font;

end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) tempHREG <= 'd0; else if(dht11_done == 1'b1) tempHREG <= tempH; else tempHREG <= tempHREG; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) tempLREG <= 'd0; else if(dht11_done == 1'b1) tempLREG <= tempL; else tempLREG <= tempLREG; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) humidityHREG <= 'd0; else if(dht11_done == 1'b1) humidityHREG <= humidityH; else humidityHREG <= humidityHREG; end

always@(posedge sys_clk or negedge rst_n) begin if(rst_n == 1'b0) humidityLREG <= 'd0; else if(dht11_done == 1'b1) humidityLREG <= humidityL; else humidityLREG <= humidityLREG; end

OLED_NumData OLED_NumDataHP(

.sys_clk        (sys_clk),
.rst_n      (rst_n),

.font_row   (font_row),
.font_sel   (font),
.index      (font_index - 'd3),

.data           (fontdata)

);

endmodule


```verilog OLED_ShowFont.v







module OLED_ShowFont(

    input               sys_clk,
    input               rst_n,

    input               ShowFont_req,        //字符显示请求
    input               write_done,          //iic一组数据写完成

    output[23:0]    ShowFont_Data,       //字符显示数据

    output          ShowFont_finish   //字符显示完成
);

reg[8:0]       showfont_index;
reg[23:0]   showfont_data_reg;

wire[7:0]   fontdata;


reg[5:0]        font_index; //当前显示第几个字符
reg[1:0]        font_size; //1 :16*16   0 : 8*16
reg[7:0]        show_x;
reg[3:0]        show_y;
reg         font_row;

wire onefont_finish;


assign onefont_finish = ((showfont_index == ('d10 + 'd8 * font_size)) && (font_row == 1'b1) && write_done == 1'b1) ? 1'b1 : 1'b0;
assign ShowFont_finish = (onefont_finish == 1'b1 && font_index == 'd14) ? 1'b1 : 1'b0;

assign ShowFont_Data = showfont_data_reg;

always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        showfont_index <= 'd0;
    else if(onefont_finish == 1'b1)
        showfont_index <= 'd0;
    else if(font_size == 'd0 && showfont_index == 'd10 && write_done == 1'b1)
        showfont_index <= 'd0;
    else if(font_size == 'd1 && showfont_index == 'd18 && write_done == 1'b1)
        showfont_index <= 'd0;
    else if(write_done == 1'b1 && ShowFont_req == 1'b1)
        showfont_index <= showfont_index + 1'b1;
    else
        showfont_index <= showfont_index;
end

always@(*)
begin
    case(showfont_index)
    'd0:    showfont_data_reg <= {8'h78,8'h00,8'hB0 + show_y + font_row};
    'd1:  showfont_data_reg <= {8'h78,8'h00,8'h00 + show_x[3:0]};
    'd2:  showfont_data_reg <= {8'h78,8'h00,8'h10 + show_x[7:4]};
    default:    showfont_data_reg <= {8'h78,8'h40,fontdata}; //fontdata
    endcase
end

always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        font_row <= 1'b0;
    else if(onefont_finish == 1'b1)
        font_row <= 1'b0;
    else if(font_size == 'd0 && showfont_index == 'd10 && write_done == 1'b1)
        font_row <= 1'b1;
    else if(font_size == 'd1 && showfont_index == 'd18 && write_done == 1'b1)
        font_row <= 1'b1;
    else
        font_row <= font_row;
end


always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        font_size <= 'd0;
    else if(font_index <= 'd3)
        font_size <= 'd0;
    else if(font_index == 'd10 || font_index == 'd12 || font_index == 'd13 || font_index == 'd14)
        font_size <= 'd0;
    else
        font_size <= 'd1;
end


always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        font_index <= 'd0;
    else if(ShowFont_finish == 1'b1)
        font_index <= 'd0;
    else if(onefont_finish == 1'b1)
        font_index <= font_index + 1'b1;
    else
        font_index <= font_index;
end

always@(posedge sys_clk or negedge rst_n)
begin
    if(rst_n == 1'b0)                                   //F
    begin
        show_x <= 'd8;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd0) //P
    begin
        show_x <= 'd24;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd1)  //G
    begin
        show_x <= 'd40;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd2)  //A
    begin
        show_x <= 'd56;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd3) //之
    begin
        show_x <= 'd77;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd4) //旅
    begin
        show_x <= 'd100;
        show_y <= 'd0;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd5)    //温
    begin
        show_x <= 'd10;
        show_y <= 'd3;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd6)     //度
    begin
        show_x <= 'd30;
        show_y <= 'd3;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd7)    //湿
    begin
        show_x <= 'd10;
        show_y <= 'd5;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd8)     //度
    begin
        show_x <= 'd30;
        show_y <= 'd5;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd9)     //.
    begin
        show_x <= 'd70;
        show_y <= 'd3;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd10)    //℃
    begin
        show_x <= 'd100;
        show_y <= 'd3;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd11)    //R
    begin
        show_x <= 'd100;
        show_y <= 'd5;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd12)    //H
    begin
        show_x <= 'd108;
        show_y <= 'd5;
    end
    else if(onefont_finish == 1'b1 && font_index == 'd13)    //.
    begin
        show_x <= 'd70;
        show_y <= 'd5;
    end
    else
    begin
        show_x <= show_x;
        show_y <= show_y;
    end

end

OLED_FontData OLED_FontData_HP(

    .sys_clk            (sys_clk),
    .rst_n          (rst_n),
    .font_row       (font_row),
    .font_sel       (font_index),
    .index          (showfont_index - 'd3),
    .data               (fontdata)
);


endmodule 

```verilog OLED_Top.v

//OLED顶层模块 module OLED_Top(

input           sys_clk,
input           rst_n,

//DHT11数值显示
input               dht11_done,
input[7:0]     tempH,   
input[7:0]     tempL,
input[7:0]     humidityH,
input[7:0]     humidityL,



//OLED IIC
output      OLED_SCL,
inout           OLED_SDA

);

localparam OLED_INIT = 'd0; //初始化 localparam OLED_Refresh = 'd1; //刷新,将oled全部写0 localparam OLED_ShowFont = 'd2; //显示字符 localparam OLED_IDLE = 'd3; //空闲 localparam OLED_ShowData = 'd4; //显示数据

reg[4:0] state , next_state;

//IIC相关信号 wire IICWriteReq; wire[23:0] IICWriteData; wire IICWriteDone;

//初始化相关信号 wire init_finish; wire[23:0] Init_data; wire init_req;

//refresh相关信号 wire refresh_finish; wire[23:0] refresh_data; wire refresh_req;

//字符显示相关信号 wire showfont_finish; wire[23:0] showfont_data; wire showfont_req;

//显示数据相关信号 wire showdata_finish; wire[23:0] showdata_data; wire showdata_req;

assign init_req = (state == OLED_INIT) ? 1'b1 : 1'b0;

assign refresh_req = (state == OLED_Refresh) ? 1'b1 : 1'b0;

assign showfont_req = (state == OLED_ShowFont) ? 1'b1 : 1'b0;

assign showdata_req = (state == OLED_ShowData) ? 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_Refresh; else next_state <= OLED_INIT; OLED_Refresh: if(refresh_finish == 1'b1) next_state <= OLED_ShowFont; else next_state <= OLED_Refresh; OLED_ShowFont: if(showfont_finish == 1'b1) next_state <= OLED_IDLE; else next_state <= OLED_ShowFont; OLED_IDLE: if(dht11_done == 1'b1) next_state <= OLED_ShowData; else next_state <= OLED_IDLE; OLED_ShowData: if(showdata_finish == 1'b1) next_state <= OLED_IDLE; else next_state <= OLED_ShowData; default: next_state <= OLED_INIT; endcase end

OLED_Init OLED_InitHP(

.sys_clk                (sys_clk),
.rst_n              (rst_n),

.init_req           (init_req),             //初始化请求
.write_done         (IICWriteDone),         //一组初始化数据完成信号

.init_finish        (init_finish),          //初始化完成输出

.Init_data          (Init_data)//初始化的数据

);

OLED_Refresh( .sys_clk (sys_clk), .rst_n (rst_n),

.refresh_req        (refresh_req),              //初始化请求
.write_done         (IICWriteDone),             //一组初始化数据完成信号

.refresh_finish (refresh_finish),           //初始化完成输出

.refresh_data       (refresh_data)  //初始化的数据

);

OLED_ShowFont OLED_ShowFont_HP(

.sys_clk            (sys_clk),
.rst_n          (rst_n),

.ShowFont_req   (showfont_req),         //字符显示请求
.write_done     (IICWriteDone),          //iic一组数据写完成

.ShowFont_Data      (showfont_data),         //字符显示数据

.ShowFont_finish(showfont_finish)       //字符显示完成

);

OLED_ShowData OLED_ShowDataHP(

.sys_clk            (sys_clk),
.rst_n          (rst_n),

.dht11_done     (dht11_done),
.tempH          (tempH),            //温度数据整数
.tempL          (tempL),            //温度数据小数
.humidityH      (humidityH),        //温度数据整数
.humidityL      (humidityL),        //温度数据小数


.ShowData_req   (showdata_req),      //字符显示请求
.write_done     (IICWriteDone),          //iic一组数据写完成

.ShowData_Data  (showdata_data),         //字符显示数据

.ShowData_finish    (showdata_finish)   //字符显示完成

);

//数据选择 OLED_SelData OLED_SelDataHP(

.sys_clk            (sys_clk),
.rst_n          (rst_n),


.init_req       (init_req),
.init_data      (Init_data),

.refresh_req    (refresh_req),
.refresh_data   (refresh_data),

.showfont_req   (showfont_req),
.showfont_data  (showfont_data),

.showdata_req   (showdata_req),
.showdata_data  (showdata_data),


.IICWriteReq    (IICWriteReq),  
.IICWriteData   (IICWriteData)

);

IIC_Driver IIC_DriverHP_OLED( .sys_clk (sys_clk), /系统时钟/ .rst_n (rst_n), /系统复位/

.IICSCL             (OLED_SCL),            /*IIC 时钟输出*/
.IICSDA             (OLED_SDA),             /*IIC 数据线*/


.IICSlave           ({IICWriteData[15:8],IICWriteData[23:16]}),           /*从机 8bit的寄存器地址 + 8bit的从机地址*/

.IICWriteReq        (IICWriteReq),       /*IIC写寄存器请求*/
.IICWriteDone       (IICWriteDone),      /*IIC写寄存器完成*/
.IICWriteData       (IICWriteData[7:0]),       /*IIC发送数据  8bit的数据*/

.IICReadReq         (1'b0),        /*IIC读寄存器请求*/
.IICReadDone            (),       /*IIC读寄存器完成*/
.IICReadData            ()    /*IIC读取数据*/

);

endmodule ```

参考链接

[1] STM32 7针0.96寸OLED显示屏(硬件SPI+DMA)无需内核响应 超高刷新率!_0.96oled速率-CSDN博客

[2] 7脚spi OLED屏幕改造成IIC屏幕_7针spioled改4针iic-CSDN博客

[3] FPGA之旅设计99例之第九例-----驱动0.96寸OLED屏_fpga oled 12864-CSDN博客