Chapter 5 Code

To comply the Chapter 5 Verilog codes within the book titled Fundamental Digital Circuits and FPGA

Section 5.1: LED chaser

State Diagram

Verilog Code

Code 5.1: Complete Verilog code for 8-bit LED chaser with 50ms time interval
/*---------------------------------------------------------------------------------------------------    
*- File name:        LEDchaser.v
*- Top Module name:  LEDchaser
*- Submodules:       None
*- Description:      Implementation of an LED chaser with 8 states
*-
*- Example of Usage:
    This code is designed to cycle through LEDs in a chaser pattern. It can be implemented on 
    any FPGA development board with an 8-bit LED array. To observe the LED chaser effect:
        - Connect the LEDs output to the 8 on-board LEDs.
        - Provide the system clock to the clk input.

- Reliability:       
                     This code is intended for educational and demonstration purposes and has not been
                     validated for use in production systems. Users are advised to thoroughly test the 
                     module in their specific application context.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module LEDchaser (
    input clk,
    output reg [7:0] LEDs
);
/**************** Defining the 8 states with binary numbers *******************/
parameter   S0 = 3'b000,   
            S1 = 3'b001,   
            S2 = 3'b010,   
            S3 = 3'b011,   
            S4 = 3'b100,   
            S5 = 3'b101,   
            S6 = 3'b110,   
            S7 = 3'b111; 
/****************  Describing the LED actions in each state  *******************/
reg [2:0] state;                   
always @ (posedge clk) begin     
    case (state)  
        S0: LEDs = 8'b11111110;  
        S1: LEDs = 8'b11111101;  
        S2: LEDs = 8'b11111011;  
        S3: LEDs = 8'b11110111;  
        S4: LEDs = 8'b11101111;  
        S5: LEDs = 8'b11011111;  
        S6: LEDs = 8'b10111111;  
        S7: LEDs = 8'b01111111;  
        default: LEDs = 8'b11111111; // Default case to turn off all LEDs if state is unknown
    endcase
end
/****************  Enable jumping among different states  **********************/
reg [23:0] cnt; 
parameter CNT_NUM = 600000;       
always @ (posedge clk) begin
    if (cnt == CNT_NUM-1)  
        cnt <= 20'b0; 
    else
        cnt <= cnt + 1'b1;           
end
always @ (posedge clk) begin
    if (cnt == CNT_NUM-1)  
        state <= state + 1'b1; 
    if (state > S7)         // Reset state to S0 after reaching S7
        state <= S0;
end
endmodule

Implementation

Section 5.2: Traffic Light

This is a simple version of traffic light system that can be fully implemented by the STEPFPGA board alone. A more sophisticated and delicate traffic light system can be found in this Project for Smart Traffic Light.

Timing Diagram

State Machine

Digital Structure

Verilog Code

Code 5.2: Complete code for traffic light3
/*--------------------------------------------------------------------------------------------------- 	
*- File name: 			simple_traffic.v
*- Top Module name: 	simple_traffic
  - Submodules:		divider_integer
*- Description:			Using a state machine to control two RGB LEDs to simulate a traffic light
					
*- Example of Usage:
       - You may assign the output directly to the 2 RGB LEDs on the STEPFPGA board

- Reliability:       
                     This code is intended for educational and demonstration purposes and has not been
                     validated for use in production systems. Users are advised to thoroughly test the 
                     module in their specific application context.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module simple_traffic (
	input clk, rst_n,
	output reg [5:0] RGB_out		// connects the TWO RGB lights
);

// The four states
reg             [1:0] state;
parameter       S1 = 2'b00,       
                S2 = 2'b01,   
                S3 = 2'b10,   
                S4 = 2'b11; 

// RGB light, inverted logic; 111 means all OFF; 011 means R is ON, G and B are OFF
parameter       led_s1 = 6'b101011,   // '101' for Green, '011' for RED
                led_s2 = 6'b001011,   // '001' for Yellow, '011' for RED (yellow is not obvious)
                led_s3 = 6'b011101,   // '011' for Red, '101' for Green
                led_s4 = 6'b011001;   // '011' for Red, '001' for Yellow

// RGB light behaviors in each state
always @ (*)   begin
    case  (state)  
        S1:  RGB_out = led_s1; 
        S2:  RGB_out = led_s2; 
        S3:  RGB_out = led_s3; 
        S4:  RGB_out = led_s4; 
        default:  RGB_out = led_s1; 
    endcase
end

/**************************************   Integer Clock Divider  **********************************
	>>	Instantiate the clock divider module, and divide the 12MHz clock frequency by
	12000000 time thus generated a 1Hz clock signal
  *************************************************************************************************/	
