WS2812驱动 SPI+DMA 无需降频 一个灯占用9Byte的RAM

WS2812驱动 STM32F103 SPI+DMA 无需降频 一个灯占用9Byte的RAM

对于WS2812不了解的朋友可以先看一下这些
【STM32】WS2812介绍、使用SPI+DMA发送数据
在这里插入图片描述

WS2812的驱动我想到的主要有三种

  • 延时
  • SPI
  • UART
    三者区分:
  1. 延时,占用资源,需要用到ASM nop不然容易被优化,需要用示波器抓时间。
  2. UART 起始位低,结束位高,如果要强行实现也是可以但是实现起来过于复杂,不够优美。
  3. 没有片选的功能,会占用一整个硬件SPI,觉得较为优美。

在网上看了很多SPI例子都是使用 SPI的8bit数据来模拟WS2812的一个bit颜色的数据,但是由于STM32F103主频72M,要凑出来这个SPI的频率我看某些做法是进行降频,吾不喜,要么还有就是和协议时序差异挺大但是有些WS2812能运行,但是考虑到可能有些ws2812会不能兼容,吾不喜。

STM32F103 设主频72M,SPI分频数设置为32,则SPI的通信频率为2.25M,传输一位数据的时间约为444纳秒(ns)444ns 888ns 符合WS281X芯片的通信时序。

//  __
// |  |_|   0b110  high level
//  _   
// | |__|   0b100  low level

这个方式和协议时序更加接近,占用RAM应该是笔者认为最小的了
一个灯24bit颜色,只需要24*3/8 = 9Byte的Buff。

写代码的时候需要注意一下大小端的问题,尽量保持大小端的兼容性

/**
 * @brief 设置某一个WS2812
 * 
 * @param num 
 * @param RGB 
 */
void WS2812_OneSet( uint8_t num, uint32_t RGB )
{
    uint8_t i;
    uint32_t TempR = 0, TempG = 0, TempB = 0;

    //MSB First
    for( i = 0; i < 8; ++i,RGB>>=1 )
    {
        (RGB & 0x00010000) != 0 ? (TempR |= (WS2812_HIG<<(i*3))) : (TempR |= (WS2812_LOW<<(i*3)));
        (RGB & 0x00000100) != 0 ? (TempG |= (WS2812_HIG<<(i*3))) : (TempG |= (WS2812_LOW<<(i*3)));
        (RGB & 0x00000001) != 0 ? (TempB |= (WS2812_HIG<<(i*3))) : (TempB |= (WS2812_LOW<<(i*3)));
    }

    for( i = 0; i < 3; ++i )
    {
        g_ws2812.Col[num].RGB.R[i] = TempR >> (16-8*i);
        g_ws2812.Col[num].RGB.G[i] = TempG >> (16-8*i);
        g_ws2812.Col[num].RGB.B[i] = TempB >> (16-8*i);
    }
}

这里有参考的代码,有积分的给点积分用吧,没积分的可以去Github下。
Github
CSDN下载

