Dual Variable Environment Controller

EE552

Raymond Richmond

Tam Hung Chau

 

Executive Summary

Efficiency is the catch-phrase for everyone in this day and age. Waste is regarded as costly and simply not tolerated. This trend reaches into every facet of life, even the way we conduct our personal lives.

One place that is always targeted for improvements in efficiency is the home. Low energy emitting windows, high quality insulation, and florescent light bulbs are all examples of initiatives aimed at reducing energy loss in the home. The definition of waste is using something that you do not need to use, like heating a room when you are not there. Technology is coming to the point where individual rooms in a house can be controlled to maximize efficiency, but this really only works on new homes where such elaborate systems can be more easily installed.

To address the needs and concerns of owners with finished houses, compromises on the ideal must be made. Our design focused on a single controller for a whole house who could be pre-programmed with a generic usage pattern. While this is not optimal, it does however provide significant savings over no pattern at all.

This report will cover the operation and design principles of the completed, smaller project. Extra material is attached in the appendix outlining the design and simulation of the remaining blocks required producing a controller, which filled all of the parameters of the original proposal.

 

Introduction:

The initial project proposal was for a system capable of controlling two devices (Furnace and Air Conditioner) to produce an environmental temperature in accordance with preprogrammed values. These values were to be time based so that a temperature profile could be produced which would repeat every 24 hours. Examples of how this could be utilized would be to lower the temperature during periods when the house is unoccupied and raise it for occupied periods.

Due to space restrictions on the device chosen for the course (in our case ACT1 series), we were unable to implement the full design. The final, submitted project is a scaled-back version of the controller, which has only one programmable temperature. This choice allowed us to remove the 24-hour clock sub-system as well as reduce the complexity of the register system, which held and controlled the user-programmed information and comprised the majority of the space used.

The system has a power-on default of 25 degree’s, and once operational the user can program a desired temperature in the range of -40° C to +120° C. The system then evaluates the present temperature as provided by a digitally sampled analog thermometer. If the temperature moves 3° above or below the set temperature, the system activates the A/C or Furnace as appropriate to return the temperature to the desired level.

 

Description:

The thermostat system was based completely on a block system, each module had to operate in such a way that the amount of tasks for each module was minimized. Operation was therefore broken down into the following units:

Operation of each unit will be examined individually, and then simulation of each unit will be shown and discussed in the next section.

 

Keypad Interface:

The function of this block is to watch the inputs from the keypad for a certain sequence of keypresses and, if they are entered properly, pass the temperature the user entered off to the register (see block diagram Appendix page ). A single bit control signal is used to tell the register to accept the incoming data, beyond this the keypad interface has no control of the data.

This block is implemented using a closed-loop state machine (illustrated in Figure 1.). The first state is the holding state, if an invalid keypress is detected during programming, or until programming begins, the system holds in this state.

The system leaves this state only when key "1100" (Key ‘C’ on the hex-keypad) is detected the system moves into the next state, waiting for the key to be released (This holding state is in effect for all keypresses, but will be omitted from the discussion here out). We changed this feature key "1100" for programming the temperature to just a simple DIP SWITCH since it is due to modules and ACT1 technology limitations. ACT1 contains no flip-flops nor SEQUENTIAL logic. The next key pressed must be the sign (+ or -) of the temperature, valid keys for this are key ‘E’ for negative or anything <’E’ for positive. The next 3 digits represent the magnitude of the temperature, e.g. 025 for 25° C, 100 for 100° C, etc..

Producing a properly working state machine in VHDL (or perhaps ACT1) is difficult in the extreme. We discovered that Design Architect would read the design without difficulty and when we simulated the block, operation was confirmed to be exactly what we expected. However, when we compiled the code in Actmap, converted the EDN to VHDL and simulated it again, we found MANY problems, especially stated machines. (Part of our CAD tool documentation includes an approach to design that addresses this problem and a related one.) It seems that when the state machine is implemented, using the components available to the ACT1 libraries (although we did not get a chance to test this using other chip types), signal continuity is lost. An example of this is a signal which is initialized to ‘1’ in state0 goes to ‘0’ in state1 even though there is no signal assignment statement. Obviously, this is not good when you have a signal you wish to remain untouched through several states. Even putting reinforcing statements in each state helped little. This proved to be frustrating to say the least.

Figure 1: Keypad controller

We solved this problem by implementing a ONE-HOT State machine methology. Figure 1 shows how we implement our state machine. We assigned the states uniquely so that only one bit is allowed to change at any given time.

We can implement the Keypad encoder by either building another internal block to do this function or simply use an external chip that provide suitable options. Both must correctly interpret the 16 keys that can be possibly pressed by the user and translate each of these values into a BCD digit. Figure 2 show how the keypad encoder looks like if it were to be implemented within the FPGA. We have to write a VHDL code to scan 4 ROW and 4 COLUMNS. Therefore, it requires to scan 16 different combinations (S1 to S32). The switch debouncing is resolved when we use 3 INVERTERS as illustrated in Figure 2.

 

Figure 2: Keypad Encoder or use external chip MM54C922

We implement our design in a way so that every number entered by the user is always in a 4 bits BCD number. These 4 bit BCD numbers (in our case we have 4 four 4 bits BCD number) are then latches to the REGISTER and the CALCULATOR.

Register:

