基于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 实物图

image

3 电气参数

image

4 超声波时序图

image

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

开发板与外设连接

image

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.

image

image

image

image
image
image

7段数码管

image

LED、按键、开关

image
image

管脚分配

实体连接

A端 B端 线类型
JP1 11 HC-SR04 VCC 母对母
JP1 12 HC-SR04 GND 母对母
JP1 13 HC-SR04 TRIG 母对母
JP1 14 HC-SR04 ECHO 母对母
JP1 29 9042 + 母对母
JP1 30 9042 - 母对母
JP2 11 SG90 VCC 红线 公对母
JP2 12 SG90 GND 褐线 公对母
JP2 13 SG90 信号线 黄线 公对母
JP2 29 9042 + 母对母
JP2 30 9042 - 母对母

实现思路

  1. 7段数码管总计使用6个。前三个用于显示舵机转的度数,精确到每度。后三个用于显示距离,单位为厘米,精确到个位。
  2. 开关总计使用4个。用于表示自动扫描/固定扫描模式2个,自动扫描模式即180度自动扫描,固定扫描则可通过利用按键进行左右调整到某个方位。用于复位1个,距离探测控制开关1个。
  3. 按键总计使用2个。用于左右调整各1个。
  4. 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码的问题:

  1. 传统的循环乘除法。不做过多介绍。
  2. 移位加 3 法。这种方法是数字逻辑里使用的方法,但在位数变化后,对代码需要做一定调整。
  3. 在数据源头上就使用 BCD 码处理数字,直接判断何时需要进位。这种方法只能解决一类问题,泛化性差。
  4. 通过 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 

实现效果

在线仿真和调试

image
image

视频展示

点此查看

一些报错和实验心得整理

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.

这个错误不一定出现在这行,可能出现在其他地方,需要仔细检查语法。只有敏感信号才用 andor,其他语句里是不能用的。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. 所有位宽都要确认是不是能够满足所存的数,不能满足并不会报错!
  2. 所有数字都要写清楚位宽和表示方法,就算 + 1 也最好写成 + 'd1
  3. 在每一次更改代码后都要仔细检查语法错误,每编译一次都需要2分钟,考虑时间成本!
  4. 在从0开始构建项目时,一定要首先确保每个模块都正常,再考虑互相连接。切忌全部连接后在测试,否则全编译能过但根本不知道为什么出错
    点此查看
posted @ 2023-05-12 21:02  青灰色的风  阅读(516)  评论(0)    收藏  举报