📄 up3_clock.vhd
字号:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
-- This code displays time in the UP3's LCD Display
-- SW8 (GLOBAL RESET) resets time
ENTITY UP3_CLOCK IS
PORT(reset, clk_48Mhz, TIME_SET, INC, alarm_set, alarm, hour_alarm, cancel, shift : IN STD_LOGIC;
LCD_RS, LCD_E, TIME_SET_LED, SEC_LED, alarm_set_led, alarm_led : OUT STD_LOGIC;
LCD_RW : BUFFER STD_LOGIC;
DATA_BUS : INOUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END UP3_CLOCK;
ARCHITECTURE a OF UP3_CLOCK IS
TYPE STATE_TYPE IS (HOLD, FUNC_SET, DISPLAY_ON, MODE_SET, WRITE_CHAR1,
WRITE_CHAR2,WRITE_CHAR3,WRITE_CHAR4,WRITE_CHAR5,WRITE_CHAR6,WRITE_CHAR7,
WRITE_CHAR8, WRITE_CHAR9, WRITE_CHAR10, WRITE_CHAR11, WRITE_CHAR12, WRITE_CHAR13, WRITE_CHAR14,
WRITE_CHAR15, WRITE_CHAR16, WRITE_CHAR17, WRITE_CHAR18, WRITE_CHAR19, WRITE_CHAR20, WRITE_CHAR21,
hour_mode, alarm_flag, enter, RETURN_HOME, TOGGLE_E, RESET1, RESET2,
RESET3, DISPLAY_OFF, DISPLAY_CLEAR);
SIGNAL state, next_command: STATE_TYPE;
type state_type_set is (count, mdhr1, mdhr0, mdmin1, mdmin0, mdsec1, mdsec0, mdyr3, mdyr2, mdyr1, mdyr0,
mdmon1, mdmon0, mdda1, mdda0, alhr1, alhr0, almin1, almin0, alsec1, alsec0);
signal modify :state_type_set;
type state_type_alarm is (normal, alarm_on, hour_on);
signal current :state_type_alarm;
SIGNAL DATA_BUS_VALUE: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL CLK_COUNT_400HZ: STD_LOGIC_VECTOR(19 DOWNTO 0);
SIGNAL CLK_COUNT_10HZ: STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL BCD_SECD0,BCD_SECD1,BCD_MIND0,BCD_MIND1: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL BCD_HRD0,BCD_HRD1,bcd_mond1,bcd_mond0,bcd_dad1,bcd_dad0 : STD_LOGIC_VECTOR(3 DOWNTO 0);
signal bcd_yrd3,bcd_yrd2,bcd_yrd1,bcd_yrd0 : STD_LOGIC_VECTOR(3 DOWNTO 0);
signal bcd_tsec, am_pm :std_logic_vector(7 downto 0);
SIGNAL set_SECD0,set_SECD1,set_MIND0,set_MIND1, set_HRD0, set_HRD1: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL set_yrd3, set_yrd2, set_yrd1, set_yrd0, set_mond1, set_mond0,
set_dad0, set_dad1 : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL count_SECD0,count_SECD1,count_MIND0,count_MIND1: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL count_HRD0,count_HRD1,count_TSEC : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL alarm_SECD0,alarm_SECD1,alarm_MIND0,alarm_MIND1: STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL alarm_HRD0,alarm_HRD1 : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL CLK_400HZ, CLK_10HZ : STD_LOGIC;
SIGNAL TIME_SET_FLOP1, TIME_SET_FLOP2, TIME_SET_PULSEOUT, TIME_SET_VALID : STD_LOGIC;
SIGNAL alarm_SET_FLOP1, alarm_SET_FLOP2, alarm_SET_PULSEOUT, alarm_SET_VALID : STD_LOGIC;
SIGNAL INC_FLOP1, INC_FLOP2, INC_PULSEOUT, INC_VALID : STD_LOGIC;
SIGNAL TIME_SET_COUNT, INC_COUNT, alarm_set_count : STD_LOGIC_VECTOR(19 DOWNTO 0);
CONSTANT DEBOUNCE_COUNT : STD_LOGIC_VECTOR(19 DOWNTO 0) := X"2FFFF";
SIGNAL TIME_SET_STATE, alarm_set_state :STD_LOGIC;
BEGIN
SEC_LED <= BCD_SECD0(0);
TIME_SET_LED <= TIME_SET_STATE;
alarm_set_led <= alarm_set_state;
-- BIDIRECTIONAL TRI STATE LCD DATA BUS
DATA_BUS <= DATA_BUS_VALUE WHEN LCD_RW = '0' ELSE "ZZZZZZZZ";
TIME_SET_FLOP: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
TIME_SET_FLOP1 <= '1';
TIME_SET_FLOP2 <= '1';
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
TIME_SET_FLOP1 <= TIME_SET;
TIME_SET_FLOP2 <= TIME_SET_FLOP1;
END IF;
END PROCESS;
INC_FLOP: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
INC_FLOP1 <= '1';
INC_FLOP2 <= '1';
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
INC_FLOP1 <= INC;
INC_FLOP2 <= INC_FLOP1;
END IF;
END PROCESS;
alarm_SET_FLOP: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
alarm_SET_FLOP1 <= '1';
alarm_SET_FLOP2 <= '1';
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
alarm_SET_FLOP1 <= alarm_SET;
alarm_SET_FLOP2 <= alarm_SET_FLOP1;
END IF;
END PROCESS;
TIME_SET_PULSE: PROCESS (TIME_SET, TIME_SET_FLOP1, TIME_SET_FLOP2)
BEGIN
TIME_SET_PULSEOUT <= TIME_SET_FLOP2 AND (NOT TIME_SET_FLOP1);
END PROCESS;
INC_PULSE: PROCESS (INC, INC_FLOP1, INC_FLOP2)
BEGIN
INC_PULSEOUT <= INC_FLOP2 AND (NOT INC_FLOP1);
END PROCESS;
alarm_SET_PULSE: PROCESS (alarm_SET, alarm_SET_FLOP1, alarm_SET_FLOP2)
BEGIN
alarm_SET_PULSEOUT <= alarm_SET_FLOP2 AND (NOT alarm_SET_FLOP1);
END PROCESS;
TIME_SET_DEBOUNCE: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
TIME_SET_COUNT <= (OTHERS => '0');
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
IF (TIME_SET_FLOP1 = '0') THEN
IF (TIME_SET_PULSEOUT = '1') THEN
TIME_SET_COUNT <= DEBOUNCE_COUNT;
ELSE
IF (TIME_SET_COUNT = X"00000") THEN
TIME_SET_COUNT <= (OTHERS => '0');
ELSE
TIME_SET_COUNT <= TIME_SET_COUNT - 1;
END IF;
END IF;
ELSE
TIME_SET_COUNT <= (OTHERS => '0');
END IF;
END IF;
END PROCESS;
TIME_SET_OUT: PROCESS (TIME_SET_COUNT)
BEGIN
CASE TIME_SET_COUNT IS
WHEN X"00001" =>
IF (TIME_SET_PULSEOUT = '0') THEN
TIME_SET_VALID <= '1';
ELSE
TIME_SET_VALID <= '0';
END IF;
WHEN OTHERS => TIME_SET_VALID <= '0';
END CASE;
END PROCESS;
INC_DEBOUNCE: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
INC_COUNT <= (OTHERS => '0');
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
IF (INC_FLOP1 = '0') THEN
IF (INC_PULSEOUT = '1') THEN
INC_COUNT <= DEBOUNCE_COUNT;
ELSE
IF (INC_COUNT = X"00000") THEN
INC_COUNT <= (OTHERS => '0');
ELSE
INC_COUNT <= INC_COUNT - 1;
END IF;
END IF;
ELSE
INC_COUNT <= (OTHERS => '0');
END IF;
END IF;
END PROCESS;
INC_OUT: PROCESS (INC_COUNT)
BEGIN
CASE INC_COUNT IS
WHEN X"00001" =>
IF (INC_PULSEOUT = '0') THEN
INC_VALID <= '1';
ELSE
INC_VALID <= '0';
END IF;
WHEN OTHERS => INC_VALID <= '0';
END CASE;
END PROCESS;
alarm_SET_DEBOUNCE: PROCESS (CLK_48MHZ, reset)
BEGIN
IF reset = '0' THEN
alarm_SET_COUNT <= (OTHERS => '0');
ELSIF CLK_48MHZ'EVENT AND CLK_48MHZ = '1' THEN
IF (alarm_SET_FLOP1 = '0') THEN
IF (alarm_SET_PULSEOUT = '1') THEN
alarm_SET_COUNT <= DEBOUNCE_COUNT;
ELSE
IF (alarm_SET_COUNT = X"00000") THEN
alarm_SET_COUNT <= (OTHERS => '0');
ELSE
alarm_SET_COUNT <= alarm_SET_COUNT - 1;
END IF;
END IF;
ELSE
alarm_SET_COUNT <= (OTHERS => '0');
END IF;
END IF;
END PROCESS;
alarm_SET_OUT: PROCESS (alarm_SET_COUNT)
BEGIN
CASE alarm_SET_COUNT IS
WHEN X"00001" =>
IF (alarm_SET_PULSEOUT = '0') THEN
alarm_SET_VALID <= '1';
ELSE
alarm_SET_VALID <= '0';
END IF;
WHEN OTHERS => alarm_SET_VALID <= '0';
END CASE;
END PROCESS;
--48MHZ TO 400HZ
PROCESS
BEGIN
WAIT UNTIL CLK_48MHZ'EVENT AND CLK_48MHZ = '1';
IF RESET = '0' THEN
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ <= '0';
ELSE
IF CLK_COUNT_400HZ < X"0EA60" THEN
CLK_COUNT_400HZ <= CLK_COUNT_400HZ + 1;
ELSE
CLK_COUNT_400HZ <= X"00000";
CLK_400HZ <= NOT CLK_400HZ;
END IF;
END IF;
END PROCESS;
PROCESS (CLK_400HZ, reset)
BEGIN
IF reset = '0' THEN
state <= RESET1;
DATA_BUS_VALUE <= X"38";
next_command <= RESET2;
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
ELSIF CLK_400HZ'EVENT AND CLK_400HZ = '1' THEN
-- GENERATE 1 SEC CLOCK SIGNAL FOR SECOND COUNT PROCESS
IF CLK_COUNT_10HZ < 19 THEN
CLK_COUNT_10HZ <= CLK_COUNT_10HZ + 1;
ELSE
CLK_COUNT_10HZ <= X"00";
CLK_10HZ <= NOT CLK_10HZ;
END IF;
-- SEND TIME TO LCD
CASE state IS
-- Set Function to 8-bit transfer and 2 line display with 5x8 Font size
-- see Hitachi HD44780 family data sheet for LCD command and timing details
WHEN RESET1 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"38";
state <= TOGGLE_E;
next_command <= RESET2;
WHEN RESET2 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"38";
state <= TOGGLE_E;
next_command <= RESET3;
WHEN RESET3 =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"38";
state <= TOGGLE_E;
next_command <= FUNC_SET;
-- EXTRA STATES ABOVE ARE NEEDED FOR RELIABLE PUSHBUTTON RESET OF LCD
WHEN FUNC_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"38";
state <= TOGGLE_E;
next_command <= DISPLAY_OFF;
-- Turn off Display and Turn off cursor
WHEN DISPLAY_OFF =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"08";
state <= TOGGLE_E;
next_command <= DISPLAY_CLEAR;
-- Turn on Display and Turn off cursor
WHEN DISPLAY_CLEAR =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"01";
state <= TOGGLE_E;
next_command <= DISPLAY_ON;
-- Turn on Display and Turn off cursor
WHEN DISPLAY_ON =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"0C";
state <= TOGGLE_E;
next_command <= MODE_SET;
-- Set write mode to auto increment address and move cursor to the right
WHEN MODE_SET =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"06";
state <= TOGGLE_E;
next_command <= WRITE_CHAR1;
-- Write ASCII hex character in first LCD character location
WHEN WRITE_CHAR1 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
if am_pm = X"50" then
if bcd_hrd0 < 2 then
DATA_BUS_VALUE <= X"3" & (BCD_HRD1 - 2);
else
DATA_BUS_VALUE <= X"3" & (BCD_HRD1 - 1);
end if;
else
DATA_BUS_VALUE <= X"3" & BCD_HRD1;
end if;
state <= TOGGLE_E;
next_command <= WRITE_CHAR2;
-- Write ASCII hex character in second LCD character location
WHEN WRITE_CHAR2 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
if am_pm = X"50" then
if bcd_hrd0 < 2 then
DATA_BUS_VALUE <= X"3" & (BCD_HRD0 + 8);
else
DATA_BUS_VALUE <= X"3" & (BCD_HRD0 - 2);
end if;
else
DATA_BUS_VALUE <= X"3" & BCD_HRD0;
end if;
state <= TOGGLE_E;
next_command <= WRITE_CHAR3;
-- Write ASCII hex character in third LCD character location
WHEN WRITE_CHAR3 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3A" ;
state <= TOGGLE_E;
next_command <= WRITE_CHAR4;
-- Write ASCII hex character in fourth LCD character location
WHEN WRITE_CHAR4 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & BCD_MIND1;
state <= TOGGLE_E;
next_command <= WRITE_CHAR5;
-- Write ASCII hex character in fifth LCD character location
WHEN WRITE_CHAR5 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & BCD_MIND0;
state <= TOGGLE_E;
next_command <= WRITE_CHAR6;
-- Write ASCII hex character in sixth LCD character location
WHEN WRITE_CHAR6 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3A" ;
state <= TOGGLE_E;
next_command <= WRITE_CHAR7;
-- Write ASCII hex character in seventh LCD character location
WHEN WRITE_CHAR7 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & BCD_SECD1;
state <= TOGGLE_E;
next_command <= WRITE_CHAR8;
-- Write ASCII hex character in eighth LCD character location
WHEN WRITE_CHAR8 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & BCD_SECD0;
state <= TOGGLE_E;
next_command <= WRITE_CHAR9;
WHEN WRITE_CHAR9 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"2E";
state <= TOGGLE_E;
next_command <= WRITE_CHAR10;
WHEN WRITE_CHAR10 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= BCD_TSEC;
state <= TOGGLE_E;
next_command <= hour_mode;
WHEN hour_mode =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
if shift = '1' then
DATA_BUS_VALUE <= X"20";
else
DATA_BUS_VALUE <= am_pm;
end if;
state <= TOGGLE_E;
next_command <= alarm_flag;
WHEN alarm_flag =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"8C";
state <= TOGGLE_E;
next_command <= WRITE_CHAR11;
WHEN WRITE_CHAR11 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
IF alarm = '0' or hour_alarm = '0' then
DATA_BUS_VALUE <= X"2A";
ELSE
DATA_BUS_VALUE <= X"20";
END IF;
state <= TOGGLE_E;
next_command <= enter;
WHEN enter =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"C0";
state <= TOGGLE_E;
next_command <= WRITE_CHAR12;
WHEN WRITE_CHAR12 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_yrd3;
state <= TOGGLE_E;
next_command <= WRITE_CHAR13;
WHEN WRITE_CHAR13 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_yrd2;
state <= TOGGLE_E;
next_command <= WRITE_CHAR14;
WHEN WRITE_CHAR14 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_yrd1;
state <= TOGGLE_E;
next_command <= WRITE_CHAR15;
WHEN WRITE_CHAR15 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_yrd0;
state <= TOGGLE_E;
next_command <= WRITE_CHAR16;
WHEN WRITE_CHAR16 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"2D";
state <= TOGGLE_E;
next_command <= WRITE_CHAR17;
WHEN WRITE_CHAR17 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_mond1;
state <= TOGGLE_E;
next_command <= WRITE_CHAR18;
WHEN WRITE_CHAR18 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_mond0;
state <= TOGGLE_E;
next_command <= WRITE_CHAR19;
WHEN WRITE_CHAR19 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"2D";
state <= TOGGLE_E;
next_command <= WRITE_CHAR20;
WHEN WRITE_CHAR20 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_dad1;
state <= TOGGLE_E;
next_command <= WRITE_CHAR21;
WHEN WRITE_CHAR21 =>
LCD_E <= '1';
LCD_RS <= '1';
LCD_RW <= '0';
DATA_BUS_VALUE <= X"3" & bcd_dad0;
state <= TOGGLE_E;
next_command <= RETURN_HOME;
-- Return write address to first character postion
WHEN RETURN_HOME =>
LCD_E <= '1';
LCD_RS <= '0';
LCD_RW <= '0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -