FPGA + WS2812采灯控制

文章目录

  • 一、WS2812C-2020-V1
    • 1、产品概述
    • 2、引出端排列及功能
    • 3、数据传输时间
    • 4、数据传输方法
  • 二、使用WS2812C显示图片
    • 1、静态显示
    • 2、动态显示

一、WS2812C-2020-V1

1、产品概述

WS2812C-2020-V1是一个集控制电路与发光电路于一体的智能外控LED光源;其外型采用最新的molding封
装工艺,将IC与发光芯片封装在一个2020的封装尺寸中,每个元件即为一个像素点;像素点内部包含了智能数字
接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素
点光的颜色高度一致。

主要特点:
● IC控制电路与LED点光源共用一个电源。
● 每个通道工作电流5mA.
● 控制电路与RGB芯片集成在一个2020封装的元器件中,构成一个完整的外控像素点。
● 内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加。
● 内置上电复位和掉电复位电路。
● 每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示。
● 端口扫描频率2KHz/s。
● 串行级联接口,能通过一根信号线完成数据的接收与解码。
● 任意两点传输距离在不超过5米时无需增加任何电路。
● 当刷新速率30帧/秒时,级联数不小于1024点。
● 数据发送速度可达800Kbps。
● 光的颜色高度一致,性价比高。

2、引出端排列及功能

在这里插入图片描述

序号符号管脚名功能描述
1DO数据输出控制数据信号输出
2GND信号接地和电源接地
3DI数据输入控制数据信号输入
4VDD电源供电管脚

3、数据传输时间

在这里插入图片描述
时序波形图
在这里插入图片描述

4、数据传输方法

在这里插入图片描述
注:其中 D1 为 MCU 端发送的数据,D2、D3、D4 为级联电路自动整形转发的数据。
24bit 数据结:
在这里插入图片描述

二、使用WS2812C显示图片

1、静态显示

显示F为例:
在这里插入图片描述
首先将图片信息存入rom中,通过读出rom中的数据,将数据中的值通过高低电平的脉宽调制,显示至WS2812C上。
显示模块:

module ws2812b_driver (
    input       wire        clk         ,
    input       wire        rst_n       ,
    input       wire [23:0] data_in     ,//输入的RGB
    input       wire        data_vld    ,

    output      wire        ready       ,
    output      wire        pwm                 //输出波形
);


localparam      IDLE = 3'b001,
                RST  = 3'b010,
                DATA = 3'b100;

localparam      T0H = 300/20,
                T0L = 900/20,
                T1H = 600/20,
                T1L = 600/20;

parameter MAX_RES = 15'd20_000;

reg [2:0]       state_c;//现态
reg [2:0]       state_n;//次态


wire            idle_rst    ;//IDLE -> RST
wire            rst_data    ;//RST -> DATA
wire            data_idle   ;//DATA -> IDLE


wire [23:0]      fifo_wr_data;
wire [23:0]      fifo_rd_data;
wire             fifo_wr_req;
wire             fifo_rd_req;
wire             fifo_empty;
wire             fifo_full;

reg			[14:0]	cnt_res	   	;
wire				add_cnt_res	;
wire				end_cnt_res	;


reg			[5:0]	cnt_time	   	;
wire				add_cnt_time	;
wire				end_cnt_time	;


reg			[4:0]	cnt_bit	   	;
wire				add_cnt_bit	;
wire				end_cnt_bit	;

reg			[6:0]	cnt_num	   	;
wire				add_cnt_num	;
wire				end_cnt_num	;


reg               pwm_r;

//****************************************************************
//--                状态机
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n ;
    end
end


always @( *) begin
    case (state_c) 
        IDLE : begin
            if(idle_rst) begin
                state_n = RST;
            end
            else begin
                state_n = state_c;
            end
        end

        RST : begin
            if(rst_data) begin
                state_n = DATA;
            end
            else begin
                state_n = state_c;
            end
        end

        DATA : begin
            if(data_idle) begin
                state_n = IDLE;
            end
            else begin
                state_n = state_c;
            end
        end
    endcase
end

assign  idle_rst   = state_c == IDLE && data_vld; 
assign  rst_data   = state_c == RST  && end_cnt_res;
assign  data_idle  = state_c == DATA  && end_cnt_num;


//****************************************************************
//--fifo
//****************************************************************
fifo	fifo_inst (
	.aclr ( ~rst_n ),
	.clock ( clk ),
	.data ( fifo_wr_data ),//GRB
	.rdreq ( fifo_rd_req ),
	.wrreq ( fifo_wr_req ),//GRB
	.empty ( fifo_empty ),
	.full ( fifo_full ),
	.q ( fifo_rd_data ),
	.usedw ( )
	);

