UART串口传图LCD显示----图像处理
设计介绍
首先需要准备一个txt文本,里面存储一个16进制200* 200的图片数据,通过串口调试助手使用串口传输一个200* 200图片,然后通过开发板上的480* 272LCD屏幕显示此图片(数据格式为RGB565)。本篇博客也是图像处理的基础篇,在此基础上可以做一些图像处理项目然后通过LCD屏幕观察实验效果。整体效果如下图所示,因为图片大小为200* 200而显示屏为480* 272,所以剩余部分填充为黑色。
设计思路
通过串口接收模块输出的po_flag信号高电平作为写使能,po_data信号作为写数据,往lcd显示模块中的RAMIP核中写入200*200个图片数据,然后通过po_flag信号低电平作为读使能从RAMIP核中读出数据,通过LCD屏幕显示(这里为了方便,写使能和读使能采用一个数据线的高低电平,要是不理解可以看一下RAMIP核的使用方法)。下图为整体设计流程框图。
工程生成rtl视图如下所示。
具体设计步骤
下面代码所实现的就是把一个500* 500RGB888格式图片转换为200* 200RGB332格式的图片(数据位宽为8位)然后生成TXT文本,为什么要转换成RGB332格式而不是RGB565格式的呢,因为怕麻烦哈哈,RGB332格式数据为8位,串口一字节就传输过去了,要是RGB565格式的数据为16位,需要串口传输两个字节的数据然后进行拼接。在LCDdisplay模块将串口输出的RGB332格式得8位数据转换成RGB565格式得16位数据然后传递给下一模块。
500* 500RGB888转换为200* 200RGB332代码如下(不懂可以看注释很详细哈哈)
clc;
clear;
img = imread('cat.jpg');
i = imresize(img,[200,200]); %把500*500的图片裁剪为200*200的图片
R1 = i(:,:,1);
G1 = i(:,:,2);
B1 = i(:,:,3);
R2 = R1/32 - 1 ; %把8位的R分量数据按比例转换为3位数据,以数据255为例255/32-1=6.968取整为7
G2 = G1/32 - 1 ; %把8位的G分量数据按比例转换为3位数据
B2 = B1/64 - 1 ; %把8位的B分量数据按比例转换为2位数据
b = uint8(zeros(200,200)); %产生一个大小200*200数据位宽为8位的全零矩阵b
b = bitor(bitand(bitshift(R2, 5),224),b); %十进制 224 为二进制 1110 0000
%上一条语句执行的操作如下条注释
%以R2的数据为7(二进制位111)为例 左移五位为1110_0000然后和28(二进制位1110_0000)相与然后再和0000_0000相或最后结果为1110_0000
b = bitor(bitand(bitshift(G2, 2),28),b); %十进制 28 为二进制 0001 1100
b = bitor(bitand(bitshift(B2, 0), 3),b); %十进制 3 为二进制 0000 0011
fid=fopen('data_2.txt','w+'); %打开data_2.txt文件返回句柄
fprintf(fid,'%02x ',b') ; %将图像转置行列对换(默认matlab 是1列1列打印会导致图像竖着的),向文件中写入16进制字符数据两个数据间加空格,为了串口发送做准备
figure(1)
subplot(1,3,1);imshow(img),title('原始图像'); %显示原始图像500*500*3
subplot(1,3,2);imshow(i),title('裁剪后图像'); %显示裁剪后图像200*200*3
subplot(1,3,3);imshow(b),title('修改后图像'); %显示裁剪后图像200*200*1
最后生成的TXT文本如下所示,其中就是8位的16进制图像数据。(只截取了一部分)
串口输出数据写入LCDdisplay模块的RAM中程序设计
这里就不一点点写代码了全部代码可以上资源里下载免费的哦,思路就是使用串口输出的po_flag信号的高电平作为RAM的写使能,低电平作为RAM的读使能。
写地址部分代码
//产生写地址
always @(posedge clk_50 or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
// reset
addra <= 'd0;
end
else if (pi_flag == 1'b1 && addra == 'd39999) begin
addra <= 'd0;
end
else if (pi_flag == 1'b1) begin
addra <= addra + 1'b1;
end
end
读地址部分代码
//当前像素点坐标位于图案显示区域内时,读RAM使能信号拉高
assign ram_rd_en = (pixel_xpos >= POS_X) && (pixel_xpos < POS_X + WIDTH)
&& (pixel_ypos >= POS_Y) && (pixel_ypos < POS_Y + HEIGHT)
? 1'b1 : 1'b0;
//控制读地址
always @(posedge s_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
ram_addr <= 16'd0;
end
else if(ram_rd_en) begin
if(ram_addr < TOTAL - 1'b1)
ram_addr <= ram_addr + 1'b1; //每次读ROM操作后,读地址加1
else
ram_addr <= 1'b0; //读到ROM末地址后,从首地址重新开始读操作
end
else
ram_addr <= ram_addr;
end
RGB332数据换为RGB565代码
assign doutb_b = { doutb[7:5],2'b00,doutb[4:2],3'b000,doutb[1:0],3'b000} ;
把8位doutb的RGB三个分量的数据分别对应到16位的doutb_b上不够的位数补零
虽然这种方法还是有一些缺陷但是比价简单后面会接着更新比较严谨的转换方法
RGB565图像数据输出
//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always @(posedge s_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
pixel_data <= 16'd0;
else begin
if((pixel_xpos >= 10'd140) && (pixel_xpos <= 10'd339) && (pixel_ypos >= 10'd36) && (pixel_ypos <= 10'd235)) //显示图片区域
pixel_data <= doutb_b;
else
pixel_data <= BLACK;
end
end
这里需要注意RAM读出数据会落后地址一拍需要处理好从RAM中读出数据的问题。
上板验证
将data_2.txt文件中数据拷贝到串口调试助手然后发送,如下图所示,点击发送。
等一会观察LCD显示屏上就会出现一个200* 200的图片了如下图所示。哈哈 代码可以私信我啊。