Temperature alarm system based on FPGA (12864 display, audible and visual alarm)

Keywords: FPGA

Temperature alarm system based on FPGA (12864 display, audible and visual alarm)

preface

In this experiment, the DS18B20 is driven by FPGA to collect the temperature in real time and display it on the LCD screen 12864. At the same time, the specified temperature can be set by pressing the key. When the actual temperature is lower than the set temperature, the breathing lamp flashes normally, and the running water lamp lights up from left to right. When the actual temperature exceeds the set temperature, the buzzer sounds and the breathing lamp is always on. At the same time, the water lamp changes direction and turns on from right to left.
At the same time, the digital tube is also used to display the temperature in real time. (punctual atomic routine for comparison with the temperature I collected)

Finally, the experimental results are attached. Only part of the code is shown here.

Students who want a complete code can directly add my wechat: wxid_c82ezb72s7cf22 or QQ:1871478767.

1, DS18B20 temperature acquisition module

module ds18b20_ctrl(
    //module clock
    input              clk        ,         // Clock signal (50MHz)
    input              rst_n      ,         // Reset signal

    //user interface
    inout              dq         ,         // DQ pin data of DS18B20
    output reg [19:0]  temp_data  ,         // Temperature value obtained after conversion
    output reg         sign                 // Sign bit
);

//parameter define
localparam  ROM_SKIP_CMD = 8'hcc;           // Skip ROM command
localparam  CONVERT_CMD  = 8'h44;           // Temperature conversion command
localparam  READ_TEMP    = 8'hbe;           // Read DS1820 temperature register command
//state define
localparam  init         = 3'd1 ;           // Initialization status
localparam  rom_skip     = 3'd2 ;           // Load skip ROM command
localparam  wr_byte      = 3'd3 ;           // Write byte status
localparam  temp_convert = 3'd4 ;           // Load temperature conversion command
localparam  delay        = 3'd5 ;           // Delay waiting for the end of temperature conversion
localparam  rd_temp      = 3'd6 ;           // Load read temperature command
localparam  rd_byte      = 3'd7 ;           // Read byte status

//reg define
reg     [ 4:0]         cnt         ;        // Frequency division counter
reg                    clk_1us     ;        // 1MHz clock
reg     [19:0]         cnt_1us     ;        // Microsecond count
reg     [ 2:0]         cur_state   ;        // current state
reg     [ 2:0]         next_state  ;        // Next status
reg     [ 3:0]         flow_cnt    ;        // Flow count
reg     [ 3:0]         wr_cnt      ;        // Write count
reg     [ 4:0]         rd_cnt      ;        // Read count
reg     [ 7:0]         wr_data     ;        // Data written to DS18B20
reg     [ 4:0]         bit_width   ;        // Bit width of read data
reg     [15:0]         rd_data     ;        // Collected data
reg     [15:0]         org_data    ;        // Read raw temperature data
reg     [10:0]         data1       ;        // Symbol processing of principle temperature
reg     [ 3:0]         cmd_cnt     ;        // Send command count
reg                    init_done   ;        // Initialization completion signal
reg                    st_done     ;        // Completion signal
reg                    cnt_1us_en  ;        // Enable timing
reg                    dq_out      ;        // dq output of DS18B20

//wire define
wire    [19:0]         data2       ;        // Convert the processed

//*****************************************************
//**                    main code
//*****************************************************

assign dq = dq_out;

