基于FPGA的超声波雷达感应预警系统 全过程记录
FPGA系统开发 综合实验记录
实验时间节点与想法记录
-
2023.4.24 新建本文档。目前决定有以下两个方案,要根据学校发的器件和自己的水平和后面时间决定。
课设想法 具体情况 基于FPGA的高速运动体速度测量系统设计 难,可以当小型的毕业设计 基于FPGA的智能交通装置 做的人比较多,要有创新点 -
2023.4.27 决定使用超声波雷达作为项目。目前想法是使用舵机+雷达实现360度探测障碍物,如果在某一方向有距离接近,则在某一方向锁定探测范围,并报告距离。如果距离达到设定值则蜂鸣器报警。
-
2023.5.12 购买以下器件用于实验
器件 具体情况 备注 杜邦线 公对母/母对母若干条 HC-SR04超声波模块 宽电压3-5.5V SG90舵机 9克经典舵机180度 无源蜂鸣器 2-4V无源9042电磁式16欧2731HZ 2只 -
2023.5.13 完成比较清晰的实现思路
厂家把GPIO对应图放在User Manner里很难吗? -
2023.5.15 完成实体连接
每周一晚固定在Uboot上浪费2小时😪 -
2023.5.21 要做了才发现舵机买错了,360°舵机没法控制特定角度,只能控制转速。下单180°
-
2023.5.22 完成状态转移图 超声波测距模块 舵机模块和数码管模块的编写
-
2023.5.25 Good News:谢天谢地,全编译能过了! Bad News: IO口只有16mA的电流,蜂鸣器要50mA的电流,估计响不起来,硬件真难!
-
2023.5.26 Good News:舵机能转! Bad News:数码管显示全部无效,按钮无效。蜂鸣器响不起来。
-
2023.5.27 写二进制转BCD的最好方法——写一个Python代码直生成对应CASE直接查,要多快有多快。
-
2023.5.29 Good News:超声波模块能用了! Bad News:效果太差,器件原因很不稳定,没法做到检测物体位置变化。
-
2023.6.1 位宽又错了!😒 如何在浩如烟海的Warning中找到错误?
-
2023.6.2 Good News:基本实现功能,等待进一步测试。 Bad News:舵机驱动不到0°,范围只能在30°到180°。
-
2023.6.4 完成全部内容。
器件功能与使用
HC-SR04超声波模块
1 基本工作原理
(1)采用 IO 口 TRIG 触发测距,需要给最少 10us 的高电平信号。
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
测试距离=(高电平时间*声速(340M/S))/2
2 实物图
3 电气参数
4 超声波时序图
5 使用建议
建议测量周期为 60ms 以上,以防止发射信号对回响信号的影响。
模块不宜带电连接,若要带电连接,则先让模块的 GND 端先连接,否则会影响模块的正常工作。
测距时,被测物体的面积不少于 0.5 平方米且平面尽量要求平整,否则影响测量的结果。
SG90舵机
1 基本工作原理
控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。
2 实物连接
黄线接信号线,红线接VCC 5V,褐色线接GND。
3 FPGA与舵机
FPGA可以很方便地将脉宽的精度精确地控制在2微秒甚至2微秒以下。主要还是Delay Memory这样的具有创造性的指令发挥了功效。该指令的延时时间为数据单元中的立即数的值加1个指令周期(数据0除外,详情请参见Delay指令使用注意事项)因为是8位的数据存储单元,所以Memory中的数据为(0~255),记得前面有提过,舵机的角度级数一般为1024级,所以只用一个存储空间来存储延时参数好像还不够用的,所以可以采用2个内存单元来存放舵机的角度伺服参数了。所以这样一来,我们可以采用这样的软件结构了。
SG90(360°)需要什么信号? 首先必须明确,SG90不论是90°、180°还是360°,它需要的控制信号都是周期为20ms的脉宽调制(PWM)信号,只是脉冲宽度从0.5ms-2.5ms在三种舵机上的作用不同。对于360°舵机来说,0.5-1.5ms的脉冲宽度实现顺时针转动,只是速度不同;1.5-2.5ms的脉冲宽度实现逆时针转动,也只是速度不同;1.5ms的脉冲宽度实现暂停。 这里还需要明确一点(举例来说),脉冲宽度为1ms、周期为20ms的脉宽调制信号需要不断传输给舵机才能保证舵机不停地顺时针转动,并不是给了一个周期信号就完事了!https://blog.csdn.net/SHRtuji/article/details/113354315
无源蜂鸣器
基本工作原理
何为有源,何为无源?有源指的是蜂鸣器内部包含振荡电路。无源指的是蜂鸣器内部不包含振荡电路。有源蜂鸣器接入电源即可发声,但发声频率是固定的。无源蜂鸣器因为它本身没有内部振荡电路,所以需要一个外部的时钟信号才能将其驱动起来,令其发声。
PWM方波
通过输入不同频率和占空比的PWM方波实现驱动蜂鸣器。频率影响音调,占空比影响大小。
https://blog.csdn.net/cabinGGG/article/details/124745482
开发板与外设连接
GPIO
The board has two 40-pin expansion headers. Each header has 36 user pins connected directly to the Cyclone V SoC FPGA. It also comes with DC +5V (VCC5), DC +3.3V (VCC3P3), and two GND pins. The maximum power consumption allowed for a daughter card connected to one or two GPIO ports is shown in Table 3-10.
7段数码管
LED、按键、开关
管脚分配
实体连接
A端 | B端 | 线类型 |
---|---|---|
JP1 11 | HC-SR04 VCC | 母对母 |
JP1 12 | HC-SR04 GND | 母对母 |
JP1 13 | HC-SR04 TRIG | 母对母 |
JP1 14 | HC-SR04 ECHO | 母对母 |
JP2 11 | SG90 VCC 红线 | 公对母 |
JP2 12 | SG90 GND 褐线 | 公对母 |
JP2 13 | SG90 信号线 黄线 | 公对母 |
实现思路
- 7段数码管总计使用6个。前三个用于显示舵机转的度数,精确到每度。后三个用于显示距离,单位为厘米,精确到个位。
- 开关总计使用4个。用于表示自动扫描/固定扫描模式2个,自动扫描模式即180度自动扫描,固定扫描则可通过利用按键进行左右调整到某个方位。用于复位1个,距离探测控制开关1个。
- 按键总计使用2个。用于左右调整各1个。
- LED总计使用8个。用于4个开关状态的工作情况各1个。距离告警4个。
5. 蜂鸣器使用2个。用于报警声,报警声在探测到目标时即响起,当目标接近时报警声频率音量改变,目标远离时消失。
Verilog 代码
十进制转BCD码模块
module decimalToBCD
( input [9:0] bin , // binary
output reg [11:0] bcd ); // bcd {...,thousands,hundreds,tens,ones}
always @(*) begin
case(bin)
10'd0:bcd=12'b000000000000;
10'd1:bcd=12'b000000000001;
// 同上,省略
10'd998:bcd=12'b100110011000;
10'd999:bcd=12'b100110011001;
endcase
end
endmodule
十进制转BCD码在高级代码语言是很简单的事,但在FPGA开发中有些麻烦,因为在FPGA开发中乘除法会占用一定的系统资源。通过查阅资料,有以下方法用于在Verilog语言下解决十进制转BCD码的问题:
- 传统的循环乘除法。不做过多介绍。
- 移位加 3 法。这种方法是数字逻辑里使用的方法,但在位数变化后,对代码需要做一定调整。
- 在数据源头上就使用 BCD 码处理数字,直接判断何时需要进位。这种方法只能解决一类问题,泛化性差。
- 通过 Python 生成 SwitchCase 语句,直接查表。这种方法简单有效,非常符合本次实验设计的需要。以下是相关的Python代码。
for i in range(1000):
num = str(i).zfill(3)
bcd = ''
for digit in num:
bcd += bin(int(digit))[2:].zfill(4)
print(' 10\'d{0}:bcd=12\'b{1}'.format(i,bcd))
数码管显示模块
修改了原有数字 9 的设计,把最下面的也点亮。
/* 数码管显示模块
*/
module SEG7_LUT(
input [3:0] iDIG, //BCD码
output reg [6:0] oSEG //数码管各段信号
);
always @(iDIG) begin
case(iDIG)
4'h1:oSEG=7'b1111001;
4'h2:oSEG=7'b0100100;
4'h3:oSEG=7'b0110000;
4'h4:oSEG=7'b0011001;
4'h5:oSEG=7'b0010010;
4'h6:oSEG=7'b0000010;
4'h7:oSEG=7'b1111000;
4'h8:oSEG=7'b0000000;
4'h9:oSEG=7'b0010000;
4'h0:oSEG=7'b1000000;
endcase
end
endmodule
数码管综合模块
该模块把输入的角度值和距离值,转化为BCD码,在转换为数字管输出信号。
module Seg7_Display
(
input rst_n, //低电平有效
input [9:0] angle, //角度值,显示在前三个数码管
input [9:0] distance, //距离值,显示在后三个数码管
output [6:0] HEX0, //各数码管输出信号
output [6:0] HEX1,
output [6:0] HEX2,
output [6:0] HEX3,
output [6:0] HEX4,
output [6:0] HEX5
);
wire [23:0] mSEG7_DIG;
wire [6:0] mHEX0,mHEX1,mHEX2,mHEX3,mHEX4,mHEX5;
assign {HEX5,HEX4,HEX3,HEX2,HEX1,HEX0}=rst_n?{mHEX5,mHEX4,mHEX3,mHEX2,mHEX1,mHEX0}:42'h0;
decimalToBCD b3(.bin(angle),.bcd(mSEG7_DIG[23:12]));
decimalToBCD b4(.bin(distance),.bcd(mSEG7_DIG[11:0]));
SEG7_LUT u0(.oSEG(mHEX0),.iDIG(mSEG7_DIG[3:0]));
SEG7_LUT u1(.oSEG(mHEX1),.iDIG(mSEG7_DIG[7:4]));
SEG7_LUT u2(.oSEG(mHEX2),.iDIG(mSEG7_DIG[11:8]));
SEG7_LUT u3(.oSEG(mHEX3),.iDIG(mSEG7_DIG[15:12]));
SEG7_LUT u4(.oSEG(mHEX4),.iDIG(mSEG7_DIG[19:16]));
SEG7_LUT u5(.oSEG(mHEX5),.iDIG(mSEG7_DIG[23:20]));
endmodule
按键去抖模块
通过延时20个时间单位再次检测,实现按键去抖的效果。
/* 按键去抖检测模块
*/
module debounce(
input clk, //时钟
input rst_n, //低电平复位
input btn, //原始按键信号
output reg btn_pressed //去抖后的按键信号
);
parameter debounce_time = 20; // 设置去抖时间
reg [debounce_time - 1:0] counter;
reg btn_state, btn_sample;
always @(posedge clk) begin
if (!rst_n) begin
btn_pressed <= 0;
btn_state <= 1;
counter <= 0;
end else begin
// 按键状态和采样值
btn_state <= btn;
btn_sample <= btn & btn_state;
if (counter == debounce_time - 1) begin
if (btn_sample == 0 && btn_state == 1) begin
// 去抖完成,并且检测到按键按下
btn_pressed <= 1;
end else begin
btn_pressed <= 0;
end
end else begin
// 倒计时减少
counter <= counter + 'd1;
end
end
end
endmodule
舵机控制模块
这个模块总体实现不难,主要是了解控制舵机的原理和角度与占空比之间的关系,该模块的代码也大部分来自网络公开资料。
/* 舵机控制模块
*/
module Steering_Gear(
input sys_clk, //时钟
input rst_n, //低电平有效
input gear_req, //舵机转动请求
input[9:0] angle, //转动角度 最大值180
output gear_ack, //舵机转动完成信号
output gear //舵机IO口
);
localparam T_20ms = 'd1000_000;// 周期20ms
reg[20:0] T_cnt; // 周期计时器
reg gear_reg;
assign gear = gear_reg;
assign gear_ack = ( T_cnt == T_20ms ) ? 1'b1 : 1'b0;
//周期计数
always@(posedge sys_clk or negedge rst_n )
begin
if( rst_n == 1'b0 )
T_cnt <= 'd0;
else if( gear_ack == 1'b1 )
T_cnt <= 'd0;
else if( gear_req == 1'b1 )
T_cnt <= T_cnt + 1'b1;
else
T_cnt <= 'd0;
end
//脉冲输出 根据度数转换为每 20ms 里高电平所占的时间。
always@(posedge sys_clk or negedge rst_n)
begin
if( rst_n == 1'b0 )
gear_reg <= 1'b0;
else if( gear_req == 1'b1 && T_cnt < ( angle * 'd555 + 'd2500) )
gear_reg <= 1'b1;
else
gear_reg <= 1'b0;
end
endmodule
超声波测距模块
该模块的代码也大部分来自网络公开资料,但在距离换算上进行改动。原有的距离换算包括乘除法,为避免这种情况,可通过改变时钟频率,实现 1cm = 1 次计数,这样计数器的值就是距离,虽然失去一定精度,然而本身数字管显示的单位是CM,对最终结果影响并不大。17kHZ时钟的计算来源如下:
声速取 340 m/s ,设所需要的时钟频率为 P,(1/P) = (34000 / 2) cm/s
(1/17k)/(1/50M) 取 2940 。
同时,增加每隔一定时间检测的部分,避免超声信号发送和接受时的干扰。
/* 超声波测距模块
*/
module Ultrasonic(
input sys_clk, //时钟
input rst_n, //低电平复位
output trig, //超声波模块的触发信号
input echo, //超声波模块的回响信号
input trig_req, //超声波测距请求信号
output trig_ack, //超声波测距响应信号
output [9:0] distance //超声波测距结果,单位cm
);
localparam trig_time = 'd2250; //触发时间计时 45us
localparam S_IDLE = 'd0; //初始状态
localparam S_SEND_Trig = 'd1; //发送触发信号状态
localparam S_WATI_Echo = 'd2; //等待全部响应信号状态
localparam S_END = 'd3; //响应结束状态
reg[3:0] state, next_state;
reg[31:0] request_cnt;
reg[21:0] trig_cnt; //触发信号计时器
reg[21:0] echo_cnt; //回响信号计时器
reg[21:0] clk_17k; //17kHZ时钟
reg echo_d0, echo_d1;
wire echo_posedge, echo_negedge; //回响信号的上下边沿
assign echo_posedge = echo_d0 & (~echo_d1);
assign echo_negedge = (~echo_d0) & echo_d1;
assign distance = (echo_cnt);
assign trig_ack = ( echo_negedge == 1'b1 ) ? 1'b1 : 1'b0;
assign trig = (state == S_SEND_Trig) ? 1'b1 : 1'b0;
always@(posedge sys_clk or negedge rst_n )
begin
if( rst_n == 1'b0)
begin
echo_d0 <= 1'b0;
echo_d1 <= 1'b0;
end
else if( state == S_WATI_Echo )
begin
echo_d0 <= echo;
echo_d1 <= echo_d0;
end
else
begin
echo_d0 <= 1'b0;
echo_d1 <= 1'b0;
end
end
always@( posedge sys_clk or negedge rst_n)
begin
if ( rst_n == 1'b0 )
state <= S_IDLE;
else
state <= next_state;
end
always@(*)
begin
case (state)
S_IDLE:
if(trig_req == 1'b1)
next_state <= S_SEND_Trig;
else
next_state <= S_IDLE;
S_SEND_Trig:
if(trig_cnt == trig_time)
next_state <= S_WATI_Echo;
else
next_state <= S_SEND_Trig;
S_WATI_Echo:
if(echo_negedge == 1'b1)
next_state <= S_END;
else
next_state <= S_WATI_Echo;
S_END:
next_state <= S_IDLE;
default: next_state <= S_IDLE;
endcase
end
// 为保证返回信号不与发送信号冲突,需要间隔 60ms 以上发送下次触发信号。
always@(posedge sys_clk or negedge rst_n)
begin
if( rst_n == 1'b0) begin
trig_cnt <= 'd0;
request_cnt <= 'd0;
end else if (state == S_SEND_Trig & request_cnt < 'd5000000) begin
request_cnt <= request_cnt + 'd1;
trig_cnt <= 'd0;
end else if (state == S_SEND_Trig & request_cnt >= 'd5000000) begin
trig_cnt <= trig_cnt + 1'b1;
end else begin
trig_cnt <= 'd0;
request_cnt <= 'd0;
end
end
// 使用17kHZ信号计算echo信号值,echo_cnt的值 = 距离,避免乘除运算导致电路复杂化。
always@(posedge sys_clk or negedge rst_n)
begin
if( rst_n == 1'b0)
begin
echo_cnt <= 'd0;
clk_17k <= 'd0;
end
else if(state == S_WATI_Echo && echo == 1'b1)
begin
if(clk_17k < 'd2940)
begin
clk_17k <= clk_17k + 1'b1;
end
else
begin
clk_17k <= 'b0;
echo_cnt <= echo_cnt + 1'b1;
end
end
else if(state == S_END) begin
echo_cnt <= echo_cnt;
clk_17k <= clk_17k;
end
else begin
echo_cnt <= 'd0;
clk_17k <= 'd0;
end
end
endmodule
顶层模块
根据上述实验实现思路,编写顶层模块。
module RADAR(
input sys_clk, //系统时钟
input [1:0] Key_in, //2 按键 1 - 0
input [3:0] Switch_on, //4 开关 3 - 0
output reg [7:0] LED, //8 LED 7 - 0
output trig, //超声波模块的触发信号
input echo, //超声波模块的回响信号
output signal_gear, //舵机驱动信号
output [6:0] THEX0, //6 数码管
output [6:0] THEX1,
output [6:0] THEX2,
output [6:0] THEX3,
output [6:0] THEX4,
output [6:0] THEX5
);
Seg7_Display d1(.rst_n(rst_n_d1),.angle(ANGLE),.distance(DISTANCE),.HEX0(THEX0),.HEX1(THEX1),.HEX2(THEX2),.HEX3(THEX3),.HEX4(THEX4),.HEX5(THEX5));
Steering_Gear s1(.sys_clk(sys_clk),.rst_n(rst_n_s1),.gear_req(1'b1),.angle(ANGLE),.gear_ack(),.gear(signal_gear));
debounce b1(.clk(sys_clk),.rst_n(rst_n_b),.btn(Key_in[0]),.btn_pressed(left));
debounce b2(.clk(sys_clk),.rst_n(rst_n_b),.btn(Key_in[1]),.btn_pressed(right));
Ultrasonic u1(.sys_clk(sys_clk),.rst_n(rst_n_u),.trig(trig),.echo(echo),.trig_req(Switch_on[3]),.trig_ack(ACK_trig),.distance(distance_out));
wire [9:0] distance_out;
reg [9:0] ANGLE = 'd90;
reg [9:0] DISTANCE = 'd999;
reg [31:0] count = 'd0;
wire right, left;
reg direction = 1'b0;
always @(posedge sys_clk) begin
if (distance_out > 'd1) begin
DISTANCE <= distance_out; // 超声波模块信号输入至寄存器
end else begin
DISTANCE <= DISTANCE;
end
// 在不同的距离区间下,LED 7 - 4 依次亮起提示
if (DISTANCE < 'd25 & DISTANCE >= 'd1) begin
LED[7] <= 1'b1;
end else begin
LED[7] <= 1'b0;
end
if (DISTANCE < 'd50 & DISTANCE >= 'd25) begin
LED[6] <= 1'b1;
end else begin
LED[6] <= 1'b0;
end
if (DISTANCE < 'd75 & DISTANCE >= 'd50) begin
LED[5] <= 1'b1;
end else begin
LED[5] <= 1'b0;
end
if (DISTANCE < 'd100 & DISTANCE >= 'd75) begin
LED[4] <= 1'b1;
end else begin
LED[4] <= 1'b0;
end
// 开关 3 打开时,超声波模块不断探测;关闭时,超声波模块暂停探测。
if (Switch_on[3]) begin
LED[3] <= 1'b1;
end else begin
LED[3] <= 1'b0;
end
end
// 依次为数码管模块,舵机模块,按键模块,超声波模块的复位信号
reg rst_n_d1 = 1'b1, rst_n_s1 = 1'b1, rst_n_b = 1'b1, rst_n_u = 1'b1;
always @(posedge sys_clk) begin
if (Switch_on[0]) begin // 开关 0 打开时,各模块均低电平复位。
rst_n_d1 <= 1'b0;
rst_n_s1 <= 1'b0;
rst_n_b <= 1'b0;
rst_n_u <= 1'b0;
LED[2:0] <= 3'b001; // LED 0 亮起提示
count <= 'd0;
end else if (Switch_on[1]) begin // 开关 1 打开时,自动扫描模式开启。
rst_n_d1 <= 1'b1;
rst_n_s1 <= 1'b1;
rst_n_b <= 1'b0; // 屏蔽按键模块
rst_n_u <= 1'b1;
LED[2:0] <= 3'b010; // LED 1 亮起提示
if (count == 'd8000000) begin //如果达到预定值,则执行下面的操作
count <= 'd0;
if (direction == 1'b0) begin //方向是递增
if (ANGLE + 'd1 <= 'd179) begin //如果当前角度小于 180 度,则将其递增 1 度
ANGLE <= ANGLE + 'd1;
end
if (ANGLE + 'd1 > 'd179) begin //否则,改变方向为递减
direction <= 2'b01;
end
end
if (direction == 2'b01) begin //方向是递减
if (ANGLE - 'd1 >= 'd30) begin //如果当前角度大于 30 度,则将其递增 1 度
ANGLE <= ANGLE - 'd1;
end
if (ANGLE - 'd1 < 'd30) begin //否则,改变方向为递增
direction <= 2'b00;
end
end
end else begin
count <= count + 'd1; //否则,继续递增计数器
end
end else if (Switch_on[2]) begin // 开关 2 打开时,手动调整模式开启。
rst_n_d1 <= 1'b1;
rst_n_s1 <= 1'b1;
rst_n_b <= 1'b1;
rst_n_u <= 1'b1;
LED[2:0] <= 3'b100; // LED 2 亮起提示
if (right == 1'b1) begin // 按键 0 按下代表舵机角度递增
if (ANGLE + 'd1 <= 'd179 ) begin // 如果当前角度小于 180 度,则将其递增 1 度
ANGLE <= ANGLE + 'd1;
end
end
if (left == 1'b1) begin // 按键 1 按下代表舵机角度递增
if (ANGLE - 'd1 >= 'd30) begin // 如果当前角度大于 30 度,则将其递增 1 度
ANGLE <= ANGLE - 'd1;
end
end
end else begin // 开关 2 - 0 均关闭时,舵机重置至 90 度。
rst_n_d1 <= 1'b1;
rst_n_s1 <= 1'b1;
rst_n_b <= 1'b0; // 按键屏蔽
rst_n_u <= 1'b1;
LED[2:0] <= 3'b000;
ANGLE <= 'd90;
end
end
endmodule
实现效果
在线仿真和调试
视频展示
一些报错和实验心得整理
Error (10759): Verilog HDL error at LabFinal.v(20): object SINGAL_gear declared in a list of port declarations cannot be redeclared within the module body
在模块体内和模块声明中,不能重复定义。
Error (10170): Verilog HDL syntax error at LabFinal.v(140) near text: "and"; expecting ")". Check for and fix any syntax errors that appear immediately before or at the specified keyword. The Intel FPGA Knowledge Database contains many articles with specific details on how to resolve this error. Visit the Knowledge Database at https://www.altera.com/support/support-resources/knowledge-base/search.html and search for this specific error message number.
这个错误不一定出现在这行,可能出现在其他地方,需要仔细检查语法。只有敏感信号才用 and
和 or
,其他语句里是不能用的。Python 的习惯带过来了。
Error (10267): Verilog HDL Module Instantiation error at LabFinal.v(266): cannot connect instance ports both by order and by name
仔细检查模块对应的端口名称,确保对应。
Error (10734): Verilog HDL error at decimalToBCD.v(10): i is not a constant
位宽必须是个定值,在位宽内注意循环变量的使用。并注意bcd[i*4+3:i*4] = decimal % 10;
和 genvar
的使用。
Error (10219): Verilog HDL Continuous Assignment error at LabFinal.v(34): object "LED" on left-hand side of assignment must have a net type
Error (10663): Verilog HDL Port Connection error at LabFinal.v(263): output or inout port "btn_pressed" must be connected to a structural net expression
模块input的端口,可以是wire
也可是reg
,但是output的端口必须是wire
.
Error (12007): Top-level design entity "LabFinal" is undefined
确认顶层模块名称是否和项目设置对应。
Error (10028): Can't resolve multiple constant drivers for net "rst_neg_g" at LabFinal.v(64)
一个变量不能在多个always
语句块内赋值,即使在设计中两个模块的赋值时并不会冲突。
Error (10110): Verilog HDL error at LabFinal.v(222): variable "flag" has mixed blocking and nonblocking Procedural Assignments -- must be all blocking or all nonblocking assignments
一个变量要么在时序逻辑中,要么在组合逻辑中,不能混合存在。
- 所有位宽都要确认是不是能够满足所存的数,不能满足并不会报错!
- 所有数字都要写清楚位宽和表示方法,就算
+ 1
也最好写成+ 'd1
! - 在每一次更改代码后都要仔细检查语法错误,每编译一次都需要2分钟,考虑时间成本!
- 在从0开始构建项目时,一定要首先确保每个模块都正常,再考虑互相连接。切忌全部连接后在测试,否则全编译能过但根本不知道为什么出错。
点此查看