HDL bits 题目知识点----持续更新

文章介绍了数字电路中的一些关键概念,包括使用符号如+和-进行切片操作,SOP和POS形式的逻辑函数表示,以及信号的打拍处理。此外,还详细阐述了双边采样的工作原理,并给出了示例代码。接着,文章提到了BCD计数器的实现,并展示了如何设计FIFO深度以适应不同频率的读写操作,确保数据传输的稳定性。最后,文章提到了算术右移的概念。

1、符号  +:   或者   -:

in[sel*4 +: 4]    代表取in的sel*4 到  sel*4 + (4-1)位,比如当sel为0 时,即in[0 +: 4] 代表从0开始取4位,也就是  in[3:0]

in[3 -: 4]  代表从3开始(包含3)向下取4个数 ,即in[3:0]

2、SOP和POS形式的逻辑函数分别通过最小项和最大项来获得。

SOP : 画 Y=1 时的式子

POS :画 Y = 0 的式子

3、对信号进行打拍的理解

4、双边采样

即对信号打半拍

module top_module (
    input clk,
    input d,
    output q
);
    wire clk_reg;
    reg d1;
    reg d2;
    /*
    assign q = clk? d1 : d2;
    always@ (posedge clk ) begin
          d1 <= d;
    end
    
    always@ (negedge clk ) begin
          d2 <= d;
    end
    */
    assign q = d1 ^ d2;
     always@ (posedge clk ) begin
          d1 <= d ^ d2;
    end
    
    always@ (negedge clk ) begin
          d2 <= d ^ d1;
    end
    
endmodule

5、BCD计数器

module top_module (
    input clk,
    input reset,   // Synchronous active-high reset
    output [3:1] ena,
    output [15:0] q);
    
    wire [3:0]c;
    
    assign ena = {c[0] & c[1]& c[2], c[1]& c[0], c[0]};
    
    ten one (
        .clk  (clk),
        .reset (reset),
        .count (q[3:0]),
        .ena (c[0]),
        .val(1'b1)
    );
    ten ten_inst (
        .clk  (clk),
        .reset (reset),
        .count (q[7:4]),
        .ena (c[1]),
        .val(c[0])
    );
    ten hud (
        .clk  (clk),
        .reset (reset),
        .count (q[11:8]),
        .ena (c[2]),
        .val(c[0] & c[1])
    );
    ten thou (
        .clk  (clk),
        .reset (reset),
        .count (q[15:12]),
        .ena (c[3]),
        .val(c[0] & c[1] & c[2])
    );
 
endmodule
 
module ten(
    input clk,
    input reset, 
    input val,
    output wire ena,
    output reg [3:0] count
);
    
    assign ena = count == 4'd9 ? 1'b1 : 1'b0;
    
    
	always@ (posedge clk)
        if(reset)
            count <= 4'd0;
    else if (count == 4'd9 && val)
        count <= 4'd0;
    else if(val)
        count <= count + 1;
    
    
    
endmodule

 5、设计 FIFO 的深度

假设 FIFO 的写时钟为 100MHZ,读时钟为 80MHZ。在 FIFO 输入侧,每 100 个时钟,写入

80 个数据;FIFO 读入测,每个时钟读取一个数据。设计合理的 FIFO 深度,使 FIFO 不会溢

出。

我们需要考虑数据轻载和重载的情况,对缓存能力要求最高的情况为背靠背传输,则 FIFO

深度为 160-(160/100)*80=32

我们将问题一般化:

1) 写时钟频率 WCLK

2) 读时钟频率 RCLK

3) 写入测每 B 个时钟周期有 A 个数据写入

4) 读取测每 Y 个时钟周期有 X 个数据读出

则 FIFO 的深度为,

其中 burst_length 与写入测情况有关。

 如果100个写时钟周期可以写入80个数据,10个读时钟可以读出8个数据。令wclk=rclk ,考虑背靠背(20个clk不发数据+80clk发数据+80clk发数据+20个clk不发数据的200个clk)代入公式可计算FIFO的深度
fifo_depth = 160-160X(80%)=160-128=32

    如果令wclk=200mhz,改为100个wclk里写入40个,rclk=100mhz,10个rclk里读出8个。那么fifo深度为48
计算如下fifo_depth =80-80X(80%)X(100/200)=80-32=48

6、>>>是算术右移,考虑符号位,如果是0,则左边补0,如果是1,则左边补1

7、

 

/******************************************************************************* @file HDL_WS2812B.c @author huiyang @version V1.0 @date 01/21/2022 ****************************************************************************/ #include “HDL_WS2812B.h” #include “stm32f10x.h” // Device header #include <math.h> #include “Delay.h” //延时函数加自己对应的头文件,在复位处使用 #include “OLED.h” uint32_t mode1[3] = {0xff0000,0x00ff00,0x0000ff};//绿红蓝 uint32_t mode2[3] = {0xffffff,0x00ff00,0x0000ff};//白红蓝 uint32_t mode3[3] = {0x0000ff,0x00ff00,0xffffff};//蓝红白 uint32_t mode_red[1] = {0x00ff00};//红 Bst arr[4] = { {0, 0, 0, mode1, 3}, // arr[0] {0, 0, 0, mode2, 3}, // arr[1] {0, 0, 0, mode3, 3}, // arr[2] {0, 0, 0, mode_red, 1} }; / 单个灯珠的编码对应的比较值数组 / uint16_t Single_LED_Buffer[DATA_SIZELED_NUM]; uint16_t All_LED_DE[LED_NUM]; / *作用:通用定时器2 TIM2_CH2 PWM输出+DMA初始化 *参数:arr:自动重装值 说明:定时器溢出时间计算方法:Tout=((arr+1)(psc+1))/Ft us. Ft=定时器工作频率,单位:Mhz */ void PWM_WS2812B_Init(uint16_t arr) { //结构体变量 GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; DMA_InitTypeDef DMA_InitStructure; //使能RCC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //使能TIM2时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //使能DMA1时钟 //初始化GPIO口 GPIO_InitStructure.GPIO_Pin = WS2812B_PIN; //GPIO口 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(WS2812B_PORT,&GPIO_InitStructure); //根据指定的参数初始化GPIO口 //初始化TIM2 TIM_TimeBaseStructure.TIM_Prescaler=0; //定时器分频:(0+1)=1,不分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分割 TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //根据指定的参数初始化TIM2 //初始化TIM2 Channel2 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 //TIM_OCInitStructure.TIM_Pulse = 0; //待装入捕获比较寄存器的脉冲值(此程序不用加初值) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC2Init(TIM2, &TIM_OCInitStructure); //根据指定的参数初始化外设TIM2 Channel2 /* 此处为知识点所描述处的对应代码,一定要有。移植时注意0C2代表定时器通道2*/ TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR2上的预装载寄存器 TIM_Cmd(TIM2, DISABLE); //失能TIM2,防止第一个脉冲异常 TIM_DMACmd(TIM2, TIM_DMA_CC2, ENABLE); //使能TIM2_CH2的DMA功能(CC2对应通道2) DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM2->CCR2); //设置DMA目的地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Single_LED_Buffer; //设置DMA源地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //方向:从内存SendBuff到内存ReceiveBuff DMA_InitStructure.DMA_BufferSize = DATA_SIZE; //一次传输大小DMA_BufferSize=SendBuffSize DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //ReceiveBuff地址不增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //SendBuff地址自增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //ReceiveBuff数据单位,16bit DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //SENDBUFF_SIZE数据单位,16bit DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA模式:正常模式(传输一次) DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级:中 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //内存到内存的传输 DMA_Init(DMA1_Channel7, &DMA_InitStructure); //配置DMA1的7通道(不同定时器的通道不一样) DMA_Cmd(DMA1_Channel7, DISABLE); //失能DMA1的7通道,因为一旦使能就开始传输 } //复位灯带 void WS2812B_Reset(void) { TIM_Cmd(TIM2, DISABLE); WS2812B_LOW; Delay_ms(1); //此处延时时间最小值大于50us即可 } //写数据编码 void PWM_WS2812B_Write_24Bits(uint16_t num, uint32_t GRB_Data) { // 参数解释变更: // num: 如果为特定值(如0xFFFF),则表示写入所有灯珠(保持向后兼容) // 否则,num代表要设置的单个灯珠的索引 // GRB_Data: 要写入的颜色值 uint8_t i; // 判断是设置所有灯珠还是单个灯珠 if (num == 0xFFFF) { // 使用一个特殊值表示设置全部灯珠 for (uint16_t j = 0; j < LED_NUM; j++) { for (i = 0; i < DATA_SIZE; i++) { Single_LED_Buffer[j * DATA_SIZE + i] = ((GRB_Data << i) & 0x800000) ? T1H : T0H; } } } else { // 设置单个灯珠 if (num >= LED_NUM) return; // 索引检查 for (i = 0; i < DATA_SIZE; i++) { Single_LED_Buffer[num * DATA_SIZE + i] = ((GRB_Data << i) & 0x800000) ? T1H : T0H; } } } //点亮灯珠 void PWM_WS2812B_Show(uint16_t num) typedef struct { uint16_t breath_step; uint8_t current_color_index; uint32_t current_color; uint8_t breath_direction; // 0:增加亮度, 1:减小亮度 } BreathingState_t; static BreathingState_t breath_state = {0, 0, 0, 0}; void PWM_WS2812B_SetBrightness(uint32_t* grb_color, uint8_t brightness) { if (brightness > MAX_BRIGHTNESS) brightness = MAX_BRIGHTNESS; // 分离GRB分量 uint8_t g = (*grb_color >> 16) & 0xFF; uint8_t r = (*grb_color >> 8) & 0xFF; uint8_t b = *grb_color & 0xFF; // 应用亮度缩放(保持颜色比例) g = (g * brightness) / MAX_BRIGHTNESS; r = (r * brightness) / MAX_BRIGHTNESS; b = (b * brightness) / MAX_BRIGHTNESS; // 重新组合GRB颜色 *grb_color = ((uint32_t)g << 16) | ((uint32_t)r << 8) | b; } void PWM_WS2812B_Breathing_MultiColor(uint16_t start_id, uint16_t end_id, Bst *current, uint8_t color_count, uint16_t speed) { if (start_id >= LED_NUM || end_id >= LED_NUM || start_id > end_id || color_count == 0) return; //static uint16_t breath_step = 0; //static uint8_t current_color_index = 0; uint16_t i; // 计算颜色过渡比例 uint8_t next_color_index = (current->current_color_index + 1) % color_count; OLED_ShowNum(3,1,next_color_index, 2); float transition_ratio = (float)current->breath_step / BREATH_STEP_MAX; // 获取当前和下一个颜色 uint32_t current_grb = current->color_palette[current->current_color_index]; uint32_t next_grb = current->color_palette[next_color_index]; // 分离当前颜色的GRB分量 uint8_t current_g = (current_grb >> 16) & 0xFF; uint8_t current_r = (current_grb >> 8) & 0xFF; uint8_t current_b = current_grb & 0xFF; // 分离下一个颜色的GRB分量 uint8_t next_g = (next_grb >> 16) & 0xFF; uint8_t next_r = (next_grb >> 8) & 0xFF; uint8_t next_b = next_grb & 0xFF; // 线性插值计算过渡颜色 uint8_t final_g = current_g + (uint8_t)((next_g - current_g) * transition_ratio); uint8_t final_r = current_r + (uint8_t)((next_r - current_r) * transition_ratio); uint8_t final_b = current_b + (uint8_t)((next_b - current_b) * transition_ratio); uint32_t final_color = ((uint32_t)final_g << 16) | ((uint32_t)final_r << 8) | final_b; // 应用正弦波亮度变化 float sin_value = sinf(2 * 3.14159f * current->breath_step / BREATH_STEP_MAX); uint8_t brightness = (uint8_t)((sin_value + 1.0f) * 50.0f); PWM_WS2812B_SetBrightness(&final_color, brightness); // 设置灯珠颜色 for (i = start_id; i <= end_id; i++) { PWM_WS2812B_Write_24Bits(i, final_color); } // 显示更新 // 更新状态 current->breath_step += speed; if (current->breath_step >= BREATH_STEP_MAX) { current->breath_step = 0; current->current_color_index = next_color_index; } } void PWM_WS2812B_BreathingCycle_Segment(uint16_t start_id, uint16_t end_id, uint16_t speed, Bst current) { PWM_WS2812B_Breathing_MultiColor(start_id, end_id, current, current->color_count, speed); } void PWM_WS2812B_Allreset(void) { uint16_t i; for(i = 0; i < LED_NUM; i++) { PWM_WS2812B_Write_24Bits(i, Dead_color);//先让所有熄灭 All_LED_DE[i] = 0;//同时让所有失能 } } /****************************************************************************** @file HDL_WS2812B.h @author huiyang @version V1.0 @date 01/21/2022 ******************************************************************************/ #ifndef _HDL_WS2812B_H #define _HDL_WS2812B_H #include “stm32f10x.h” #define MAX_BRIGHTNESS 100 // 最大亮度百分比 #define BREATH_STEP_MAX 512 // 呼吸步进最大值 #define WS2812B_PIN GPIO_Pin_1 #define WS2812B_PORT GPIOA #define WS2812B_LOW GPIO_ResetBits(WS2812B_PORT,WS2812B_PIN) #define WS2812B_HIGH GPIO_SetBits(WS2812B_PORT,WS2812B_PIN) #define Dead_color 0x000000 #define GREEN 0xFF0000 #define RED 0x00FF00 #define BLUE 0x0000FF #define WHITE 0xFFFFFF /* 根据DataSheet定义0/1编码对应的高电平比较值,因为高电平在前,定义高电平的即可 ** 高低电平的比例约为2:1 */ #define WS2812B_ARR 90 //TIM2的自动重装载值 #define T0H 29 //0编码高电平时间占1/3 #define T1H 58 //1编码高电平时间占2/3 /* 灯珠亮的个数 / #define LED_NUM 100 //底层驱动未用,为应用方便,先加上 #define DATA_SIZE 24 //WS2812B一个编码的bit数,38\uint32_t mode1[3] = {0xff00,0x00ff00,0x0000ff};//绿--蓝 extern uint32_t mode1[3]; extern uint32_t mode2[3]; extern uint32_t mode3[3]; extern uint32_t mode_red[1]; typedef struct { uint16_t breath_step; uint8_t current_color_index; uint8_t breath_direction; uint32_t* color_palette; uint8_t color_count; } Bst; extern Bst arr[4]; void PWM_WS2812B_Init(uint16_t arr); void WS2812B_Reset(void); void PWM_WS2812B_Write_24Bits(uint16_t num,uint32_t GRB_Data); void PWM_WS2812B_Show(uint16_t num); void PWM_WS2812B_Red(uint16_t num); void PWM_WS2812B_Green(uint16_t num); void PWM_WS2812B_Blue(uint16_t num); void PWM_WS2812B_BreathingCycle_Segment(uint16_t start_id, uint16_t end_id, uint16_t speed, Bst current); void PWM_WS2812B_SetBrightness(uint32_t grb_color, uint8_t brightness); void PWM_WS2812B_Breathing_SingleColor(uint16_t start_id, uint16_t end_id, uint32_t base_color, uint16_t speed); void PWM_WS2812B_Breathing_MultiColor(uint16_t start_id, uint16_t end_id, Bst current, uint8_t color_count, uint16_t speed); void PWM_WS2812B_Allreset(void); #endif 基于以上代码,不要修改已经确定的量,实现控制N个级联的10*10WS2812B板显示波纹的RGB渐变效果,要求能自定义精确控制能以第几个板的某一点或某一中心区域(4个点)为中心的水波纹效果,可以实现多个同时出现的波纹效果
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eachanm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值