wire clk1hz;
divider_integer # (.WIDTH (24),.N (12_000_000)) u1  (    
    .clk        (clk),      
    .clkout     (clk1hz)     
);

/***********************************   Traffic Control State Machine  ****************************/
// Implementing the state machine; use the 1Hz clock signal
reg	[4:0] time_cnt;		// Reserve 5 bit register space for timer counter
always @ (posedge clk1hz or negedge rst_n) begin
    if(!rst_n) begin
        state <= S1; 
        time_cnt <= 0;
    end
    else begin
        case  (state)  
            S1: if  (time_cnt < 4'd15) begin	// 15s
                    state <= S1; 
                    time_cnt <= time_cnt + 1; 
                end
                else begin
                    state <= S2; 
                    time_cnt <= 0; 
                end
            S2: if  (time_cnt < 4'd3) begin		// 3s
                    state <= S2; 
                    time_cnt <= time_cnt + 1; 
                end
                else begin
                    state <= S3; 
                    time_cnt <= 0; 
                end
            S3: if  (time_cnt < 4'd7) begin		// 7s
                    state <= S3; 
                    time_cnt <= time_cnt + 1; 
                end
                else begin
                    state <= S4; 
                    time_cnt <= 0; 
                end 
            S4: if  (time_cnt < 4'd3) begin		// 3s
                    state <= S4; 
                    time_cnt <= time_cnt + 1; 
                end
                else begin
                    state <= S1; 
                    time_cnt <= 0; 
                end
            default: begin
                    state <= S1; 
                    time_cnt <= 0;
            end
        endcase 
    end
end 
endmodule



/**************************************   Integer Clock Divider  **********************************
	>>	Frequency divider code; seen in Section 3.7 of the book
  *************************************************************************************************/	
module divider_integer # (           
    parameter   WIDTH = 24,          
    parameter   N     = 12000000     
)  
(
    input clk,
    output reg clkout 
);
reg [WIDTH-1:0] cnt; 
always @ (posedge clk) begin
    if(cnt>=(N-1))
        cnt <= 1'b0;
    else
        cnt <= cnt + 1'b1;
    clkout <= (cnt<N/2)?1'b1:1'b0;
end
endmodule

Implementation

Section 5.3: Switch Debouncing

Digital Structure

Verilog Code

Code 5.2: Implementation of debounce module
/*--------------------------------------------------------------------------------------------------- 	
- File name:         debounce.v
- Top Module name:   debounce
- Submodules:        dff, divider_integer
- Description:       This module debounces a mechanical switch input to produce a stable digital output.
                     It uses a clock divider to slow down the main clock and then a double flip-flop
                     setup to filter out any bouncing effects caused by the mechanical switch.
- 
- Example of Usage:  
                     To use this debounce module, connect the 'key' input to a mechanical switch and the
                     'key_deb' output to a digital circuit input that requires a debounced signal. The
                     module uses a slow clock generated by the 'divider_integer' submodule to sample the
                     switch state at a lower rate to mitigate bouncing effects.

- Reliability:       
                     This code is intended for educational and demonstration purposes and has not been
                     validated for use in production systems. Users are advised to thoroughly test the 
                     module in their specific application context.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module debounce (
    input clk, key,
    output key_deb
);

wire slow_clk;
wire Q1,Q2,Q2_bar;

divider_integer #(.WIDTH(17),.N(240000)) U1 ( 
    .clk(clk),                              
    .clkout(slow_clk)           
);
dff U2 (                        
    .clk(slow_clk),
    .D(key),
    .Q(Q1) 
);
dff U3 (                        
    .clk(slow_clk),
    .D(Q1),
    .Q(Q2) 
);

assign Q2_bar = ~Q2;
assign key_deb = Q1 & Q2_bar;   
endmodule

/********** Submodule 1 **********/
module dff(input clk, D, output reg Q);
    always @ (posedge clk) begin
        Q <= D;
    end
endmodule


/********** Submodule 2 **********/
module divider_integer # (           
    parameter   N     = 12000000,	// the divisor
    parameter   WIDTH = 24 			// the minimum bit-width to hold this divisor
)  
(
    input clk,
    output reg clkout 
);
reg [WIDTH-1:0] cnt; 
always @ (posedge clk) begin
    if(cnt>=(N-1))
        cnt <= 1'b0;
    else
        cnt <= cnt + 1'b1;
    clkout <= (cnt<N/2)?1'b1:1'b0;
end
endmodule

Implementation

Section 5.4: Ultrasonic Distance Sensor

Timing Diagram

State Machine

Digtial Structure

Verilog Code

Code 5.4: Complete code for ultrasonic distance measurement module
/*--------------------------------------------------------------------------------------------------- 
*- File name:            SR04_display.v
*- Top Module name:      SR04_display
*- Submodules:           hc_sr04, bin_to_bcd, segment7
*- Description:          Main display module that interfaces with the HC-SR04 sensor module, 
                         converts the binary distance to BCD, and drives two 7-segment displays.
*-
*- Example of Usage:
    - The `SR04_display` module can be instantiated within a top-level design file.
      Connect the `clk`, `rst_n`, and `echo` inputs to the respective signals.
      Connect the `trig`, `segment_led_1`, and `segment_led_2` to the HC-SR04 sensor
      and 7-segment display inputs respectively.
*-
*- Reliability:       
                     This code is provided 'as is', primarily for educational purposes and is not guaranteed 
                     for any industrial or commercial applications. Users must validate the functionality 
                     before use in any critical systems.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module SR04_display(
    input clk, rst_n ,              
    input echo,                     // reads the ECHO signal from HC_SR04
    output trig,                    // send trigger pulse to HC_SR04 module
    output [8:0] segment_led_1,     // 7-Segment display 1
    output [8:0] segment_led_2      // 7-Segment display 2
);

hc_sr04 ultrsonic (clk, rst_n, echo, trig, distance);
wire    [15:0] distance;            // 16-bit binary output from SR-04 sensor

bin_to_bcd bin_to_bcd_U(rst_n, distance, bcd_distance);
wire    [19:0] bcd_distance;        // 19-bit BCD output from BCD module    

wire    [3:0] bcd_digit1;       
wire    [3:0] bcd_digit2;
assign  bcd_digit1 = bcd_distance[7:4]; // convert smaller 4 bits BCD to binary 
assign  bcd_digit2 = bcd_distance[3:0]; // convert higher 4 bits BCD to binary

segment7 seg_x1(                        // display the first digit on Segment1
        .seg_data(bcd_digit1),
        .segment_led (segment_led_1)
);
segment7 seg_x10(                       // display the second digital on Segment2
        .seg_data(bcd_digit2),
        .segment_led (segment_led_2)
);
endmodule

/*******************************************************************************************************
* Module Name: hc_sr04
* Description:
*   This module interfaces with the HC_SR04 ultrasonic sensor to measure distance. The primary 
*   operations are:
*     1. Generating a 10us pulse for triggering the HC_SR04 sensor.
*     2. Detecting the rising and falling edges of the Echo signal from the sensor.
*     3. Generating a 17kHz pulse, where each pulse corresponds to 1cm of the real distance 
*        measured by the HC_SR04 sensor.
*     4. Counting the number of 17kHz pulses between the rising and falling edges of the Echo signal 
*        to determine the distance measurement in centimeters.

- Reliability:       
                     This code is provided 'as is', primarily for educational purposes and is not guaranteed 
                     for any industrial or commercial applications. Users must validate the functionality 
                     before use in any critical systems.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
********************************************************************************************************/
module hc_sr04 (
    input clk, rst_n,               // STPFFPGA has on board frequency of 12MHz  
    input echo,                     // Module input, connects to HC_SR04 -> echo
    output trig,                    // Module output, connects to HC_SR04 -> trig     
    output reg [15:0] distance      
);  
/****************************************   Generate a 10us pulse  ************************************
	>>	This piece of code generates a 10us pulse to enable trigger of the HC_SR04 sensor 			
  ******************************************************************************************************/	
	reg [25:0] cnt_10us;		// Counter for generating 10us pulse
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n) begin
			cnt_10us <= 0;
		end
		else if(cnt_10us == 11_999_999)
			cnt_10us <= 0;
		else
			cnt_10us <= cnt_10us + 1'b1;
	end
	assign trig = (cnt_10us < 120) ? 1:0;

/*********************************   Edge detection of Echo signal  *****************************
	>>	This piece of code detects the rising edge and falling edge of Echo signal
	>>	when 'pose_echo' is 1, rising edge; when 'nege_echo' is 1, falling edge		
  *************************************************************************************************/	
	reg echo_2;
	reg echo_1;
	wire pose_echo;
	wire nege_echo;
	always @(posedge clk17k or negedge rst_n)begin
		if(!rst_n)begin
			echo_1 <= 0;
			echo_2 <= 0;
		end
		else begin
			echo_1 <= echo;
			echo_2 <= echo_1;
		end
	end
	assign pose_echo = echo_1 && (~echo_2);
	assign nege_echo = (~echo_1) && echo_2;

/***********************************   Generate a 17kHz pulse  **********************************
	>>	This piece of code generates a 17kHz pulse signal
	>>	By calculation (see Chapter 5 of the book), each pulse corresponds to 1cm
	of the real distance measured by the HC_SR04 ultrasonic sensor.  			
  *************************************************************************************************/
	reg clk17k;
	reg [15:0] cnt17k;		   // Counter for a 17KHz signal (explained in the book)
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt17k <= 0;
		end
		else if(cnt17k == 706)			// divide 12MHz by 706 times will get 17kHz
			cnt17k <= 0;
		else
			cnt17k <= cnt17k + 1;
	end
	always @(posedge clk or negedge rst_n)begin
		if(!rst_n)
			clk17k <= 0;
		else if(cnt17k < 706>>1)
			clk17k <= 0;
		else
			clk17k <= 1;
	end
	
/*************************  Convert counter result to the actual distance  ************************
	>>	Since we have generated a 17kHz pulse, as soon as we detected the rising edge
	of the Echo, then the system starts counting how many pulses for clk17k, until a
	falling edge is received to stop counting. 
	>> 	Each pulse of 'clk17k' represents 1cm in the physical measurement		
*****************************************************************************************************/
	parameter S0 = 2'b00; 	// state S0 is when rising edge of echo is detected begin of distance measurement
	parameter S1 = 2'b01; 	// state S1 is when echo stays HIGH, and we will calculate distance in this state 
	parameter S2 = 2'b10; 	// state S2 is when falling edge of echo is detected, end of distance measurement
	reg [1:0] state;
	reg [15:0] cnt_dist;						// Counter for final measured distance with smallest unit of 'cm'
	always@(posedge clk17k or negedge rst_n)begin
		if(!rst_n)begin
			cnt_dist<= 0; 
			distance <= 0;
			state <= S0;
		end
		else
			begin
               case(state)
				S0:begin						// detected the rising edge of the echo signal
					cnt_dist <= 0;				// start to count for distance
					if (pose_echo) 				
						state <= S1;	
					else	
						state <= S0;	
				end	
				S1:begin						// the echo signal level stays HIGH	
					cnt_dist <= cnt_dist + 1;	// counts for distance, each 'cnt_dist' increments 1cm
					if (nege_echo) 				
						state <= S2;			
					else	
						state <= S1;	
                end	
				S2:begin	
					distance <= cnt_dist; 		// detected the falling edge of the echo signal
					cnt_dist <= 0;				// save the 'cnt_dist' result for the actual distance
					state <= S0;	
				end	
				default:begin					// default
					cnt_dist <= 0;	            
					state <= S0;	
				end	
        endcase	
    end	
end	
endmodule


/*--------------------------------------------------------------------------------------------------- 	
*- File name: 			bin_to_bcd.v
*- Top Module name: 	bin_to_bcd
*- Submodules:			N/A
*- Description:			Conversion of 16-bit binary data to 20-bit Binary Coded Decimal (BCD) representation 
                        using the double dabble algorithm.
                        
*- Example of Usage:
	You can implement this code on all variants of STEPFPGA family boards. 
	If you intend to implement this module on a board and observe its operation:
		- Connect a 16-bit binary input to bin_code.
		- Observe the 20-bit BCD output on bcd_code.
		- Utilize the rst_n signal to reset the conversion process when needed.

*- Additional comments: 	 
   This BCD converter is designed to handle up to a 16-bit binary number and convert it into a 
   20-bit BCD representation. It is especially useful when interfacing with displays that 
   require decimal number representation, such as 7-segment displays.

- Reliability:       
                     This code is provided 'as is', primarily for educational purposes and is not guaranteed 
                     for any industrial or commercial applications. Users must validate the functionality 
                     before use in any critical systems.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module bin_to_bcd (
    input               rst_n,      // Reset signal (active low)
    input       [15:0]  bin_code,
    output  reg [19:0]  bcd_code    
);

// Internal shift register for the algorithm
reg [35:0] shift_reg;

always @(posedge bin_code or negedge rst_n) begin
    if (!rst_n) begin
        shift_reg <= 36'b0;  // Reset the shift register on active low reset signal
    end else begin
        shift_reg <= {16'b0, bin_code};  // Initialize shift register with binary code at the rightmost position
        
        // Using repeat statement for the conversion process
        repeat (16) begin
            if (shift_reg[3:0] > 4) shift_reg[3:0] <= shift_reg[3:0] + 3;
            if (shift_reg[7:4] > 4) shift_reg[7:4] <= shift_reg[7:4] + 3;
            if (shift_reg[11:8] > 4) shift_reg[11:8] <= shift_reg[11:8] + 3;
            if (shift_reg[15:12] > 4) shift_reg[15:12] <= shift_reg[15:12] + 3;
            if (shift_reg[19:16] > 4) shift_reg[19:16] <= shift_reg[19:16] + 3;
            
            shift_reg <= shift_reg << 1;
        end
        
        bcd_code <= shift_reg[19:0];  // Assign the 20-bit BCD result
    end
end

endmodule


/*--------------------------------------------------------------------------------------------------- 	
*- File name: 			segment7.v
*- Top Module name: 	segment7
  - Submodules:		N/A
*- Description:			Implementation of a 7-segment display driver (common cathod)
*- 
*- Example of Usage:
	You can implement this code on all variants of STEPFPGA family boards. 
	If you want to implement this code on board and observe the logic behaviors: 
		- assign seg_data[3]...seg_data[0] to the 4 on-board swiches
		- assign segment_led[8] to SEG, segment_led[7] to DP
		- assign segment_led[6]...segment_led[0] to 'g, f, ... a' accordingly

* - Additional comments: 	 
   If you want to display decimal numbers only, the 4-bit input data must be in BCD converted
   form; will explain in Chapter 5 when implement the Elevator project. 

- Reliability:       
                     This code is provided 'as is', primarily for educational purposes and is not guaranteed 
                     for any industrial or commercial applications. Users must validate the functionality 
                     before use in any critical systems.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module segment7 (
    input  wire [3:0] seg_data,       // The 4 bit input data in binary form	
    output reg  [8:0] segment_led	  //  9 output for the 7-segment LEDs from MSB to LSB: SEG, DP, g, f, e, d, c, b, a
) ; 
always @ (seg_data) begin
    case  (seg_data) 
      4'b0000: segment_led = 9'h3f;   //  0
      4'b0001: segment_led = 9'h06;   //  1
      4'b0010: segment_led = 9'h5b;   //  2
      4'b0011: segment_led = 9'h4f;   //  3
      4'b0100: segment_led = 9'h66;   //  4
      4'b0101: segment_led = 9'h6d;   //  5
      4'b0110: segment_led = 9'h7d;   //  6
      4'b0111: segment_led = 9'h07;   //  7
      4'b1000: segment_led = 9'h7f;   //  8
      4'b1001: segment_led = 9'h6f;   //  9
      4'b1010: segment_led = 9'h77;   //  A
      4'b1011: segment_led = 9'h7C;   //  b
      4'b1100: segment_led = 9'h39;   //  C
      4'b1101: segment_led = 9'h5e;   //  d
      4'b1110: segment_led = 9'h79;   //  E
      4'b1111: segment_led = 9'h71;   //  F
    endcase
 end
endmodule

Implementation

Section 5.5: Matrix Keypad

State Machine

Verilog Code

Code 5.5: Complete code to interface with 4-by-3 matrix keypad with number displaed
/*--------------------------------------------------------------------------------------------------- 	
- File name:         keypad_3by4.v
- Top Module name:   keypad_3by4
- Description:       Implements a 3x4 matrix keypad scanner with debouncing and 7-segment display decoding.
                     The module scans the keypad, debounces the keypresses, identifies the pressed key,
                     and translates it to a corresponding 7-segment display code.
  
- Example of Usage:  
                     This module can be instantiated in a system that requires keypad interfacing with
                     visual feedback via a 7-segment display. Connect the rows and columns to the
                     respective keypad terminals and the segment_led1 output to a 7-segment display driver.

- Reliability:       
                     This code is intended for educational and prototype purposes. For commercial
                     applications, thorough testing and validation are required.

- Copyright:         Copyright (c) 2023 by EIM Technology
- License:           MIT License
--------------------------------------------------------------------------------------------------- */

module keypad_3by4 (
	input					clk,		
	input					rst_n,		
	input			[2:0]	col,		// the 3 output signals for 3 Columns 
	output	reg		[3:0]	row,		// the 4 input signals for 4 Rows 
	output	reg		[3:0]	keyPressed,
	
	 output	reg		[8:0]	segment_led1
);

	localparam			NUM_FOR_200HZ = 60000;	// Used to generate a 200Hz frequency for column scanning
	localparam			ROW0_SCAN = 2'b00;      // the state when scanning first row
	localparam			ROW1_SCAN = 2'b01;      // the state when scanning second row
	localparam			ROW2_SCAN = 2'b10;      // the state when scanning third row
	localparam			ROW3_SCAN = 2'b11;		// the state when scanning forth row
 
	reg		[11:0]	key,key_r;
	reg		[11:0]	key_out;		// debounce all keys

	reg		[15:0]	cnt;
	reg				clk_200hz;
	
	// generate a 200Hz clock
	always@(posedge clk or negedge rst_n) begin
		if(!rst_n) begin		
			cnt <= 16'd0;
			clk_200hz <= 1'b0;
		end else begin
			if(cnt >= ((NUM_FOR_200HZ>>1) - 1)) begin	//  >>1 means divide by 2
				cnt <= 16'd0;
				clk_200hz <= ~clk_200hz;	
			end else begin
				cnt <= cnt + 1'b1;
				clk_200hz <= clk_200hz;
			end
		end
	end
 
	reg		[1:0]		c_state;
	always@(posedge clk_200hz or negedge rst_n) begin
		if(!rst_n) begin
			c_state <= ROW0_SCAN;
			row <= 4'b1110;
		end else begin
			case(c_state)
				ROW0_SCAN: begin c_state <= ROW1_SCAN; row <= 4'b1101; end	
				ROW1_SCAN: begin c_state <= ROW2_SCAN; row <= 4'b1011; end
				ROW2_SCAN: begin c_state <= ROW3_SCAN; row <= 4'b0111; end
				ROW3_SCAN: begin c_state <= ROW0_SCAN; row <= 4'b1110; end
				default:begin c_state <= ROW0_SCAN; row <= 4'b1110; end
			endcase
		end
	end
 
always@(negedge clk_200hz or negedge rst_n) begin
	if(!rst_n) begin
		key_out <= 12'hfff;
	end else begin
		case(c_state)
			ROW0_SCAN: begin 				// check for colum 0, 1, 2
						key[2:0] <= col;    
						key_r[2:0] <= key[2:0];    
						key_out[2:0] <= key_r[2:0]|key[2:0];   // double comfirm the pressed key
						
					end 
			ROW1_SCAN:begin 				// check for colum 3, 4, 5
						key[5:3] <= col;    
						key_r[5:3] <= key[5:3];    
						key_out[5:3] <= key_r[5:3]|key[5:3];   // double comfirm the pressed key
						
					end 
			ROW2_SCAN:begin 
						key[8:6] <= col;    // check for colum 6, 7, 8
						key_r[8:6] <= key[8:6];   
						key_out[8:6] <= key_r[8:6]|key[8:6];   // double comfirm the pressed key
						
					end 
			ROW3_SCAN:begin 
						key[11:9] <= col;    // check for colum 9, 10, 11
						key_r[11:9] <= key[11:9];    
						key_out[11:9] <= key_r[11:9]|key[11:9]; // double comfirm the pressed key
						
					end 
			default:key_out <= 12'hfff;
		endcase
	end
end
	
	
reg	[3:0]	key_code;	

reg		[11:0]		key_out_r;
wire	[11:0]		 key_pulse;
always @ ( posedge clk  or  negedge rst_n )begin
	if (!rst_n) key_out_r <= 12'hfff;
	else  key_out_r <= key_out;  
end 

assign key_pulse= key_out_r & (~key_out);   

always@(*)begin
	case(key_pulse)
		12'b0000_0000_0001: key_code=4'd1 ;	// key 1
		12'b0000_0000_0010: key_code=4'd2 ;	// key 2
		12'b0000_0000_0100: key_code=4'd3 ;	// key 3
		12'b0000_0000_1000: key_code=4'd4 ;	// key 4
		12'b0000_0001_0000: key_code=4'd5 ; 	// key 5
		12'b0000_0010_0000: key_code=4'd6 ; 	// key 6
		12'b0000_0100_0000: key_code=4'd7 ; 	// key 7
		12'b0000_1000_0000: key_code=4'd8 ; 	// key 8
		12'b0001_0000_0000: key_code=4'd9 ;	// key 9
		12'b0010_0000_0000: key_code=4'd10;	// key *
		12'b0100_0000_0000: key_code=4'd0 ;	// key 0
		12'b1000_0000_0000: key_code=4'd12;	// key #
		default: key_code=4'd15;           
	endcase                                
end                                        
                                           
always@(posedge clk or  negedge rst_n)begin
	if(!rst_n) 	keyPressed <= 4'd15;
	else			keyPressed<=key_code;
end 

	
always@(posedge clk)begin
	case(keyPressed)
	4'd0:  begin segment_led1 <=9'h3f;		    	end 
	4'd1:  begin segment_led1 <=9'h06;		    	end 
	4'd2:  begin segment_led1 <=9'h5b;		    	end
	4'd3:  begin segment_led1 <=9'h4f;		    	end
	4'd4:  begin segment_led1 <=9'h66;		    	end
	4'd5:  begin segment_led1 <=9'h6d;		    	end
	4'd6:  begin segment_led1 <=9'h7d;		    	end 
	4'd7:  begin segment_led1 <=9'h07;		    	end
	4'd8:  begin segment_led1 <=9'h7f;		    	end
	4'd9:  begin segment_led1 <=9'h6f;		    	end 
	4'd10: begin segment_led1 <=9'h77;		    	end
	4'd12: begin segment_led1 <=9'h39;		    	end	
	default:begin segment_led1<=segment_led1;	end
	endcase 
end 
endmodule

Implementation

Section 5.6: Rotary Encoder

Incremental Rotary Encoder

Digtial Structure

Verilog Code

Code 5.6: Complete code to interface with incremental rotary encoder
//---------------------------------------------------------------------------------------------------
// File name:         RotEncoder.v
// Top Module name:   RotEncoder
// Submodules:        None
// Description:       This module detects and processes rotary encoder signals to generate clean
//                    pulses indicating clockwise (CW) and counterclockwise (CCW) movements.
//                    It includes debouncing for the encoder's A and B outputs and detects the
//                    edges to determine the direction of rotation. 
//		      This code has also included the "Soft debouncing" algorithm so no external