assign fifo_wr_data = {data_in[15:8],data_in[23:16],data_in[7:0]};
assign fifo_wr_req = data_vld && ~fifo_full;

assign fifo_rd_req = end_cnt_bit && ~fifo_empty;
//****************************************************************
//--                复位时间
//****************************************************************


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_res <= 'd0;
    end 
    else if(add_cnt_res)begin 
        if(end_cnt_res)begin 
            cnt_res <= 'd0;
        end
        else begin 
            cnt_res <= cnt_res + 1'b1;
        end 
    end
end 

assign add_cnt_res = state_c == RST;
assign end_cnt_res = add_cnt_res && cnt_res == MAX_RES - 1;

//****************************************************************
//--                数据传输时间
//****************************************************************

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_time <= 'd0;
    end 
    else if(add_cnt_time)begin 
        if(end_cnt_time)begin 
            cnt_time <= 'd0;
        end
        else begin 
            cnt_time <= cnt_time + 1'b1;
        end 
    end
end 

assign add_cnt_time = state_c == DATA;
assign end_cnt_time = add_cnt_time && cnt_time == 1200/20 - 1;



always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_bit <= 'd0;
    end 
    else if(add_cnt_bit)begin 
        if(end_cnt_bit)begin 
            cnt_bit <= 'd0;
        end
        else begin 
            cnt_bit <= cnt_bit + 1'b1;
        end 
    end
end 

assign add_cnt_bit = end_cnt_time;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 24 - 1;



always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_num <= 'd0;
    end 
    else if(add_cnt_num)begin 
        if(end_cnt_num)begin 
            cnt_num <= 'd0;
        end
        else begin 
            cnt_num <= cnt_num + 1'b1;
        end 
    end
end 

assign add_cnt_num = end_cnt_bit;
assign end_cnt_num = add_cnt_num && cnt_num == 64 - 1;

//****************************************************************
//--            pwm输出
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        pwm_r <= 0;
    end
    else begin
        case (state_c)
            IDLE : begin
                pwm_r <= 0;
            end

            RST : begin
                pwm_r <= 0;
            end

            DATA : begin
                if(fifo_rd_data[23-cnt_bit] == 0) begin
                    if(cnt_time < T0H)begin
                        pwm_r <= 1;
                    end
                    else begin
                        pwm_r <= 0;
                    end
                end
                else if(fifo_rd_data[23-cnt_bit] == 1) begin
                    if(cnt_time < T1H)begin
                        pwm_r <= 1;
                    end
                    else begin
                        pwm_r <= 0;
                    end
                end
            end

            default  : pwm_r <= 0;
                
        endcase
    end
end

assign pwm = pwm_r;
assign ready = state_c == IDLE;

endmodule //led_control

数据控制模块:

/*
 * @Description: 显示图片
 * @Author: Fu Yu
 * @Date: 2023-08-14 10:04:45
 * @LastEditTime: 2023-08-14 15:32:59
 * @LastEditors: Fu Yu
 */

module ws2812_control(
    input               clk             ,
    input               rst_n           ,
    output     [23:0]   pix_data        ,
    output              pix_data_vld    ,
    input               ready                   //可以接收图像数据了
);

    parameter   IDLE    =   0,
                DATA     =   1,
                DONE     =   2;

    reg     [2:0]   state   ;

    reg	[5:0] cnt_x;
    wire		  add_x_cnt,end_x_cnt;	

        reg	[4:0] cnt_y;
    wire		  add_y_cnt,end_y_cnt;	

localparam	RED     =   24'hFF0000,   //红色
            ORANGE  =   24'hFF8000,   //橙色
            YELLOW  =   24'hFFFF00,   //黄色
            GREEN   =   24'h00FF00,   //绿色
            CYAN    =   24'h00FFFF,   //青色
            BLUE    =   24'h0000FF,   //蓝色
            PURPPLE =   24'h8000FF,   //紫色
            BLACK   =   24'h000000,   //黑色
            WHITE   =   24'hFFFFFF,   //白色
            GRAY    =   24'hC0C0C0;	  //灰色


wire        rom_rd_req      ;
wire        rom_rd_data_vld ;
reg         rom_rd_req1     ;
reg         rom_rd_req2     ;
/**************************************************************
                            状态机
**************************************************************/
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            state <= IDLE;
        else case(state)
                IDLE		:	if(ready)
                                    state <=DATA;
                DATA		:	if(end_y_cnt)
                                    state <=DONE;
                default :	state <= IDLE;
        endcase

