• FPGA——WS2812B彩灯点亮


    前言

    本篇博客是记录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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262

    三、总结

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

  • 相关阅读:
    使用Cpolar+freekan源码 创建在线视频网站
    Redis的常用数据结构之字符串类型
    【ArcGIS微课1000例】0077:ArcGIS生成经纬网(shp格式)
    专项技能训练五《云计算网络技术与应用》实训6-1:安装OpenDayLight控制器
    11.Spring security跨域问题
    区块链的风潮
    nginx配置http负载均衡转发
    UE4 后期处理体积 (角色受到伤害场景颜色变淡案例)
    dede:arclist标签判断有缩略图则显示否则不显示或显示其他自定义图片
    redis命令学习
  • 原文地址:https://blog.csdn.net/asdhnkhn/article/details/133206543