The function of this block is to route information between all the other blocks in the system. It accepts programming values from the keypad, real-time data from the sensor interface, and outputs data to the calculator and the display interface. Implementation of this block could be best described as a switching network coupled with latches.

Figure 3: Flowchart of the REGISTER

When the control signal from the keypad interface goes high, the register copies the data coming in from the keypad directly to the display (for visual feedback for the user). While routing to the display, data is also copied to latched data lines for use by the calculator (see block diagram). When the control signal goes low, the data from the sensor interface is routed to the display.

 

Display interface:

The function of the display interface is to take 4 BCD digits in and do 7 segment conversion on each digit to produce 7 bits suitable for controlling a group of 4 seven-segment displays. Were we not limited by space this would be implemented by a large look-up table. When originally coded, the LUT took the form of a large case statement.

(See the sensor interface section for a discussion on LUT versus high level statements)

Implementing this method results in a VHDL file with 16x4 cases (one for each possible digit type for 4 different signals)

Again, we were limited on the amount of modules and therefore we simply use four external chips, TTL logic 7448’s, which include built in pull-up resistors for directly driving the LED’s.

 

Calculator:

The function of this block is to take the desired temperature settings from the register and the actual temperature from the sensor interface and perform a calculation using the two values. Depending on the results of the calculation the block will turn on either the A/C or the Furnace or both or neither.

The calculator has 4 different sets of inputs:

The calculator forms its decision using a cascading subtraction scheme (Illustrated in Figure 4). First, the calculator determines the sign of each number. There are 4 possible combinations and the way is performs the remaining calculations is slightly different for same sign situations than for mixed sign situations. As an example, let’s consider that both values are positive. The calculator then looks at the first magnitude digit, the hundreds, if desired is higher than actual obviously the heater needs to be turned on, so the furnace value is set high and the calculator exits the calculation. If the hundreds values are the same it looks at the second magnitude digits (or tens values) the decision process here is the same as for the hundreds.

Now, if the hundreds and the tens are the same, the calculator looks at the third magnitude digits or ones values. In this case a control signal is set only if the temperature rises or falls 3 degrees above the programmed value. This was chosen to remove possible oscillation in the operation of the whole system (Example: furnace is turned on and before it can shut off the heat rises above programmed value which turns on the A/C. Before A/C can be shut off, the temperature falls below set point and the furnace turns on.). At the same time, we are hopefully providing an operation envelope small enough that the occupants will not detect the variation.

Figure 3 (Process flow for Calculator)

 

Sensor Interface:

The function of the sensor interface is to communicate with an external Analog to Digital converter, take in the data it provides, and manipulate the data to work around various vagaries of the A/D converter chosen. (See Figure 4.)

For the project, we chose to use an ACD0808 A/D converter from National Semiconductor. Unfortunately, this A/D is only able to provide conversion for values ranging from "00000000" to "11111111" representing positive values only. To be useful for this system it was required that we be able to distinguish between -40° C and over +100° C. We therefore decided to set the analog portion of the hardware such that at -40° C the A/D would output "00000000".

Now that we had a range of continuous values provided by the A/D we were next required to shift that data coming in down by a value of 40. To do this the two’s complement of 40 was added to the sampled 8 bit value. If the result was positive, it is simply passed it on to the register. If the result was negative it is converted to a positive number and set the MSB to 1 (This limited our system to 7 bits of magnitude, or values below +127° C). Once this is done, it is passed on to the register.

To obtain the data from the A/D, bi-directional communication must be established between the A/D and the FPGA. This communication is accomplished by three single bit lines. These lines, Start, EOC (end of conversion), and OUTEN (output enable) operate as follows. Start is used to signal the A/D to begin the conversion process, the A/D is configured to do constant conversion but it is recommended to provide a start pulse to initialize the process. Once the conversion process is complete the A/D sets EOC high telling the system that data is available. When the sensor interface sees EOC go high, it in turn sets OUTEN high to enable the tri-state outputs on the A/D, then reads the 8bit value into internal latches.

It was relatively easy to communicate with the A/D, however, due to decisions we made to accommodate the display of data in our system 8bit numbers were inappropriate.

What the system needed was 4 BCD digits. Initially we worked on an algorithm to convert the digit. If the incoming data was positive, BCD1 was set to "0000" if it were negative it would be set to "1110" (the display driver interpreted this as ‘-‘). Next, if the magnitude was > 100, 100 would be subtracted from the data and BCD2 would be incremented by one. After this calculation it would go back to the start of the loop, if the number was still > 100 it would increment again. The same process was applied to the 10’s and 1’s digits. This process worked exceptionally well and was suitable for our purposes it was, however large (250 modules).

There was no way for us to avoid using BCD without changing the whole system, nor could we easily change the A/D system. Instead, we took an approach that would generate a LUT. Using a CASE statement with 256 possible values, we built a converter by explicit specification. (This method will be included in CAD tools documentation) Producing our converter in this way had three results. First, we were able to produce the converter with a VERY small logic module count, (to produce a LUT for four BCD digits from an 8 bit number used under 50 modules). Look up tables are very fast so we removed possible timing issues which were introduced by a recursive algorithm. Finally, specifying something explicitly like this results in a design with HUGE complexity, (Compiler complexity, not module). Compiling this particular block of code took about 35 minutes on the UltraSparc stations (7 minutes on PentiumII) while the rest of our components took only a couple minutes. This is the price to pay for small area usage.

 