/**************************************************************
                        图像数据个数计数器
**************************************************************/       
    always@(posedge clk or negedge rst_n)	
        if(!rst_n)								
            cnt_x <= 'd0;						
        else    if(add_x_cnt) begin				
            if(end_x_cnt)						
                cnt_x <= 'd0;  				
            else									
                cnt_x <= cnt_x + 1'b1;		
        end											
    assign add_x_cnt = state == DATA;
    assign end_x_cnt = add_x_cnt && cnt_x == 8 - 1;


    always@(posedge clk or negedge rst_n)	
        if(!rst_n)								
            cnt_y <= 'd0;						
        else    if(add_y_cnt) begin				
            if(end_y_cnt)						
                cnt_y <= 'd0;  				
            else									
                cnt_y <= cnt_y + 1'b1;		
        end											
    assign add_y_cnt = end_x_cnt;
    assign end_y_cnt = add_y_cnt && cnt_y == 8 - 1;

//    assign pix_data_vld = add_x_cnt;

    // always@(*)
    //     case(cnt_y)
    //         0       :   pix_data = RED      ;
    //         1       :   pix_data = ORANGE   ;
    //         2       :   pix_data = YELLOW   ;
    //         3       :   pix_data = GREEN    ;
    //         4       :   pix_data = CYAN     ;
    //         5       :   pix_data = BLUE     ;
    //         6       :   pix_data = PURPPLE  ;
    //         7       :   pix_data = GRAY     ;
    //         default :   pix_data = RED      ;
    //     endcase

rom	rom_inst (
	.aclr       ( ~rst_n ),
	.address    ( cnt_x + cnt_y*8 ),
	.clock      ( clk ),
	.rden       (  rom_rd_req),
	.q          ( pix_data)
	);



assign rom_rd_req = state == DATA;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rom_rd_req1 <= 0 ;
        rom_rd_req2 <= 0 ;
    end
    else begin
        rom_rd_req1 <= rom_rd_req ;
        rom_rd_req2 <= rom_rd_req1 ;
    end
end

assign pix_data_vld = rom_rd_req2;


endmodule

2、动态显示

动态显示图片时,只需要改变数据控制模块,以及所需要显示的数据图片,

/*
 * @Description: 动态显示图片
 * @Author: Fu Yu
 * @Date: 2023-08-14 15:34:55
 * @LastEditTime: 2023-08-14 17:21:36
 * @LastEditors: Fu Yu
 */

module ws2812_control_dynamic(
    input               clk             ,
    input               rst_n           ,
    output     [23:0]   pix_data        ,
    output              pix_data_vld    ,
    input               ready                   //可以接收图像数据了
);

    parameter   IDLE     =   0 ,
                DATA     =   1 ,
                DELAY    =   2 ,
                DONE     =   3 ;

    reg     [2:0]   state   ;

    reg	[5:0] cnt_x;
    wire		  add_x_cnt,end_x_cnt;	

        reg	[4:0] cnt_y;
    wire		  add_y_cnt,end_y_cnt;	

    reg			[24:0]	cnt_500ms	   	;
wire				add_cnt_500ms	;
wire				end_cnt_500ms	;

parameter MAX_500MS = 25'd24_999_999;

reg			[5:0]	cnt_offest	   	;
wire				add_cnt_offest	;
wire				end_cnt_offest	;

wire  [4:0] real_row;//0~31

wire        rom_rd_req      ;
wire        rom_rd_data_vld ;
reg         rom_rd_req1     ;
reg         rom_rd_req2     ;
/**************************************************************
                            状态机
**************************************************************/
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            state <= IDLE;
        else case(state)
                IDLE		:	if(ready)
                                    state <=DATA;
                DATA		:	if(end_y_cnt)
                                    state <=DELAY;
                DELAY       :   if(end_cnt_500ms)
                                    state <= IDLE;
                default :	state <= IDLE;
        endcase

//****************************************************************
//--500ms
//****************************************************************

always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_500ms <= 'd0;
    end 
    else if(add_cnt_500ms)begin 
        if(end_cnt_500ms)begin 
            cnt_500ms <= 'd0;
        end
        else begin 
            cnt_500ms <= cnt_500ms + 1'b1;
        end 
    end
end 

assign add_cnt_500ms = state == DELAY;
assign end_cnt_500ms = add_cnt_500ms && cnt_500ms == MAX_500MS;



