本帖最后由 捷波 于 2018-8-21 16:24 编辑
最近用小梅哥FPGA开发板制作了一款红外遥控式VGA测试图卡,也可称为VGA测试信号发生器。它可以用来检测显示器在亮度、对比度、色彩还原、清晰度等方面的性能,在测试时可以用红外遥控器来切换不同的测试画面,还是相当的方便实用。实际使用效果如视频所示,画面看着是不是还挺专业的,之前用过类似视频信号发生器的同学,对这些图谱应该感觉很亲切吧!
下面我就来介绍一下,这款测试图卡是如何用小梅哥FPGA开发板实现的。首先你要准备以下一些材料:
1. 小梅哥FPGA开发板套件。本来就是基于它来制作的嘛!当然必不可少了。有能力的朋友也可以选择类似的FPGA板子,不过要是没有配套的VGA接口模块的话就要另想办法了。
2. Quartues II v13.0,这里使用的是小梅哥官方提供的版本。为避免出现因版本不同而带来的一些不可预知的问题,建议采用官方推荐的这个版本。当然使用其它版本也未尝不可。
3. 带VGA 15针接口的显示器。这个应该还是比较常见的,家里没有台式机显示器的,可以考虑用你家的平板电视,VGA接口基本都是标配。
下面就开始搬砖了,首先下载小梅哥提供的VGA控制器设计与验证例程——VGA_CTRL,文件下载地址:http://pan.baidu.com/s/1qYBHiFU。下载解压后,打开Quartues II v13.0,载入VGA_CTRL项目文件。小梅哥提供的例程文件归档还是很有序的,工程文件,源代码,测试代码都分开目录存放。
将工程直接编译,并下载到开发板后,在VGA显示器上就可以看到图示的彩条图像。看上去这和要实现的VGA测试卡比较接近了,接下来只需要在这个项目中增加红外遥控接收处理,并根据遥控能够信号输出特定的测试图即可。
红外遥控接收部分可以拷贝小梅哥精品例程calculator中的ir_decode.v和ir_code_lut.v,并将这两个文件添加到VGA_CTRL项目中。
在Top_Level Entity文件VGA_CTRL_test.v中添加有关红外处理模块的例化代码及相关变量。
接着还需要添加遥控接收用到的引脚,打开菜单Assignments -> Pin Planner,按下图所示设置即可。
至此,已经为项目添加好了红外遥控接收解码的功能。下面需要做的是添加键码处理程序,根据收到的红外键码,对应产生不同的测试图像。按键事件的处理通过case(user_code)完成,下面这段代码是处理接收到“0”~“7”键后,将disp_data赋值,该值对应的白、黄、青、绿、粉、红、蓝纯色信号。
彩条信号代码及输出到显示器的效果。
多波群信号代码及输出到显示器的效果。
格子线信号代码及输出到显示器的效果。
其它测试图显示效果。
相关Verilog文件:
module VGA_CTRL_test(
Clk, //50MHZ时钟
Rst_n,
VGA_RGB,//TFT数据输出
VGA_HS, //TFT行同步信号
VGA_VS, //TFT场同步信号
iIR //Ir
);
input Clk;
input Rst_n;
output VGA_RGB;
output VGA_HS;
output VGA_VS;
reg disp_data;
wire hcount;
wire vcount;
wire Clk25M;
// add IR
input iIR;//红外键盘输入
wire ir_Get_Flag;
wire user_code;
wire op_flag;
wire num_flag;
wire irData;
vga_test_pll vga_test_pll(
.inclk0(Clk),
.c0(Clk25M)
);
VGA_CTRL VGA_CTRL(
.Clk25M(Clk25M), //系统输入时钟25MHZ
.Rst_n(Rst_n),
.data_in(disp_data), //待显示数据
.hcount(hcount), //VGA行扫描计数器
.vcount(vcount), //VGA场扫描计数器
.VGA_RGB(VGA_RGB), //VGA数据输出
.VGA_HS(VGA_HS), //VGA行同步信号
.VGA_VS(VGA_VS) //VGA场同步信号
);
ir_decode ir_decode
(
.Clk50M(Clk),
.Rst_n(Rst_n),
.iIR(iIR),
.Get_Flag(ir_Get_Flag),
.irData(irData),
.irAddr()
);
ir_code_lut ir_code_lut(
.ir_data(irData), //红外键值
.user_code(user_code), //译码得到的用户码(0~9,+ - * /)
.num_flag(num_flag), //用户码为数字标志
.op_flag(op_flag) //用户码为操作(加减乘除=标志)
);
//定义颜色编码
localparam
BLACK = 8'h00, //黑色
BLUE = 8'h03, //蓝色
RED = 8'hE0, //红色
PURPPLE = 8'hE3, //紫色
GREEN = 8'h1C, //绿色
CYAN = 8'h1F, //青色
YELLOW = 8'hFC, //黄色
WHITE = 8'hFF, //白色
GRAY5 = 8'hDB, //GRAY5
GRAY4 = 8'hB7, //GRAY4
GRAY3 = 8'h92, //GRAY3
GRAY2 = 8'h6E, //GRAY2
GRAY1 = 8'h49, //GRAY1
GRAY0 = 8'h24; //GRAY0
always@(*)
case(user_code)
4'h0: // Key 0 WHITE
disp_data = WHITE;
4'h1: // Key 1 YELLOW
disp_data = YELLOW;
4'h2: // Key 2 CYAN
disp_data = CYAN;
4'h3: // Key 3 GREEN
disp_data = GREEN;
4'h4: // Key 4 PURPPLE
disp_data = PURPPLE;
4'h5: // Key 5 RED
disp_data = RED;
4'h6: // Key 6 BLUE
disp_data = BLUE;
4'h7: // Key 7 Vertical Color Bar
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
4'h8: // Key 8 Vertical Multiburst
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
4'h9: // Key 9 Half Color Bar and Half Multiburst
if(vcount >= 240)begin
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
end
else begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
end
4'ha: // Key A Vertical Color_Gray_Multiburst Bar
if(vcount >= 320)begin
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
end
else begin
if(vcount >= 160)begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = GRAY5;
3'h2:
disp_data = GRAY4;
3'h3:
disp_data = GRAY3;
3'h4:
disp_data = GRAY2;
3'h5:
disp_data = GRAY1;
3'h6:
disp_data = GRAY0;
3'h7:
disp_data = BLACK;
endcase
end
else begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
end
end
4'hb: // Key B Herizontal half Color Bar
if(hcount >= 0 && hcount < 320)begin
if(vcount >= 0 && vcount < 120)
disp_data = WHITE;
else if(vcount >= 120 && vcount < 240)
disp_data = YELLOW;
else if(vcount >= 240 && vcount < 360)
disp_data = CYAN;
else
disp_data = GREEN;
end
else begin
if(vcount >= 0 && vcount < 120)
disp_data = PURPPLE;
else if(vcount >= 120 && vcount < 240)
disp_data = RED;
else if(vcount >= 240 && vcount < 360)
disp_data = BLUE;
else
disp_data = BLACK;
end
4'hc: // Key C Herizontal Color Bar
case(vcount/60)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
4'hd: // Key D Cross Hatch
if((vcount/40)*40 < vcount && vcount < (vcount/40)*40 + 3)begin
disp_data = WHITE;
end
else begin
if((hcount/40)*40 < hcount && hcount < (hcount/40)*40 + 3)
disp_data = WHITE;
else
disp_data = BLACK;
end
4'hf: // Key E Circle
if(((320-hcount)*(320-hcount) + (240-vcount)*(240-vcount)) <= 160000)
disp_data = WHITE;
else
disp_data = BLACK;
default: // default Black
disp_data = BLACK;
endcase
endmodule
本帖最后由 捷波 于 2018-8-21 16:24 编辑
最近用小梅哥FPGA开发板制作了一款红外遥控式VGA测试图卡,也可称为VGA测试信号发生器。它可以用来检测显示器在亮度、对比度、色彩还原、清晰度等方面的性能,在测试时可以用红外遥控器来切换不同的测试画面,还是相当的方便实用。实际使用效果如视频所示,画面看着是不是还挺专业的,之前用过类似视频信号发生器的同学,对这些图谱应该感觉很亲切吧!
下面我就来介绍一下,这款测试图卡是如何用小梅哥FPGA开发板实现的。首先你要准备以下一些材料:
1. 小梅哥FPGA开发板套件。本来就是基于它来制作的嘛!当然必不可少了。有能力的朋友也可以选择类似的FPGA板子,不过要是没有配套的VGA接口模块的话就要另想办法了。
2. Quartues II v13.0,这里使用的是小梅哥官方提供的版本。为避免出现因版本不同而带来的一些不可预知的问题,建议采用官方推荐的这个版本。当然使用其它版本也未尝不可。
3. 带VGA 15针接口的显示器。这个应该还是比较常见的,家里没有台式机显示器的,可以考虑用你家的平板电视,VGA接口基本都是标配。
下面就开始搬砖了,首先下载小梅哥提供的VGA控制器设计与验证例程——VGA_CTRL,文件下载地址:http://pan.baidu.com/s/1qYBHiFU。下载解压后,打开Quartues II v13.0,载入VGA_CTRL项目文件。小梅哥提供的例程文件归档还是很有序的,工程文件,源代码,测试代码都分开目录存放。
将工程直接编译,并下载到开发板后,在VGA显示器上就可以看到图示的彩条图像。看上去这和要实现的VGA测试卡比较接近了,接下来只需要在这个项目中增加红外遥控接收处理,并根据遥控能够信号输出特定的测试图即可。
红外遥控接收部分可以拷贝小梅哥精品例程calculator中的ir_decode.v和ir_code_lut.v,并将这两个文件添加到VGA_CTRL项目中。
在Top_Level Entity文件VGA_CTRL_test.v中添加有关红外处理模块的例化代码及相关变量。
接着还需要添加遥控接收用到的引脚,打开菜单Assignments -> Pin Planner,按下图所示设置即可。
至此,已经为项目添加好了红外遥控接收解码的功能。下面需要做的是添加键码处理程序,根据收到的红外键码,对应产生不同的测试图像。按键事件的处理通过case(user_code)完成,下面这段代码是处理接收到“0”~“7”键后,将disp_data赋值,该值对应的白、黄、青、绿、粉、红、蓝纯色信号。
彩条信号代码及输出到显示器的效果。
多波群信号代码及输出到显示器的效果。
格子线信号代码及输出到显示器的效果。
其它测试图显示效果。
相关Verilog文件:
module VGA_CTRL_test(
Clk, //50MHZ时钟
Rst_n,
VGA_RGB,//TFT数据输出
VGA_HS, //TFT行同步信号
VGA_VS, //TFT场同步信号
iIR //Ir
);
input Clk;
input Rst_n;
output VGA_RGB;
output VGA_HS;
output VGA_VS;
reg disp_data;
wire hcount;
wire vcount;
wire Clk25M;
// add IR
input iIR;//红外键盘输入
wire ir_Get_Flag;
wire user_code;
wire op_flag;
wire num_flag;
wire irData;
vga_test_pll vga_test_pll(
.inclk0(Clk),
.c0(Clk25M)
);
VGA_CTRL VGA_CTRL(
.Clk25M(Clk25M), //系统输入时钟25MHZ
.Rst_n(Rst_n),
.data_in(disp_data), //待显示数据
.hcount(hcount), //VGA行扫描计数器
.vcount(vcount), //VGA场扫描计数器
.VGA_RGB(VGA_RGB), //VGA数据输出
.VGA_HS(VGA_HS), //VGA行同步信号
.VGA_VS(VGA_VS) //VGA场同步信号
);
ir_decode ir_decode
(
.Clk50M(Clk),
.Rst_n(Rst_n),
.iIR(iIR),
.Get_Flag(ir_Get_Flag),
.irData(irData),
.irAddr()
);
ir_code_lut ir_code_lut(
.ir_data(irData), //红外键值
.user_code(user_code), //译码得到的用户码(0~9,+ - * /)
.num_flag(num_flag), //用户码为数字标志
.op_flag(op_flag) //用户码为操作(加减乘除=标志)
);
//定义颜色编码
localparam
BLACK = 8'h00, //黑色
BLUE = 8'h03, //蓝色
RED = 8'hE0, //红色
PURPPLE = 8'hE3, //紫色
GREEN = 8'h1C, //绿色
CYAN = 8'h1F, //青色
YELLOW = 8'hFC, //黄色
WHITE = 8'hFF, //白色
GRAY5 = 8'hDB, //GRAY5
GRAY4 = 8'hB7, //GRAY4
GRAY3 = 8'h92, //GRAY3
GRAY2 = 8'h6E, //GRAY2
GRAY1 = 8'h49, //GRAY1
GRAY0 = 8'h24; //GRAY0
always@(*)
case(user_code)
4'h0: // Key 0 WHITE
disp_data = WHITE;
4'h1: // Key 1 YELLOW
disp_data = YELLOW;
4'h2: // Key 2 CYAN
disp_data = CYAN;
4'h3: // Key 3 GREEN
disp_data = GREEN;
4'h4: // Key 4 PURPPLE
disp_data = PURPPLE;
4'h5: // Key 5 RED
disp_data = RED;
4'h6: // Key 6 BLUE
disp_data = BLUE;
4'h7: // Key 7 Vertical Color Bar
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
4'h8: // Key 8 Vertical Multiburst
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
4'h9: // Key 9 Half Color Bar and Half Multiburst
if(vcount >= 240)begin
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
end
else begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
end
4'ha: // Key A Vertical Color_Gray_Multiburst Bar
if(vcount >= 320)begin
case(hcount/80)
3'h0:
if(hcount%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h1:
if((hcount/2)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h2:
if((hcount/3)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h3:
if((hcount/4)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h4:
if((hcount/5)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h5:
if((hcount/6)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h6:
if((hcount/7)%2)
disp_data = WHITE;
else
disp_data = BLACK;
3'h7:
if((hcount/8)%2)
disp_data = WHITE;
else
disp_data = BLACK;
endcase
end
else begin
if(vcount >= 160)begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = GRAY5;
3'h2:
disp_data = GRAY4;
3'h3:
disp_data = GRAY3;
3'h4:
disp_data = GRAY2;
3'h5:
disp_data = GRAY1;
3'h6:
disp_data = GRAY0;
3'h7:
disp_data = BLACK;
endcase
end
else begin
case(hcount/80)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
end
end
4'hb: // Key B Herizontal half Color Bar
if(hcount >= 0 && hcount < 320)begin
if(vcount >= 0 && vcount < 120)
disp_data = WHITE;
else if(vcount >= 120 && vcount < 240)
disp_data = YELLOW;
else if(vcount >= 240 && vcount < 360)
disp_data = CYAN;
else
disp_data = GREEN;
end
else begin
if(vcount >= 0 && vcount < 120)
disp_data = PURPPLE;
else if(vcount >= 120 && vcount < 240)
disp_data = RED;
else if(vcount >= 240 && vcount < 360)
disp_data = BLUE;
else
disp_data = BLACK;
end
4'hc: // Key C Herizontal Color Bar
case(vcount/60)
3'h0:
disp_data = WHITE;
3'h1:
disp_data = YELLOW;
3'h2:
disp_data = CYAN;
3'h3:
disp_data = GREEN;
3'h4:
disp_data = PURPPLE;
3'h5:
disp_data = RED;
3'h6:
disp_data = BLUE;
3'h7:
disp_data = BLACK;
endcase
4'hd: // Key D Cross Hatch
if((vcount/40)*40 < vcount && vcount < (vcount/40)*40 + 3)begin
disp_data = WHITE;
end
else begin
if((hcount/40)*40 < hcount && hcount < (hcount/40)*40 + 3)
disp_data = WHITE;
else
disp_data = BLACK;
end
4'hf: // Key E Circle
if(((320-hcount)*(320-hcount) + (240-vcount)*(240-vcount)) <= 160000)
disp_data = WHITE;
else
disp_data = BLACK;
default: // default Black
disp_data = BLACK;
endcase
endmodule