怎么使用verilog进行按键消抖和新建STM32F4的工程模板文件
1、按键消抖
key_fliter.v
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
| module key_fliter #( parameter CNT_20MS=20'd1000000 )( input clk, input rst, input key_in, output reg key_flag );
reg [19:0] counter;
always@(posedge clk or negedge rst) begin if(!rst) counter<=1'b0; else if(key_in==1'b1) counter<=1'b0; else if(counter==CNT_20MS) counter<=CNT_20MS; else counter<=counter+1'b1; end
always@(posedge clk or negedge rst) begin if(!rst) key_flag<=1'b0; else if(counter==CNT_20MS-1) key_flag<=1'b1; else key_flag<=1'b0; end
endmodule
|
key.v
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
| module led( input clk, input rst, input key_in, output reg led );
wire key_flag;
key_fliter #( .CNT_20MS(20'd1000000) )led_inst ( .clk(clk), .rst(rst), .key_in(key_in), .key_flag(key_flag) );
always@(posedge clk or negedge rst) begin if(!rst) led<=1'b0; else if(key_flag==1'b1) led<=~led; else led<=led; end
endmodule
|
2、梅花代码小疑问
1 2
| #include <stdbool.h> #include <stdint.h>
|
#include <stdbool.h>:提供布尔类型支持,定义 bool、true、false,用于逻辑判断和状态标志,提升代码可读性。
#include <stdint.h>:提供精确位宽整数类型(如 uint8_t、int32_t),确保数据跨平台一致性,适用于硬件寄存器和协议数据处理。
初始化结构体,我们可以使用下列操作:
GPIO_InitTypeDef GPIO_InitStructure={0};
作用:将结构体所有成员显式清零(数值型为0,指针为NULL)。
我们也可以使用另外一种方法:
memset(&GPIO_InitStructure, 0, sizeof(GPIO_InitTypeDef));
但是要注意要引入头文件 #include<string.h>
memset是 C 语言标准库中的内存操作函数,其核心作用为 对指定内存区域进行快速填充。用一句话概括:
memset将一段连续内存的每个字节强制设置为指定值,常用于初始化内存块或数据清零。
memset函数举例子:
1 2 3 4 5 6 7
| GPIO_InitTypeDef config; memset(&config, 0, sizeof(config));
uint8_t buffer[100]; memset(buffer, 0xFF, sizeof(buffer));
|
static const led_desc_t led1 =
{
.clk_source = RCC_AHB1Periph_GPIOE,
.port = GPIOE,
.pin = GPIO_Pin_6,
.on_lvl = Bit_RESET,
.off_lvl = Bit_SET,
};
static用于修饰结构体变量 led1(而非结构体类型 led_desc_t)
核心作用:
将 led1变量的作用域限制为当前源文件,其他文件无法通过 extern引用该变量,实现以下目标:
避免命名冲突:多个文件可定义同名的 led1变量而不会引发链接错误。
const的作用:
硬件配置的确定性:
LED的引脚、时钟源等参数在硬件设计阶段就已固定,运行时修改无意义且可能导致故障。
示例(尝试修改会触发编译错误):
const修饰的变量会被编译器特殊处理,其存储位置和访问方式与普通变量不同。具体到您的代码:
1
| static const led_desc_t led1 = { ... };
|
存储位置:Flash(而非RAM)
普通变量:存储在RAM中,可读可写,但RAM空间有限(如STM32F4仅有192KB RAM)。
const变量:
编译器会将其放入 Flash(只读存储器) 中(例如STM32F4的1MB Flash),因为它的值在运行时不需要修改。
意义:节省宝贵的RAM空间,尤其对资源紧张的嵌入式设备至关重要。
我们在这里再来详细得讲解一下static这个关键字的作用吧
①修饰局部变量(函数内部)
作用:
✅ 延长生命周期
普通局部变量在函数调用结束后销毁,而static局部变量在程序整个运行期间存在(存储在静态存储区)。
1 2 3 4 5
| void counter() { static int count = 0; count++; printf("%d\n", count); }
|
- 第一次调用:输出 1
- 第二次调用:输出 2(保留上次的值)
②在C语言中,不加static的全局变量或函数可以被整个程序中的所有源文件访问,而加了static的全局变量或函数则只能被当前所在的源文件访问,其他文件无法使用它。
通俗解释
不加 static(默认情况):
全局变量或函数是“公开的”,其他文件只要用 extern声明就能访问。
比如:
1 2 3 4 5 6 7 8 9
| int global_var = 10; void public_func() { printf("Hello"); }
extern int global_var; extern void public_func();
|
加 static:
全局变量或函数变成“私有的”,只能在当前文件内使用,其他文件无法访问。
比如:
1 2 3 4 5 6 7 8 9
| static int private_var = 20; static void private_func() { printf("Secret"); }
extern int private_var; extern void private_func();
|
C语言标准规定:
static不能用于修饰结构体类型定义,它只能修饰变量或函数。这样的代码在 C 语言中 没有实际作用,编译器可能会忽略 static或给出警告。
1 2 3 4 5
| static struct Point { int x; int y; };
|
static可以用于修饰结构体变量
此时结构体类型仅在当前文件可用
1 2 3 4 5 6 7
| struct SecretData { int id; char name[20]; };
static struct SecretData data;
|
3、常规方法点亮LED
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
| #include <stdbool.h> #include <stdint.h> #include <string.h> #include "stm32f4xx.h"
static void led_delay(void) { for (uint32_t a = 0; a < 1000; a++) { for (uint32_t b = 0;b < 1000; b++) { __NOP(); __NOP(); __NOP(); __NOP(); } } }
static void led_init(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitTypeDef gpio_init; memset(&gpio_init, 0, sizeof(GPIO_InitTypeDef));
gpio_init.GPIO_Pin = GPIO_Pin_5; gpio_init.GPIO_Mode = GPIO_Mode_OUT; gpio_init.GPIO_OType = GPIO_OType_PP; gpio_init.GPIO_Speed = GPIO_Medium_Speed; GPIO_Init(GPIOE, &gpio_init);
gpio_init.GPIO_Pin = GPIO_Pin_6; gpio_init.GPIO_Mode = GPIO_Mode_OUT; gpio_init.GPIO_OType = GPIO_OType_PP; gpio_init.GPIO_Speed = GPIO_Medium_Speed; GPIO_Init(GPIOE, &gpio_init);
gpio_init.GPIO_Pin = GPIO_Pin_13; gpio_init.GPIO_Mode = GPIO_Mode_OUT; gpio_init.GPIO_OType = GPIO_OType_PP; gpio_init.GPIO_Speed = GPIO_Medium_Speed; GPIO_Init(GPIOC, &gpio_init);
}
int main(void) { led_init();
while(1) { GPIO_WriteBit(GPIOE, GPIO_Pin_5, Bit_RESET); GPIO_WriteBit(GPIOE, GPIO_Pin_6, Bit_RESET); GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); led_delay(); GPIO_WriteBit(GPIOE, GPIO_Pin_5, Bit_SET); GPIO_WriteBit(GPIOE, GPIO_Pin_6, Bit_SET); GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET); led_delay(); } }
|
4、使用对象方法点亮LED
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
| #include <stdbool.h> #include <stdint.h> #include <string.h> #include "stm32f4xx.h"
typedef struct led_desc { uint32_t clk_source; GPIO_TypeDef *port; uint16_t pin; BitAction on_lvl; BitAction off_lvl; } led_desc_t;
static const led_desc_t led0 = { .clk_source = RCC_AHB1Periph_GPIOE, .port = GPIOE, .pin = GPIO_Pin_5, .on_lvl = Bit_RESET, .off_lvl = Bit_SET, }; static const led_desc_t led1 = { .clk_source = RCC_AHB1Periph_GPIOE, .port = GPIOE, .pin = GPIO_Pin_6, .on_lvl = Bit_RESET, .off_lvl = Bit_SET, }; static const led_desc_t led2 = { .clk_source = RCC_AHB1Periph_GPIOC, .port = GPIOC, .pin = GPIO_Pin_13, .on_lvl = Bit_RESET, .off_lvl = Bit_SET, };
static void led_delay(void) { for (uint32_t a = 0; a < 1000; a++) { for (uint32_t b = 0;b < 1000; b++) { __NOP(); __NOP(); __NOP(); __NOP(); } } }
static void led_init(const led_desc_t *desc) { RCC_AHB1PeriphClockCmd(desc->clk_source, ENABLE);
GPIO_InitTypeDef ginit; memset(&ginit, 0, sizeof(GPIO_InitTypeDef)); ginit.GPIO_Pin = desc->pin; ginit.GPIO_Mode = GPIO_Mode_OUT; ginit.GPIO_OType = GPIO_OType_PP; ginit.GPIO_Speed = GPIO_Medium_Speed; GPIO_Init(desc->port, &ginit);
GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl); }
static void led_deinit(const led_desc_t *desc) { GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl); }
static void led_on(const led_desc_t *desc) { GPIO_WriteBit(desc->port, desc->pin, desc->on_lvl); }
static void led_off(const led_desc_t *desc) { GPIO_WriteBit(desc->port, desc->pin, desc->off_lvl); }
int main(void) { led_init(&led0); led_init(&led1); led_init(&led2);
while(1) { led_on(&led0); led_on(&led1); led_on(&led2); led_delay();
led_off(&led0); led_off(&led1); led_off(&led2); led_delay(); } }
|