/**************************************************************
                        图像数据个数计数器
**************************************************************/       
    always@(posedge clk or negedge rst_n)	
        if(!rst_n)								
            cnt_x <= 'd0;						
        else    if(add_x_cnt) begin				
            if(end_x_cnt)						
                cnt_x <= 'd0;  				
            else									
                cnt_x <= cnt_x + 1'b1;		
        end											
    assign add_x_cnt = state == DATA;
    assign end_x_cnt = add_x_cnt && cnt_x == 8 - 1;


    always@(posedge clk or negedge rst_n)	
        if(!rst_n)								
            cnt_y <= 'd0;						
        else    if(add_y_cnt) begin				
            if(end_y_cnt)						
                cnt_y <= 'd0;  				
            else									
                cnt_y <= cnt_y + 1'b1;		
        end											
    assign add_y_cnt = end_x_cnt;
    assign end_y_cnt = add_y_cnt && cnt_y == 8 - 1;

//****************************************************************
//--帧偏移
//****************************************************************


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_offest <= 'd0;
    end 
    else if(add_cnt_offest)begin 
        if(end_cnt_offest)begin 
            cnt_offest <= 'd0;
        end
        else begin 
            cnt_offest <= cnt_offest + 1'b1;
        end 
    end
end 

assign add_cnt_offest = end_cnt_500ms;
assign end_cnt_offest = add_cnt_offest && cnt_offest == 32 - 1;

assign real_row = cnt_x + cnt_offest;

rom2	rom2_inst  (
	.aclr       ( ~rst_n ),
	.address    ( real_row + cnt_y*32 ),
	.clock      ( clk ),
	.rden       (  rom_rd_req),
	.q          ( pix_data)
	);



assign rom_rd_req = state == DATA;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rom_rd_req1 <= 0 ;
        rom_rd_req2 <= 0 ;
    end
    else begin
        rom_rd_req1 <= rom_rd_req ;
        rom_rd_req2 <= rom_rd_req1 ;
    end
end

assign pix_data_vld = rom_rd_req2;


endmodule




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/73413.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谷粒商城第十一天-完善商品分组(主要添上关联属性)

目录 一、总述 二、前端部分 2.1 改良前端获取分组列表接口及其调用 2.2 添加关联的一整套逻辑 三、后端部分 四、总结 一、总述 前端部分和之前的商品品牌添加分类差不多。 也是修改一下前端的分页获取列表的接口&#xff0c;还有就是加上关联的那一套逻辑&#xff0c;…

7.3 详解NiN模型--首次使用多层感知机(1x1卷积核)替换掉全连接层的模型

一.前提知识 多层感知机&#xff1a;由一个输入层&#xff0c;一个或多个隐藏层和一个输出层组成。&#xff08;至少有一个隐藏层&#xff0c;即至少3层&#xff09; 全连接层&#xff1a;是MLP的一种特殊情况&#xff0c;每个节点都与前一层的所有节点连接&#xff0c;全连接…

7.5.tensorRT高级(2)-RAII接口模式下的生产者消费者多batch实现

目录 前言1. RAII接口模式封装生产者消费者2. 问答环节总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-RAI…

前后端分离------后端创建笔记(05)用户列表查询接口(上)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

City Walk带动茶饮品牌售1200万,媒介盒子带你探究奥秘

年轻人生活趋势又出现了一个新鲜词——City Walk&#xff0c;简单来说&#xff0c;City Walk就是没有目的地&#xff0c;没有目标&#xff0c;只是出行&#xff0c;填充自己的生活。 其实这个词源于gap year&#xff0c;而这个说法一直是国外的一些毕业生&#xff0c;大多会在…

plt取消坐标轴刻度、自定义取消绘图边框(或坐标轴)、白边处理、自定义颜色图谱、设置坐标轴刻度朝向

目录 1、取消坐标轴刻度 2、自定义取消绘图边框&#xff08;或坐标轴&#xff09; 3、去掉图片周边白边 4、自定义颜色图谱 5、设置坐标轴刻度朝向 import matplotlib.pyplot as plt 1、取消坐标轴刻度 ax plt.subplot() ax.set_xticks([]) ax.set_yticks([]) 2、自定…

自定义 视频/音频 进度条

复制代码根据自己需求改动就可以了 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><metaname"viewport"conten…

模仿火星科技 基于cesium+水平面积测量+可编辑

