FPGA驱动OLED Verilog代码 (三)------ 顶层模块 点亮OLED

 一、代码

        顶层模块比较简单,直接实例化各个模块进行连接就好了,下载程序到板子是哪个后,现象应该是整个OLED屏被填满

代码如下:

module oled_drive(
	input clk,			//时钟信号 50MHz
	input rst_n,		//按键复位
	output oled_rst,	//oled res 复位信号
	output oled_dc,	//oled dc 0:写命令 1:写数据
	output oled_sclk,	//oled do 时钟信号
	output oled_mosi	//oled d1 数据信号
);

wire clk_1m;			//分频后的1M时钟
wire ena_write;		//spi写使能信号
wire [7:0] data;		//spi写的数据
wire init_done;		//初始化完成信号

//时钟分频模块 产生1M的时钟
clk_fenpin clk_fenpin_inst(
	.clk(clk),
	.rst_n(rst_n),
	.clk_1m(clk_1m)
);

//spi传输模块
spi_writebyte spi_writebyte_inst(
	.clk(clk_1m),
	.rst_n(rst_n),
	.ena_write(ena_write),
	.data(data),
	.sclk(oled_sclk),
	.mosi(oled_mosi),
	.write_done(write_done)
);

//oled初始化模块 产生初始化数据
oled_init oled_init_inst(
	.clk(clk_1m),
	.rst_n(rst_n),
	.write_done(write_done),
	.oled_rst(oled_rst),
	.oled_dc(oled_dc),
	.data(data),
	.ena_write(ena_write),
	.init_done(init_done)
);

endmodule

其中用到了一个时钟分频模块,代码如下:

module clk_fenpin(
	input clk,
	input rst_n,
	output reg clk_1m
);

reg    [25:0]   clk_cnt     ;        //分频计数器
//得到1Mhz分频时钟
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clk_cnt <= 5'd0;
        clk_1m  <= 1'b0;
    end 
    else if (clk_cnt < 26'd24) 
        clk_cnt <= clk_cnt + 1'b1;       
    else begin
        clk_cnt <= 5'd0;
        clk_1m  <= ~ clk_1m;
    end 
end

endmodule

        也许有人会异或为什么25的值却用了一个26位的计数器~~~

        答案就是把时钟调慢去观察数据的变化,哭泣.jpg


顶层模块测试用的testbench,可以用来观察mosi的输出

`timescale 1ns/1ns //仿真单位为1ns,精度为1ns

module oled_drive_tb();

reg clk;
reg rst_n;
wire oled_rst;
wire oled_dc;
wire oled_sclk;
wire oled_mosi;
wire oled_cs;

oled_drive oled_drive_inst(
	.clk(clk),
	.rst_n(rst_n),
	.oled_rst(oled_rst),
	.oled_dc(oled_dc),
	.oled_sclk(oled_sclk),
	.oled_mosi(oled_mosi)
);

initial begin
	#0	clk = 0;
		rst_n = 0;
	#20 rst_n = 1;
end

always #5 clk = ~clk;

endmodule

二、小结

        当所有模块都搭建完成,然后仿真数据也正确时,我以为一切都结束了,没想到刚好是噩梦的开始。使用板子实际测试时,最直观的现象就是OLED没反应,但这玩意没反应咱也不知道是啥问题。就去网上找了找大佬的代码来先看看,当然烧进去肯定是完美显示的。但是理解别人的代码还是比较困难的,我就只是拷贝了他的初始化命令,又开始测试自己的代码了。一次有一次测试不成功之后想起来用signal tap查看一下数据的输出是否和仿真的一样的,然后发现数据是一直在乱跳的,完全没逻辑可循。后面又开始去找Quartus的警告,看看有什么地方是不是写得不对(因为看到好多警告,但是没有在意,而且好久没实机操作过了)

        就发现输出的数据有一个警告,之前在HDLBits上练习的时候出现过的,而且算是比较严重的一个警告了吧。(警告:Latch 有不安全的行为

        查了很多,改了又改,还是改不对。最后看到官方的解释中说,造成这种Latch的原因是一个变量被同时赋多个值,,但我怎么看也看不出哪里还给输出数据赋值了。后面猜测是always@(*)有问题,然后就把它改了,一瞬间,,,,OLED亮了,不得不说,还是挺激动的。不过还是搞不懂为什么always@(*)就会造成这样的现象了?然后拿去仿真会发现时序非常的乱(搞不懂怎么显示出来的)

        第二天突然想起来,为什么不把状态转换和赋值的哪些分开了?状态转换用组合逻辑always@(*),而赋值都使用时序逻辑,经测试,完美解决。仿真的时序图没有紊乱,也能出结果。

        后续将会去实现OLED的动态显示。

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值