Figure 5 (Functional flow of Sensor Interface.)

Simulation:

Functional Simulation

Functional simulation is a sore spot with me. I feel that the method of using Mentor Graphics to simulate while needing to work with Actmap for final designs introduces a level of unnecessary difficulty. After talking with several groups who experienced what they called timing problems when back annotating their systems I found that most of them were victims of one of 2 things.

First Mentor graphics interprets code differently than actmap. As an example, I compiled a small piece of code in both Mentor and Actmap. I converted the actmap EDN to VHDL, compiled this on Mentor and simulated the results of both. The result of this simulation was significantly different between the two files when they should have been exactly the same. Most people noticed these differences at the end of their project when they did back-annotation and assumed that it was a timing and delay problem. However, most projects were not especially frequency sensitive and operated in the kHz range.

I found that if I simulated the code created after converting Actmap EDN files, rather than just working from Mentor, that when I did my back annotation testing there was really no change in operation.

The second problem is with the actmap netlist optimizer. As I understand it, this utility is supposed to optimize code for space, speed, or fan-out, without altering the functional operation. When we were simulating our project we compiled all our code then did a functional simulation on it, which worked fine. Then we optimized the code to reduce the size slightly as we were just slightly too large. Testing of the optimized file showed radically different operation than the we saw from the original EDN file. I am not sure what the reason for this change is but I feel it should be brought up with Actel.

 

 

 

 

Back-Annotated Simulations (waveforms and procedures)

Conclusion:

We were able to produce a system which operates quite well as a digital thermostat. With only a bit more work and a larger FPGA we would be able to implement the full system including programmability of multiple time based temperature settings.

This project provided both of us with what we feel is a really useful exposure to using programmable logic. We encountered problems which we think are quite comparable to work-force situations and I know I have a new respect for the work required in producing a market ready system when you have iron-clad restrictions (namely the fpga).

 

******Off topic*************

I would like to see this course focus more on using programmable logic rather than the large amount of theoretical information offered. The information about logic types, SRAM or anti-fuse technology and related items can be picked up in other courses like EE572 and others. While the information was good I think a focus on larger projects with fewer labs (thus offering more lab time for the project and associated questions) would be of great benefit. I have several friends who work at Nortel, 3Com and even Cisco who all use various Actel chips and they all say that a firmer functional understanding of how these devices work would have helped immesurably.

 

 

 

 

Appendix:

--Project.vhd

LIBRARY ieee;

use ieee.std_logic_1164.all;

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

--use work.std_arith.all -- uncomment for Warp

---------------------------------------------------------------

--

--********* THIS SHOULD BE FINAL AS FAR AS SIGNALS *******

--********* FOR EACH BLOCK IS CONCERNED. IF THERE IS *******

--********* A PROBLEM CONTACT ME!!!!!!! *******

--

--SYSTEM I/O PINS AS FOLLOWS

--4 7BIT GROUPS FOR DISPLAY. (28 PINS) - out - Disp1-4

--1 2BIT GROUP for memory address (2 pins) - in - Address

--1 4BIT GROUP for keypad input (4 pins) - in - Keypad

--1 8 BIT GROUP FOR DIGITAL TEMP IN (8 PINS) - in - Data_In

--3 1 bit groups FOR A/D CONTROL (3 PINS) - out, in - START OUTEN, EOC

--2 1bit groups for operating mode (2 pins) - in - HOT, COLD

--2 1BIT GROUPS for System Control (2 pins) - out - Fur, AC

--1 Bit in clock (1 pin) - in - Clock

--1 Bit in Enable (1 pin) - in - Enable

--(Pin total so far is 51)

----------------------------------------------------------------

ENTITY Project IS

port(

DATA_IN : IN std_logic_vector(7 downto 0);

PAD_IN : IN std_logic_vector(3 downto 0);

Data_Ready : IN std_logic;

EOC, HOT, COLD, RESET, CLOCK : IN std_logic;

Keypad_switch : IN std_logic;

Display1out, Display2out, Display3out, Display4out : OUT std_logic_vector(3 downto 0);

START, OUTEN, FUR, AC : OUT std_logic

);

END Project ;

 

ARCHITECTURE Operation OF Project IS

--Define Signals here, may have to move them later.

--

---------- For distributing temp from sensor.

Signal RLTMP1, RLTMP2, RLTMP3, RLTMP4: std_logic_vector(3 downto 0);

---------- For passing set status info to/from RTC to Kepad

Signal SET, FINISHED: std_logic;

----------For distributing Temp values from keypad to REGISTERS.

Signal TMPPROG: std_logic_vector(7 downto 0);

----------For distributing Time set values from keypad to RTC and REGISTERS.

Signal KPDTMP1, KPDTMP2, KPDTMP3, KPDTMP4: std_logic_vector(3 downto 0);

----------For communication between Keypad and Display, is an interrupt to display prog info.

Signal DISPMODE: std_logic;

----------For distributing temp set from registers

Signal SETTMP1, SETTMP2, SETTMP3, SETTMP4: std_logic_vector(3 downto 0);

----------For conversion of 8bit to 4x4bit

Signal TMPBCD1, TMPBCD2, TMPBCD3, TMPBCD4: std_logic_vector(3 downto 0);

