WS2812B————动/静态显示

一,系统架构

在这里插入图片描述

二,芯片介绍

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.mfbz.cn/a/78873.html

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

相关文章

LeetCode150道面试经典题-- 合并两个有序链表(简单)

1.题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 2.示例 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输…

STM32 FLASH 读写数据

1. 《STM32 中文参考手册》&#xff0c;需要查看芯片数据手册&#xff0c;代码起始地址一般都是0x8000 0000&#xff0c;这是存放整个项目代码的起始地址 2. 编译信息查看代码大小&#xff0c;修改代码后第一次编译后会有这个提示信息 2.1 修改代码后编译&#xff0c;会有提示…

谈谈IP地址和子网掩码的概念及应用

个人主页&#xff1a;insist--个人主页​​​​​​ 本文专栏&#xff1a;网络基础——带你走进网络世界 本专栏会持续更新网络基础知识&#xff0c;希望大家多多支持&#xff0c;让我们一起探索这个神奇而广阔的网络世界。 目录 一、IP地址的概念 二、IP地址的分类 1、A类 …

centos安装pandoc

1、首先从官网下载安装包(Release pandoc 3.1.6 jgm/pandoc GitHub) 2、上传到服务器(这里放到 /root目录下了)&#xff0c;进行解压 tar -zxvf pandoc-3.1.6-linux-amd64.tar.gz&#xff0c;解压后的文件 3、然后使用命令 ln -s /root/pandoc-3.1.6/bin/pandoc /usr/bin/p…

20230818 数据库自整理部分

并发事务 脏读 一个事务读取到另一事务还没有提交的数据 事务B读取了事务A还没有提交的数据 不可重复读 一个事务先后读取同一条记录&#xff0c;但是两次读取的数据不同&#xff0c;称之为不可重复读 查询出来的数据不一样 1步骤b还没有提交 3步骤b已经提交 幻读 一个…

CSS中的transform属性有哪些值?并分别描述它们的作用。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ translate()⭐ rotate()⭐ scale()⭐ skew()⭐ matrix()⭐ scaleX() 和 scaleY()⭐ rotateX()、rotateY() 和 rotateZ()⭐ translateX() 和 translateY()⭐ skewX() 和 skewY()⭐ perspective()⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&…

解决生成式AI落地之困,亚马逊云科技提供完整解决方案

生成式AI技术无疑是当前最大的时代想象力之一。 资本、创业者、普通人都在涌入生成式AI里去一探究竟&#xff1a;“百模大战”连夜打响&#xff0c;融资规模连创新高&#xff0c;各种消费类产品概念不断涌现……根据Bloomberg Intelligence 的报告&#xff0c;2022年生成式AI 市…

8.利用matlab完成 符号微积分和极限 (matlab程序)

1.简述 一、符号微积分 微积分的数值计算方法只能求出以数值表示的近似解&#xff0c;而无法得到以函数形式表示的解析解。在 MATLAB 中&#xff0c;可以通过符号运算获得微积分的解析解。 1. 符号极限 MATLAB 中求函数极限的函数是 limit&#xff0c;可用来求函数在指定点的…

java面试基础 -- 方法重载 方法重写

