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、引出端排列及功能

| 序号 | 符号 | 管脚名 | 功能描述 |
|---|---|---|---|
| 1 | DO | 数据输出 | 控制数据信号输出 |
| 2 | GND | 地 | 信号接地和电源接地 |
| 3 | DI | 数据输入 | 控制数据信号输入 |
| 4 | VDD | 电源 | 供电管脚 |
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 ,//输入的RGBinput 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 -> IDLEwire [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) beginif(!rst_n) beginstate_c <= IDLE;endelse beginstate_c <= state_n ;end
endalways @( *) begincase (state_c) IDLE : beginif(idle_rst) beginstate_n = RST;endelse beginstate_n = state_c;endendRST : beginif(rst_data) beginstate_n = DATA;endelse beginstate_n = state_c;endendDATA : beginif(data_idle) beginstate_n = IDLE;endelse beginstate_n = state_c;endendendcase
endassign 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)begincnt_res <= 'd0;end else if(add_cnt_res)begin if(end_cnt_res)begin cnt_res <= 'd0;endelse 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)begincnt_time <= 'd0;end else if(add_cnt_time)begin if(end_cnt_time)begin cnt_time <= 'd0;endelse 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)begincnt_bit <= 'd0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 'd0;endelse 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)begincnt_num <= 'd0;end else if(add_cnt_num)begin if(end_cnt_num)begin cnt_num <= 'd0;endelse 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) beginif(!rst_n) beginpwm_r <= 0;endelse begincase (state_c)IDLE : beginpwm_r <= 0;endRST : beginpwm_r <= 0;endDATA : beginif(fifo_rd_data[23-cnt_bit] == 0) beginif(cnt_time < T0H)beginpwm_r <= 1;endelse beginpwm_r <= 0;endendelse if(fifo_rd_data[23-cnt_bit] == 1) beginif(cnt_time < T1H)beginpwm_r <= 1;endelse beginpwm_r <= 0;endendenddefault : pwm_r <= 0;endcaseend
endassign 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 ;// endcaserom 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) beginif(!rst_n) beginrom_rd_req1 <= 0 ;rom_rd_req2 <= 0 ;endelse beginrom_rd_req1 <= rom_rd_req ;rom_rd_req2 <= rom_rd_req1 ;end
endassign 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~31wire 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)begincnt_500ms <= 'd0;end else if(add_cnt_500ms)begin if(end_cnt_500ms)begin cnt_500ms <= 'd0;endelse 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)begincnt_offest <= 'd0;end else if(add_cnt_offest)begin if(end_cnt_offest)begin cnt_offest <= 'd0;endelse 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) beginif(!rst_n) beginrom_rd_req1 <= 0 ;rom_rd_req2 <= 0 ;endelse beginrom_rd_req1 <= rom_rd_req ;rom_rd_req2 <= rom_rd_req1 ;end
endassign pix_data_vld = rom_rd_req2;endmodule相关文章:
FPGA + WS2812采灯控制
文章目录 一、WS2812C-2020-V11、产品概述2、引出端排列及功能3、数据传输时间4、数据传输方法 二、使用WS2812C显示图片1、静态显示2、动态显示 一、WS2812C-2020-V1 1、产品概述 WS2812C-2020-V1是一个集控制电路与发光电路于一体的智能外控LED光源;其外型采用最…...
【视频】使用OBS将MP4推流至腾讯云直播
1、下载OBS OBS官网:https://obsproject.com/ OBS支持Win、Mac、Linux,如果下载速度很慢,建议使用迅雷下载 2、OBS推流设置 2.1 添加场景 默认会有一个“场景”,如果想继续添加可以点击“+”按钮 2.2 添加媒体源 1)点击“来源”窗口中“+”按钮 2)支持的媒体源如…...
Vue基本知识
一、vue入门 Vue为前端的框架,免除了原生js的DOM操作。简化书写。 基于MVVM的思想,实现数据的双向绑定,使编程的重点放在数据上。 1、引入vue.js文件 2、定义vue核心对象,定义数据模型 3、编写视图 //1、引入vue.js <scr…...
item_get_sales-获取商品销量详情
一、接口参数说明: item_get_sales-获取商品销量详情,点击更多API调试,请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_get_sales 名称类型必须描述keyString是调用key(…...
LangChain手记 Memory
整理并翻译自DeepLearning.AILangChain的官方课程:Memory Memory 使用open ai的API调用GPT都是单次调用,所以模型并不记得之前的对话,多轮对话的实现其实是将前面轮次的对话过程保留,在下次对话时作为输入的message数组的一部分&…...
linux下安装.run后缀名文件
1.文件传输 对于大文件,不能直接拖拽,可以借助工具,例如WinSCP 创建会话时,需要提供虚拟机的主机名,可以采取输入ifconfig的命令,如图所示: ifconfig(接口配置)命令在 …...
Angular 性能优化实战
Angular 性能优化实战 Angular 是一个非常强大的前端框架,但是如果不注意性能优化,应用程序可能会变得非常慢并增加加载时间。 以下是一些Angular性能优化经验的实战建议: 1. 使用 OnPush 变更检测策略 默认情况下,Angular检查…...
在vue项目使用数据可视化 echarts ,柱状图、折线图、饼状图使用示例详解及属性详解
官网地址:Apache ECharts 一、下载插件并在页面中引入 npm install echarts --save 页面导入: import * as echarts from echarts 全局导入: main.js 中,导入并注册到全局 import echarts from echarts Vue.prototype.$echart…...
九耶丨阁瑞钛伦特-井字棋html5代码
你想了解关于井字棋(Tic-Tac-Toe)的HTML代码吗?以下是一个简单的井子棋的HTML代码示例: <!DOCTYPE html> <html> <head><title>Tic-Tac-Toe</title><style>.board {display: flex;flex-wrap…...
Linux服务器上配置HTTP和HTTPS代理
本文将向你分享如何在Linux服务器上配置HTTP和HTTPS代理的方法,解决可能遇到的问题,让你的爬虫项目顺利运行,畅爬互联网! 配置HTTP代理的步骤 1. 了解HTTP代理的类型:常见的有正向代理和反向代理两种类型。根据实际需求…...
OpenZFS 2.2 发布 RC3,支持 Linux 6.4
导读之前的 OpenZFS 2.2 候选版本已致力于实现与 Linux 6.4 内核的兼容性,而在 2.2-rc3 中,Linux 6.4 支持的元跟踪器已标记为已完成。 OpenZFS 2.2 发布了第 3 个 RC 版本。 之前的 OpenZFS 2.2 候选版本已致力于实现与 Linux 6.4 内核的兼容性&#x…...
嵌入式 C 语言程序数据基本存储结构
一、5大内存分区 内存分成5个区,它们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 1、栈区(stack):FIFO就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。 …...
记录VS2022离线安装NuGet包的过程
离线安装NuGet包主要分为两个阶段:指定安装源及下载包及其依赖项。本文记录在VS2022中离线安装NuGet包的过程及注意事项。 离线安装NuGet包,主要有两种方式:1)搭建局域网或本机NuGet服务器,将VS2022的源指定为NuGe…...
tomcat的多实例和动静分离
目录 多实例 安装tomcat 配置 tomcat 环境变量 修改server.xml文件 修改开关文件,添加环境变量 tomcat1 tomcat2 启动 浏览器访问测试 nginxtomcat实现动静分离 Nginx实现负载均衡的原理 部署nginx的负载器 搭建第三台tomcat 配置多实例服务器 Tomcat…...
点成案例丨比浊仪用于乳酸菌抑菌活性测定
乳酸菌概述 自1929年英国科学家弗莱明发现青霉素以来,抗生素为人类医学的进步做出了巨大贡献。然而,抗生素在临床上广泛且持续的使用导致病原微生物产生了耐药性。目前,病原微生物对抗生素的耐药性正在威胁人们的健康,寻找具有抑…...
总结synchronized
一.synchronized的特性 synchronized 是 Java 语言中内置的关键字,用于实现线程同步,以确保多线程环境下共享资源的安全访问。 互斥性:synchronized保证了同一时刻只有一个线程可以执行被synchronized修饰的代码块或方法。当一个线程进入sync…...
react实现模拟弹框遮罩的自定义hook
需求描述 点击按钮用于检测鼠标是否命中按钮 代码实现 import React from react; import {useState, useEffect, useRef} from react;// 封装一个hook用来检测当前点击事件是否在某个元素之外 function useClickOutSide(ref,cb) {useEffect(()>{const handleClickOutside…...
直接在html中引入Vue.js的cdn来实现一个简单的博客
摘要 其实建立一个博客系统是非常简单的,有很多开源的程序,如果你不喜欢博客系统,也可以自己开发,也可以自己简单做一个。我这次就是用Vue.js和php做后端服务实现一个简单的博客。 界面 代码结构 代码 index.html <!DOCTYP…...
Android Studio瀑布流实现
效果: ImageDetail class package com.example.waterfallflow; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.ImageView;public class ImageDetail extends Activity{Overrideprotected void …...
Java 中的 == 运算符、equals 方法和 hashcode 方法
一、 运算符 是 Java 中的一个运算符,用于比较两个对象,但在比较两个对象的时候需要根据比较类型分情况进行讨论。 1.1 基本数据类型与基本数据类型 基本数据类型之间通过 进行比较的时候,是直接比较它们的大小,而与它们的具体…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
