--作者:肖肖肖 --案例作者:WB_Yih
本文为明德扬原创及录用文章,转载请注明出处! 1.1 总体设计
1.1.1 概述随着生活质量的不断提高,加强家庭防盗安全变得非常重要,但传统机械锁的构造过于简单,很容易被打开,从而降低了安全性。数字密码锁因为它的保密性很高,安全系数也非常高,再加上其不需要携带避免了丢失的可能,省去了因钥匙丢失而需要换锁的麻烦,受到了越来越多的人的欢迎。随看人们对高科技产品也越来越推崇,在当今社会科技的高度集中和创新,人们对日常生活中保护自身及财产安全的物品非常追捧,对其安全性的要求也非常的高。为了达到人们对锁具安全性的高要求,加强锁具的安全保密性,用密码锁来取代传统机械锁的锁具是必然趋势。数字密码锁比传统机械锁具更加的安全。在本案例的设计过程中,应用了至简设计法、状态机模板应用等,在经过逐步改进、调试等一系列工作之后,最终达到了设计目标。
基于明德扬至简设计法和明德扬设计规范,设计一个基于FPGA的密码锁、并将数值显示在数码管上,然后根据输入的键值判断密码是否正确。
1.1.2 设计目标
实现电子密码锁的功能,具体功能要求如下: 1. 密码4位,初始密码2345。 2. 密码锁状态:LOCKED和OPEN,初始状态为LOCKED。 1) 当在LOCKED状态时,连续两次输入正确密码,状态变为OPEN状态。当输入错误密码时(包括第一次就输入错误;或者第一次输入正确,第二次输入错误的情况),数码管显示ERROR 2秒后重新显示原来的状态(LOCKED)。 2) 当在OPEN状态时,一次输入错误密码,状态变为LOCKED状态。当输入正确密码时,数码管无显示,10秒后重新显示原来的状态(OPEN)。 3) 不管在何状态,当输入4位密码或者某几位密码,但未按下确认键,并超过10S时,返回原来的状态。(即输入密码超时,返回原状态)
对于点拨开发板,使用矩阵按键输入(本文以点拨603 开发板为例)。 对于Mp801开发板,密码显示及确认:无论在OPEN,还是LOCKED状态下,均可以通过拨码开关输入密码。当有拨码开关拨动时,数码管当前显示的OPEN或LOCKED消失,并显示当前输入的密码,暂未输入的密码位不显示。4位密码输入完毕后,再拨动拨码开关时视为无效输入,当前显示的密码不改变。4位密码输入完毕后,按下确认键后,系统判断密码是否正确。
拨码开关及按键:初始状态下,拨码开关全部往下拨。当拨码开关向上拨后,再向下拨(回到初始状态),表示一个数字的有效输入。按键每按下一次(会自动弹起),为一次有效输入(复位/确认)。
1.1.3 系统结构框图
系统结构框图如下图一所示:
图一 1.1.4模块功能按键检测模块实现功能
1、 检测按键的数值
控制模块实现功能
1、 对接收到的按键数值进行判断和控制对应的密码锁状态,实现对输入密码的正误判断和对密码锁的开启和闭合控制。
数码管显示模块实现功能
1、 显示输入的密码数值; 2、 显示当前密码锁的状态(开启状态或者闭锁状态); 3、 提示密码输入错误的状态。
1.1.5顶层信号
1.1.6参考代码
下面是使用工程的顶层代码:
- module top_mdyPwdlock_keyscan(
- clk ,
- rst_n ,
- key_col ,
- key_row ,
- seg_sel ,
- segment
-
- );
- input clk ;
- input rst_n ;
- input [3:0] key_col ;
- output[5:0] seg_sel ;
- output[7:0] segment ;
- output[3:0] key_row ;
- wire [5:0] seg_sel ;
- wire [7:0] segment ;
- wire [3:0] key_row ;
- wire [3:0] key_out ;
- wire key_vld ;
- wire [6*5-1:0] seg_dout ;
- wire [5:0] seg_dout_vld ;
-
-
- key_scan u_key_scan(
- .clk (clk ),
- .rst_n (rst_n ),
- .key_col (key_col ),
- .key_row (key_row ),
- .key_out (key_out ),
- .key_vld (key_vld )
- );
- control u_ctrl(
- .clk (clk ),
- .rst_n (rst_n ),
-
- .key_num (key_out ),
- .key_vld (key_vld ),
-
- .seg_dout (seg_dout ),
- .seg_dout_vld (seg_dout_vld )
- );
- seg_display u_segment(
- .clk (clk ),
- .rst_n (rst_n ),
- .din (seg_dout ),
- .din_vld (seg_dout_vld ),
- .segment (segment ),
- .seg_sel (seg_sel )
- );
- endmodule
复制代码
1.2 按键检测模块设计1.2.1接口信号
1.2.2 设计思路
在前面的案例中已经有矩阵按键检测模块的介绍,所以这里不在过多介绍,详细介绍请看下方链接: http://www.fpgabbs.cn/forum.php?mod=viewthread& tid=310&highlight=%BE%D8%D5%F3 其中,按键的功能面板如下图所示:
1.2.3参考代码
1.3 控制模块设计1.3.1接口信号 信号名 | | | | | | | | | | | | | | | | | | | | | | | 30bit的数码管显示数据,每5bit为一个字符(对应一个数码管),一共表示6个数码管的显示数据。 | | | | 数码管显示数据有效指示信号,seg_dout_vld [0]为1时,seg_dout[4:0]有效;seg_dout_vld [1]为1时,seg_dout[9:5]有效,以此为推。 |
1.3.2设计思路
Ø 状态机架构 本模块的主要功能是根据输入的按键信息进行不同状态的判断和切换当前工作状态。根据项目功能要求,一共有四种工作状态:密码锁开启状态(open)、密码锁闭合状态(clocked)、输入密码状态(password)和提示输入错误状态(error)。 以下为本模块的状态跳转图:
复位后,状态机进入LOCKED的状态,即初始状态为LOCKED; 在LOCKED状态下: A. 有按键按下,跳到PASSWORD状态; B. 否则,保持LOCKED状态不变; 在OPEN状态下: A. 有按键按下,跳到PASSWORD状态; B. 否则,保持OPEN状态不变; 在PASSWORD状态下: A. 有密码输入但超过10秒没有确认,跳到原来的LOCKED状态或者OPEN状态; B. 密码正确输入并确认两次,跳到OPEN状态; C. 密码错误输入并确认,跳到ERROR状态; D. 否则,保持PASSWORD状态不变; 在ERROR状态下: A. 提示输入错误2秒,跳到LOCKED状态; B. 否则,保持ERROR状态不变; 无论当前处于什么状态,只要不满足状态间的跳转条件就跳到LOCKED状态。 Ø 计数器架构 本模块的某些状态跳转之间存在一定的时间间隔,根据项目功能要求,一共有两种时间的间隔:10秒的等待输入时间间隔和2秒的显示提示时间间隔。 以下为计数器的架构示意图:
10秒计数器cnt_10s_nvld:用于计算10秒的时间。加一条件为state_c==PASSWORD,表示进入密码输入状态就开始计数。结束条件为数500_000_000个,系统时钟为50M,一个时钟周期为20ns,500_000_000个时钟周期就是10秒。 2秒计数器cnt_2s:用于计算2秒的时间。加一条件为state_c==ERROR,表示进入提示输入错误状态就开始计数。结束条件为数100_000_000个,系统时钟为50M,一个时钟周期为20ns,100_000_000个时钟周期就是2秒。
1.3.3参考代码
- module control(
- clk ,
- rst_n ,
- key_num ,
- key_vld ,
- seg_dout ,
- seg_dout_vld
-
- );
- parameter PASSWORD_INI = 16'h2345 ;
- parameter CHAR_O = 5'h10 ;
- parameter CHAR_P = 5'h11 ;
- parameter CHAR_E = 5'h12 ;
- parameter CHAR_N = 5'h13 ;
- parameter CHAR_L = 5'h14 ;
- parameter CHAR_C = 5'h15 ;
- parameter CHAR_K = 5'h16 ;
- parameter CHAR_D = 5'h17 ;
- parameter CHAR_R = 5'h18 ;
- parameter NONE_DIS = 5'h1F ;
- parameter C_10S_WID = 29 ;
- parameter C_10S_NUM = 500_000_000 ;
- parameter C_2S_WID = 27 ;
- parameter C_2S_NUM = 100_000_000 ;
- parameter C_PWD_WID = 3 ;
- input clk ;
- input rst_n ;
- input [3:0] key_num ;
- input key_vld ;
- output[6*5-1:0] seg_dout ;
- output[5:0] seg_dout_vld ;
- reg [6*5-1:0] seg_dout ;
- wire [5:0] seg_dout_vld ;
- reg [1:0] state_c ;
- reg [1:0] state_n ;
- reg lock_stata_flag ;
- reg password_correct_twice ;
-
- reg [C_2S_WID-1:0] cnt_2s ;
- reg [C_10S_WID-1:0] cnt_10s_nvld ;
- reg [C_PWD_WID-1:0] cnt_password ;
- reg [15:0] password ;
-
- parameter LOCKED = 2'b00 ;
- parameter OPEN = 2'b01 ;
- parameter PASSWORD = 2'b10 ;
- parameter ERROR = 2'b11 ;
- //current state
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- state_c <= LOCKED;
- end
- else begin
- state_c <= state_n;
- end
- end
- //next state and the condition of state LOCKEDtransition
- always@(*)begin
- case(state_c)
- LOCKED:begin
- if(locked2password_switch)begin
- state_n = PASSWORD;
- end
- else begin
- state_n = state_c;
- end
- end
- OPEN:begin
- if(open2password_switch)begin
- state_n = PASSWORD;
- end
- else begin
- state_n = state_c;
- end
- end
- PASSWORD:begin
- if(password2locked_switch0)begin
- state_n = LOCKED;
- end
- else if(password2open_switch0 || password2open_switch1)begin
- state_n = OPEN;
- end
- else if(password2error_switch || password2locked_switch1)begin
- state_n = ERROR;
- end
- else begin
- state_n = state_c;
- end
- end
- ERROR:begin
- if(error2locked_switch0 )begin
- state_n = LOCKED;
- end
- else begin
- state_n = state_c;
- end
- end
- default:begin
- state_n = LOCKED;
- end
- endcase
- end
- assign locked2password_switch = state_c==LOCKED && lock_stata_flag && key_num<10 && key_vld;
- assign open2password_switch = state_c==OPEN && !lock_stata_flag && key_num<10 && key_vld;
- assign password2locked_switch0 = state_c==PASSWORD && lock_stata_flag && end_cnt_10s_nvld;
- assign password2locked_switch1 = state_c==PASSWORD && lock_stata_flag && confirm && password!=PASSWORD_INI ;//TO ERROR
- assign password2open_switch0 = state_c==PASSWORD && lock_stata_flag && confirm && password==PASSWORD_INI && password_correct_twice;
- assign password2open_switch1 = state_c==PASSWORD && !lock_stata_flag && end_cnt_10s_nvld;
- assign password2error_switch = state_c==PASSWORD && !lock_stata_flag && confirm && password!=PASSWORD_INI;
- assign error2locked_switch0 = state_c==ERROR && end_cnt_2s;
- //lock_stata_flag
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- lock_stata_flag <= 1;
- end
- else if(password2locked_switch0 || password2locked_switch1 || error2locked_switch0)begin
- lock_stata_flag <= 1;
- end
- else if(password2open_switch0 || password2open_switch1 )begin
- lock_stata_flag <= 0;
- end
- end
- //cnt_10s_nvld
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- cnt_10s_nvld <= 0;
- end
- else if(end_cnt_10s_nvld)begin
- cnt_10s_nvld <= 0;
- end
- else if(add_cnt_10s_nvld)begin
- cnt_10s_nvld <= cnt_10s_nvld + 1;
- end
- end
- assign add_cnt_10s_nvld = state_c==PASSWORD;
- assign end_cnt_10s_nvld = add_cnt_10s_nvld && cnt_10s_nvld==C_10S_NUM-1;
- //confirm
- assign confirm = key_num==10 && key_vld;
- //password_correct_twice
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- password_correct_twice <= 0;
- end
- else if(state_c==PASSWORD && lock_stata_flag && confirm && password==PASSWORD_INI && !password_correct_twice)begin
- password_correct_twice <= 1;
- end
- else if(password2locked_switch0 || password2locked_switch1 || password2open_switch0 || password2open_switch1 || password2error_switch)begin
- password_correct_twice <= 0;
- end
- end
- //cnt_2s
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- cnt_2s <= 0;
- end
- else if(end_cnt_2s )begin
- cnt_2s <= 0;
- end
- else if(add_cnt_2s )begin
- cnt_2s <= cnt_2s + 1;
- end
- end
- assign add_cnt_2s = state_c==ERROR;
- assign end_cnt_2s = add_cnt_2s && cnt_2s==C_2S_NUM-1;
- //seg_dout
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- seg_dout <= 0;
- end
- else if(state_c==OPEN)begin
- seg_dout <= {NONE_DIS,NONE_DIS,CHAR_O,CHAR_P,CHAR_E,CHAR_N};
- end
- else if(state_c==LOCKED)begin
- seg_dout <= {CHAR_L,CHAR_O,CHAR_C,CHAR_K,CHAR_E,CHAR_D};
- end
- else if(state_c==ERROR)begin
- seg_dout <= {NONE_DIS,CHAR_E,CHAR_R,CHAR_R,CHAR_O,CHAR_R};
- end
- else if(state_c==PASSWORD)begin
- if(cnt_password==0)
- seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS};
- else if(cnt_password==1)
- seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[3:0]}};
- else if(cnt_password==2)
- seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[7:4]},{1'b0,password[3:0]}};
- else if(cnt_password==3)
- seg_dout <= {NONE_DIS,NONE_DIS,NONE_DIS,{1'b0,password[11:8]},{1'b0,password[7:4]},{1'b0,password[3:0]}};
- else if(cnt_password==4)
- seg_dout <= {NONE_DIS,NONE_DIS,{1'b0,password[15:12]},{1'b0,password[11:8]},{1'b0,password[7:4]},{1'b0,password[3:0]}};
- end
- end
-
- //seg_dout_vld
- assign seg_dout_vld = 6'b11_1111;
- //cnt_password
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- cnt_password <= 0;
- end
- else if(end_cnt_password)begin
- cnt_password <= 0;
- end
- else if(add_cnt_password)begin
- cnt_password <= cnt_password + 1;
- end
- end
- assign add_cnt_password = state_c!=ERROR && key_num<10 && key_vld && cnt_password<4;
- assign end_cnt_password = confirm || end_cnt_10s_nvld;
- //password
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- password <= 16'h0000;
- end
- else if(add_cnt_password)begin
- password <= {password[11:0],key_num};
- end
- end
- endmodule
复制代码
1.4 数码管显示模块设计1.4.1接口信号
信号名 | | | | | | | | | | | | | | | 30位的输入数码管显示数据。每5bit一个字符(对应一个数码管),6个数码管则一共30bit。 | | | | 输入数据有效指示信号,din_vld[0]为1时,din[4:0]有效;din_vld[1]为1时,din[9:5]有效,以此类推。 | | | | | | | | |
1.4.2设计思路
在前面的案例中已经有数码管显示的介绍,所以这里不在过多介绍,详细介绍请看下方链接: http://fpgabbs.com/forum.php?mod=viewthread&tid=1085&fromuid=100105 其中,数码管显示的数值和英文字母对应图像如下图所示:
1.4.3参考代码
- module seg_display(
- clk ,
- rst_n ,
- din ,
- din_vld ,
- segment ,
- seg_sel
- );
- parameter SEGMENT_NUM = 6 ;
- parameter W_DATA = 5 ;
- parameter SEGMENT_WID = 8 ;
- parameter TIME_300US = 15_000 ;
- parameter SEG_DATA_0 = 7'b100_0000 ;
- parameter SEG_DATA_1 = 7'b111_1001 ;
- parameter SEG_DATA_2 = 7'b010_0100 ;
- parameter SEG_DATA_3 = 7'b011_0000 ;
- parameter SEG_DATA_4 = 7'b001_1001 ;
- parameter SEG_DATA_5 = 7'b001_0010 ;
- parameter SEG_DATA_6 = 7'b000_0010 ;
- parameter SEG_DATA_7 = 7'b111_1000 ;
- parameter SEG_DATA_8 = 7'b000_0000 ;
- parameter SEG_DATA_9 = 7'b001_0000 ;
- parameter SEG_CHAR_O = 7'b010_0011 ;
- parameter SEG_CHAR_P = 7'b000_1100 ;
- parameter SEG_CHAR_E = 7'b000_0110 ;
- parameter SEG_CHAR_N = 7'b010_1011 ;
- parameter SEG_CHAR_L = 7'b100_0111 ;
- parameter SEG_CHAR_C = 7'b100_0110 ;
- parameter SEG_CHAR_K = 7'b000_0101 ;
- parameter SEG_CHAR_D = 7'b010_0001 ;
- parameter SEG_CHAR_R = 7'b010_1111 ;
- parameter SEG_NONE_DIS = 7'b111_1111 ;
- input clk ;
- input rst_n ;
- input [SEGMENT_NUM*W_DATA-1:0] din ;
- input [SEGMENT_NUM-1:0] din_vld ;
- output[SEGMENT_WID-1:0] segment ;
- output[SEGMENT_NUM-1:0] seg_sel ;
- reg [SEGMENT_WID-1:0] segment ;
- reg [SEGMENT_NUM-1:0] seg_sel ;
- reg [W_DATA-1:0] segment_pre ;
- reg [SEGMENT_NUM*W_DATA-1:0] din_get ;
- reg [14:0] cnt_300us ;
- reg [2:0] cnt_sel ;
- wire dot ;
-
- wire add_cnt_300us ;
- wire end_cnt_300us ;
- always @(posedge clk or negedge rst_n) begin
- if (rst_n==0) begin
- cnt_300us <= 0;
- end
- else if(add_cnt_300us) begin
- if(end_cnt_300us)
- cnt_300us <= 0;
- else
- cnt_300us <= cnt_300us+1 ;
- end
- end
- assign add_cnt_300us =1;
- assign end_cnt_300us = add_cnt_300us && cnt_300us == TIME_300US-1 ;
-
- wire add_cnt_sel ;
- wire end_cnt_sel ;
- always @(posedge clk or negedge rst_n) begin
- if (rst_n==0) begin
- cnt_sel <= 0;
- end
- else if(add_cnt_sel) begin
- if(end_cnt_sel)
- cnt_sel <= 0;
- else
- cnt_sel <= cnt_sel+1 ;
- end
- end
- assign add_cnt_sel = end_cnt_300us;
- assign end_cnt_sel = add_cnt_sel && cnt_sel == SEGMENT_NUM-1 ;
- reg [SEGMENT_NUM-1:0] din_vvld;
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_vvld <= 0 ;
- end
- else begin
- din_vvld <= din_vld ;
- end
- end
- reg [ 2:0] cnt ;
- wire add_cnt ;
- wire end_cnt ;
- always @(posedge clk or negedge rst_n) begin
- if (rst_n==0) begin
- cnt <= 0;
- end
- else if(add_cnt) begin
- if(end_cnt)
- cnt <= 0;
- else
- cnt <= cnt+1 ;
- end
- end
- assign add_cnt = 1;
- assign end_cnt = add_cnt && cnt == SEGMENT_NUM-1 ;
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- din_get <= 0;
- end
- else if(din_vvld[cnt])begin
- din_get[W_DATA*(cnt+1)-1 -:W_DATA] <= din[W_DATA*(cnt+1)-1 -:W_DATA];
- end
- end
- always @(*)begin
- segment_pre = din_get[W_DATA*(cnt_sel+1)-1 -:W_DATA];
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- segment <= {dot,SEG_NONE_DIS};
- end
- else if(add_cnt_300us && cnt_300us ==10-1)begin
- case(segment_pre)
- 5'h00: segment <= {dot,SEG_DATA_0};
- 5'h01: segment <= {dot,SEG_DATA_1};
- 5'h02: segment <= {dot,SEG_DATA_2};
- 5'h03: segment <= {dot,SEG_DATA_3};
- 5'h04: segment <= {dot,SEG_DATA_4};
- 5'h05: segment <= {dot,SEG_DATA_5};
- 5'h06: segment <= {dot,SEG_DATA_6};
- 5'h07: segment <= {dot,SEG_DATA_7};
- 5'h08: segment <= {dot,SEG_DATA_8};
- 5'h09: segment <= {dot,SEG_DATA_9};
- 5'h10: segment <= {dot,SEG_CHAR_O};
- 5'h11: segment <= {dot,SEG_CHAR_P};
- 5'h12: segment <= {dot,SEG_CHAR_E};
- 5'h13: segment <= {dot,SEG_CHAR_N};
- 5'h14: segment <= {dot,SEG_CHAR_L};
- 5'h15: segment <= {dot,SEG_CHAR_C};
- 5'h16: segment <= {dot,SEG_CHAR_K};
- 5'h17: segment <= {dot,SEG_CHAR_D};
- 5'h18: segment <= {dot,SEG_CHAR_R};
- 5'h1F: segment <= {dot,SEG_NONE_DIS};
- default:segment <= {dot,SEG_NONE_DIS};
- endcase
- end
- end
- assign dot = 1'b1;
- always@(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- seg_sel <= {SEGMENT_NUM{1'b0}};
- end
- else begin
- seg_sel <= ~(1'b1<
- end
- end
- endmodule
复制代码
1.5 效果和总结
下图是该工程在db603开发板上的现象——密码锁初始状态和闭合状态
下图是该工程在db603开发板上的现象——提示输入错误状态
下图是该工程在db603开发板上的现象——密码锁开启状态
下图是该工程在db603开发板上的现象——输入密码状态
下图是该工程在mp801开发板上的现象——密码锁初始状态和闭合状态
下图是该工程在mp801开发板上的现象——提示输入错误状态
下图是该工程在mp801开发板上的现象——密码锁开启状态
下图是该工程在mp801开发板上的现象——输入密码状态
下图是该工程在ms980开发板上的现象——密码锁初始状态和闭合状态
下图是该工程在ms980开发板上的现象——提示输入错误状态
下图是该工程在ms980开发板上的现象——密码锁开启状态
下图是该工程在ms980开发板上的现象——输入密码状态
由于该项目的上板现象是在数码管上显示输入的密码,并且判断密码是否正确:正确则在数码管上显示OPEN,错误则在数码管上显示ERROR并提示输入错误2秒,然后数码管显示LOCKED。想观看完整现象的朋友可以看一下上板演示的视频。 感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/ )进行FPGA 相关工程设计学习,也可以看一下我们往期的文章: 《波形相位频率可调DDS信号发生器》 《基于FPGA的曼彻斯特编码解码设计》 《基于FPGA的出租车计费系统》 《数电基础与Verilog设计》 《基于FPGA的频率、电压测量》 《基于FPGA的汉明码编码解码设计》 《关于锁存器问题的讨论》 《阻塞赋值与非阻塞赋值》 《参数例化时自动计算位宽的解决办法》
1.6 公司简介
明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。
MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。
【设计教程下载】
【设计代码下载】
0
|
|
|
|