Signal TMPWRK: std_logic_vector(7 downto 0);

----------For passing values from DISPLAY block to BCD block.

Signal DISPOUT1, DISPOUT2, DISPOUT3, DISPOUT4: std_logic_vector(3 downto 0);

Signal RBI, RBO, LT: std_logic;

----------For passing info from Keypad to Register

Signal DTP : std_logic;

----------for passing infro from register to display

signal REGT1, REGT2, REGT3, REGT4: std_logic_vector(3 downto 0);

----------

 

 

 

--

--COMPONENT DECLARATIONS!!!!!!!!!!!!!!!!

--

 

COMPONENT Sensor

port (

Reset, EOC : in std_ulogic;

DataIN: in std_logic_vector(7 downto 0);

Start, OutEn: out std_ulogic;

Temp: out std_logic_vector(7 downto 0)

);

END COMPONENT ;

 

COMPONENT Calc

port (

Reset, Hot, Cold, clock : in std_logic;

TMP_USE1, TMP_USE2, TMP_USE3, TMP_USE4: in std_logic_vector(3 downto 0);

Des_USE1, Des_USE2, Des_USE3, Des_USE4: in std_logic_vector(3 downto 0);

Fur, AC : out std_logic

);

END COMPONENT ;

 

COMPONENT REG

PORT (

Temp_prog1, Temp_prog2, Temp_prog3, Temp_prog4 : IN std_logic_vector (3 downto 0);

Temp_in1, Temp_in2, Temp_in3, Temp_in4 : IN std_logic_vector(3 downto 0);

DES_Temp1, DES_Temp2, DES_Temp3, DES_Temp4 : OUT std_logic_vector (3 downto 0);

DispT1, DispT2, DispT3, DispT4 : OUT std_logic_vector (3 downto 0);

Display_Temp_Press : IN std_logic;

Reset : IN std_logic;

Clock : IN std_logic

);

END COMPONENT ;

 

COMPONENT display

PORT (RESET : in std_logic;

DispT1, DispT2, DispT3, DispT4 : IN std_logic_vector (3 downto 0);

Display1, Display2, Display3, Display4 : OUT std_logic_vector (3 downto 0);

Clock : IN std_logic

);

END COMPONENT;

 

COMPONENT keypad

PORT (

PAD_IN : IN std_logic_vector (3 downto 0);

Data_Ready : IN std_logic;

Clock : IN std_logic;

Reset : IN std_logic;

Temp_prog1, Temp_prog2, Temp_prog3, Temp_prog4 : OUT std_logic_vector (3 downto 0);

Keypad_switch : IN std_logic;

display_temp_press : out std_logic

);

END COMPONENT;

COMPONENT CONVERTER

port (

RESET: in std_logic;

clock: in std_logic;

TEMP: in std_logic_vector(7 downto 0);

BCD1, BCD2, BCD3, BCD4: out std_logic_vector(3 downto 0)

);

END COMPONENT;

--

-- DEFINE WHO IS WHO!!!!!

--

for all: Calc use entity work.calc(behavior);

for all: Sensor use entity work.Sensor(behavior);

for all: Reg use entity work.reg(behavior);

for all: Display use entity work.display(behavior);

for all: Keypad use entity work.keypad(behavior);

for all: converter use entity work.converter(behavior);

 

BEGIN -- Architecture that is.

--

--DO all the component instantiations.

--

--

Calcmap: Calc port map ( RESET => RESET,

Hot => HOT,

Cold => COLD,

clock => clock,

-- Items below were altered by raymond to conform to BCD throughout cct.

TMP_USE1 => RLTMP1, -- these connect to 8bit2bcd output

TMP_USE2 => RLTMP2,

TMP_USE3 => RLTMP3,

TMP_USE4 => RLTMP4,

Des_USE1 => SETTMP1, -- These connect to register output.

Des_USE2 => SETTMP2,

Des_USE3 => SETTMP3,

Des_USE4 => SETTMP4,

Fur => FUR,

AC => AC );

Sensormap: Sensor port map ( RESET => RESET,

EOC => EOC,

DataIN => DATA_IN,

Start => START,

OutEn => OUTEN,

Temp => TMPWRK );

 

Registermap : reg PORT MAP (

Temp_prog1 => KPDTMP1,

Temp_prog2 => KPDTMP2,

Temp_prog3 => KPDTMP3,

Temp_prog4 => KPDTMP4,

Temp_in1 => RLTMP1,

Temp_in2 => RLTMP2,

Temp_in3 => RLTMP3,

Temp_in4 => RLTMP4,

DispT1 => REGT1,

DispT2 => REGT2,

DispT3 => REGT3,

DispT4 => REGT4,

DES_Temp1 => SETTMP1,

DES_Temp2 => SETTMP2,

DES_Temp3 => SETTMP3,

DES_Temp4 => SETTMP4,

Display_Temp_Press => DTP,

Reset => reset,

Clock => Clock );

 

Keypadmap : keypad PORT MAP ( PAD_IN => PAD_IN,

Data_Ready => Data_Ready,

Clock => Clock,

Reset => Reset,

Temp_prog1 => KPDTMP1,

Temp_prog2 => KPDTMP2,

Temp_prog3 => KPDTMP3,

Temp_prog4 => KPDTMP4,

Display_Temp_Press => DTP,

Keypad_switch => Keypad_switch

);

