本次使用开发环境:
软件: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协议中判断数据接收设备的基本步骤:
- 地址分配:每个连接到I²C总线的设备都有一个唯一的地址。这个地址在设备制造时被设定,并且通常通过硬件方式设置。
- 开始条件:在数据传输开始之前,主机设备会发送一个开始条件,这通常涉及到SDA(数据线)和SCL(时钟线)的特定电平变化。
- 发送地址:主机设备随后会在SDA线上发送目标设备的7位地址,加上一个额外的读/写位(R/W位)。这个位指示了接下来的操作是读取(1)还是写入(0)。
- 确认应答:当地址和R/W位被发送后,目标设备需要在下一个时钟脉冲的开始时将SDA线拉低,以表示它已经接收到了地址并且准备好进行通信。这个过程称为应答(ACK)。
- 数据传输:一旦接收到应答,主机设备就会开始发送数据。如果是写入操作,主机发送数据;如果是读取操作,从设备发送数据。
- 非应答(NACK):如果目标设备不是预期的接收者,或者由于其他原因无法接收数据,它会在下一个时钟脉冲的开始时不拉低SDA线,表示非应答。
- 停止条件:数据传输完成后,主机设备会发送一个停止条件,这涉及到SDA和SCL线的特定电平变化,以结束数据传输。
- 多主机环境:在多主机环境中,如果有多个主机尝试同时控制总线,它们会使用仲裁机制来决定哪个主机获得控制权。仲裁是基于发送的数据位,如果两个主机尝试发送不同的位,发送0的主机会放弃控制权。
2. IIC驱动7Pin 0.96寸 OLED显示屏实例
1. 硬件修改
在驱动显示屏时,显示屏默认使用SPI协议驱动,要改为IIC协议驱动需要将硬件电路进行简单的修改,具体就是:
将背面R3电阻移动到R4的 位置
短接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 程序设计
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
`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温湿度数据获取模块*/
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的程序
//中文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 初始化模块
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
/*数字数据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屏幕全部变为黑色
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
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
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
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顶层模块
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博客