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 基本数据类型与基本数据类型 基本数据类型之间通过 进行比较的时候,是直接比较它们的大小,而与它们的具体…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
