WS2812B————动/静态显示

news2024/12/23 22:07:47

一,系统架构

在这里插入图片描述

二,芯片介绍

1.管脚说明

在这里插入图片描述

2.数据传输时间

在这里插入图片描述

3.时序波形

在这里插入图片描述

4.数据传输方法

在这里插入图片描述

5.常用电路连接

在这里插入图片描述

三,代码展示及说明

  1. 驱动模块
    在驱动模块首先选择使用状态机,其中包括,空闲状态,复位清空状态,和读数据状态,其中空闲状态是向fifo中写入数据,复位清空状态是清空ws2812b中的数据,读数据状态是讲fifo中存的数据依次读到ws2812b中,以这样的流程来达到对ws2812b的控制,以下是我的驱动代码:
/**************************************功能介绍***********************************
Date	: 
Author	: WZY.
Version	: 
Description: 这是项目的逻辑状态机模块
*********************************************************************************/
    
//---------<模块及端口声名>------------------------------------------------------
module state( 
    input 	wire				clk		,
    input 	wire				rst_n	,
    input   wire    [23:0]      data_in ,
    input   wire                fifo_wr_vld,
    output  reg                 ws2812b_io ,
    output  wire                ready
);								 
//---------<参数定义>--------------------------------------------------------- 
 //状态机参数定义
 parameter IDLE = 3'b001,//空闲状态
           RST  = 3'b010,//复位状态
           DATA = 3'b100;//数据传输状态    

//---------<内部信号定义>-----------------------------------------------------

reg 	[2:0]	cstate      ;//现态
reg	    [2:0]	nstate      ;//次态
wire            idle2rst    ;
wire            rst2data    ;
wire            data2idle   ;


//fifoIP核参数定义
wire    [23:0]  fifo_wr_data;
wire    [23:0]  fifo_rd_data;
wire            empty       ;
wire            full        ;
wire            fifo_rd_req ;
wire            fifo_wr_req ;

//复位参数定义
reg			[14:0]	cnt_rst	   	;
wire				add_cnt_rst	;
wire				end_cnt_rst	;

//数据传输参数定义
reg			[5:0]	cnt_cyc	   	;
wire				add_cnt_cyc	;
wire				end_cnt_cyc	;

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

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


//****************************************************************
//                  状态机
//****************************************************************

//第一段:时序逻辑描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        cstate <= IDLE;
    end 
    else begin 
        cstate <= nstate;
    end 
end

//第二段:组合逻辑描述状态转移规律和状态转移条件
always @(*) begin
    case(cstate)
        IDLE  : begin
            if (idle2rst) begin
                nstate = RST;
            end
            else begin
                nstate = cstate;
            end
        end
        RST   : begin
            if (rst2data) begin
                nstate = DATA;
            end
            else begin
                nstate = cstate;
            end
        end
        DATA : begin
            if (data2idle) begin
                nstate = IDLE;
            end
            else begin
                nstate = cstate;
            end
        end
        default : nstate = IDLE;
    endcase
end
assign idle2rst  = cstate == IDLE && fifo_wr_vld;//当检测到读使能时由空闲状态转换到复位状态
assign rst2data  = cstate == RST  && end_cnt_rst;//当复位完成后转到数据输入状态
assign data2idle = cstate == DATA && end_cnt_num;//当数据输入完成后返回空闲状态           
//第三段:描述输出,时序逻辑或组合逻辑皆可


//****************************************************************
//                      IP核FIFO读取
//****************************************************************           
fifo_test	fifo_test_inst (
	.aclr ( ~rst_n ),
	.clock ( clk ),
	.data ( fifo_wr_data ),
	.rdreq ( fifo_rd_req ),
	.wrreq ( fifo_wr_req),
	.empty ( empty ),
	.full ( full ),
	.q ( fifo_rd_data ),
	.usedw (  )
	);       

assign fifo_wr_data = {data_in[15:8],data_in[23:16],data_in[7:0]} ;//RGB->GRB
assign fifo_wr_req = fifo_wr_vld&&~full;//当检测到写使能并且不为满时拉高
assign fifo_rd_req = end_cnt_bit&& ~empty;//每次读取计时到一个数据后并且不为空时读出一个数据
    
//****************************************************************
//                  复位计时
//****************************************************************    


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_rst <= 15'd0;
    end 
    else if(add_cnt_rst)begin 
        if(end_cnt_rst)begin 
            cnt_rst <= 15'd0;
        end
        else begin 
            cnt_rst <= cnt_rst + 1'b1;
        end 
    end
end 

assign add_cnt_rst = cstate == RST;
assign end_cnt_rst = add_cnt_rst && cnt_rst == 400_000/20 - 1;

