-

本次使用开发环境:

软件:Quartus II 64-Bit

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

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 程序设计

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
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
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的程序

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
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
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
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
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
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
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
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博客


本站由 John Doe 使用 Stellar 1.28.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本"页面"访问 次 | 👀总访问 次 | 🥷总访客