​ 当您进入Cesium的编辑水平积测量世界&#xff0c;下面是一个详细的操作过程&#xff0c;帮助您顺利使用这些功能&#xff1a; 1. 创建提示窗&#xff1a; 启动Cesium应用&#xff0c;地图场景将打开&#xff0c;欢迎您进入编辑模式。 在屏幕的一角&#xff0c;一个友好的提…

计算机网络:网络通信相关概念入门

目录 一、网络发展背景二、理解网络通信三、理解IP地址1.简述IP地址2.IP地址的版本3.提高地址利用率的技术 四、理解端口1.简述端口2.使用端口的原因 五、理解网络通信协议 一、网络发展背景 网络发展背景&#xff1a; 最初的计算机是单机&#xff0c;那么单机是这样传输数据的…

【金融量化】Python实现根据收益率计算累计收益率并可视化

1 理论 理财产品&#xff08;本金100元&#xff09; 第1天&#xff1a;3% &#xff1a;&#xff08;13%&#xff09; ✖ 100 103 第2天&#xff1a;2% &#xff1a;&#xff08;12%&#xff09;✖ 以上 103 2.06 第3天&#xff1a;5% : &#xff08;15%&#xff09;✖ 以上…

企业直播MR虚拟直播(MR混合现实直播技术)视频介绍

到底什么是企业直播MR虚拟直播&#xff08;MR混合现实直播技术&#xff09;&#xff1f; 企业直播MR虚拟直播新玩法&#xff08;MR混合现实直播技术&#xff09; 我的文章推荐&#xff1a; [视频图文] 线上研讨会是什么&#xff0c;企业对内对外培训可以用线上研讨会吗&#x…

2023年新学期12306高铁火车学生票如何在线核验享受优惠?

2023学年优惠资质核验已开始&#xff0c;完成学生优惠资质核验后&#xff0c;您可以在线购买2022年10月1日至2023年9月30日的学生优惠票。&#xff08;注&#xff1a;非该时间段需要重新核验&#xff0c;可享受学生优惠票&#xff09;&#xff1b; 『扩展阅读』 1、美团外卖红…

QT:UI控件(按设计师界面导航界面排序)

基础部分 创建新项目&#xff1a;QWidget&#xff0c;QMainWindow&#xff0c;QDialog QMainWindow继承自QWidget&#xff0c;多了菜单栏; QDialog继承自QWidget&#xff0c;多了对话框 QMainWindow 菜单栏和工具栏&#xff1a; Bar: 菜单栏&#xff1a;QMenuBar&#xff0…

【Sklearn】基于随机森林算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于随机森林算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理1.1 模型原理1.2 数学模型 2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 随机森林&#xff08;Random Forest&#xff09;是一种集成学习方法…

【深度学习】PyTorch快速入门

【深度学习】学习PyTorch基础 介绍PyTorch 深度学习框架是一种软件工具&#xff0c;旨在简化和加速构建、训练和部署深度学习模型的过程。深度学习框架提供了一系列的函数、类和工具&#xff0c;用于定义、优化和执行各种深度神经网络模型。这些框架帮助研究人员和开发人员专注…

RabbitMQ 安装教程

RabbitMQ 安装教程 特殊说明 因为RabbitMQ基于Erlang开发&#xff0c;所以安装时需要先安装Erlang RabbitMQ和Erlang版本对应关系 查看地址&#xff1a;www.rabbitmq.com/which-erlan… 环境选择 Erlang: 23.3及以上 RabbitMQ: 3.10.1Windows 安装 1. 安装Erlang 下载地…

Spark 学习记录

基础 SparkContext是什么&#xff1f;有什么作用&#xff1f; https://blog.csdn.net/Shockang/article/details/118344357 SparkContext 是什么&#xff1f; SparkContext 是通往 Spark 集群的唯一入口&#xff0c;可以用来在 Spark 集群中创建 RDDs 、累加和广播变量( Br…

【css】渐变

渐变是设置一种颜色或者多种颜色之间的过度变化。 两种渐变类型&#xff1a; 线性渐变&#xff08;向下/向上/向左/向右/对角线&#xff09; 径向渐变&#xff08;由其中心定义&#xff09; 1、线性渐变 语法&#xff1a;background-image: linear-gradient(direction, co…

黑客必备的操作系统——kali linux安装

大家经常会在电视里面看到各种炫酷的黑客操作&#xff0c;那么黑客一般用什么操作系统呢&#xff1f;今天小训带大家来安装黑客必备的kali linux-2022操作系统&#xff0c;有兴趣的一起来学习下吧&#xff01; 1、安装前准备 1.1 VMware下载 VMware官网下载&#xff1a; ht…