Displaymap : display PORT MAP (

DispT1 => REGT1,

DispT2 => REGT2,

DispT3 => REGT3,

DispT4 => REGT4,

Display1 => Display1out,

Display2 => Display2out,

Display3 => Display3out,

Display4 => Display4out,

reset => reset,

Clock => Clock );

Convertmap : converter PORT MAP ( TEMP => TMPWRK,

RESET => RESET,

clock => clock,

BCD1 => RLTMP1,

BCD2 => RLTMP2,

BCD3 => RLTMP3,

BCD4 => RLTMP4 );

END Operation;

 

 

 

--keypadw.vhd

library ieee;

use ieee.std_logic_1164.all;

 

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

entity keypad is

port (

PAD_IN : IN std_logic_vector (3 downto 0);

Data_Ready : IN std_logic;

Clock : IN std_logic;

Reset : IN std_logic;

Temp_prog1, Temp_prog2, Temp_prog3, Temp_prog4 : OUT std_logic_vector (3 downto 0);

DISPLAY_TEMP_Press : OUT std_logic;

Keypad_switch : IN std_logic

);

end keypad;

 

ARCHITECTURE behavior OF keypad IS

TYPE state_temp IS ( a, b, c, d, e, f, g, h ); --For Temperature Process

SIGNAL current_stateA, next_stateA : state_temp;

SIGNAL TEMP1, TEMP2, TEMP3, TEMP4 : std_logic_vector (3 downto 0);

 

BEGIN

 

 

--If DIP SWICTH, Keypad_switch, is "ON" this will guarantee we will get that key press will be display, otherwise don't

Display_Key : PROCESS ( Keypad_switch, reset)

BEGIN

IF (Keypad_switch = '1') THEN --REMEMBER "Keypad_switch" is a DIP SWITCH

DISPLAY_TEMP_PRESS <= '1';

Temp_prog1 <= TEMP1;

Temp_prog2 <= TEMP2;

Temp_prog3 <= TEMP3;

Temp_prog4 <= TEMP4;

END IF;

IF (Keypad_switch = '0') THEN

DISPLAY_TEMP_PRESS <= '0';

END IF;

END PROCESS Display_Key;

 

key_control_temp : PROCESS ( current_stateA, Reset, Clock, PAD_IN, Data_Ready)

BEGIN

IF (Reset = '1') THEN

DISPLAY_TEMP_PRESS <= '0';

Temp_prog1 <= "0000";

Temp_prog2 <= "0000";

Temp_prog3 <= "0000";

Temp_prog4 <= "0000";

next_Statea <= a;

TEMP1 <= "0000";

TEMP2 <= "0000";

TEMP3 <= "0000";

TEMP4 <= "0000";

END IF;

IF (Clock = '1') THEN

current_stateA <= next_stateA;

END IF;

IF (Reset = '1') THEN

current_stateA <= a;

END IF;

CASE current_stateA IS

WHEN a => --get 1st key press

IF (Data_Ready = '0') THEN

Next_stateA <= a;

END IF;

IF (Data_Ready = '1') THEN

CASE PAD_IN IS

WHEN "0000" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0001" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0010" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0011" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0100" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0101" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0110" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "0111" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "1000" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN "1001" =>

TEMP1 <= PAD_IN;

next_stateA <= b;

WHEN others =>

next_stateA <= a; --wait for correct key press

END CASE;

END IF;

WHEN b => --waiting for next key press release

IF (Data_Ready = '1') THEN

next_stateA <= b;

END IF;

IF (Data_Ready = '0') THEN

Next_stateA <= c;

END IF;

WHEN c =>

IF (Data_Ready = '0') THEN

Next_stateA <= c;

END IF;

IF (Data_Ready = '1') THEN

CASE PAD_IN IS

WHEN "0000" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0001" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0010" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0011" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0100" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0101" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0110" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "0111" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "1000" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN "1001" =>

TEMP2 <= PAD_IN;

next_stateA <= d;

WHEN others =>

next_stateA <= c; --wait for correct key press

END CASE;

END IF;

WHEN d => --waiting for next key press release

IF (Data_Ready = '1') THEN

next_stateA <= d;

END IF;

IF (Data_Ready = '0') THEN

Next_stateA <= e;

END IF;

WHEN e =>

IF (Data_Ready = '0') THEN

Next_stateA <= e;

END IF;

IF (Data_Ready = '1') THEN

CASE PAD_IN IS

WHEN "0000" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0001" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0010" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0011" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0100" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0101" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0110" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "0111" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "1000" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN "1001" =>

TEMP3 <= PAD_IN;

next_stateA <= f;

WHEN others =>

next_stateA <= e; --wait for correct keypress

END CASE;

END IF;

WHEN f => --waiting for next key press release

IF (Data_Ready = '1') THEN

next_stateA <= f;

END IF;

IF (Data_Ready = '0') THEN

Next_stateA <= g;

END IF;

WHEN g =>

IF (Data_Ready = '0') THEN

Next_stateA <= g;

END IF;

IF (Data_Ready = '1') THEN

CASE PAD_IN IS

WHEN "0000" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0001" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0010" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0011" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0100" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0101" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0110" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "0111" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "1000" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN "1001" =>

TEMP4 <= PAD_IN;

next_stateA <= h;

WHEN others =>

NULL;

next_stateA <= g; --wait for correct key press