//Frequency division generates a 1MHz clock signal
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt     <= 5'b0;
        clk_1us <= 1'b0;
    end
    else if(cnt < 5'd24) begin
        cnt     <= cnt + 1'b1;
        clk_1us <= clk_1us;
    end
    else begin
        cnt     <= 5'b0;
        clk_1us <= ~clk_1us;
    end
end

//Microsecond timing
always @ (posedge clk_1us or negedge rst_n) begin
    if (!rst_n)
        cnt_1us <= 20'b0;
    else if (cnt_1us_en)
        cnt_1us <= cnt_1us + 1'b1;
    else
        cnt_1us <= 20'b0;
end

//state transition 
always @ (posedge clk_1us or negedge rst_n) begin
    if(!rst_n)
        cur_state <= init;
    else 
        cur_state <= next_state;
end

//Combinational logic state judgment transition condition
always @( * ) begin
    case(cur_state)
        init: begin                             // Initialization status
            if (init_done)
                next_state = rom_skip;
            else
                next_state = init;
        end
        rom_skip: begin                         // Load skip ROM command
            if(st_done)
                next_state = wr_byte;
            else
                next_state = rom_skip;
        end
        wr_byte: begin                          // dispatch orders
            if(st_done)
                case(cmd_cnt)                   // Judge the next status according to the command sequence number
                    4'b1: next_state = temp_convert;
                    4'd2: next_state = delay;
                    4'd3: next_state = rd_temp;
                    4'd4: next_state = rd_byte;
                    default: 
					      next_state = temp_convert;
                endcase
            else
                next_state = wr_byte;
        end
        temp_convert: begin                     // Load temperature conversion command
            if(st_done)
                next_state = wr_byte;
            else
                next_state = temp_convert;
        end
        delay: begin                            // Delay waiting for the end of temperature conversion
            if(st_done)
                next_state = init;
            else
                next_state = delay;
        end
        rd_temp: begin                          // Load read temperature command
            if(st_done)
                next_state = wr_byte;
            else
                next_state = rd_temp;
        end
        rd_byte: begin                          // Read data on data line
            if(st_done)
                next_state = init;
            else
                next_state = rd_byte;
        end
        default: next_state = init;
    endcase
end

//The whole operation steps are initialization, sending skip ROM operation command, sending temperature conversion command
//Reinitialize, send skip ROM operation instructions, and send read data instructions.
always @ (posedge clk_1us or negedge rst_n) begin
    if(!rst_n) begin
        flow_cnt     <=  4'b0;
        init_done    <=  1'b0;
        cnt_1us_en   <=  1'b1;
        dq_out       <=  1'bZ;
        st_done      <=  1'b0;
        rd_data      <= 16'b0;
        rd_cnt       <=  5'd0;
        wr_cnt       <=  4'd0;
        cmd_cnt      <=  3'd0;
    end
    else begin
        st_done <= 1'b0;
        case (next_state)
            init:begin                              //initialization
                init_done <= 1'b0;
                case(flow_cnt)
                    4'd0:
						flow_cnt <= flow_cnt + 1'b1;
						4'd1: begin					//Send 500us reset pulse
                        cnt_1us_en <= 1'b1;         
                        if(cnt_1us < 20'd500)
                            dq_out <= 1'b0;         
                        else begin
                            cnt_1us_en <= 1'b0;
                            dq_out <= 1'bz;
                            flow_cnt <= flow_cnt + 1'b1;
                        end
                    end
                    4'd2:begin						//Release the bus and wait for 30us
                        cnt_1us_en <= 1'b1;
                        if(cnt_1us < 20'd30)
                            dq_out <= 1'bz;
                        else
                            flow_cnt <= flow_cnt + 1'b1;
                    end
                    4'd3: begin						//Detection response signal
                        if(!dq)
                            flow_cnt <= flow_cnt + 1'b1;
                        else
                            flow_cnt <= flow_cnt;
                    end
                    4'd4: begin						//Wait for initialization to complete
                        if(cnt_1us == 20'd500) begin
                            cnt_1us_en <= 1'b0;
                            init_done  <= 1'b1;		//Initialization complete
                            flow_cnt   <= 4'd0;
                        end
                        else
                            flow_cnt <= flow_cnt;
                    end
                    default: flow_cnt <= 4'd0;
                endcase
            end
            rom_skip: begin                         //Load skip ROM operation instruction
                wr_data  <= ROM_SKIP_CMD;
                flow_cnt <= 4'd0;
                st_done  <= 1'b1;
            end
            wr_byte: begin                          //Write byte status (send instruction)
                if(wr_cnt <= 4'd7) begin
                    case (flow_cnt)
                        4'd0: begin
                            dq_out <= 1'b0;			//Pull down the data cable and start the write operation
                            cnt_1us_en <= 1'b1;		//Start timer
                            flow_cnt <= flow_cnt + 1'b1;
                        end
                        4'd1: begin					//Data cable pulled down 1us
                            flow_cnt <= flow_cnt + 1'b1;
                        end
                        4'd2: begin
                            if(cnt_1us < 20'd60)	//send data
                                dq_out <= wr_data[wr_cnt];
                            else if(cnt_1us < 20'd63) 	
                                dq_out <= 1'bz;		//Release bus (send interval)
                            else
                                flow_cnt <= flow_cnt + 1'b1;
                        end
                        4'd3: begin					//Sending 1-bit data completed
                            flow_cnt <= 0;
                            cnt_1us_en <= 1'b0;
                            wr_cnt <= wr_cnt + 1'b1;//Write counter plus 1
                        end
                        default : flow_cnt <= 0;
                    endcase
                end
                else begin							//End of sending command (1Byte)
                    st_done <= 1'b1;
                    wr_cnt <= 4'b0;
                    cmd_cnt <= (cmd_cnt == 3'd4) ?  //Mark the sequence number of the currently sent instruction
					           3'd1 : (cmd_cnt+ 1'b1);
                end
            end
            temp_convert: begin                     //Load temperature conversion command
                wr_data <= CONVERT_CMD;
                st_done <= 1'b1;
            end
            delay: begin                            //Wait for the temperature conversion to end after a delay of 500ms
                cnt_1us_en <= 1'b1;
                if(cnt_1us == 20'd500000) begin
                    st_done <= 1'b1;
                    cnt_1us_en <= 1'b0;
                end 
            end 
            rd_temp: begin                          //Load read temperature command
                wr_data <= READ_TEMP;
                bit_width <= 5'd16;					//Specifies the number of read data
                st_done <= 1'b1;
            end
            rd_byte: begin                          //Receive 16 bit temperature data
                if(rd_cnt < bit_width) begin
                    case(flow_cnt)
                        4'd0: begin
                            cnt_1us_en <= 1'b1;
                            dq_out <= 1'b0;			//Pull down the data cable and start the read operation
                            flow_cnt <= flow_cnt + 1'b1;
                        end
                        4'd1: begin
                            dq_out <= 1'bz;			//Release the bus and receive data within 15us
                            if(cnt_1us == 20'd14) begin
                                rd_data <= {dq,rd_data[15:1]};
                                flow_cnt <= flow_cnt + 1'b1 ;
                            end
                        end
                        4'd2: begin
                            if (cnt_1us <= 20'd64)	//End of reading 1-bit data
                                dq_out <= 1'bz;
                            else begin
                                flow_cnt <= 4'd0;	
                                rd_cnt <= rd_cnt + 1'b1;//Read counter plus 1
                                cnt_1us_en <= 1'b0;
                            end
                        end
                        default : flow_cnt <= 4'd0;
                    endcase
                end
                else begin
                    st_done <= 1'b1;
                    org_data  <= rd_data;
                    rd_cnt <= 5'b0;
                end
            end
            default: ;
        endcase
    end 
end

//Judgment symbol bit
always @(posedge clk_1us or negedge rst_n) begin
    if(!rst_n) begin
        sign  <=  1'b0;
        data1 <= 11'b0;
    end
    else if(org_data[15] == 1'b0) begin
        sign  <= 1'b0;
        data1 <= org_data[10:0];
    end
    else if(org_data[15] == 1'b1) begin
        sign  <= 1'b1;
        data1 <= ~org_data[10:0] + 1'b1;
    end
end

//Convert the collected temperature
assign data2 = (data1 * 11'd625)/ 7'd100;

//Temperature output
always @(posedge clk_1us or negedge rst_n) begin
    if(!rst_n)
        temp_data <= 20'b0;
    else
        temp_data <= data2;
end

endmodule

2, Nixie tube display module

module seg_led(
    input                   clk    ,        // clock signal
    input                   rst_n  ,        // Reset signal

    input         [19:0]    data   ,        // Value to be displayed by 6-digit nixie tube
    input         [5:0]     point  ,        // The specific display position of the decimal point, from high to low, and the high level is valid
    input                   en     ,        // Nixie tube enable signal
    input                   sign   ,        // Symbol bit (high level display "-")

    output   reg  [5:0]     seg_sel,        // The nixie tube position is selected, and the leftmost nixie tube is the highest position
    output   reg  [7:0]     seg_led         // Nixie tube segment selection
    );

//parameter define
localparam  CLK_DIVIDE = 4'd10     ;        // Clock divide factor 
localparam  MAX_NUM    = 13'd5000  ;        // Count value required to count 1ms for nixie tube drive clock (5MHz)

//reg define
reg    [ 3:0]             clk_cnt  ;        // Clock division counter
reg                       dri_clk  ;        // Nixie tube drive clock, 5MHz
reg    [23:0]             num      ;        // 24 bit bcd code register
reg    [12:0]             cnt0     ;        // Nixie tube driven clock counter
reg                       flag     ;        // Flag signal (indicates that cnt0 count reaches 1ms)
reg    [2:0]              cnt_sel  ;        // Nixie tube position selection counter
reg    [3:0]              num_disp ;        // Data displayed by current nixie tube
reg                       dot_disp ;        // The decimal point displayed by the current nixie tube

//wire define
wire   [3:0]              data0    ;        // Single digit
wire   [3:0]              data1    ;        // Ten digits
wire   [3:0]              data2    ;        // Hundreds
wire   [3:0]              data3    ;        // thousands 
wire   [3:0]              data4    ;        // Ten thousand digits
wire   [3:0]              data5    ;        // 100000 digits

//*****************************************************
//**                    main code
//*****************************************************

//Extract each bit of the decimal number corresponding to the displayed value
assign  data0 = data % 4'd10;               // Single digit
assign  data1 = data / 4'd10 % 4'd10   ;    // Ten digits
assign  data2 = data / 7'd100 % 4'd10  ;    // Hundreds
assign  data3 = data / 10'd1000 % 4'd10 ;   // thousands 
assign  data4 = data / 14'd10000 % 4'd10;   // Ten thousand digits
assign  data5 = data / 17'd100000;          // 100000 digits

//Divide the system clock by 10 to obtain a nixie tube drive clock DRI with a frequency of 5MHz_ clk
always @(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
       clk_cnt <= 4'd0;
       dri_clk <= 1'b1;
   end
   else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
       clk_cnt <= 4'd0;
       dri_clk <= ~dri_clk;
   end
   else begin
       clk_cnt <= clk_cnt + 1'b1;
       dri_clk <= dri_clk;
   end
end

//Convert a 20 bit binary number to 8421bcd code (i.e. use a 4-bit binary number to represent a 1-bit decimal number)
always @ (posedge dri_clk or negedge rst_n) begin
    if (!rst_n)
        num <= 24'b0;
    else begin
        if (data5 || point[5]) begin     //If the displayed data is a 6-digit decimal number,
            num[23:20] <= data5;         //Then assign values to the 6-bit nixie tube in turn
            num[19:16] <= data4;
            num[15:12] <= data3;
            num[11:8]  <= data2;
            num[ 7:4]  <= data1;
            num[ 3:0]  <= data0;
        end
        else begin                         
            if (data4 || point[4]) begin //If the displayed data is a 5-digit decimal number, assign a value to the lower 5-digit nixie tube
                num[19:0] <= {data4,data3,data2,data1,data0};
                if(sign)                    
                    num[23:20] <= 4'd11; //If a negative sign needs to be displayed, the highest bit (bit 6) is the sign bit
                else
                    num[23:20] <= 4'd10; //When a negative sign is not required, no character is displayed in bit 6
            end
            else begin                   //If the displayed data is a 4-digit decimal number, assign a value to the lower 4-digit nixie tube
                if (data3 || point[3]) begin
                    num[15: 0] <= {data3,data2,data1,data0};
                    num[23:20] <= 4'd10; //No characters are displayed in bit 6
                    if(sign)             //If a negative sign needs to be displayed, the highest bit (5th bit) is the sign bit
                        num[19:16] <= 4'd11;
                    else                 //When a negative sign is not required, no character is displayed in the fifth digit
                        num[19:16] <= 4'd10;
                end
                else begin               //If the display data is a 3-digit decimal number, assign a value to the lower 3-digit nixie tube
                    if (data2 || point[2]) begin
                        num[11: 0] <= {data2,data1,data0};
                                         //No characters are displayed in bits 6 and 5
                        num[23:16] <= {2{4'd10}};
                        if(sign)         //If a negative sign needs to be displayed, the highest bit (Bit 4) is the sign bit
                            num[15:12] <= 4'd11;
                        else             //When a negative sign is not required, no character is displayed in the fourth digit
                            num[15:12] <= 4'd10;
                    end
                    else begin           //If the display data is a 2-digit decimal number, assign a value to the lower 2-digit nixie tube
                        if (data1 || point[1]) begin
                            num[ 7: 0] <= {data1,data0};
                                         //No characters are displayed in bits 6, 5 and 4
                            num[23:12] <= {3{4'd10}};
                            if(sign)     //If a negative sign needs to be displayed, the highest bit (bit 3) is the sign bit
                                num[11:8]  <= 4'd11;
                            else         //When a negative sign is not required, no character is displayed in the third digit
                                num[11:8] <=  4'd10;
                        end
                        else begin       //If the display data is a 1-digit decimal number, assign a value to the lowest nixie tube
                            num[3:0] <= data0;
                                         //No characters are displayed in bits 6 and 5
                            num[23:8] <= {4{4'd10}};
                            if(sign)     //If a negative sign needs to be displayed, the highest bit (bit 2) is the sign bit
                                num[7:4] <= 4'd11;
                            else         //When a negative sign is not required, no character is displayed in the second digit
                                num[7:4] <= 4'd10;
                        end
                    end
                end
            end
        end
    end
end

//Whenever the counter counts the nixie tube drive clock for 1ms, it outputs a pulse signal of one clock cycle
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        cnt0 <= 13'b0;
        flag <= 1'b0;
     end
    else if (cnt0 < MAX_NUM - 1'b1) begin
        cnt0 <= cnt0 + 1'b1;
        flag <= 1'b0;
     end
    else begin
        cnt0 <= 13'b0;
        flag <= 1'b1;
     end
end

//cnt_sel counts from 0 to 5, which is used to select the nixie tube currently in the display state
always @ (posedge dri_clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        cnt_sel <= 3'b0;
    else if(flag) begin
        if(cnt_sel < 3'd5)
            cnt_sel <= cnt_sel + 1'b1;
        else
            cnt_sel <= 3'b0;
    end
    else
        cnt_sel <= cnt_sel;
end

//Control the nixie tube position selection signal to make the 6-bit nixie tube display in turn
always @ (posedge dri_clk or negedge rst_n) begin
    if(!rst_n) begin
        seg_sel  <= 6'b111111;              //Bit select signal low level active
        num_disp <= 4'b0;           
        dot_disp <= 1'b1;                   //Common anode nixie tube, low-level conduction
    end
    else begin
        if(en) begin
            case (cnt_sel)
                3'd0 :begin
                    seg_sel  <= 6'b111110;  //Display the lowest position of nixie tube
                    num_disp <= num[3:0] ;  //Displayed data
                    dot_disp <= ~point[0];  //Displayed decimal point
                end
                3'd1 :begin
                    seg_sel  <= 6'b111101;  //Display digit 1 of nixie tube
                    num_disp <= num[7:4] ;
                    dot_disp <= ~point[1];
                end
                3'd2 :begin
                    seg_sel  <= 6'b111011;  //Display digit 2 of nixie tube
                    num_disp <= num[11:8];
                    dot_disp <= ~point[2];
                end
                3'd3 :begin
                    seg_sel  <= 6'b110111;  //Display digit 3 of nixie tube
                    num_disp <= num[15:12];
                    dot_disp <= ~point[3];
                end
                3'd4 :begin
                    seg_sel  <= 6'b101111;  //Display digit 4 of nixie tube
                    num_disp <= num[19:16];
                    dot_disp <= ~point[4];
                end
                3'd5 :begin
                    seg_sel  <= 6'b011111;  //Display the highest position of nixie tube
                    num_disp <= num[23:20];
                    dot_disp <= ~point[5];
                end
                default :begin
                    seg_sel  <= 6'b111111;
                    num_disp <= 4'b0;
                    dot_disp <= 1'b1;
                end
            endcase
        end
        else begin
            seg_sel  <= 6'b111111;          //When the enable signal is 0, all nixie tubes do not display
            num_disp <= 4'b0;
            dot_disp <= 1'b1;
        end
    end
end

//Control the nixie tube segment selection signal and display characters
always @ (posedge dri_clk or negedge rst_n) begin
    if (!rst_n)
        seg_led <= 8'hc0;
    else begin
        case (num_disp)
            4'd0 : seg_led <= {dot_disp,7'b1000000}; //Display number 0
            4'd1 : seg_led <= {dot_disp,7'b1111001}; //Display number 1
            4'd2 : seg_led <= {dot_disp,7'b0100100}; //Display number 2
            4'd3 : seg_led <= {dot_disp,7'b0110000}; //Display number 3
            4'd4 : seg_led <= {dot_disp,7'b0011001}; //Display number 4
            4'd5 : seg_led <= {dot_disp,7'b0010010}; //Display number 5
            4'd6 : seg_led <= {dot_disp,7'b0000010}; //Display number 6
            4'd7 : seg_led <= {dot_disp,7'b1111000}; //Display number 7
            4'd8 : seg_led <= {dot_disp,7'b0000000}; //Display number 8
            4'd9 : seg_led <= {dot_disp,7'b0010000}; //Display number 9
            4'd10: seg_led <= 8'b11111111;           //No characters are displayed
            4'd11: seg_led <= 8'b10111111;           //Show negative sign (-)
            default: 
                   seg_led <= {dot_disp,7'b1000000};
        endcase
    end
end

endmodule 

3, Breathing lamp and water lamp module

module led_breath(
input clk,    //50MHz
input rst,

input en,
  output   reg    led1 ,
  output   reg    led2 ,
  output   reg    led3 ,

output reg led_o
);

//1s counter
reg flag_1s;
reg [28:0] cnt_1s;
always @(posedge clk)
begin
        if (! rst)begin
            cnt_1s <= 27'b0;
            flag_1s <= 1'b0;
        end
        else if(cnt_1s == 27'd49_999_999 ) begin
            cnt_1s <= 27'b0;
            flag_1s <= 1'b1;
        end
        else begin
            cnt_1s <= cnt_1s + 1'b1;
            flag_1s <= 1'b0;
        end
end

//1ms counter
reg flag_1ms;
reg [17:0] cnt_1ms;
always @(posedge clk)
begin
        if (! rst)begin
            cnt_1ms <= 18'b0;
            flag_1ms <= 1'b0;
        end
        else if(cnt_1ms == 18'd49_999 ) begin
            cnt_1ms <= 18'b0;
            flag_1ms <= 1'b1;
        end
        else begin
            cnt_1ms <= cnt_1ms + 1'b1;
            flag_1ms <= 1'b0;
        end
end

//1us counter
reg flag_1us;
reg [13:0] cnt_1us;
always @(posedge clk)
begin
        if (! rst)begin
            cnt_1us <= 7'b0;
            flag_1us <= 1'b0;
        end
        else if(cnt_1us == 7'd999) begin
            cnt_1us <= 7'b0;
            flag_1us <= 1'b1;
        end
        else begin
            cnt_1us <= cnt_1us + 1'b1;
            flag_1us <= 1'b0;
        end
end

//How many ms are counted
reg [9:0] number_ms;
always @(posedge clk)
begin
        if (! rst )begin
            number_ms <= 10'd0;
        end
        else begin
                if(number_ms == 10'd1000)begin
                    number_ms <= 10'd0;
                end
                else if(flag_1ms == 1'b1) begin
                    number_ms <= number_ms + 1'b1;
                end
                else begin
                    number_ms <= number_ms;
                end
        end
end



//How many us are counted
reg [9:0] number_us;
always @(posedge clk or negedge rst)
begin
        if (! rst )begin
            number_us <= 10'd0;
        end
        else begin
                if(number_us == 10'd1000)begin
                    number_us <= 10'd0;
                end
                else if(flag_1us == 1'b1) begin
                    number_us <= number_us + 1'b1;
                end
                else begin
                    number_us <= number_us;
                end
        end
end

//module of led breath
//
wire led_flag0; //From dark to bright
wire led_flag1; //From light to dark
assign  led_flag0 = (number_ms > number_us)? 1: 0;
assign  led_flag1 = (number_ms > number_us)? 0: 1;


reg led_flag;		//Flip the signal every 1s
always @(posedge clk or negedge rst)
begin
        if (! rst)begin
                led_flag <= 1'b1;
        end
        else if (flag_1s == 1'b1) begin
                led_flag <= ~ led_flag;
        end
        else begin
                led_flag <= led_flag;
        end

end

always @ (posedge clk or negedge rst) begin
	if(!rst)
	 led_o <= led_o;
	else if(en)
	 led_o <= 1'b1;
	else if(led_flag)
	 led_o <= led_flag0;
	else if(!led_flag)
    led_o <= led_flag1;	
	else
	led_o <= led_o;
end



reg [2:0] state;//State machine

reg                clk_E;
reg     [30:0]     counter;


always@(posedge clk or negedge rst)   //frequency division
	begin
		if(!rst)
			begin
				counter<=0;
				clk_E<=0;
			end 
		else	
			begin
				if(counter == 5_000_000)begin
					clk_E <= ~clk_E;
                    counter<=0;
                end
				else 
					begin
						counter  <= counter + 1'b1;
					end 
			end 
	end 
    


always @ (posedge clk_E or negedge rst) begin
	if(!rst) begin
    led1  <= 1'b0   ;
    led2  <= 1'b0   ;
    led3  <= 1'b0   ;
	 state <= 3'd0;
            end
	else begin
		case(state)
			3'd0 : begin
			if(en == 1'b1)begin 
	                    led1  <= 1'b0   ;
                       led2  <= 1'b0   ;
                       led3  <= 1'b1   ;
							 state <= state + 1;
							end  
	             else begin
					        led1  <= 1'b1   ;
                       led2  <= 1'b0   ;
                       led3  <= 1'b0   ;
							  state <= state + 1;
							end  
                  end
         3'd1 : begin
			if(en == 1'b1)begin 
	                    led1  <= 1'b0   ;
                       led2  <= 1'b1   ;
                       led3  <= 1'b0   ;
							  state <= state + 1;
							end  
	             else begin
					        led1  <= 1'b0   ;
                       led2  <= 1'b1   ;
                       led3  <= 1'b0   ;
							  state <= state + 1;
							end 
						end
			3'd2 : begin
			if(en == 1'b1)begin 
	                    led1  <= 1'b1   ;
                       led2  <= 1'b0   ;
                       led3  <= 1'b0   ;
							  state <= 3'd0;
							end  
	             else begin
					        led1  <= 1'b0   ;
                       led2  <= 1'b0   ;
                       led3  <= 1'b1   ;
							  state <= 3'd0;
							end
						end	
         endcase
end
end


endmodule

experimental result


Students who want a complete code can directly add my wechat: wxid_c82ezb72s7cf22 or QQ:1871478767.

summary

1: In this experiment, I encountered many problems. For example, when comparing values, the same type is required for comparison. For input, it is wire type, while output can be wire or register reg type. Here, a type conversion is required. For example

input  wire  a;
otput  reg   b;
reg c;
always @(posedge clk or negedge rst)
if(!rst) 
    c  <=   a   ;
else
	 if(b > c);
	 .......
            end

Just like this, wire type can be converted to reg type for comparison. In the final analysis, the basic knowledge is not solid.

2: As for the display of words on the LCD screen, we provide a way for you. The word library in the online data manual is not easy to find the words you want. We recommend you to go to Taobao. Many businesses will attach their PDF documents of similar data manuals to the back of the goods. In it, we can directly find the words we want by Ctrl+F, This will be much faster than reading word by word in the font.

3: You must type more code and do it yourself. For example, I thought out the water lamp in my experiment above. At that time, when I looked at the water lamp routine, I didn't have much feeling. When I learned the state machine later, I suddenly had an idea, why can't the water lamp be written with the state machine? It is not necessary to use the method of bit splicing in the example. Although the method of state machine takes up more logical resources, it is quite successful to write it with your own ideas.
I hope you won't stop at the water lamp because of the introduction of the water lamp.

Finally, I hope you will praise and pay more attention. I only eat potato chips, not shredded potatoes.

Posted by fotofx on Tue, 12 Oct 2021 18:17:10 -0700