//****************************************************************
//                      数据传输计时
//****************************************************************


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_cyc <= 6'd0;
    end 
    else if(add_cnt_cyc)begin 
        if(end_cnt_cyc)begin 
            cnt_cyc <= 6'd0;
        end
        else begin 
            cnt_cyc <= cnt_cyc + 1'b1;
        end 
    end
end 

assign add_cnt_cyc = cstate == DATA;
assign end_cnt_cyc = add_cnt_cyc && cnt_cyc == 1200/20 - 1;




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

assign add_cnt_bit = end_cnt_cyc;
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 <= 6'd0;
    end 
    else if(add_cnt_num)begin 
        if(end_cnt_num)begin 
            cnt_num <= 6'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;
//****************************************************************
//                      用户接口
//****************************************************************

always @(posedge clk or negedge rst_n) begin
    case (cstate)
        IDLE : ws2812b_io = 0;
        RST  : ws2812b_io = 0;
        DATA : begin
                    if (fifo_rd_data[23-cnt_bit] == 1) begin
                        ws2812b_io = (cnt_cyc <30)?1:0;
                    end
                    else  begin
                        ws2812b_io = (cnt_cyc<15)?1:0;
                    end
                end
        default: ws2812b_io = 0;
    endcase
end

//****************************************************************
//                      ready控制
//****************************************************************
assign ready = cstate == IDLE;
endmodule
  1. 数据传输
    接下来是数据选择传输模块,这个模块同样使用到了ip核以及状态机,通过三个状态,空闲状态,读数据状态,以及延迟状态,其中空闲状态下,等待驱动模块准备完成跳转到读数据状态,在读数据状态下根据三个计数器即横坐标,纵坐标还有偏移坐标来作为ROM的地址,依次向外读出数据,同时驱动模块向fifo中写入数据,当读取完64个数据后跳转到等待状态,延迟500ms后再次回到IDLE状态并且偏移坐标+1,以此循环就可以达到动态显示,下面是代码展示:
/**************************************************************
@File    :   ws2812_control2.v
@Time    :   2023/08/14 10:04:56
@Author  :   WangHaodong 
@EditTool:   VS Code 
@Font    :   UTF-8 
@Function:   显示一张图片
**************************************************************/
module ws2812_control(
    input               clk             ,
    input               rst_n           ,
    output      [23:0]  pix_data        ,
    output              pix_data_vld    ,
    input               ready                   //可以接收图像数据了
);

    parameter   IDLE    =   0,
                DATA     =   1,
                DELAY     =   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;	

    reg			[24:0]	cnt_delay	   	;
    wire				add_cnt_delay	;
    wire				end_cnt_delay	;

    reg			[5:0]	cnt_offset	   	;
    wire				add_cnt_offset	;
    wire				end_cnt_offset	;

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;	  //灰色
parameter   MAX_500S =  24_999_999;


    wire        rom_rd_req      ;
    wire        rom_rd_data_vld ;
    reg         rom_rd_req_r1   ;
    reg         rom_rd_req_r2   ;

/**************************************************************
                            状态机
**************************************************************/
    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_delay) 
                                    state <= IDLE;
                default :	state <= IDLE;
        endcase
//****************************************************************
//                  延时计数器
//****************************************************************


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_delay <= 'd0;
    end 
    else if(add_cnt_delay)begin 
        if(end_cnt_delay)begin 
            cnt_delay <= 'd0;
        end
        else begin 
            cnt_delay <= cnt_delay + 1'b1;
        end 
    end
    else begin
        cnt_delay <= 0;
    end
end 

assign add_cnt_delay = state == DELAY;
assign end_cnt_delay = add_cnt_delay && cnt_delay == MAX_500S;


/**************************************************************
                        图像数据个数计数器
**************************************************************/       
//横坐标
    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_offset <= 'd0;
        end 
        else if(add_cnt_offset)begin 
            if(end_cnt_offset)begin 
                cnt_offset <= 'd0;
            end
            else begin 
                cnt_offset <= cnt_offset + 1'b1;
            end 
        end
    end 
    
    assign add_cnt_offset = end_cnt_delay;
    assign end_cnt_offset = add_cnt_offset && cnt_offset == 31;
    wire[4:0]  num_x;
    assign num_x = (cnt_x+cnt_offset)%32;//避免超出32的坐标限制

//存放了一张图片
    rom	rom_inst (
        .aclr       ( ~rst_n ),
        .address    (  cnt_y*32+num_x ),
        .clock      ( clk ),
        .rden       (rom_rd_req),
        .q          (pix_data)
	);


    assign rom_rd_req = state == DATA;

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

    assign rom_rd_data_vld = rom_rd_req_r2;
    assign pix_data_vld = rom_rd_data_vld;//打两拍使得读出数据和fifo中写入数据同步





