FPGA——WS2812B彩灯点亮

news2024/11/20 13:23:27

文章目录

    • 前言
    • 一、WS2812B手册分析原理
      • 1.1 主要特点
      • 1.2 器件图
      • 1.3 接口
      • 1.4 输入码型
      • 1.5 归零码(RZ)和非归零码(NRZ)(拓展)
      • 1.6 级联输出
      • 1.7 输入数据格式
    • 二、FPGA点亮彩灯
      • 2.1 代码
    • 三、总结

前言

本篇博客是记录WS2812手册的学习,实现FPGA驱动WS2812B的器件去显示F P G A四个字母,每隔1秒变化一个字母,循环显示。

一、WS2812B手册分析原理

1.1 主要特点

内置上电复位和掉电复位电路。
每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示。
串行级联接口,能通过一根信号线完成数据的接收与解码。
数据发送速度可达800Kbps。
数据传输协议采用单NZR通信模式。
复位时间大于280us。
电源反接不会损坏。

1.2 器件图

在这里插入图片描述
一个8x8的正方形器件,上面有64个led灯。

1.3 接口

在这里插入图片描述
四根线,一个电源,一个接地,一个输入,一个输出。

1.4 输入码型

在这里插入图片描述
在这里插入图片描述
从图中就可以看出,对于输入的数据不能是简单的高低电平了。
在这里插入图片描述
由前面的特点可知它的传输速率为800kbps,也就是说它传输1bit数据的时间为1/800k=1220ns,然后由手册给出的特性图可以设计0码为320ns的高电平 和900ns的低电平组成,1码为900ns的高电平和320ns的低电平组成。

1.5 归零码(RZ)和非归零码(NRZ)(拓展)

归零码(RZ)分为单极性归零码和双极性归零码:
在这里插入图片描述
在这里插入图片描述

非归零码(NRZ):即正电平表示1,低电平表示0。我们常用的时钟线就是这种编码。
在这里插入图片描述

1.6 级联输出

在这里插入图片描述
它的每一个LED灯由24bit的数据控制,传进来的数据第一个24bit就控制第一个led灯,然后进来的第二个24bit数据就控制第二个led灯,就这个一个一个传递下去,直到64个led灯都有了输入控制后,此时继续传输数据是没有用的,它不会接收数据了,灯也不会改变,只有经过大于280us的低电平进行复位之后才能重新从第一个led灯开始写入数据。

1.7 输入数据格式

每个彩灯由24bit的数据进行控制,如图:
在这里插入图片描述
是GRB888的格式,同时数据是MSB的格式,高位先发。
补充:RGB格式就是控制一个像素中Red,Green,Blue的值,来确定这个像素的颜色。
在这里插入图片描述

二、FPGA点亮彩灯

2.1 代码

module rom_lan(
    input           clk     ,
    input           rst_n   ,

    output     reg  led     
);

    parameter   T0H = 6'd16,//0码高电平320ns
                T0L = 6'd45,//0码低电平900ns
                T1H = 6'd45,//1码高电平900ns
                T1L = 6'd16;//1码低电平320ns

    parameter   RST = 14'd15_000;//复位300us
    parameter   CNT_1S = 26'd50_000_000;//计数1秒

    parameter   BLUE  = 24'b0000_0000_0000_0000_1111_1111;//纯蓝色
    parameter   RED   = 24'b0000_0000_1111_1111_0000_0000;//纯红色
    parameter   GREEN = 24'b1111_1111_0000_0000_0000_0000;//纯绿色

    parameter   CNT_1BIT = 6'd60;//61个周期
    parameter   CNT_1LED = 5'd23;//24个bit
    parameter   CNT_LED  = 6'd63;//64个LED

    reg     [5:0]   cnt_1bit;//61个周期
    wire            add_cnt_1bit;
    wire            end_cnt_1bit;

    reg     [4:0]   cnt_1led;//每个led有24个bit
    wire            add_cnt_1led;
    wire            end_cnt_1led;

    reg     [5:0]   cnt_led;//64个led
    wire            add_cnt_led;
    wire            end_cnt_led;

    reg     [25:0]  cnt_1s;
    wire            add_cnt_1s;
    wire            end_cnt_1s;

    reg     [13:0]  cnt_rst    ;//复位需要的300us低电平计数器

    reg             flag        ;//复位的标志信号
    reg     [5:0]   cnt_init    ;//初始值
    wire    [23:0]  color       ;//颜色寄存器
    reg     [5:0]   num         ;//字母个数寄存器
    reg             flag_num    ;//延时1秒的标志信号
    reg             rden        ;

    rom_64x24	rom_64x24_inst (
	.address    ( num*64 + cnt_led ),
	.clock      ( clk ),
	.rden       ( rden ),

	.q          ( color )
	);