END CASE;

END IF;

 

WHEN h => --waiting for any key press releases

IF (Data_Ready = '1') THEN

next_stateA <= h;

END IF;

IF (Data_Ready = '0') THEN

Next_stateA <= a; --DONE SINCE last key is press

END IF;

END CASE;

END PROCESS key_control_temp;

 

END behavior;

 

-- REG.vhd

library ieee;

use ieee.std_logic_1164.all;

--library asyl;

--use asyl.arith.all;

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

 

ENTITY REG IS

PORT (

Temp_prog1, Temp_prog2, Temp_prog3, Temp_prog4 : IN std_logic_vector (3 downto 0);

Temp_in1, Temp_in2, Temp_in3, Temp_in4 : IN std_logic_vector(3 downto 0);

DispT1, DispT2, DispT3, DispT4 : OUT std_logic_vector (3 downto 0);

DES_Temp1, DES_Temp2, DES_Temp3, DES_Temp4 : OUT std_logic_vector (3 downto 0);

Display_Temp_Press : IN std_logic;

Reset : IN std_logic;

Clock : IN std_logic

);

END REG;

 

ARCHITECTURE behavior OF REG IS

 

 

Signal TEMP_TMP1, TEMP_TMP2, TEMP_TMP3, TEMP_TMP4, DES_TEMP1_TMP, DES_TEMP2_TMP, DES_TEMP3_TMP,

DES_TEMP4_TMP: std_logic_vector(3 downto 0);

BEGIN

 

 

------------------------------------------------------------------------------------------------------------

--HAPPENS ONLY when the user is pressing the temperature.

------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------

--HAPPENS ONLY when the user is pressing the Clock.

------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------

--HAPPENS ONLY when the user is finish PRESSING THE KEY

------------------------------------------------------------------------------------------------------------

 

Temp_Press : PROCESS ( Reset, Display_Temp_Press, Temp_prog1, Temp_prog2, Temp_prog3, Temp_prog4)

 

BEGIN

IF RESET = '1' THEN

DispT1 <= "0000";

DispT2 <= "0000";

DispT3 <= "0000";

DispT4 <= "0000";

DES_Temp1 <= "0000";

DES_Temp2 <= "0000";

DES_Temp3 <= "0000";

DES_Temp4 <= "0000";

end if;

IF Display_Temp_Press = '1' THEN

TEMP_TMP1 <= Temp_prog1;

TEMP_TMP2 <= Temp_prog2;

TEMP_TMP3 <= Temp_prog3;

TEMP_TMP4 <= Temp_prog4;

DES_Temp1_tmp <= Temp_prog1;

DES_Temp2_tmp <= Temp_prog2;

DES_Temp3_tmp <= Temp_prog3;

DES_Temp4_tmp <= Temp_prog4;

Else

TEMP_TMP1 <= Temp_in1;

TEMP_TMP2 <= Temp_in2;

TEMP_TMP3 <= Temp_in3;

TEMP_TMP4 <= Temp_in4;

END IF;

DispT1 <= TEMP_TMP1;

DispT2 <= TEMP_TMP2;

DispT3 <= TEMP_TMP3;

DispT4 <= TEMP_TMP4;

DES_Temp1 <= DES_Temp1_tmp;

DES_Temp2 <= DES_Temp2_tmp;

DES_Temp3 <= DES_Temp3_tmp;

DES_Temp4 <= DES_Temp4_tmp;

END PROCESS Temp_Press;

 

END behavior;

 

 

 

 

--Display.vhd

library ieee;

use ieee.std_logic_1164.all;

use asyl.arith.all;

use asyl.sl_arith.all;

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

--Display1 is highest digit

ENTITY display IS

PORT (

RESET : in std_logic;

DispT1, DispT2, DispT3, DispT4 : IN std_logic_vector (3 downto 0);

Display1, Display2, Display3, Display4 : OUT std_logic_vector (3 downto 0);

Clock : IN std_logic

);

end Display;

ARCHITECTURE behavior OF Display IS

BEGIN --begin ARCHIERE

--display "real_time clock" for first for 5 seconds (0000-0101 binary from DispSec2)

--it is sensitive to both Seconds(0-9) and any of the 4 key press

--4 key press are "Enter key, Clock Key, DispTerature Key, and Programming Key"

-- Keyp1 is Enter Key

-- Keyp2 is Clock Key

-- Keyp3 is DispTerature Key

-- Keyp4 is Programming Key

-- bcd_in1-4 same as DispH1, DispH2, DispM1, DispM2

-- same as Keyp1, keyp2, keyp3, keyp4

-- same as DispT1, DispT2, DispT3, DispT4

display_normal: PROCESS (Clock, reset, DispT1, DispT2, DispT3, DispT4)

BEGIN

if RESET = '1' then

Display1 <= "0000";

Display2 <= "0000";

Display3 <= "0000";

Display4 <= "0000";

end if;

IF (Clock = '1') THEN

Display1 <= DispT1;

Display2 <= DispT2;

Display3 <= DispT3;

Display4 <= DispT4;

END IF;

END PROCESS;

END behavior;

 

-- Calcualtor.vhd

-- This block must take incoming temp reading as 1 argument and desired

-- temp value from register as other value. From this it must make a decision

-- as to wether or not turn on a heater or A/C unit.