endmodule

3.仿真演示

仿真代码:

`timescale 1ns/1ns
    
module state_tb();

//激励信号定义 
    reg				 clk  	;
    reg				 rst_n	;
//输出信号定义	 
    wire                    ws2812b_io ;

//时钟周期参数定义	
    parameter		CYCLE = 20; 
    defparam        top_inst.ws2812_control_inst.MAX_500S = 10*CYCLE;  

//模块例化
 top top_inst
 (
        .clk            (clk),
        .rst_n          (rst_n),
        .ws2812b_io     (ws2812b_io)
);	

//产生时钟
    initial 		 clk = 1'b1;
    always #(CYCLE/2)  clk = ~ clk;

//产生激励
    initial  begin 
         rst_n = 1'b1;
        #(CYCLE*2);
         rst_n = 1'b0;
        #(CYCLE*20);
         rst_n = 1'b1;
        #(CYCLE*1000000);
        $stop;
        


    end

endmodule 

仿真结果展示:
在这里插入图片描述

4.结果演示

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能场景和性能需求指标

目录 一 性能场景 1、基准性能场景 2、容量性能场景 3、稳定性性能场景 4、异常性能场景 二 性能需求指标 1、业务指标 2、技术指标 2.1 时间指标 RT 2.2 容量指标 TPS 2.3 资源利用率 3、指标之间的关系 “TPS”与“响应时间” “用户数”与“TPS”与“压力工具中…

【量化课程】08_2.深度学习量化策略基础实战

文章目录 1. 深度学习简介2. 常用深度学习模型架构2.1 LSTM 介绍2.2 LSTM在股票预测中的应用 3. 模块分类3.1 卷积层3.2 池化层3.3 全连接层3.4 Dropout层 4. 深度学习模型构建5. 策略实现 1. 深度学习简介 深度学习是模拟人脑进行分析学习的神经网络。 2. 常用深度学习模型架…

DevOps系列文章 之 SpringBoot整合GitLab-CI实现持续集成

在企业开发过程中&#xff0c;我们开发的功能或者是修复的BUG都需要部署到服务器上去&#xff0c;而这部分部署操作又是重复且繁琐的工作&#xff0c;GitLab-CI 持续集成为我们解决了这一痛点&#xff0c;将重复部署的工作自动化&#xff0c;大大的节省了程序员们的宝贵时间。本…

群晖 NAS 十分精准的安装 Mysql 远程访问连接

文章目录 1. 安装Mysql2. 安装phpMyAdmin3. 修改User 表4. 本地测试连接5. 安装cpolar6. 配置公网访问地址7. 固定连接公网地址 转载自cpolar极点云文章&#xff1a;群晖NAS 安装 MySQL远程访问连接 群晖安装MySQL具有高效、安全、可靠、灵活等优势&#xff0c;可以为用户提供一…

C++初阶之一篇文章教会你queue和priority_queue(理解使用和模拟实现)

queue和priority_queue&#xff08;理解使用和模拟实现&#xff09; 什么是queuequeue的使用1.queue构造函数2.empty()3.size()4.front()5.back();6.push7.emplace8.pop()9.swap queue模拟实现什么是priority_queuepriority_queue的使用1.priority_queue构造函数1.1 模板参数 C…

如何切换goland之中的版本号(升级go 到1.20)

go 安装/版本切换_go 切换版本_云满笔记的博客-CSDN博客 用brew就行&#xff1a; echo export PATH"/opt/homebrew/opt/go1.20/bin:$PATH" >> ~/.zshrc

无涯教程-Perl - scalar函数

描述 此函数强制EXPR的判断在标量context中进行,即使它通常在列表context中也可以使用。 语法 以下是此函数的简单语法- scalar EXPR返回值 此函数返回标量。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl -wa (1,2,3,4); b (10,20,30,40);c ( a, b ); prin…

如何与 Anheuser-Busch 建立 EDI 连接?

Anheuser-Busch 于 1852 年创立&#xff0c;总部位于美国密苏里州圣路易斯市&#xff0c;出产的百威啤酒(Budweiser)名扬世界&#xff0c;深受各国消费者喜爱。推进数字化转型&#xff0c;科技赋能降费增效。在诸多举措之中&#xff0c;可以看到 EDI 的身影&#xff0c;借助 ED…

Java智慧工地APP源码带AI识别

智慧工地为建筑全生命周期赋能&#xff0c;用创新的可视化与智能化方法&#xff0c;降低成本&#xff0c;创造价值。 一、智慧工地APP概述 智慧工地”立足于互联网&#xff0c;采用云计算&#xff0c;大数据和物联网等技术手段&#xff0c;针对当前建筑行业的特点&#xff0c;…

Apipost接口自动化控制器使用详解

测试人员在编写测试用例以及实际测试过程中&#xff0c;经常会遇到两个棘手的问题&#xff1a; •稍微复杂一些的自动化测试逻辑&#xff0c;往往需要手动写代码才能实现&#xff0c;难以实现和维护 •测试用例编写完成后&#xff0c;需要手动执行&#xff0c;难以接入自动化体…

对比学习论文综述总结

第一阶段:百花齐放(18-19中) 有InstDisc(Instance Discrimination)、CPC、CMC代表工作。在这个阶段方法模型都还没有统一,目标函数也没有统一,代理任务也没有统一,所以说是一个百花齐放的时代 1 判别式代理任务---个体判别任务 1.1 Inst Dict---一个编码器+一个memory…

springboot结合element-ui实现增删改查,附前端完整代码

实现功能 前端完整代码 后端接口 登录&#xff0c;注册&#xff0c;查询所有用户&#xff0c;根据用户名模糊查询&#xff0c;添加用户&#xff0c;更新用户&#xff0c;删除用户 前端 注册&#xff0c;登录&#xff0c;退出&#xff0c;用户增删改查&#xff0c;导航栏&#…

关于单行文本input和多行文本textarea唤起自动完成功能

若不要自动完成功能&#xff0c;则增加 autocomplete"off" 属性到控件或窗体中&#xff0c;默认 autocomplete"on" 处于开启状态。 实测过程中&#xff0c;单行文本可以有自动完成功能&#xff0c;多行文本无论如何实验都不行。查了查资料&#xff0c;MDN…

算法提高-线段树

线段树 线段树和树状数组线段树的五个操作单点修改&#xff08;不需要懒标记&#xff09;要求的答案就是我们要维护的属性&#xff0c;不需要维护其他的属性帮助我们获得答案要求的答案还需要其他属性去维护 区间修改&#xff08;需要懒标记&#xff0c;pushdown&#xff09;有…

小爱同学今日起开启邀请测试, 小米Al 大模型团队整装待发

在小米雷军年度演讲中&#xff0c;小米宣布未来将在技术研发上投入超过200亿元人民币&#xff0c;并预计在2023年达到这一目标。除此之外&#xff0c;雷军还强调了5G技术在小米发展中的重要性&#xff0c;称其为必要标准&#xff0c;并预测小米将进入世界前十的位置。 雷军还透…

配置 yum/dnf 置您的系统以使用默认存储库

题目 给系统配置默认存储库&#xff0c;要求如下&#xff1a; YUM 的 两 个 存 储 库 的 地 址 分 别 是 &#xff1a; ftp://host.domain8.rhce.cc/dvd/BaseOS ftp://host.domain8.rhce.cc/dvd/AppStream vim /etc/yum.repos.d/redhat.repo [base] namebase baseurlftp:/…

釉面陶瓷器皿SOR/2016-175标准上架亚马逊加拿大站

亲爱的釉面陶瓷器皿和玻璃器皿制造商和卖家&#xff0c;亚马逊加拿大站将执行SOR/2016-175法规。这是一份新的法规&#xff0c;规定了含有铅和镉的釉面陶瓷器和玻璃器皿需要满足的要求。让我们一起来看一看&#xff0c;为什么要实行SOR/2016-175法规&#xff1f;这是一个保护消…

Unity游戏源码分享-中国象棋Unity5.6版本

Unity游戏源码分享-中国象棋Unity5.6版本 项目地址&#xff1a; https://download.csdn.net/download/Highning0007/88215699

linux系统服务学习(一)Linux高级命令扩展

文章目录 Linux高级命令&#xff08;扩展&#xff09;一、find命令1、find命令作用2、基本语法3、*星号通配符4、根据文件修改时间搜索文件☆ 聊一下Windows中的文件时间概念&#xff1f;☆ 使用stat命令获取文件的最后修改时间☆ 创建文件时设置修改时间以及修改文件的修改时间…

母牛的故事

一、题目 有一头母牛&#xff0c;它每年年初生一头小母牛。每头小母牛从第四个年头开始&#xff0c;每年年初也生一头小母牛。请编程实现在第n年的时候&#xff0c;共有多少头母牛&#xff1f; Input 输入数据由多个测试实例组成&#xff0c;每个测试实例占一行&#xff0c;包…