赞
踩
目录
安徽省机器人大赛单片机与嵌入式赛道竞赛分为多个赛道,笔者参加C赛道使用A7系列FPGA进行比赛。比赛分为两个部分,上午8:00-12:00,参赛队员需要根据现场收到的赛题进行Coding,下午1:00左右评委老师验收打分。
由于是现场根据题目比赛(有点像考试),所以要拿到好成绩的话需要做好充足的准备,且因为行程紧张(大学生特种兵式比赛),保持良好的精神状态是充分发挥的重要前提。
实现一个出租车计价系统,显示行走里程(KM)、行走耗费(FUEL)、停车等待耗费(COST)、停车等待计时(TIME)、到达目的地总耗费(Total)、每公里价格(RATE)。
前两公里每公里2元,两公里以后每公里1元,不足的公里向上取整按照整数公里计算,在RATE中计算。
没有详细说明,本题我们仅使用了分钟和秒两组数值,没有加入小时计时(考虑到一个红绿灯不可能等待一个多小时)。
小轮转动一圈表示一米。
按照行驶里程的总费用。根据要求分析,公里数在[0,1)km为2,在[1,2)为4,大于等于2为(公里数+2).
按照等待时间的总费用。根据要求,每等待20s COST加一。
为行走耗费(FUEL)与停车等待耗费(COST)的和。
整个系统需要有行驶、临时停车(模拟红灯)、结束(到达目的地)三种状态,使用两个按键S1和S2控制整个系统。按下S1,系统进入行驶状态,直流电机驱动小轮旋转;按下S2,系统进入暂时停车状态,LED灯亮起表示红灯,直流电机停止驱动,计时器开始计时;按下S2,系统恢复行驶状态;按下S1,系统进入结束状态,表示到达目的地,直流电机停止驱动。
赛题要求使用LCD12864进行显示。在行驶状态显示里程数(KM)、行走耗费(FUEL)、每公里价格(RATE);在临时停车状态显示停车等待耗费(COST)、计时器计时时间;在结束状态显示总费用(Total)和总里程数(KM)。
采用两段式状态机实现控制器,完成对直流电机、矩阵键盘、光电测速、LED、LCD12864外设的驱动,以及计时器的使能和复位。状态机状态转移图如下所示:
自顶向下,逐步求精。先完成直流电机、矩阵键盘、光电测速、LED、LCD12864、计时器各个子模块,以及控制器模块,再在顶层模块中实例化连接。
整个系统由以下六部分组成,共7个module,分别完成后在top中连接。
由于赛方提供实验平台例程,因此直流电机、矩阵键盘、光电测速、LED、LCD12864的驱动仅需要自行修改,不需要一行行输入(几千行代码不是闹着玩的,四小时肯定写不完)。其他的控制器和计数器则需要自己编写。
(1)clk_wiz_0:
将外部晶振20MHz时钟倍频为100MHz时钟。实例化IP即可。
(2)Speed_detect_module:
检测小轮的转数,小轮一圈为20个间隙,通过在固定时间间隔检测接收到的红外光上升沿数就可计算得出转速,同样可以修改为仅计转数。修改例程即可实现。
内部例化一个二进制计数器IP进行计数。
此外需要计数器控制采样时间,起始和结束标志位如下:
根据100MHz时钟测算,每3秒采样一次。
二进制计数器由start_flag使能,输出为Q。
在这里仅讲述我们对例程修改的部分。Pulse_cnt为3秒检测的小轮间隙红外光上升沿次数,由于一圈20个间隙,因此要得到累计的圈数,需要累加:
- module speed_detect_module(
- input clock,
- input reset,
- input pulse_from_motor,
- output [19:0] speed_value,
- output reg [15:0] turns_num
- );
-
- reg [32:0] cnt;
- always @(posedge clock or posedge reset)
- begin
- if (reset)
- cnt <= 0;
- // else if(cnt == 33'd6000000000)
- else if(cnt == 33'd300000000)
- cnt <= 0;
- else
- cnt <= cnt + 1'b1;
- end
- wire start_flag;
- wire end_flag;
- assign start_flag = (cnt <= 33'd5);
- //assign end_flag = (cnt == 33'd6000000000);
- assign end_flag = (cnt == 33'd300000000);
- reg [1:0] pulse_from_motor_sync;
- always @(posedge clock or posedge reset) begin
- if (reset)
- pulse_from_motor_sync <= 2'b00;
- else
- pulse_from_motor_sync <= {pulse_from_motor_sync[0],pulse_from_motor};
- end
- wire pulse_from_motor_pos;
- assign pulse_from_motor_pos = (pulse_from_motor_sync == 2'b01);//������
- wire [23 : 0] Q;
- c_counter_binary_0 c_counter_binary_0_0(
- .CLK(clock), // input wire CLK
- .CE(pulse_from_motor_pos), // input wire CE
- .SCLR(start_flag), // input wire SCLR
- .Q(Q) // output wire [23 : 0] Q
- );
- reg [23:0] pulse_cnt;
- always @(posedge clock or posedge reset)
- begin
- if (reset)begin
- pulse_cnt <= 0;
- turns_num <= 0;
- end
- else if(end_flag)begin
- pulse_cnt <= Q;
- turns_num <= turns_num + pulse_cnt / 20;
- end
- else begin
- turns_num <= turns_num;
- pulse_cnt <= pulse_cnt;
- end
- end
- //assign turns_num = turns_num + pulse_cnt / 20;
- //assign turns_num = pulse_cnt / 20;
- //assign turns_num = pulse_cnt[15:0];
- //assign turns_num = turns_num + pulse_cnt[15:0];
- assign speed_value [3:0] = turns_num % 10;
- assign speed_value [7:4] = turns_num % 100 / 10;
- assign speed_value [11:8] = turns_num % 1000 / 100;
- assign speed_value [15:12] = turns_num % 10000 / 1000;
- assign speed_value [19:16] = turns_num % 100000 / 10000;
- endmodule
(3)Button4x4_drive:
矩阵键盘动态扫描与按键消抖。直接把例程拿过来用,由于clk_20ms_flag的使能,矩阵键盘模块自带了按键消抖功能,非常nice!
- module button4x4_drive(
- input clock,
- input reset,
-
- input [3:0] row, //��
- output [3:0] col, //��
- output [3:0] key_value,
-
- output key_out_flag
- );
- reg [3:0] col;
- reg [3:0] key_value;
- reg [31:0] count;
- wire clk_20ms_flag;
- reg [2:0] state; //״̬��־
- reg key_flag; //������־λ
- reg key_out_flag;
- reg [3:0] col_reg; //�Ĵ�ɨ����ֵ
- reg [3:0] row_reg; //�Ĵ�ɨ����ֵ
- always @(posedge clock or posedge reset)
- begin
- if(reset)
- count <= 0;
- else
- count <= count + 1;
- end
-
- assign clk_20ms_flag = (count[20:0] == 21'd2000000);
- always @(posedge clock or posedge reset)
- begin
- if(reset)
- begin
- col <= 4'b0000;
- state <= 0;
- end
- else if(clk_20ms_flag)
- case (state)
- 0:
- begin
- col[3:0] <= 4'b0000;
- key_flag <= 1'b0;
- if(row[3:0] != 4'b1111)
- begin
- state <= 1;
- col[3:0] <= 4'b1110;
- end //�м����£�ɨ���һ��
- else
- state <= 0;
-
- end
- 1:
- begin
- if(row[3:0] != 4'b1111)
- state <= 5;//�ж��Ƿ��ǵ�һ��
- else
- begin
- state <= 2;
- col[3:0] <= 4'b1101;
- end //ɨ��ڶ���
- end
- 2:
- begin
- if(row[3:0] != 4'b1111)
- state <= 5;//�ж��Ƿ��ǵڶ���
- else
- begin
- state <= 3;
- col[3:0] <= 4'b1011;
- end //ɨ�������
-
- end
- 3:
- begin
- if(row[3:0] != 4'b1111)
- state <= 5; //�ж��Ƿ��ǵ���һ��
- else
- begin
- state <= 4;
- col[3:0] <= 4'b0111;
- end //ɨ�������
- end
- 4:
- begin
- if(row[3:0] != 4'b1111)
- state <= 5;//�ж��Ƿ��ǵ�һ��
- else
- state <= 0;
- end
- 5:
- begin
- if(row[3:0] != 4'b1111)
- begin
- col_reg <= col; //����ɨ����ֵ
- row_reg <= row; //����ɨ����ֵ
- state <= 5;
- key_flag <= 1'b1; //�����
- end
- else
- state <= 0;
- end
- endcase
- end
- always @(clock or col_reg or row_reg)
- begin
- if(key_flag == 1'b1)
- begin
- key_out_flag <= 1;
- case ({col_reg,row_reg})
- 8'b1110_1110:key_value <= 0;
- 8'b1110_1101:key_value <= 4;
- 8'b1110_1011:key_value <= 8;
- 8'b1110_0111:key_value <= 12;
- 8'b1101_1110:key_value <= 1;
- 8'b1101_1101:key_value <= 5;
- 8'b1101_1011:key_value <= 9;
- 8'b1101_0111:key_value <= 13;
- 8'b1011_1110:key_value <= 2;
- 8'b1011_1101:key_value <= 6;
- 8'b1011_1011:key_value <= 10;
- 8'b1011_0111:key_value <= 14;
- 8'b0111_1110:key_value <= 3;
- 8'b0111_1101:key_value <= 7;
- 8'b0111_1011:key_value <= 11;
- 8'b0111_0111:key_value <= 15;
- endcase
- end
- else
- key_out_flag <= 0;
- end
- endmodule
(4)Timer:
实现秒、分钟的计时,这个例程没有,需要自行编写,比较基础容易实现。
先设计一个分频模块产生1Hz时钟。
- module clk_1Hz(
- input clk,
- output reg clk_1Hz
- );
- reg [26:0]cnt;
- initial begin
- clk_1Hz = 0;
- cnt = 0;
- end
- always@(posedge clk)begin
- if(cnt == 27'd99999999)begin
- cnt <= 0;
- end
- else begin
- cnt <= cnt + 1;
- end
- end
- always@(posedge clk)begin
- if(cnt < 27'd49999999)begin
- clk_1Hz <= 1'b0;
- end
- else begin
- clk_1Hz <= 1'b1;
- end
- end
-
- endmodule
然后使用1Hz时钟进行计数器的控制完成秒表:
- module Timer(
- input clk,
- input en,
- input rst_n,
- output clk_1Hz,
- output reg[5:0]minute_cnt,
- output reg[5:0]second_cnt
- );
- wire second_60_flag,minute_60_flag;
- initial begin
- minute_cnt = 0;
- second_cnt = 0;
- end
-
- clk_1Hz clk_1Hz_0(
- .clk(clk),
- .clk_1Hz(clk_1Hz)
- );
-
- assign minute_60_flag = (minute_cnt == 6'd59)?1'b1:1'b0;
- assign second_60_flag = (second_cnt == 6'd59)?1'b1:1'b0;
-
- always@(posedge clk_1Hz)begin
- if(!rst_n)begin
- second_cnt <= 6'd0;
- end
- else if(en)begin
- if(second_60_flag)begin
- second_cnt <= 6'd0;
- end
- else begin
- second_cnt <= second_cnt + 6'd1;
- end
- end
- end
-
- always@(posedge clk_1Hz)begin
- if(!rst_n)begin
- minute_cnt <= 6'd0;
- end
- else if(en)begin
- if(minute_60_flag && second_60_flag)begin
- minute_cnt <= 6'd0;
- end
- else if(second_60_flag)begin
- minute_cnt <= minute_cnt + 6'd1;
- end
- else begin
- minute_cnt <= minute_cnt;
- end
- end
- end
- endmodule
(5)LCD12864_drive:
实现LCD12864的SSD1306芯片的驱动。修改例程即可实现。由于例程中为静态显示,我们要实现动态显示的话需要接收外部数据。
- module lcd12864_drive(
- input clock,
- input reset,
- input [511:0] data,
- output lcd12864_rs,
- output lcd12864_rw,
- output lcd12864_en,
- output [7:0] lcd12864_data
- );
-
- wire [511:0] data_buf;
-
- /**************************����lcd12864ʱ���ź�*************************/
- reg clk_lcd12864;
- reg [19:0]cnt;
- always @(posedge clock or posedge reset)
- begin
- if (reset)
- begin
- cnt <= 20'b0;
- clk_lcd12864 <= 0;
- end
- else if(cnt == 20'd20000) //ʱ��Ƶ�ʷdz���Ҫ��������3k����ʵ��5k���ڵ�0λ������
- begin
- cnt <= 20'd0;
- clk_lcd12864 <= ~clk_lcd12864;
- end
- else
- cnt <= cnt +1'b1;
- end
- reg [1:0] clk_lcd12864_sync;
- always @(posedge clock or posedge reset)
- begin
- if (reset)
- clk_lcd12864_sync <= 2'b00;
- else
- clk_lcd12864_sync <= {clk_lcd12864_sync[0],clk_lcd12864};
- end
- assign clk_lcd12864_pos = (clk_lcd12864_sync == 2'b01);
- //****************************lcd12864�����ź�*****************************************/
- reg [8:0] state; //State Machine code
- parameter IDLE = 4'd0;
- parameter CMD_WIDTH = 4'd1; //�������ݽӿ�����
- parameter CMD_SET = 4'd2; //ѡ��ָ�
- parameter CMD_CURSOR = 4'd3; //���ù��
- parameter CMD_CLEAR = 4'd4; //����
- parameter CMD_ACCESS = 4'd5; //���뷽ʽ���ã����ݶ�д�����
- parameter CMD_DDRAM = 4'd6; //DDRAM�е�ַ
- parameter DATA_WRITE = 4'd7; //�����
- parameter STOP = 4'd8; //
- reg lcd12864_rs_r;
- reg [7:0] lcd12864_data_r;
- reg [7:0] data_buff;
- reg [5:0] cnt_time;
- //����ܽ�����
- assign lcd12864_rs = lcd12864_rs_r;
- assign lcd12864_rw = 1'b0;
- assign lcd12864_en = clk_lcd12864_sync[1]; //��lcd12864ʱ����ͬ
- assign lcd12864_data = lcd12864_data_r;
-
- always @(posedge clock or posedge reset)
- begin
- if(reset)
- begin
- lcd12864_rs_r <= 1'b0;
- state <= IDLE;
- // lcd12864_data_r <= 8'bzzzzzzzz; //����̬
- lcd12864_data_r <= 8'b11111111; //����̬
- cnt_time <= 6'd0;
- end
- else if(clk_lcd12864_pos)
- begin
- case(state)
- IDLE:
- begin
- lcd12864_rs_r <= 1'b0;
- cnt_time <= 6'd0;
- state <= CMD_WIDTH;
- // lcd12864_data_r <= 8'bzzzzzzzz;
- lcd12864_data_r <= 8'b11111111;
- end
- CMD_WIDTH:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_SET;
- lcd12864_data_r <= 8'h30; //8λ���ݿ�
- end
- CMD_SET:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_CURSOR;
- lcd12864_data_r <= 8'h30; //����ָ�
- end
- CMD_CURSOR:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_CLEAR;
- lcd12864_data_r <= 8'h0c; // �ع��
- end
- CMD_CLEAR:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_ACCESS;
- lcd12864_data_r <= 8'h01; //����
- end
- CMD_ACCESS:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_DDRAM;
- lcd12864_data_r <= 8'h06; //������趨
- end
- CMD_DDRAM: //��������
- begin
- lcd12864_rs_r <= 1'b0;
- state <= DATA_WRITE;
- case (cnt_time)
- 6'd0: lcd12864_data_r <= 8'h80;
- 6'd16: lcd12864_data_r <= 8'h90;
- 6'd32: lcd12864_data_r <= 8'h88;
- 6'd48: lcd12864_data_r <= 8'h98;
- endcase
- end
- DATA_WRITE: //���
- begin
- lcd12864_rs_r <= 1'b1;
- cnt_time <= cnt_time + 1'b1;
- lcd12864_data_r <= data_buff;
- case (cnt_time)
- 6'd15: state <= CMD_DDRAM;
- 6'd31: state <= CMD_DDRAM;
- 6'd47: state <= CMD_DDRAM;
- 6'd63: state <= STOP;
- default: state <= DATA_WRITE;
- endcase
- end
- STOP:
- begin
- lcd12864_rs_r <= 1'b0;
- state <= CMD_DDRAM;
- lcd12864_data_r <= 8'h80; //�ӵڼ���ѭ��
- cnt_time <= 6'd0;
- end
- default:
- state <= IDLE;
- endcase
- end
- end
- always @(cnt_time)
- begin
- case (cnt_time)
- 6'd0:data_buff <= data[7:0];
- 6'd1:data_buff <= data[15:8];
- 6'd2:data_buff <= data[23:16];
- 6'd3:data_buff <= data[31:24];
- 6'd4:data_buff <= data[39:32];
- 6'd5:data_buff <= data[47:40];
- 6'd6:data_buff <= data[55:48];
- 6'd7:data_buff <= data[63:56];
- 6'd8:data_buff <= data[71:64];
- 6'd9:data_buff <= data[79:72];
- 6'd10:data_buff <= data[87:80];
- 6'd11:data_buff <= data[95:88];
- 6'd12:data_buff <= data[103:96];
- 6'd13:data_buff <= data[111:104];
- 6'd14:data_buff <= data[119:112];
- 6'd15:data_buff <= data[127:120];
- 6'd16:data_buff <= data[135:128];
- 6'd17:data_buff <= data[143:136];
- 6'd18:data_buff <= data[151:144];
- 6'd19:data_buff <= data[159:152];
- 6'd20:data_buff <= data[167:160];
- 6'd21:data_buff <= data[175:168];
- 6'd22:data_buff <= data[183:176];
- 6'd23:data_buff <= data[191:184];
- 6'd24:data_buff <= data[199:192];
- 6'd25:data_buff <= data[207:200];
- 6'd26:data_buff <= data[215:208];
- 6'd27:data_buff <= data[223:216];
- 6'd28:data_buff <= data[231:224];
- 6'd29:data_buff <= data[239:232];
- 6'd30:data_buff <= data[247:240];
- 6'd31:data_buff <= data[255:248];
- 6'd32:data_buff <= data[263:256];
- 6'd33:data_buff <= data[271:264];
- 6'd34:data_buff <= data[279:272];
- 6'd35:data_buff <= data[287:280];
- 6'd36:data_buff <= data[295:288];
- 6'd37:data_buff <= data[303:296];
- 6'd38:data_buff <= data[311:304];
- 6'd39:data_buff <= data[319:312];
- 6'd40:data_buff <= data[327:320];
- 6'd41:data_buff <= data[335:328];
- 6'd42:data_buff <= data[343:336];
- 6'd43:data_buff <= data[351:344];
- 6'd44:data_buff <= data[359:352];
- 6'd45:data_buff <= data[367:360];
- 6'd46:data_buff <= data[375:368];
- 6'd47:data_buff <= data[383:376];
- 6'd48:data_buff <= data[391:384];
- 6'd49:data_buff <= data[399:392];
- 6'd50:data_buff <= data[407:400];
- 6'd51:data_buff <= data[415:408];
- 6'd52:data_buff <= data[423:416];
- 6'd53:data_buff <= data[431:424];
- 6'd54:data_buff <= data[439:432];
- 6'd55:data_buff <= data[447:440];
- 6'd56:data_buff <= data[455:448];
- 6'd57:data_buff <= data[463:456];
- 6'd58:data_buff <= data[471:464];
- 6'd59:data_buff <= data[479:472];
- 6'd60:data_buff <= data[487:480];
- 6'd61:data_buff <= data[495:488];
- 6'd62:data_buff <= data[503:496];
- 6'd63:data_buff <= data[511:504];
- default : data_buff <= 8'h20;
- endcase
- end
- endmodule
(6)LCD_Decoder:
对来自时钟的秒、分钟计时、来自光电测速的圈数、以及要显示的FUEL、COST等数值进行数据的转换以用于LCD显示。由于例程中为静态显示,我们要实现动态显示的话需要实时向LCD12864_drive发送需要刷新的数据。
使用function来实现二进制数到LCD字库编码的转换,精简代码。
此外,我要实现界面切换的效果,需要根据控制器的state进行选择输出结果。
- module LCD_Decoder(
- input clk,
- input reset,
- input [1:0]state,
- input [19:0]speed_value,
- input [15:0]turns_num,
- input [5:0]minute_cnt,
- input [5:0]second_cnt,
- output reg [511:0]data
- );
- localparam n0 = 8'h30;
- localparam n1 = 8'h31;
- localparam n2 = 8'h32;
- localparam n3 = 8'h33;
- localparam n4 = 8'h34;
- localparam n5 = 8'h35;
- localparam n6 = 8'h36;
- localparam n7 = 8'h37;
- localparam n8 = 8'h38;
- localparam n9 = 8'h39;
- localparam nn = 8'h0f;
-
- //״̬��������
- parameter IDLE = 2'b00;
- parameter START= 2'b01;
- parameter PARK = 2'b11;
- parameter STOP = 2'b10;
-
- reg [7:0]speed_value_0,speed_value_1,speed_value_2,speed_value_3,speed_value_4;
- reg [7:0]fuel_value_0,fuel_value_1,fuel_value_2,fuel_value_3;
- reg [7:0]Total_cost_BCD_0,Total_cost_BCD_1,Total_cost_BCD_2,Total_cost_BCD_3;
-
- reg [7:0]cost_1,cost_0;
- reg [7:0]minute_1,minute_0;
- reg [7:0]second_1,second_0;
- reg [15:0]fuel;//,KM
- reg [7:0]rate;
- reg [3:0]cost;
- wire [15:0]fuel_BCD;
- wire [15:0]Total_cost_BCD;
- wire s_20_flag;
- reg [4:0]s_20_cnt;
- reg [15:0]Total_cost;
- reg [26:0]clk_div_cnt;
- reg clk_1Hz;
-
- initial begin
- speed_value_0 = 0;
- speed_value_1 = 0;
- speed_value_2 = 0;
- speed_value_3 = 0;
- speed_value_4 = 0;
- fuel_value_0 = 0;
- fuel_value_1 = 0;
- fuel_value_2 = 0;
- fuel_value_3 = 0;
- cost_1 = 0;
- cost_0 = 0;
- // KM = 0;
- fuel = 0;
- rate = n1;
- cost = 1;
- s_20_cnt = 0;
- Total_cost = 0;
- clk_1Hz = 0;
- clk_div_cnt = 0;
- end
-
- //ʼ�շ�Ƶ
- wire div_1Hz_flag;
- assign div_1Hz_flag = clk_div_cnt == 27'd99999999;
- always@(posedge clk)begin
- if(div_1Hz_flag)begin
- clk_div_cnt <= 0;
- end
- else begin
- clk_div_cnt <= clk_div_cnt + 1;
- end
- end
- always@(posedge clk)begin
- if(clk_div_cnt < 27'd49999999)begin
- clk_1Hz <= 1'b0;
- end
- else begin
- clk_1Hz <= 1'b1;
- end
- end
- //ʼ�շ�Ƶ
-
- always@(posedge clk)begin
- if(reset)begin
- Total_cost <= 16'd0;
- end
- else begin
- Total_cost <= fuel+{12'd0,cost};
- end
- end
-
- assign s_20_flag = (s_20_cnt == 5'd19)?1'b1:1'b0;
- always@(posedge clk)begin
- if(reset)begin
- s_20_cnt <= 5'd0;
- end
- else begin
- if(state != PARK)begin
- s_20_cnt <= 5'd0;
- end
- else if(s_20_flag && div_1Hz_flag)begin
- s_20_cnt <= 5'd0;
- end
- else if(div_1Hz_flag)begin
- s_20_cnt <= s_20_cnt + 5'd1;
- end
- else begin
- s_20_cnt <= s_20_cnt;
- end
- end
- end
-
- always@(posedge clk)begin
- if(reset)begin
- cost <= 4'd1;
- end
- else begin
- if(state == IDLE)begin
- cost <= 4'd1;
- end
- else if(div_1Hz_flag && s_20_flag)begin
- cost <= cost + 4'd1;
- end
- else begin
- cost <= cost;
- end
- end
- end
-
- assign fuel_BCD [3:0] = fuel % 10;
- assign fuel_BCD [7:4] = fuel % 100 / 10;
- assign fuel_BCD [11:8] = fuel % 1000 / 100;
- assign fuel_BCD [15:12] = fuel % 10000 / 1000;
-
- assign Total_cost_BCD [3:0] = Total_cost % 10;
- assign Total_cost_BCD [7:4] = Total_cost % 100 / 10;
- assign Total_cost_BCD [11:8] = Total_cost % 1000 / 100;
- assign Total_cost_BCD [15:12] = Total_cost % 10000 / 1000;
-
-
-
- //����ת�� ����
- function [7:0]binary2code;
- input [3:0]binary;
- begin
- case(binary)
- 4'd0:binary2code = n0;
- 4'd1:binary2code = n1;
- 4'd2:binary2code = n2;
- 4'd3:binary2code = n3;
- 4'd4:binary2code = n4;
- 4'd5:binary2code = n5;
- 4'd6:binary2code = n6;
- 4'd7:binary2code = n7;
- 4'd8:binary2code = n8;
- 4'd9:binary2code = n9;
- default:binary2code = nn;
- endcase
- end
- endfunction
-
- //����ת�� ����
- function [15:0]time2code;
- input [5:0]binary;
- begin
- case(binary)
- 6'd0:time2code = {n0,n0};
- 6'd1:time2code ={ n0,n1};
- 6'd2:time2code = {n0,n2};
- 6'd3:time2code ={ n0,n3};
- 6'd4:time2code ={ n0,n4};
- 6'd5:time2code ={ n0,n5};
- 6'd6:time2code = {n0,n6};
- 6'd7:time2code = {n0,n7};
- 6'd8:time2code = {n0,n8};
- 6'd9:time2code = {n0,n9};
- 6'd10:time2code ={ n1,n0};
- 6'd11:time2code ={ n1,n1};
- 6'd12:time2code ={ n1,n2};
- 6'd13:time2code ={ n1,n3};
- 6'd14:time2code = {n1,n4};
- 6'd15:time2code = {n1,n5};
- 6'd16:time2code = {n1,n6};
- 6'd17:time2code = {n1,n7};
- 6'd18:time2code = {n1,n8};
- 6'd19:time2code = {n1,n9};
- 6'd20:time2code = {n2,n0};
- 6'd21:time2code = {n2,n1};
- 6'd22:time2code = {n2,n2};
- 6'd23:time2code = {n2,n3};
- 6'd24:time2code = {n2,n4};
- 6'd25:time2code = {n2,n5};
- 6'd26:time2code = {n2,n6};
- 6'd27:time2code = {n2,n7};
- 6'd28:time2code = {n2,n8};
- 6'd29:time2code = {n2,n9};
- 6'd30:time2code = {n3,n0};
- 6'd31:time2code = {n3,n1};
- 6'd32:time2code = {n3,n2};
- 6'd33:time2code = {n3,n3};
- 6'd34:time2code = {n3,n4};
- 6'd35:time2code = {n3,n5};
- 6'd36:time2code = {n3,n6};
- 6'd37:time2code = {n3,n7};
- 6'd38:time2code = {n3,n8};
- 6'd39:time2code = {n3,n9};
- 6'd40:time2code = {n4,n0};
- 6'd41:time2code = {n4,n1};
- 6'd42:time2code = {n4,n2};
- 6'd43:time2code = {n4,n3};
- 6'd44:time2code = {n4,n4};
- 6'd45:time2code = {n4,n5};
- 6'd46:time2code = {n4,n6};
- 6'd47:time2code = {n4,n7};
- 6'd48:time2code = {n4,n8};
- 6'd49:time2code = {n4,n9};
- 6'd50:time2code = {n5,n0};
- 6'd51:time2code = {n5,n1};
- 6'd52:time2code = {n5,n2};
- 6'd53:time2code = {n5,n3};
- 6'd54:time2code = {n5,n4};
- 6'd55:time2code = {n5,n5};
- 6'd56:time2code = {n5,n6};
- 6'd57:time2code = {n5,n7};
- 6'd58:time2code = {n5,n8};
- 6'd59:time2code = {n5,n9};
- default:time2code = {nn,nn};
- endcase
- end
- endfunction
-
- always @(posedge clk) begin
- speed_value_4 <= binary2code(speed_value[19:16]);
- speed_value_3 <= binary2code(speed_value[15:12]);
- speed_value_2 <= binary2code(speed_value[11:8]);
- speed_value_1 <= binary2code(speed_value[7:4]);
- speed_value_0 <= binary2code(speed_value[3:0]);
- fuel_value_3 <= binary2code(fuel_BCD[15:12]);
- fuel_value_2 <= binary2code(fuel_BCD[11:8]);
- fuel_value_1 <= binary2code(fuel_BCD[7:4]);
- fuel_value_0 <= binary2code(fuel_BCD[3:0]);
- Total_cost_BCD_3 <= binary2code(Total_cost_BCD[15:12]);
- Total_cost_BCD_2 <= binary2code(Total_cost_BCD[11:8]);
- Total_cost_BCD_1 <= binary2code(Total_cost_BCD[7:4]);
- Total_cost_BCD_0 <= binary2code(Total_cost_BCD[3:0]);
- {minute_1,minute_0} <= time2code(minute_cnt);
- {second_1,second_0} <= time2code(second_cnt);
- end
-
- always@(posedge clk)begin
- case(cost)
- 4'd0:{cost_1,cost_0} = {n0,n0};
- 4'd1:{cost_1,cost_0} = {n0,n1};
- 4'd2:{cost_1,cost_0} = {n0,n2};
- 4'd3:{cost_1,cost_0} = {n0,n3};
- 4'd4:{cost_1,cost_0} = {n0,n4};
- 4'd5:{cost_1,cost_0} = {n0,n5};
- 4'd6:{cost_1,cost_0} = {n0,n6};
- 4'd7:{cost_1,cost_0} = {n0,n7};
- 4'd8:{cost_1,cost_0} = {n0,n8};
- 4'd9:{cost_1,cost_0} = {n0,n9};
- 4'd10:{cost_1,cost_0} = {n1,n0};
- 4'd11:{cost_1,cost_0} = {n1,n1};
- 4'd12:{cost_1,cost_0} = {n1,n2};
- 4'd13:{cost_1,cost_0} = {n1,n3};
- 4'd14:{cost_1,cost_0} = {n1,n4};
- 4'd15:{cost_1,cost_0} = {n1,n5};
- default:{cost_1,cost_0} ={nn, nn};
- endcase
- end
-
- always@(posedge clk)begin
- // KM <= turns_num/1000;
- if(reset)begin
- fuel <= 32'd2;
- rate <= n2;
- end
- else begin
- if(!(|speed_value [15:12]))begin
- fuel <= 32'd2;
- rate <= n2;
- end
- else if((speed_value [15:12]==1))begin//||(speed_value [15:12] ==2)
- fuel <= 32'd4;
- rate <= n2;
- end
- else begin
- fuel <= speed_value [15:12] + 2;
- rate <= n1;
- end
- end
- end
-
-
-
- always @(*) begin
- if(state == START)begin
- data = {
- "K","S","Z",8'h26,"Y","W","Z",8'h20,"y","b",8'h20,"e","d","a","M",8'h20,
- 8'h20,8'h20,8'h20,8'h20,8'h20,"m","k",speed_value_0,speed_value_1,speed_value_2,".",speed_value_3,speed_value_4,8'h3a,"M","K",
- rate,8'h3a,"E","T","A","R",8'h20,fuel_value_0,fuel_value_1,fuel_value_2,fuel_value_3,8'h3a,"L","E","U","F",
- 8'h20,8'h20,8'h20,8'h20
- ,8'h20,"T","R","A","T","S",8'h3a,"E","T","A","T","S"
- };
- end
- else if(state == PARK)begin
- data = {
- "K","S","Z",8'h26,"Y","W","Z",8'h20,"y","b",8'h20,"e","d","a","M",8'h20,
- 8'h20,8'h20,8'h20,8'h20,8'h20,8'h20,second_0,second_1,":",minute_0,minute_1,8'h3a,"E","M","I","T",
- rate,8'h3a,"E","T","A","R",8'h20,8'h20,8'h20,cost_0,cost_1,8'h3a,"T","S","O","C",
- 8'h20,8'h20,8'h20,8'h20,8'h20,8'h20,"K","R","A","P",8'h3a,"E","T","A","T","S"
- };
- end
- else if(state == STOP)begin
- data = {
- "K","S","Z",8'h26,"Y","W","Z",8'h20,"y","b",8'h20,"e","d","a","M",8'h20,
- 8'h20,8'h20,8'h20,8'h20,8'h20,"m","k",speed_value_0,speed_value_1,speed_value_2,".",speed_value_3,speed_value_4,8'h3a,"M","K",
- 8'h20,8'h20,8'h20,8'h20,8'h20,8'h20,Total_cost_BCD_0,Total_cost_BCD_1,Total_cost_BCD_2,Total_cost_BCD_3,8'h3a,"l","a","t","o","T",
- 8'h20,8'h20,8'h20,8'h20,8'h20,8'h20,"P","O","T","S",8'h3a,"E","T","A","T","S"
- };
- end
- else begin//IDLE
- data = {
- "K","S","Z",8'h26,"Y","W","Z",8'h20,"y","b",8'h20,"e","d","a","M",8'h20,
- 8'h20,8'h20,8'h20,8'h20,8'h20,"m","k",speed_value_0,speed_value_1,speed_value_2,".",speed_value_3,speed_value_4,8'h3a,"M","K",
- rate,8'h3a,"T","T","A","R",8'h20,fuel_value_0,fuel_value_1,fuel_value_2,fuel_value_3,8'h3a,"L","E","U","F",
- 8'h20,8'h20,8'h20,8'h20,8'h20,8'h20,"E","L","D","I",8'h3a,"E","T","A","T","S"
- };
- end
- end
- endmodule
特别声明,由于比赛时间有限,我这里使用了%和/等算数级描述来进行运算,会综合出及其复杂且性能低下的运算逻辑,这可能造成时序违例和面积的浪费,因此大家千万不要在流片的项目中使用!!!仅仅依赖综合器来对电路进行优化可不是一个合格的数字电路设计者。
(7)CTRLOR:
由于使用到了按键复用,因此需要进行上升沿检测,否则仅使用键值进行条件转移的话会在两个状态反复跳转。
控制器是整个电路的灵魂所在,有了它就能控制各个模块的运转。根据我们之前的状态转移图进行编写。
- module CTRLOR(
- input clk,
- input reset,
- input [3:0]key_value,
- input key_out_flag,
- output reg [1:0]cstate,
- output reg Timer_en,
- output reg Timer_rst_n,
- output reg LED_en,
- output reg motor_en
- );
- //״̬��������
- parameter IDLE = 2'b00;
- parameter START= 2'b01;
- parameter PARK = 2'b11;
- parameter STOP = 2'b10;
-
- //�����ڲ��ź�
- wire s1_flag,s2_flag,s3_flag;
- wire key_out_flag_pos;
- reg key_out_flag_reg;
- always@(posedge clk)begin
- if(reset)begin
- key_out_flag_reg <= 1'b0;
- end
- else begin
- key_out_flag_reg <= key_out_flag;
- end
- end
- assign key_out_flag_pos = (!key_out_flag_reg && key_out_flag);
- assign s1_flag = (key_out_flag_pos && (key_value == 4'd1))?1'b1:1'b0;
- assign s2_flag = (key_out_flag_pos && (key_value == 4'd2))?1'b1:1'b0;
- assign s3_flag = (key_out_flag_pos && (key_value == 4'd3))?1'b1:1'b0;
-
- //״̬�Ĵ���
- reg [1:0]nstate;
-
- initial begin
- cstate = IDLE;
- nstate = IDLE;
- Timer_en = 0;
- Timer_rst_n = 0;
- LED_en = 1;
- motor_en = 0;
- end
-
- always@(posedge clk)begin
- if(reset)begin
- cstate <= IDLE;
- end
- else begin
- cstate <= nstate;
- end
- end
-
- always@(*)begin
- case(cstate)
- IDLE:begin
- if(s1_flag)nstate = START;
- else nstate = IDLE;
- end
- START:begin
- if(s2_flag)nstate = PARK;
- else if(s1_flag)nstate = STOP;
- else nstate = START;
- end
- PARK:begin
- if(s2_flag)nstate = START;
- else nstate = PARK;
- end
- STOP:begin
- if(s3_flag)nstate = IDLE;
- else nstate = STOP;
- end
- default:nstate = IDLE;
- endcase
- end
-
- always@(*)begin
- case(cstate)
- IDLE:begin
- Timer_en = 0;
- Timer_rst_n = 0;
- LED_en = 1;
- motor_en = 0;
- end
- START:begin
- Timer_en = 0;
- Timer_rst_n = 0;
- LED_en = 1;
- motor_en = 1;//
- end
- PARK:begin
- Timer_en = 1;
- Timer_rst_n = 1;
- LED_en = 0;//
- motor_en = 0;//
- end
- STOP:begin
- Timer_en = 0;
- Timer_rst_n = 1;
- LED_en = 1;
- motor_en = 0;
- end
- default:begin
- Timer_en = 0;
- Timer_rst_n = 0;
- LED_en = 1;
- motor_en = 0;
- end
- endcase
- end
- endmodule
(8)top:
完成模块的实例连接。
- module top(
- //ϵͳ�ź�
- input sysclkin,
- input button,
- //��������ź�
- input [3:0] row, //��
- output [3:0] col, //��
- //LCD�ź�
- output lcd12864_rs,
- output lcd12864_rw,
- output lcd12864_en,
- output [7:0] lcd12864_data,
- //�������ź�
- input pulse_from_motor,
- //ֱ����������ź�
- output motor_en,
- //LED�ź�
- output LED_en
- );
- //�����ź���
- wire clk_100M,clk_100M_180;
- wire [3:0] key_value;
- wire key_out_flag;
- wire [511:0] data;
- wire [5:0]minute_cnt;
- wire [5:0]second_cnt;
- wire clk_1Hz,Timer_en,Timer_rst_n;
- wire [19:0] speed_value;
- wire [15:0] turns_num;
- wire [1:0]cstate;
-
- clk_wiz_0 clk_wiz_0_0(
- // Clock out ports
- .clk_out1(clk_100M), // output clk_out1
- .clk_out2(clk_100M_180), // output clk_out2
- // Clock in ports
- .clk_in1(sysclkin)
- );
- speed_detect_module speed_detect_module_0(
- .clock(clk_100M),
- .reset(!button),
- .pulse_from_motor(pulse_from_motor),
- .speed_value(speed_value),
- .turns_num(turns_num)
- );
- button4x4_drive button4x4_drive_0(
- .clock(clk_100M),
- .reset(!button),
- .row(row), //��
- .col(col), //��
- .key_value(key_value),
- .key_out_flag(key_out_flag)
- );
- CTRLOR CTRLOR_0(
- .clk(clk_100M),
- .reset(!button),
- .key_value(key_value),
- .key_out_flag(key_out_flag),
- .cstate(cstate),
- .Timer_en(Timer_en),
- .Timer_rst_n(Timer_rst_n),
- .LED_en(LED_en),
- .motor_en(motor_en)
- );
- Timer Timer_0(
- .clk(clk_100M),
- .en(Timer_en),
- .rst_n(Timer_rst_n),
- .clk_1Hz(clk_1Hz),
- .minute_cnt(minute_cnt),
- .second_cnt(second_cnt)
- );
- LCD_Decoder LCD_Decoder_0(
- .clk(clk_100M),
- .reset(!button),
- .state(cstate),
- .speed_value(speed_value),
- .turns_num(turns_num),
- .minute_cnt(minute_cnt),
- .second_cnt(second_cnt),
- .data(data)
- );
- lcd12864_drive lcd12864_drive_0(
- .clock(clk_100M),
- .reset(!button),
- .data(data),
- .lcd12864_rs(lcd12864_rs),
- .lcd12864_rw(lcd12864_rw),
- .lcd12864_en(lcd12864_en),
- .lcd12864_data(lcd12864_data)
- );
-
- endmodule
https://github.com/lionelZhaowy/Taxi_pricinghttps://github.com/lionelZhaowy/Taxi_pricing
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。