-- For initial creation, the temperature must vary 3 degrees in any direction from the

-- desired value before an action is taken, this should help to prevent oscilation in the

-- system.

-- As final add-on, there will be three modes,(A/C and heat, Heat only, A/C only)

-- these are referenced as HOT and COLD internally. They are simply AND'ed at the last stage

-- to produce the relevant signals.

-- Fur and AC are the outputs

library ieee;

use ieee.std_logic_1164.all;

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

entity calc is

port (

Reset, Hot, Cold, clock : in std_logic;

TMP_USE1, TMP_USE2, TMP_USE3, TMP_USE4: in std_logic_vector(3 downto 0);

Des_USE1, Des_USE2, Des_USE3, Des_USE4: in std_logic_vector(3 downto 0);

Fur, AC : out std_logic

);

end calc;

architecture behavior of calc is

signal TMP: std_logic_vector(7 downto 0);

signal DESN: std_logic_vector(3 downto 0);

signal DESP: std_logic_vector(3 downto 0);

signal HTSIG, CLDSIG: std_logic;

begin

keeptemp: process(TMP_USE1, DES_USE1, TMP_USE2, DES_USE2, TMP_USE3, DES_USE3, TMP_USE4, DES_USE4, Reset, clock, htsig, cldsig, hot, cold) is

begin

--Only operate while not reset

if reset = '1' then

Fur <= '0';

AC <= '0';

end if;

if Reset= '0' then

--Both TMP and Des pos.

DESN <= DES_USE4 - "0011";

DESP <= DES_use4 + "0011";

HTSIG <= '0';

CLDSIG <= '0';

if (TMP_use1 <= "1110") then

if (Des_use1 <= "1110") then

if (TMP_USE2 = Des_use2) then

if (TMP_USE3 = DES_USE3) then

if (TMP_USE4 = DES_USE4) then

HTSIG <= '0';

CLDSIG <= '0';

else

if (TMP_USE4 < DESN) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

if (TMP_USE3 < DES_USE3) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

if (TMP_USE2 < DES_USE2) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

-- both In and Des neg

if (TMP_use1 = "1111") then

if (Des_use1 = "1111") then

if (TMP_USE2 = Des_use2) then

if (TMP_USE3 = DES_USE3) then

if (TMP_USE4 = DES_USE4) then

HTSIG <= '0';

CLDSIG <= '0';

else

if (TMP_USE4 > DESP) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

if (TMP_USE3 > DES_USE3) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

if (TMP_USE2 > DES_USE2) then

HTSIG <= '1';

CLDSIG <= '0';

else

HTSIG <= '0';

CLDSIG <= '1';

end if;

end if;

else

HTSIG <= '1';

CLDSIG <= '0';

end if;

end if;

Fur <= HTSIG and HOT;

AC <= CLDSIG and COLD;

end if;

end process;

end behavior;

 

 

-- Sensorint.vhd

library ieee;

use ieee.std_logic_1164.all;

--use ieee.std_logic_unsigned.all; -- uncomment for DA

use ieee.std_logic_arith.all; -- uncomment for Actmap

entity sensor is

port (

Reset, EOC : in std_ulogic;

DataIN: in std_logic_vector(7 downto 0);

Start, OutEn: out std_ulogic;

Temp: out std_logic_vector(7 downto 0)

);

end sensor;

architecture behavior of sensor is

-- Define two signals to use internally

signal Data_wrk: std_logic_vector(7 downto 0);

signal Data_wrk2: std_logic_vector(7 downto 0);

signal Data_wrk3: std_logic_vector(7 downto 0);

begin

readsensor: process(Reset, EOC, datain, data_wrk, data_Wrk2, data_wrk3, clock) is

begin

--only operate when not Reset.

If RESET = '1' then

Temp <= "00000000";

Start <= '1';

Outen <= '0';

Data_wrk <= "00000000";

Data_wrk2 <= "00000000";

Data_wrk3 <= "00000000";

end if;

If Reset='0' then

OutEn <= '0';

Start <= '0';

--Wait for End Of Conversion

if (EOC = '1') then

--turn on the outputs of A/D so we can read them

OutEn <= '1';

--read the data into variables and "tweak" it.

Data_wrk <= DataIn;

Data_wrk2 <= Data_wrk - "00101000";

end if;

--Differentiate between positive and negative numbers and set sign bit appropriately.

if Data_wrk2 >= "10000000" then

Data_wrk3 <= not (Data_wrk2 - "00000001");

Data_wrk3(7) <= '1';

Temp <= Data_wrk3;

end if;

if Data_wrk2 < "10000000" then

Temp <= Data_wrk2;

end if;

end if;

end process;

end behavior;

-- Clock.vhd

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all; -- uncomment for DA

--use ieee.std_logic_arith.all; -- uncomment for Actmap

entity rtc is

port (

Set, CLK, RESET : in std_logic;

HourSet1: in std_logic_vector(3 downto 0);

HourSet2: in std_logic_vector(3 downto 0);

MinuteSet1: in std_logic_vector(3 downto 0);

MinuteSet2: in std_logic_vector(3 downto 0);

Hour1: out std_logic_vector(3 downto 0);

Hour2: out std_logic_vector(3 downto 0);

Minute1: out std_logic_vector(3 downto 0);

Minute2: out std_logic_vector(3 downto 0);

Second1: out std_logic_vector(3 downto 0);

Second2: out std_logic_vector(3 downto 0)

);