目录 重载 重写 重载 方法的重载是指在同一个类中定义多个方法, 他们具有相同的名称, 但是具有不同的参数列表, 例如: public void myMethod(int arg1) {// 方法体 }public void myMethod(int arg1, int arg2) {// 方法体 }public void myMethod(String arg1) {// 方法体 }…

机器学习中基本的数据结构说明

数据维度或数据结构 当我们在机器学习或深度学习的领域内处理数据&#xff0c;我们通常会遇到四种主要的数据结构&#xff1a;标量&#xff0c;向量&#xff0c;矩阵和张量。理解这些基本数据结构是非常重要的&#xff0c;因为它们是机器学习算法和神经网络的核心。下面是对这…

牛客网华为OD前端岗位,面试题库练习记录02

题目一 删除字符串中出现次数最少的字符(HJ23) JavaScript Node ACM 模式 const rl require("readline").createInterface({ input: process.stdin }); var iter rl[Symbol.asyncIterator](); const readline async () > (await iter.next()).value;void (asyn…

工业物联网网关是什么?有什么作用?

工业物联网网关是工业领域中的一种重要设备&#xff0c;它在工业物联网系统中充当桥梁和连接器的角色。作为边缘计算的关键组件之一&#xff0c;工业物联网网关用于实现工业设备、传感器、PLC、DCS、OPC等各种设备的数据采集、处理、转发和控制。它在工业物联网系统中发挥着关键…

【图书推荐 | 测试】—《测试设计思想》

前言 随着科技的不断发展&#xff0c;互联网的不断进步&#xff0c;日益出现了一种趋势&#xff1a;测试设计将成为一种跨领域的综合性工作&#xff0c;测试者将成为一种跨领域的通用型人才。由此清华大学出版社推出了一本名为《测试设计思想》的书籍&#xff0c;由知名专家周…

Chrome

Chrome 简介下载 简介 Chrome 是由 Google 开发的一款流行的网络浏览器。它以其快速的性能、强大的功能和用户友好的界面而闻名&#xff0c;并且在全球范围内被广泛使用。Chrome 支持多种操作系统&#xff0c;包括 Windows、macOS、Linux 和移动平台。 Chrome官网: https://ww…

uni-app 集成推送

研究了几天&#xff0c;终于是打通了uni-app的推送&#xff0c;本文主要针对的是App端的推送开发过程&#xff0c;分为在线推送和离线推送。我们使用uni-app官方推荐的uni-push2.0。官方文档 准备工作&#xff1a;开通uni-push功能 勾选uniPush2.0点击"配置"填写表单…

解决跨时区跨语言的国外大文件传输问题

随着信息技术的飞速发展和全球化的深入推进&#xff0c;跨国团队、跨国公司之间的合作变得越来越普遍。在这种背景下&#xff0c;大文件的传输成为了一个经常遇到的挑战。跨语言、跨时区的国外大文件传输&#xff0c;由于涉及到复杂的网络环境、不同国家法律法规等多方面的问题…

MySQL 索引为什么使用 B+ 树,而不使用红黑树 / B 树 ?

面试官问 &#xff1a;索引为什么使用 B 树&#xff0c;而不使用 B 树&#xff0c;不使用红黑树呢 首先 B 树和 B 树 都是多叉搜索树&#xff0c;然后我们先来观察一下 B 树和 B 树的数据结构&#xff1a; B 树的数据结构实现 >> B 树的数据结构实现 >> 【B 树相…

DAY2,ARM(特殊功能寄存器,数据操作指令,跳转指令)

1.cmp、sub、b指令的使用&#xff1b; 代码&#xff1a; .text .global _start _start:mov r0,#9mov r1,#15loop:cmp r0,r1beq stopsubcc r1,r1,r0subhi r0,r0,r1b loopstop:b stop .end结果&#xff1a; 2.汇编指令计算1~100之间和&#xff1b; 代码&#xff1a; .text .gl…

用友Java后端笔试2023-8-5

计算被直线划分区域 在笛卡尔坐标系&#xff0c;存在区域[A,B],被不同线划分成多块小的区域&#xff0c;简单起见&#xff0c;假设这些不同线都直线并且不存在三条直线相交于一点的情况。 img 那么&#xff0c;如何快速计算某个时刻&#xff0c;在 X 坐标轴上[ A&#xff0c;…

dB(分贝)定义及其应用(音量 dB dBA 计算 调整)

一、dB的诞生背景 dB是英文“decibel”的简写&#xff0c;其中&#xff0c;deci表示十分之一&#xff0c;Bel表示“贝”。Decibel&#xff0c;分贝就是十分之一贝。“贝”是“贝尔”的简称&#xff0c;是以杰出科学家Alexander Graham Bell的名字来命名的单位。贝尔在1876年获…