参考资料
stm32和ws2812B相对较好的方案。SPI和UART

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的数字时钟的Verilog代码,它使用了一个时钟分频器,一个时钟计数器和七段数码管显示器。 ``` module digital_clock( input clk, output reg [3:0] hour_tens, hour_ones, minute_tens, minute_ones, second_tens, second_ones, output seg_dp, seg_g, seg_f, seg_e, seg_d, seg_c, seg_b, seg_a ); wire [20:0] counter; wire [3:0] counter_100ms; wire [3:0] counter_sec; wire [3:0] counter_min; wire [3:0] counter_hr; assign seg_dp = 1'b1; // decimal point assign seg_g = (counter_sec[0] || counter_sec[3] || counter_100ms[1] || counter_100ms[3]); assign seg_f = (counter_sec[1] || counter_sec[3] || counter_100ms[0] || counter_100ms[2]); assign seg_e = (counter_sec[2] || counter_sec[3] || counter_100ms[1] || counter_100ms[3]); assign seg_d = (counter_min[0] || counter_min[3] || counter_100ms[1] || counter_100ms[3]); assign seg_c = (counter_min[1] || counter_min[3] || counter_100ms[0] || counter_100ms[2]); assign seg_b = (counter_min[2] || counter_min[3] || counter_100ms[1] || counter_100ms[3]); assign seg_a = (counter_hr[0] || counter_hr[3] || counter_100ms[0] || counter_100ms[2]); assign hour_tens = counter_hr[2:1]; assign hour_ones = counter_hr[1:0]; assign minute_tens = counter_min[2:1]; assign minute_ones = counter_min[1:0]; assign second_tens = counter_sec[2:1]; assign second_ones = counter_sec[1:0]; // 1 Hz signal div1 div1(clk, counter[20], counter[19]); // 10 Hz signal div10 div10(clk, counter[19], counter[18]); // 100 Hz signal div100 div100(clk, counter[18], counter_100ms[3], counter_100ms[2], counter_100ms[1], counter_100ms[0]); // 1 second signal div1000 div1000(clk, counter[17], counter_sec[3], counter_sec[2], counter_sec[1], counter_sec[0]); // 1 minute signal div60000 div60000(clk, counter[14], counter_min[3], counter_min[2], counter_min[1], counter_min[0]); // 1 hour signal div3600000 div3600000(clk, counter[8], counter_hr[3], counter_hr[2], counter_hr[1], counter_hr[0]); endmodule // 1 Hz signal module div1( input clk, input reset, output reg out ); always @(posedge clk or posedge reset) begin if (reset) begin out <= 1'b0; end else begin out <= !out; end endmodule // 10 Hz signal module div10( input clk, input reset, output reg out ); always @(posedge clk or posedge reset) begin if (reset) begin out <= 1'b0; end else begin out <= ~reset && (out == 5'b10000) ? 1'b0 : (out + 1); end endmodule // 100 Hz signal module div100( input clk, input reset, output reg [3:0] out3, out2, out1, out0 ); always @(posedge clk or posedge reset) begin if (reset) begin out3 <= 4'b0; out2 <= 4'b0; out1 <= 4'b0; out0 <= 4'b0; end else begin out3 <= ~reset && (out3 == 4'b1001) ? 4'b0 : (out3 + 1); out2 <= ~reset && (out3 == 4'b1001 && out2 == 4'b1001) ? 4'b0 : (out2 == 4'b1001 ? out2 : (out2 + 1)); out1 <= ~reset && (out3 == 4'b1001 && out2 == 4'b1001 && out1 == 4'b1001) ? 4'b0 : (out1 == 4'b1001 ? out1 : (out1 + 1)); out0 <= ~reset && (out3 == 4'b1001 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001) ? 4'b0 : (out0 == 4'b1001 ? out0 : (out0 + 1)); end endmodule // 1 second signal module div1000( input clk, input reset, output reg [3:0] out3, out2, out1, out0 ); always @(posedge clk or posedge reset) begin if (reset) begin out3 <= 4'b0; out2 <= 4'b0; out1 <= 4'b0; out0 <= 4'b0; end else begin out3 <= ~reset && (out3 == 4'b1010) ? 4'b0 : (out3 == 4'b1001 ? (out2 == 4'b1001 ? (out1 == 4'b1001 ? (out0 == 4'b1001 ? 4'b0 : (out0 + 1)) : (out1 + 1)) : (out2 + 1)) : out3 + 1); out2 <= ~reset && (out3 == 4'b1010 && out2 == 4'b1001) ? 4'b0 : (out3 == 4'b1010 && out2 == 4'b1001 ? out2 : (out2 == 4'b1001 ? out2 : (out2 + 1))); out1 <= ~reset && (out3 == 4'b1010 && out2 == 4'b1001 && out1 == 4'b1001) ? 4'b0 : (out3 == 4'b1010 && out2 == 4'b1001 && out1 == 4'b1001 ? out1 : (out1 == 4'b1001 ? out1 : (out1 + 1))); out0 <= ~reset && (out3 == 4'b1010 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001) ? 4'b0 : (out3 == 4'b1010 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001 ? out0 : (out0 == 4'b1001 ? out0 : (out0 + 1))); end endmodule // 1 minute signal module div60000( input clk, input reset, output reg [3:0] out3, out2, out1, out0 ); always @(posedge clk or posedge reset) begin if (reset) begin out3 <= 4'b0; out2 <= 4'b0; out1 <= 4'b0; out0 <= 4'b0; end else begin out3 <= ~reset && (out3 == 4'b0110) ? 4'b0 : (out3 == 4'b0101 ? (out2 == 4'b1001 ? (out1 == 4'b1001 ? (out0 == 4'b1001 ? 4'b0 : (out0 + 1)) : (out1 + 1)) : (out2 + 1)) : out3 + 1); out2 <= ~reset && (out3 == 4'b0110 && out2 == 4'b1001) ? 4'b0 : (out3 == 4'b0110 && out2 == 4'b1001 ? out2 : (out2 == 4'b1001 ? out2 : (out2 + 1))); out1 <= ~reset && (out3 == 4'b0110 && out2 == 4'b1001 && out1 == 4'b1001) ? 4'b0 : (out3 == 4'b0110 && out2 == 4'b1001 && out1 == 4'b1001 ? out1 : (out1 == 4'b1001 ? out1 : (out1 + 1))); out0 <= ~reset && (out3 == 4'b0110 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001) ? 4'b0 : (out3 == 4'b0110 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001 ? out0 : (out0 == 4'b1001 ? out0 : (out0 + 1))); end endmodule // 1 hour signal module div3600000( input clk, input reset, output reg [3:0] out3, out2, out1, out0 ); always @(posedge clk or posedge reset) begin if (reset) begin out3 <= 4'b0; out2 <= 4'b0; out1 <= 4'b0; out0 <= 4'b0; end else begin out3 <= ~reset && (out3 == 4'b0001) ? 4'b0 : (out3 == 4'b0000 ? (out2 == 4'b1001 ? (out1 == 4'b1001 ? (out0 == 4'b1001 ? 4'b0 : (out0 + 1)) : (out1 + 1)) : (out2 + 1)) : out3 + 1); out2 <= ~reset && (out3 == 4'b0001 && out2 == 4'b1001) ? 4'b0 : (out3 == 4'b0001 && out2 == 4'b1001 ? out2 : (out2 == 4'b1001 ? out2 : (out2 + 1))); out1 <= ~reset && (out3 == 4'b0001 && out2 == 4'b1001 && out1 == 4'b1001) ? 4'b0 : (out3 == 4'b0001 && out2 == 4'b1001 && out1 == 4'b1001 ? out1 : (out1 == 4'b1001 ? out1 : (out1 + 1))); out0 <= ~reset && (out3 == 4'b0001 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001) ? 4'b0 : (out3 == 4'b0001 && out2 == 4'b1001 && out1 == 4'b1001 && out0 == 4'b1001 ? out0 : (out0 == 4'b1001 ? out0 : (out0 + 1))); end endmodule ``` 该代码实现了一个数字时钟,使用了七段数码管显示器来显示当前时间。其中,时钟信号通过时钟分频器逐步降频,最终得到1 Hz、10 Hz、100 Hz、1秒、1分钟和1小时的信号。时钟计数器通过这些信号来计算当前时间,并将其转换为适当的格式以供七段数码管显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值