//读取数据使能
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            rden <= 1'b1;
        end
        else if(flag || flag_num)begin
            rden <= 1'b0;
        end
        else begin
            rden <= 1'b1;
        end
    end

//1bit计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_1bit <= 6'd0;
        end
        else if(flag)begin
            cnt_1bit <= 6'd0;
        end
        else if(add_cnt_1bit)begin
            if(end_cnt_1bit)begin
                cnt_1bit <= 6'd0;
            end
            else begin
                cnt_1bit <= cnt_1bit + 1'd1;
            end
        end
        else begin
            cnt_1bit <= 6'd0;
        end
    end

    assign  add_cnt_1bit = 1'b1;
    assign  end_cnt_1bit = add_cnt_1bit && cnt_1bit == CNT_1BIT;

//1个LED灯24个bit计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_1led <= CNT_1LED;
        end
        else if(flag)begin
            cnt_1led <= CNT_1LED;
        end
        else if(add_cnt_1led)begin
            if(end_cnt_1led)begin
                cnt_1led <= CNT_1LED;
            end
            else begin
                cnt_1led <= cnt_1led - 1'd1;
            end
        end
        else begin
            cnt_1led <= cnt_1led;
        end
    end

    assign add_cnt_1led = end_cnt_1bit;
    assign end_cnt_1led = add_cnt_1led && cnt_1led == 5'd0;

//64个LED计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_led <= 6'd0;
        end
        else if(flag)begin
            cnt_led <= 6'd0;
        end
        else if(add_cnt_led)begin
            if(end_cnt_led)begin
                cnt_led <= 6'd0;
                // cnt_led <= cnt_init;
            end
            else begin
                cnt_led <= cnt_led + 1'd1;
            end
        end
        else begin
            cnt_led <= cnt_led;
        end
    end

    assign add_cnt_led = end_cnt_1led;
    assign end_cnt_led = add_cnt_led && cnt_led == 6'd63;

