驱动接口SPI,用FPGA做一个小东西,要显示设备状态,于是就买了一个0.96的oled显示屏,没想到用FPGA驱动它还很麻烦,淘宝卖家只有单片机的示例程序,就自己用一个下午写了个FPGA的驱动程序,最后可以驱动0.96OLED显示,之前搞过ACM,所以代码写得不是很符合verylog规范,可能看懂需要一定的语言基础,我也不知道如何详细的解释,有问题在下面留言吧
(想用我的代码请注明出处)
这个是主程序中的接口:
module top(
input clk,
input reset,
output wire OLED_VCC, //电源
output wire OLED_D0clk, //时钟
output wire OLED_D1, //数据
output wire OLED_RES, //复位
output wire OLED_DC, //命令/数据
output wire OLED_CS //片选接地
);
///OLED模块
assign OLED_VCC=1; //
assign OLED_CS=0;
oled U4(
.clk(clk),
.reset(reset),
.key_num(key_num),
.OLED_D0clk(OLED_D0clk), //时钟
.OLED_D1(OLED_D1), //数据
.OLED_RES(OLED_RES), //复位
.OLED_DC(OLED_DC) //命令/数据
);
这个是OLED上电配置和显示控制模块,
`timescale 1ns / 1ps
//
//
//
module oled(
input clk,
input reset,
input [7:0]key_num,
output reg OLED_D0clk, //时钟
output reg OLED_D1, //数据
output reg OLED_RES, //复位
output reg OLED_DC //命令/数据
);
reg [7:0]data_tem;
always@(posedge clk)begin
if(reset==0) data_tem<=8'h55;
else begin
if(key_num>0) data_tem<=key_num;
end
end
///写8为数据或命令 30个clk
reg [7:0]data_write;
reg flag_write;
reg [5:0]count_write;
always@(posedge clk)begin
if(flag_write==1 && count_write==0)begin
count_write<=1;
end
if(count_write>=1)begin
count_write<=count_write+1;
//if(count_write==2) OLED_DC<=0;
if(count_write==3) OLED_D0clk<=0;
if(count_write==4) OLED_D1<=data_write[7];
if(count_write==5) OLED_D0clk<=1;
if(count_write==6) OLED_D0clk<=0;
if(count_write==7) OLED_D1<=data_write[6];
if(count_write==8) OLED_D0clk<=1;
if(count_write==9) OLED_D0clk<=0;
if(count_write==10) OLED_D1<=data_write[5];
if(count_write==11) OLED_D0clk<=1;
if(count_write==12) OLED_D0clk<=0;
if(count_write==13) OLED_D1<=data_write[4];
if(count_write==14) OLED_D0clk<=1;
if(count_write==15) OLED_D0clk<=0;
if(count_write==16) OLED_D1<=data_write[3];
if(count_write==17) OLED_D0clk<=1;
if(count_write==18) OLED_D0clk<=0;
if(count_write==19) OLED_D1<=data_write[2];
if(count_write==20) OLED_D0clk<=1;
if(count_write==21) OLED_D0clk<=0;
if(count_write==22) OLED_D1<=data_write[1];
if(count_write==23) OLED_D0clk<=1;
if(count_write==24) OLED_D0clk<=0;
if(count_write==25) OLED_D1<=data_write[0];
if(count_write==26) OLED_D0clk<=1;
if(count_write==27) count_write<=0;
end
end
reg flag_initial;
reg [19:0]count_initial;
reg [15:0]count_play;
reg [2:0] count_page;
always@(posedge clk)begin
if(reset==0 && flag_initial==0) begin
flag_initial<=1;count_initial<=0;flag_write<=0;count_play<=0;
end
else if(flag_initial==1)begin
count_initial<=count_initial+1;
if(flag_write==1) flag_write<=0;
if(count_initial==100) OLED_RES<=0;
if(count_initial==500000) OLED_RES<=1;
if(count_initial==600000) OLED_DC<=0;//控制
if(count_initial==700000) begin flag_write<=1;data_write<=8'hAE;end// transfer_command(0xae); //关显示
if(count_initial==700030) begin flag_write<=1;data_write<=8'hD5;end// transfer_command(0xd5); //晶振频率
if(count_initial==700060) begin flag_write<=1;data_write<=8'h80;end// transfer_command(0x80);
if(count_initial==700090) begin flag_write<=1;data_write<=8'hA8;end// transfer_command(0xa8); //duty设置
if(count_initial==700120) begin flag_write<=1;data_write<=8'h3F;end// transfer_command(0x3f); //duty=1/64
if(count_initial==700150) begin flag_write<=1;data_write<=8'hD3;end// transfer_command(0xd3); //显示偏移
if(count_initial==700180) begin flag_write<=1;data_write<=8'h00;end// transfer_command(0x00);
if(count_initial==700210) begin flag_write<=1;data_write<=8'h40;end// transfer_command(0x40); //起始行
if(count_initial==700240) begin flag_write<=1;data_write<=8'h8D;end// transfer_command(0x8d); //升压允许
if(count_initial==700270) begin flag_write<=1;data_write<=8'h14;end// transfer_command(0x14);
if(count_initial==700300) begin flag_write<=1;data_write<=8'h20;end// transfer_command(0x20); //page address mode
if(count_initial==700330) begin flag_write<=1;data_write<=8'h02;end// transfer_command(0x02);
if(count_initial==700360) begin flag_write<=1;data_write<=8'hC8;end// transfer_command(0xc8); //行扫描顺序:从上到下 //c1
if(count_initial==700390) begin flag_write<=1;data_write<=8'hA1;end// transfer_command(0xa1); //列扫描顺序:从左到右 //a0
if(count_initial==700420) begin flag_write<=1;data_write<=8'hDA;end// transfer_command(0xda); //sequential configuration
if(count_initial==700450) begin flag_write<=1;data_write<=8'h12;end// transfer_command(0x12);
if(count_initial==700480) begin flag_write<=1;data_write<=8'h81;end// transfer_command(0x81); //微调对比度,本指令的0x81不要改动,改下面的值
if(count_initial==700510) begin flag_write<=1;data_write<=8'hCF;end// transfer_command(0xcf); //微调对比度的值,可设置范围0x00~0xff
if(count_initial==700540) begin flag_write<=1;data_write<=8'hD9;end// transfer_command(0xd9); //Set Pre-Charge Period
if(count_initial==700570) begin flag_write<=1;data_write<=8'hF1;end// transfer_command(0xf1);
if(count_initial==700600) begin flag_write<=1;data_write<=8'hDB;end// transfer_command(0xdb); //Set VCOMH Deselect Level
if(count_initial==700630) begin flag_write<=1;data_write<=8'h40;end// transfer_command(0x40);
if(count_initial==700660) begin flag_write<=1;data_write<=8'hAF;end// transfer_command(0xaf); //开显示
if(count_initial==720000) begin flag_initial<=0;end
end
else begin
count_play<=count_play+1;
if(flag_write==1) flag_write<=0;
if(count_play==9) begin OLED_DC<=0;end//控制
if(count_play==10) begin flag_write<=1;data_write<=8'hB0+count_page[2:0];end//0~7设置页地址。每页是8行。一个画面的64行被分成8个页。
if(count_play==40) begin flag_write<=1;data_write<=8'h10;end//设置列地址的高4位8'h1_ 0~127
if(count_play==70) begin flag_write<=1;data_write<=8'h00;end//设置列地址的低4位8'h0_ 0~127
if(count_play==100)begin OLED_DC<=1;end//数据
if(count_play>=101 && count_play<=4100 ) begin flag_write<=1;data_write<=data_tem; end//
if(count_play==4200) begin count_page<=count_page+1; count_play<=0; end
end
end
endmodule