end rtc;

architecture behavior of rtc is

signal done, Reset1, Reset2, Reset3, Reset4, Reset5, Reset6, Increment: std_logic;

signal count: integer;

signal SecSet: std_logic_vector(3 downto 0);

signal CO1, CO2, CO3, CO4, CO5, CO6: std_logic;

signal Hour1_int, Hour2_int, Minute1_int, Minute2_int, Second1_int, Second2_int: std_logic_Vector(3 downto 0);

component bcdcount1

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

component bcdcount2

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

component bcdcount3

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

component bcdcount4

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

component bcdcount5

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

component bcdcount6

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end component;

for all: BCDcount1 use entity work.BCDcount3(behavior);

for all: BCDcount2 use entity work.BCDcount(behavior);

for all: BCDcount3 use entity work.BCDcount5(behavior);

for all: BCDcount4 use entity work.BCDcount(behavior);

for all: BCDcount5 use entity work.BCDcount5(behavior);

for all: BCDcount6 use entity work.BCDcount(behavior);

BEGIN -- Architecture that is.

--

--DO all the component instantiations.

--

--

Countmap1: BCDcount1 port map ( Clock => CLK,

Carry_in => CO2,

Reset => RESET1,

Set => SET,

Digit_in => HourSet1,

digit_out => Hour1_Int,

Carry_out => CO1 );

Countmap2: BCDcount2 port map ( Clock => CLK,

Carry_in => CO3,

Reset => RESET2,

Set => SET,

Digit_in => HourSet2,

digit_out => Hour2_int,

Carry_out => CO2 );

Countmap3: BCDcount3 port map ( Clock => CLK,

Carry_in => CO4,

Reset => RESET3,

Set => SET,

Digit_in => MinuteSet1,

digit_out => Minute1_int,

Carry_out => CO3 );

Countmap4: BCDcount4 port map ( Clock => CLK,

Carry_in => CO5,

Reset => RESET4,

Set => SET,

Digit_in => MinuteSet2,

digit_out => Minute2_int,

Carry_out => CO4 );

Countmap5: BCDcount5 port map ( Clock => CLK,

Carry_in => CO6,

Reset => RESET5,

Set => SET,

Digit_in => SecSet,

digit_out => Second1_int,

Carry_out => CO5 );

Countmap6: BCDcount6 port map ( Clock => CLK,

Carry_in => Done,

Reset => RESET6,

Set => SET,

Digit_in => SecSet,

digit_out => Second2_int,

Carry_out => CO6 );

keeptime: process(done, RESET) is

begin

Secset <= "0000";

if RESET = '1' then

Increment <= '0';

Reset1 <= '1';

Reset2 <= '1';

Reset3 <= '1';

Reset4 <= '1';

Reset5 <= '1';

Reset6 <= '1';

else

If Hour2_int = "0100" then

if Hour1_int = "0010" then

if Minute1_int = "0000" then

if Minute2_int = "0000" then

Reset1 <= '1';

Reset2 <= '1';

end if;

end if;

end if;

end if;

if Hour2_int < "0100" then

Reset1 <= '0';

Reset2 <= '0';

Reset3 <= '0';

Reset4 <= '0';

Reset5 <= '0';

Reset6 <= '0';

end if;

Hour1 <= Hour1_int;

Hour2 <= Hour2_int;

Minute1 <= Minute1_int;

Minute2 <= Minute2_int;

Second1 <= Second1_int;

Second2 <= Second2_int;

end if;

end process;

onesec: process (CLK, RESET, Count)

-- Wait one second (Clock freq must be 1 MHz for a loop size of 1Meg, this can be altered to

-- produce a proper time response if clock frew must be different)

begin

if rising_edge(ClK) then

count <= count + 1;

if count >= 1000000 then

done <= '1';

count <= 0;

end if;

if count < 0 then

count <= 0;

end if;

end if;

if count = 1 then

done <= '0';

end if;

if Reset = '1' then

count <= 0;

done <= '0';

end if;

end process;

end behavior;

 

-- BCDCOUNT.vhd

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all; -- uncomment for DA

--use ieee.std_logic_arith.all; -- uncomment for Actmap

entity bcdcount is

port (

Clock, Carry_in, Reset, Set : in std_logic;

Digit_in: in std_logic_vector(3 downto 0);

Digit_out: out std_logic_vector(3 downto 0);

Carry_out: out std_logic

);

end bcdcount;

architecture behavior of bcdcount is

signal carry_out_int: std_logic;

signal Count_Int: std_logic_vector(3 downto 0);

begin

countbcd: process(Carry_in, Set, Reset, Count_int, Digit_in) is

begin

if (Set = '1') then

Count_Int <= Digit_in;

else

if Reset = '1' then

Count_Int <= "0000";

Carry_out_Int <= '0';

end if;

end if;

if Rising_edge(Carry_In) then

If Count_int > "1000" then

Carry_out_int <= '1';

end if;

If Count_int <= "1000" then

Carry_out_int <= '0';

end if;

If Count_Int >= "1001" then

Count_Int <= "0000";

end if;

if COunt_Int < "1001" then

Count_Int <= Count_Int + "0001";

end if;

end if;

Carry_out <= Carry_out_int;

Digit_out <= Count_Int;

end process;

end behavior;