//复位使能信号持续300us
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            flag <= 1'b0;
        end 
        else if(end_cnt_1s)begin
            flag <= 1'b1;
        end
        else if(cnt_rst == RST - 1'd1)begin
            flag <= 1'b0;
        end
        else begin
            flag <= flag;
        end
    end

//300us计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_rst <= 14'd0;
        end
        else if(cnt_rst == RST - 1'd1)begin
            cnt_rst <= 14'd0;
        end
        else if(flag)begin
            cnt_rst <= cnt_rst + 1'd1;
        end
        else begin
            cnt_rst <= 14'd0;
        end
    end

//延时一秒的标志信号
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            flag_num <= 1'b0;
        end 
        else if(end_cnt_led)begin
            flag_num <= 1'b1;
        end
        else if(end_cnt_1s)begin
            flag_num <= 1'b0;
        end
        else begin
            flag_num <= flag_num;
        end
    end

//1秒计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_1s <= 26'd0;
        end
        else if(add_cnt_1s)begin
            if(end_cnt_1s)begin
                cnt_1s <= 26'd0;
            end
            else begin
                cnt_1s <= cnt_1s + 1'd1;
            end
        end
        else begin
            cnt_1s <= 26'd0;
        end
    end

    assign add_cnt_1s = flag_num;
    assign end_cnt_1s = add_cnt_1s && cnt_1s == CNT_1S - 1'd1;

//字母个数
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            num <= 6'd0;
        end
        else if(end_cnt_1s)begin
            if(num == 6'd4)begin
                num <= 6'd0;
            end
            else begin
                num <= num + 1'd1;
            end
        end
        else begin
            num <= num;
        end
    end

//颜色控制


//LED输出控制
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            led <= 1'b0;
        end
        else if(flag || flag_num)begin
            led <= 1'b0;
        end
        else if(color[cnt_1led] == 1'b0)begin
            if(cnt_1bit < T0H)begin
                led <= 1'b1;
            end
            else begin
                led <= 1'b0;
            end
        end
        else if(color[cnt_1led] == 1'b1)begin
            if(cnt_1bit < T1H)begin
                led <= 1'b1;
            end
            else begin
                led <= 1'b0;
            end
        end
        else begin
            led <= 1'b0;
        end
    end

endmodule

三、总结

由于此项目十分简单,因此就直接上代码了,代码中最主要的就是三个计数器的设计,分别是每个bit的计数器,每个led灯有24bit,一个是64个led灯。然后要显示的F P G A四个字母的RGB数据是直接存在了ROM的IP核里面,只需要通过计数器将对应的数据读出来就可以了。这个项目是挺久之前写的了,上板也是成功了的,只是忘记拍视频了,因此就没有上板演示视频了。最主要的是掌握WS2812B的原理。

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

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

相关文章

基于Docker_Nginx+LVS+Flask+MySQL的高可用Web集群

一.项目介绍 1.拓扑图 2.详细介绍 项目名称&#xff1a;基于Docker_NginxLVSFlaskMySQL的高可用Web集群 项目环境&#xff1a;centos7.9&#xff0c;docker24.0.5&#xff0c;mysql5.7.30&#xff0c;nginx1.25.2,mysqlrouter8.0.21&#xff0c;keepalived 1.3.5&#xff0c;…

Maven官方镜像仓库与阿里云云效Maven

一、Maven官方镜像仓库 download maven-3 右击复制链接地址&#xff0c;使用wget命令直接在linux中下载&#xff1a; wget 链接地址history 二、阿里云云效Maven 详情查看maven 配置指南 打开 maven 的配置文件&#xff08; windows 机器一般在 maven 安装目录的 conf/…

Rt-Thread 移植1--开发环境搭建(KF32)

1.1软件 1.1.1 ChipONKongFu 下载地址 链接: ChipONKongFu 1.1.2 软件包 链接:软件包 1.2 硬件 1.2.1 开发板 1.2.2 烧录器 1.3 软件安装 1.3.1 安装KongFu32 1.4 例程编译 1.4.1找到例程 1.4.2导入例程 如上&#xff0c;编译后发现还是会缺很多东西 添加system_init.c…

9.19~9.20elf论文(浮点数的二进制表示确定擦除尾随0的数量)

小数转二进制 小数部分呈6&#xff0c;2&#xff0c;4&#xff0c;8循环&#xff0c;则二进制序列为1001循环 小数点前的0应该没有任何用&#xff0c;就是表示这是个小数&#xff0c;第一位转化后如果是1&#xff0c;应该是在小数点后的第一位位置 原始小数&#xff08;通过机…

如何看待著名游戏引擎 Unity 宣布将更改收费模式,收取「运行时费用」?这将造成哪些影响?

先下结论&#xff1a;Unity 的高管是不是【不友善内容&#xff0c;请于 24 小时内及时更改】&#xff1f; 简单介绍下这个收费模式&#xff1a;年收入大于 20w 美金且安装量大于 20w 的&#xff0c;每一份额外下载需要给 Unity 交 0.2 刀。 首先&#xff1a;听上去好像不会影响…

有关哈希的概念,哈希表(哈希桶),unordered_map和unordered_set的模拟实现

前言 在C中unordered系列的容器效率很高原因是在底层使用了哈希结构&#xff0c;让我们一起来了解一下哈希相关的知识&#xff0c;并且简单的实现以下哈希思想相关的容器。 目录 1.哈希概念 2.哈希冲突 3.哈希函数 4.哈希冲突解决 4.1闭散列 1.线性探测 2.二次探测 S 4.2…

高效批量剪辑,轻松缩小视频尺寸!一键解决视频文件大小问题!

对于那些喜欢拍摄和分享视频的人来说&#xff0c;视频文件大小往往成为一个头疼的问题。为了让您能够更加方便地处理视频尺寸&#xff0c;我们提供了一项高效的批量剪辑服务&#xff0c;让您能够轻松缩小多个视频的尺寸 首先&#xff0c;我们要进入视频剪辑高手主页面&#xf…

Linux系统如何将新硬盘挂载到Home目录下

Linux系统如果将硬盘挂载到Home目录下 目录 1、对新增磁盘进行分区 2、分区格式化 3、将新硬盘临时挂载在一个目录下

TCP协议和UDP协议

TCP通信原理 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种传输层协议&#xff0c;它主要负责点对点的数据传输TCP 主要特点是面向连接的&#xff0c;也就是说&#xff0c;在数据传输之前&#xff0c;它需要先建立一个连接。连接建…

国产AI网址

【国产AI网址】 讯飞星火&#xff1a;xinghuo.xfyun.cn 文心一言&#xff1a;yiyan.baidu.com 天工AI&#xff1a;search.tiangong.cn 通义千问&#xff1a;qianwen.aliyun.com 有很多国产AI网址可以提供各种功能和应用。以下是其中一些&#xff1a; * 一起用AI&#xff1a;ht…

负载均衡 —— SpringCloud Netflix Ribbon

Ribbon 简介 Ribbon 是 Netfix 客户端的负载均衡器&#xff0c;可对 HTTP 和 TCP 客户端的行为进行控制。为 Ribbon 配置服务提供者地址后&#xff0c;Ribbon 就可以基于某种负载均衡算法自动帮助服务消费者去请求。Ribbon 默认提供了很多负载均衡算法&#xff0c;例如轮询、随…

useCallBack

React.memo 保证了只有props发生变化时&#xff0c;该组件才会重新渲染 &#xff08;当然组件内部的state 和 context 变化也会导致组件重新渲染&#xff09;&#xff0c;但咱们只要将咱们的子组件包裹&#xff0c;便可以保证Child组件在props不变的情况下&#xff0c;不会重新…

一篇聊聊Mybatis插件开发

Mybatis的插件&#xff0c;主要用于在执行sql前后&#xff0c;对sql进行封装加工&#xff0c;或者在sql执行后&#xff0c;对数据进行加工处理。常用于一些公共数据操作处理&#xff0c;例如&#xff1a; 分页插件&#xff0c;在执行sql查询前增加分页参数多租户系统中&#x…

[winerror 5] 拒绝访问。: ‘..\\data‘解决方案

使用Jupyter Notebook学习深度学习时出现错误如下&#xff1a;[winerror 5] 拒绝访问。: ‘…\data’ 解决方法&#xff1a; 打开anaconda3找到对应环境的python.exe 点开属性&#xff0c;点安全&#xff0c;选择如下&#xff1a; 点编辑&#xff0c;选择User&#xff0c;勾…

k8s集群-3 pod 管理

pod是可以创建和管理k 8 s 计算的最小可部署单元&#xff0c;一个pod 代表着集群中运行的一个进程&#xff0c;每个pod 都有一个唯一的ip 一个pod 类似一个豌豆荚&#xff0c;包含一个或者多个容器&#xff0c;多个容器间共享IPC Network和UTC namespace pod 包裹了容器 下载…

Unity之NetCode多人网络游戏联机对战教程(2)--简单实现联机

文章目录 1.添加基本组件2.创建NetworkManager组件3.创建Player4.创建地面5.创建GameManager6.编译运行7. 测试联机后话 1.添加基本组件 NetworkManagerPlayerScene 2.创建NetworkManager组件 创建一个空物体&#xff0c;命名为NetworkManager 选择刚刚创建的NetworkManager…

Android Jetpack组件架构:Lifecycle的使用 和 原理

Android Jetpack组件架构&#xff1a;Lifecycle的使用和原理 导言 作为Jetpack中关于生命周期管理的核心组件&#xff0c;Lifecycle组件是其他比如LiveDate和ViewModel等组件的基础&#xff0c;本篇文章主要就将介绍关于Lifecycle的使用和它的运作原理。 Lifecycle的使用 我…

【05】FISCOBCOS中的节点配置

官方文档https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/configuration.html 配置黑名单列表 基于防作恶考虑&#xff0c;FISCO BCOS允许节点将不受信任的节点加入到黑名单列表&#xff0c;并拒绝与这些黑名单节点建立连接&#xff0c;通过[certif…

MySQL数据库的索引和事务

目录 一、索引 1.1Mysql索引 1.2索引的作用 1.3 创建索引的依据 1.4 普通索引 修改表方式创建索引 删除索引 1.5 唯一索引 修改表方式创建 删除索引 1.6 主键索引 修改表方式创建 1.7 组合索引 1.8 全文索引 1.9查看索引 二、事务 2.1事务概念 2.2事务的ACID特…

Java 核心技术卷 I —— 第2章 Java 编程环境

文章目录 2.1 安装 Java 开发工具包&#xff08;*&#xff09;2.2 使用命令行工具2.3 使用集成开发环境&#xff08;*&#xff09;2.4 JShell 2.1 安装 Java 开发工具包&#xff08;*&#xff09; 2.2 使用命令行工具 ​ 打开终端窗口&#xff0c;进入 Java 的 bin 目录&…