EE 459 Senior Design Project DURACELL DURASAVER By TEAM 1 Sara Adkins Paul VanWieren Robert Whitley Introduction Most modern electronic devices consume small amounts of electrical power even when they have been turned off. This standby power, or “vampire power”, can be a significant portion of electrical power usage in a typical home. Our power controller is designed to minimize this wasteful power consumption by providing the user with user-programmable power outlets that virtually “unplug” devices during non-usage times. A standard application, for example, would be to program a television to virtually unplug during the typical eight-hour workday, thereby eliminating its standby power consumption during the portion of the day that it is unused. Section I: Hardware Design In order to describe the layout of our project in the most systematic way possible, we have chosen to break our hardware report into two parts: one for each of the two component boards (the main module and the RF remote control). Each of these component boards, in turn, is analyzed using a simple block diagram, whose description is broken into sections outlining each of the important or interesting components. In order to save space, simple, widely-used components such as LED’s and the like will not be explained in detail. Our description begins with the main module board: Main Module: Block Diagram: The following is a block diagram of the hardware layout of the main module: User input consists of six push-buttons, while user feedback is accomplished using a 24 character x 2 line LCD. The primary functional outputs of the device are four outlet plugs which allow virtual unplugging of devices as per the project description. The microcontroller communicates with the real-time clock through an I2C interface, requiring two bidirectional hardware lines. There is also a test LED for running test programs on the prototype board. In addition, the microcontroller receives inputs from a 10MHz clock and a 315MHz RF receiver. User Input Buttons: User input to the device is achieved using six buttons to navigate menus, make selections, and reset the device. The layout of the buttons in shown below. The four white directional buttons allow the user to progress through the menus. In general, the left and right buttons move between menus, while the up and down buttons allow changing the current option within a given menu. The black select button allows the user to select the menu option currently being displayed. A reset button allows the user to force a hardware reset of the device. The input buttons, with the exception of the reset button (which has no need for debouncing) are de-bounced using the following RC circuit network: This design is an improved version of a well-accepted SPST button de-bouncing scheme. The initial design did not include the 4.7uF capacitor (values for the resistors and the other capacitor were not given by the initial design, which was meant as a design template rather than a complete circuit). However, this initial design has a critical weakness. In order to be able to effectively “pull down” the signal to an appropriate TTL logic 0, the value of the first resistor (470 Ohm in our circuit) must be kept very small in relation to the second resistor (10 kOhm in our circuit). Using the values given in our circuit, in the absence of the larger capacitor, the RC time constant of the circuit upon closing the switch is roughly 20 times smaller than the time constant upon opening the switch (due to the two resistors acting in parallel, thus dramatically decreasing the resistance to AC ground). We found in experiments that the bounce duration of the button signal was ~2ms regardless of the switch being opened or closed. Thus, use of the initial circuit would require a closed-switch time constant of at least 2ms, thereby necessitating a huge open-switch time constant (on the order of 40ms or so). This would greatly reduce the pulse duration of the button-press, and possibly even eliminate it completely. In order to address this critical weakness in the initial design, the 4.7uF capacitor was added to the RC network such that the two capacitances add upon closing the switch. In essence, when the button is pressed, the large decrease in resistance to AC ground is counteracted by a large increase in capacitance to AC ground. If we call the open-switch time constant To and the closed-switch time constant Tc (with similar labels for the resistance and capacitance to AC ground), the following calculations apply (assuming a Schmitt-trigger inverter with a current draw of ~0mA and approximately infinite input impedance): To = RoCo = (10kΩ)(0.22µF) = 2.2 ms Tc = RcCc = (10kΩ//470Ω)(0.22µF+4.7µF) = (448.9Ω)(4.92µF) = 2.2 ms Vo = 5V Vc = 5V*[(470Ω)/(470Ω+ 10kΩ)] = 0.22 V This switch de-bouncing scheme fulfills the necessary requirements, and it does it for a fraction of the price of the commonly used EDE2008 button de-bouncing integrated circuit (the EDE2008 runs about $3.82 per unit if purchased in bulk, while our de-bouncing scheme costs our board around $0.79 if purchased in bulk). LCD: User feedback was accomplished using a 24x2 character LCD display, purchased from BG micro. Its layout in the main module is shown below. This LCD was a used part that had been pulled from old equipment. The advantage of this was that it was very economical ($3.95), but the disadvantage was that the LCD was rather temperamental (which caused plenty of head-ache in debugging our board). In addition, the parallel connector was wired backward to the normally accepted fashion for 8-bit parallel LCD interfaces. The image below displays the connection grid: This image, as well as plenty of other useful data for getting this LCD to work, can be found at the following URL: http://www.serialwombat.com/parts/lcd107.htm Outlet Outputs: The primary functional outputs of the main module are the outlet outputs, which are displayed as components and in the schematic below: As can be seen from the schematic, we used SPST-NO reed relays to establish a connection on the AC load line and thus enable the outlet in question. A green LED next to each outlet on the main module lights up when the outlet is enabled by the microcontroller. Since the current drive capabilities of the I/O pins of the JL16 are limited, we constructed a simple, single-transistor amplifier to drive the large amount of necessary current through the relay coils (~170mA of current drive was achieved using this amplification technique). Interestingly, the small DIP relays we used were unable to handle the current load of the AC load simulation board. While the AC load simulator was found to draw ~0.54A of AC current, the particular relays we used only had contact ratings of 0.5ADC “switching current,” as demonstrated in the annotated datasheet extract below. In order to solve this problem (three relays were burnt out completely before we identified the cause), 10 Ohms of in-series resistance was added to each AC load line connection in order to limit the AC load current to less than the 0.5A limit (a load current of slightly above 0.4A AC was achieved). This was done by wiring two high-power 5 Ohm resistors in series on each AC load line (the big pink cylinders in the middle of the red boxed area in the above figure). While this limited the AC load to an appropriate level, the bulb brightness of the AC load simulator was still plenty good. This was an imperfect solution (a better solution would have been to obtain and install more robust relays), but given our time constraints, it was the most realistic option. The use of more robust relays is covered in the “possible improvements” section of this report. RF Receiver: In order to enable communication with the RF remote control, a 315MHz RF link receiver obtained from SparkFun electronics was used on the main module board and connected to the serial receiver port of the microcontroller. The placement of this receiver in the board layout is shown below. This IC, in conjunction with the 315MHz transmitter we used on the remote control, is designed to form a wireless link between two devices. Ideally, whatever data is present as input to the transmitter data pin will be present as output from the receiver data pin. We found the performance of these RF link ICs to be moderate at best. In particular, the devices seemed to fall out of sync if the transmitter data was not made to constantly oscillate. In particular, if the transmitter data pin was held at a TTL logic 1 for around 50 ms or so, the receiver would fall out of sync and begin to oscillate wildly at ~60Hz, presumably as a result of power line noise effects. This would naturally cause the SCI port of the microcontroller to register garbage data. This problem was partially solved by sending several known transmission characters to the receiver before the real data was sent. However, we did not have enough time to get the RF link working perfectly, and its operation is still fidgety. Possible improvements to the RF link mechanism, which we did not have time to implement this semester, are discussed in the “possible improvements” section of this report. Real-Time Clock: We used a DS1307 real-time clock, in conjunction with a 32kHz oscillator chip, to provide time information to our board – as did most groups. A 3V battery was attached to both the RTC and the 32kHz oscillator to provide backup power in the case of a power outage. This way, the user would not need to re-set the clock after a power outage. The real-time clock, and in particular its I2C interface, was a source of constant frustration in our programming and debugging efforts. In particular, we believe there may be a problem with the RTC’s acknowledge bit transmission. However, after much de-bugging and experimentation, we were able to get accurate time results. In addition, the battery back-up effectively held the clock’s time upon unplugging and re-plugging the project board. 10MHz Oscillator: We used a simple DIP oscillator to provide the microcontroller with a 10MHz clock. We found it unnecessary to do any external shaping of the clock signal, as the oscillator signal was clean enough to provide the microcontroller with a good functional signal. Remote Control: Block Diagram: In order to provide the user with remote manual override capabilities, we implemented an RF-enabled remote control that allows the user to manually override the programmed outlet onoff times with a simple button-press. Below is a functional block diagram of the remote control: User input to the remote control consists of four manual device override buttons and a single reset button. Naturally, the microcontroller is also provided a 10MHz clock. The primary functional output of the microcontroller is the 315MHz RF link transmitter. A green power verification LED was also included on this board, as well as a red test LED for running test programs (this test LED is not shown in the above functional block diagram). Power to the board was provided without the need for an external power supply. A 9V battery holder was mounted on the board, and the output of the 9V battery run through a 5V regulator to provide TTL-level power to the board. User Input Buttons: The diagram below outlines the layout of the four manual override buttons that serve as the user input to the remote control. Each of these numbered buttons corresponds to the outlet which, when pressed, it will override. For ease of construction (because of limited project completion time), we used an EDE2008 DIP button de-bouncer on our remote control prototype board, as opposed to our custom de-bouncing scheme developed for the main module board. RF Transmitter: To provide the wireless RF link between the main module and the remote control, we used a 315MHz RF link transmitter from SparkFun electronics. The position of the transmitter in the board layout is shown in the diagram below: The functional description of the RF link transmitter/receiver pair is outlined in the “Main Module” section of this report, under the “RF Receiver” heading. Please see this section for more information on the theoretical function and the problems associated with this device. As mentioned before, improvements that could be made to this RF link pair are outlined in the “Possible Improvements” section. PCB Implementation of Remote Control: In order to get more experience with printed-circuit board implementation (the industry standard for consumer electronics), we designed, ordered, and assembled a custom PCB for the remote control portion of the project. The PCB was designed using ExpressPCB’s free software (downloadable online at expresspcb.com). A screenshot of our final board design in the free software window is shown below. We used ExpressPCB’s “miniboard” service, which provides three of the same 2.5”x3.8” boards at around $50 cost (plus tax and shipping). We found the printing and shipping of the board to be very fast; we ordered our board early in the week and received it at the end of the same week. We assembled the board without the use of any special surface-mount prototyping tools, which was rather challenging. Tweezers were used to hold the tiny surface-mount resistors, switch, and oscillator in place while soldering. All pads were tinned before component placement for a solid connection. The diagram below gives an idea of the general change in board layout from prototype to PCB, as well as a qualitative comparison of the relative sizes of the surface-mount parts in relation to the DIP components. It may be noted that both the microcontroller and the EDE2008 button de-bouncing IC were placed on the PCB in DIP packages. It was necessary to use the DIP microcontroller package, since the zero-insertion-force sockets used in the USB programming devices are designed to hold these packages. However, the DIP EDE2008 was used for the sake of convenience and time conservation – these DIP components were readily available from Professor Weber, while we would have had to order surface-mount components separately. Section II: Software Design Memory Considerations Because of the limited memory space on the JL16 microcontroller, variable declarations had to be carefully planned. For each LCD menu prompt there was a known string. These were declared as ‘const’ so that they would be stored in ROM. Similarly, ports that were used often were defined constants. For example, each button was defined as LEFT, RIGHT, UP, DOWN, and SELECT for ease of access later in the code so that they wouldn’t need to be referenced with PTA_PTA1, etc. A similar concept was used to keep track of where things were stored in the Real Time Clock (RTC). The DS1307 RTC we used had a 3-volt battery to keep the time even when the board was powered off, but it also stored 56 bytes of internal RAM non-volatilely. We decided to use these 56-bytes to store the programmable turn-on and turn-off times of our Durasaver such that they are not lost in the event of a power outage. The 56 bytes divided by 7 days each week and 4 devices leaves 2 bytes per device per day – 1 byte for turn-off and 1 byte for turn-on. However, 1 byte is not enough to store hours (5 bits) in addition to minutes (7 bits), so we designed it so each programmed time would include an hour (1-12), a 10-minute-interval minute (0-5 to represent 0, 10, 20, 30, 40, 50), and 1 bit to represent AM/PM. This added up to 4 bits for hour, 3 bits for minute interval, and 1 bit for AM/PM – 8 bits or 1 byte total. We decided that 10minute intervals was sufficient for the needs of this project, since it is easy to round a turnoff/turn-on time to the nearest 10-minute interval, and it is cheaper to utilize the RAM included with the RTC instead of installing an additional EPROM. Given these 2 bytes per outlet per day, we had two options for how we could organize their storage in the RTC’s RAM. One option was to store it organized by outlet. This means that outlet 1’s programmed times would be stored starting with Sunday’s turn-off time stored at address 0x08. Sunday’s turn-on time would come next, followed by Monday starting at 0x0A, etc. This definitely got the job done, but complicated the determination of an address for reading and writing. Since the monitoring of outlet times in the main loop was based on the current day of the week, that was a more efficient way by which to organize the RTC RAM for storing programmed times. Below is a table of the memory map we used for storing the programmed times in the RTC RAM; the bolded addresses are the ones we stored as constants to keep track of the starting address for each day of the week: 0x08 Day of the Week Sunday 0x09 0x0A Sunday Sunday Address Outlet Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) 0x0B 0x0C Sunday Sunday 0x0D 0x0E Sunday Sunday 0x0F 0x10 Sunday Monday 0x11 0x12 Monday Monday 0x13 0x14 Monday Monday 0x15 0x16 Monday Monday 0x17 0x18 Monday Tuesday 0x19 0x1A Tuesday Tuesday 0x1B 0x1C Tuesday Tuesday 0x1D 0x1E Tuesday Tuesday 0x1F 0x20 Tuesday Wednesday 0x21 0x22 Wednesday Wednesday 0x23 0x24 Wednesday Wednesday 0x25 0x26 Wednesday Wednesday 0x27 0x28 Wednesday Thursday Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) 0x29 0x2A Thursday Thursday 0x2B 0x2C Thursday Thursday 0x2D 0x2E Thursday Thursday 0x2F 0x30 Thursday Friday 0x31 0x32 Friday Friday 0x33 0x34 Friday Friday 0x35 0x36 Friday Friday 0x37 0x38 Friday Saturday 0x39 0x3A Saturday Saturday 0x3B 0x3C Saturday Saturday 0x3D 0x3E Saturday Saturday 0x3F Saturday Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) Outlet 1 (off) Outlet 1 (on) Outlet 2 (off) Outlet 2 (on) Outlet 3 (off) Outlet 3 (on) Outlet 4 (off) Outlet 4 (on) This makes the organization much cleaner, since each day of the week is organized into a nice 8 bytes, versus the less natural 14 bytes when organized by outlet number. This simplified the source code significantly as well. Both the setting and the checking of the programmed times is done relative to a day of the week. Therefore, if just the starting addresses of each day of the week is defined at the top of the source code, it is easy to use a derived offset to quickly lookup any outlet for any day of the week. This offset is defined as: (outletNumber - 1) * 2. For example, outlet 1 needs no offset since its 2 bytes are stored at the starting address for each day of the week. Outlet 3, however, is stored (3 – 1)*2 = 4 bytes lower than outlet 1. This offset is simply added to the initial address for any day of the week in order to get the address for a different outlet for that day of the week. This simplifies the code into for-loops and switch statements for getting and setting programmed times stored in the RTC’s RAM. User Interface & LCD Menus The DuraSaver features a 2-line 24-character LCD, four directional buttons, and one select button with which the user interacts to program and use their power controller. When in ‘idle’ mode – meaning that the power controller is handling programmed on/off times and managing the outlet’s on/off status accordingly – the LCD displays the time and date (see Figure 1). The user can press any of the four directional buttons to navigate away from this idle screen and traverse the other menus. From the idle screen, the user can press LEFT to get to the programming menu for the outlets; RIGHT to get to the programming menu for the clock; UP to turn on manual override for each of the outlets; DOWN to turn off manual override for each of the outlets. Below is a state-machine diagram of the main LCD menu interface: Once in the outlet programming menu, the user can either choose an outlet to program (or view programmed times for) or choose to exit back to the main LCD menu. After choosing an outlet, the user can either choose a day of the week or choose to exit back to the outlet selection. After choosing a day of the week, the user can view or change the turn-off and turn-on times for the chosen outlet and day, and the LCD menu returns to the day selection: turn-off hour turn- off minute turn-on hour turn-on minute day of the week. There is no way to exit from this stream without viewing all four, but the user can just press RIGHT four times to get back to the day selection screen. Additionally, the user can press LEFT or RIGHT to pan through and simply view these times without changing them, or change them but choose not to save the changes; only by pressing SELECT are the altered times saved back to the RTC for implementation. On the current prototype, the menus only function in one direction; a future improvement would be to make the menus more bi-directional so that pressing RIGHT would advance to the next menu (as above) but LEFT would go back. UP and DOWN scroll through the various options on the current LCD menu screen, while the LCD updates the current selection in real-time. The turn-on/turn-off hours are displayed in 12-hour format with AM/PM. The hours are displayed with the turn-on/turn-off minutes in case the user forgets what was saved in the previous menu, though only the minutes are alterable in that menu. Again, the minutes are in 10-minute intervals. The clock and date programming menu is very similar to the outlet programming menu with a few differences. First, there are no intermediate selections like outlet or day from which the user can exit; once inside this menu, the user must pan through each of them before returning to the main LCD menu. Again, an ideal future improvement would be ‘back’ functionality of the LEFT button. However, it is pure convenience, as the user merely must press RIGHT a few times to get back to the main menu: Day of the Week Month Date Year Hour (12hour, am/pm format) Minute Main Menu (display the time and date). Similar to the outlet programming menu, UP and DOWN scroll through the options for each of these screens with the LCD updating in real-time, SELECT saves them, and RIGHT cancels/moves on to the next screen. The manual override menus are very simple. UP and DOWN scroll among the outlets and “exit”, while SELECT acts on the current selection. For the “manual override on” menu, when an outlet is selected, its manual override is turned (or kept) on and its ‘on’ state is toggled – if the outlet is on, it is turned off, and vice versa. This is immediately implemented while still in the “manual override on” menu. In contrast, for the “manual override off” menu, the manual override for the chosen outlet is turned off and the outlet’s ‘on’ state is defaulted back to the programmed times. This effect is only visible after exiting the “manual override off” menu, as the rest of the “check on/off times” program must be executed. As expected, if “exit” is chosen in either of these menus, the LCD screen returns to the main idle menu. In addition to the hardware debouncing of the buttons, we implemented simple software debouncing of the buttons as well. When a button is pressed, the software waits for the button to be released before moving on. This could be improved but storing a state of each button (waiting, pressed down, and released) so that the software continues to execute while it waits for a pressed-button to be released; however, because of the simplicity of our program, this simpler debouncing works efficiently. Additionally, because of how the program is structured, only 1 button press is acknowledged at a time. Even if a user pressed both RIGHT and LEFT at the same time, a hierarchy chooses which one is acted upon. The only hazard is that the second button could be acted upon later in a different context based on the timing of its release relative to the first button. For example, if RIGHT were pressed and held and then LEFT were pressed and held before releasing RIGHT, the program would wait for RIGHT to be released regardless of whether or not LEFT is released before, simultaneously, or after. However, if LEFT is held down long enough after RIGHT is released, and the following menu looks for a LEFT button press, LEFT will be acted on once it is released. Again, storing a state for each button could prevent this by keeping track of if the LEFT button was pressed down before or after the program starts checking for LEFT. This is a “dummy-proofing” mechanism that was not necessary for our prototype but which would be important to implement in future builds. The Main Program The main loop that executes infinitely checks for a list of things. First, it checks if any buttons have been pressed – LEFT for programming outlets menu, RIGHT for programming clock menu, UP for turning on manual override, DOWN for turning off manual override. If no buttons are being pressed, it checks if the RF remote is requesting manual override. Last, it does a check for each outlet to see if it needs to be turned on or off. For an outlet to be turned on, manual override must be off and the outlet must be off; for an outlet to be turned off, manual override must be on and the outlet must be on. Additionally, “check_ontime(outlet)” and “check_offtime(outlet)” subroutines are called, which return true if an action (either turning an outlet on, or turning and outlet off, respectively) can be taken. Each of these subroutines that check if an outlet needs to be turned on or off look at 3 cases: (1) Always On: Turn-on time = Turn-off time (2) Usually On: Turn-on time > Turn-off time (3) Usually Off: Turn-on time < Turn-off time Since outlets are on by default, the first case means that an outlet is never turned off. The second case is “usually on”, meaning the outlet is on except for the programmed window of time when it is off. Conversely, the third case is “usually off”, meaning that the outlet is off except for the programmed window of time when it is on. In the check for turn-off time, if case (2) is true and the time now is inside of the “off” window (time-now > time-off and time-now < time-on), then check_offtime returns true. If case (3) is true and the time now is outside of the “on” window (time-now < time-on or time-now > time-off), then check_offtime returns true. In all other cases, check_offtime returns false, meaning that the outlets do not need to be turned off. The check for turn-on time works similarly. If case (2) is true, it checks if the time now is outside of the “on” window, and if case (3) is true, it checks if the time now is inside of the “on” window. It seems at first glance as though this wastes a lot of cycles on checking, but these check on/off time subroutines are only called if the outlet is currently in the opposite state (e.g. check_ontime is only called if the outlet is currently off). It is still constantly checking, but only for valid things to check (e.g. if the outlet is on, the program does not check if the outlet needs to be turned on, because that is an invalid thing to check). In order to simplify the code to check if time-on > time-off, etceteras, we implemented a “qualifyTime” method. This transforms any time into a whole integer value that can be compared with other times. It does this by giving the 10’s hour a weight of 1000, the 1’s hour a weight of 100, the 10’s minute a weight of 10, and the 1’s minute a weight of 1. The AM/PM value adds 1200 to the time to convert from 12-hour to 24-hour format when qualifying time. Below is a visual representation of the value qualify-time returns; each box represents a digit in the integer returned: 10’s Hour 1’s Hour 10’s Minute 1’s Minute This method is called for time-now, time-on, and time-off so they can be easily compared to one another multiple times without messy if-else statements. It modularizes the code to make it cleaner and easier to understand, as well as more efficient since qualifyTime only needs to be called once at the beginning of each check on/off time method call while the values it returns are used multiple times within the method. Section III: System Integration & Testing Before testing the software itself, the hardware – especially in connection to the microcontroller – needed to be tested. This was done from low-level to high-level. First we tested the microcontroller’s pins as outputs by toggling an output put on and off and reading it on an LED. Second we tested the microcontroller’s pins as inputs by pressing a button and outputting to the LED when a button is pressed. Third we tested multiple buttons as inputs by blinking the LED a different number of times based on which button was pressed. Once we verified this basic functionality, we moved on to testing higher level components. Since most of the system functionality and debugging is verified via the LCD, we tested that next. First we tried printing something static to each line of the LCD, and when that worked, we added interaction with the buttons to print out which button was pressed. Once we verified the LCD response to code, we tested and debugged the LCD menus – do they flow as expected? Do values increment, decrement, and cycle around from min to max and max to min all as expected? A clearLCD () method was also added to clear the LCD display in between prints, if necessary, so that extra characters are not left over in the case where the previous print statement is longer than the next one. Methods to clear each of the 2 lines independently were also coded, but never used. Lastly, before implementing and testing the main routine, we tested writing to and reading from the Real Time Clock on the I2C bus. From there we tested the format for storing time and date, followed by manipulation of those values. Once we could successfully set and save the current date and time, we verified battery back-up. From there, we tested writing to and reading from the various locations of the RTC RAM – are the start addresses for each day of the week correct? Does the offset work as it is supposed to? Once all the basic components were tested and verified as working individually, we tested our main loop to verify that outlets turned on and off when expected based on the programmed time, date, and on/off times. We used LEDs to represent the outlets until we had relays on the board. Once we had relays and outputs to a test board, we verified that we could turn on and off the outlets at will, then tested our main program. When all the main functionality was working, we added in manual override. In case we could not get the RF remote to work, we implemented it using buttons directly on the board. This seemed important in order to make our product reliable. This proved true because our RF remote did not communicate button presses 100% of the time, and we ran out of time to fix this issue before the prototype deadline. However, we did successfully test the remote toggling outlets on and off external to the main program, and this worked at least part of the time. A future improvement would be to make this reliable all the time – by finding and solving the cause of the synchronization failing between RF sender and receiver – and then integrating it into the main program. Section IV: Obstacles Software Struggles In addition to all of the regular and expected challenges of integrating and testing software and hardware in a system, we had two major hurdles that significantly impeded our progress throughout the project. Initially, we were not aware of the extremely limited amount of memory dedicated to the stack, and this caused us to spend a lot of time searching in the wrong places for the source of strange program behavior. Upon learning that other groups had strange behavior caused by overflowing from their stack space, the solution was simple – make the 24-character test string a global variable instead of a local one used in several subroutines. Had we made note of the 50byte stack space in the beginning, we could have very easily avoided this issue. Secondly, our LCD caused us a lot of headaches throughout the semester. In order to cut costs, we ordered a pre-used LCD; it was only 10% of the cost of similar new items, but as we found, it made it temperamental. For the most part, the LCD did what we expected, but on random occasions would print garbage or freeze, even though nothing in the source code had changed. Every once in a while, it would refuse to turn on at all. At first we thought that we might be sending characters to the LCD too quickly and tried adding in delays, but the routine that sends characters one at a time to the LCD checks the busy flag, so that would not have been an issue. It is possible that when we were testing it out and initially hooked it up backwards that something was burnt out. We did not conclude this until the very end, so if we had more time we could have tried swapping our LCD out for another, which may have solved the garbage and refresh issues instantly. Section V: Future Improvements Software Improvements In addition to the improvements already stated that would improve efficiency, reliability, and “dummy proofing” of our prototype, there are several features that could be added to future releases that would improve our product. The most obvious improvement is the ability to store more than just 2 programmable time for each day. This would mean adding an EPROM, since our RTC RAM is completely full with our current configuration. Doing this would also make it possible to program times independent of each other. For example, right now we have the user select an outlet and then a day, and from there they program one off time and one on time. The improvement would be to have the user select an outlet, select a day, and then select which action they want associated with the time they are setting (on, or off) such that the outlet can be turned off one day and turned on again on a completely separate day. This would also mean that an outlet could be turned off and on again multiple times in the same day, subject to the limits of EPROM space that we add. Hardware Improvements Though we already have two different methods of manual override – setting with buttons interfaced with the microcontroller, and toggling with the RF remote – it would be good to add a physical switch to implement manual override independent of the microcontroller in case it is malfunctioning. A 3-position switch would be best for 3 settings: manual override everything ‘on’, manual override everything ‘off’, and autopilot such that the microcontroller takes over the outlets’ on/off status. This would make it possible to override the whole system and hard-set the outlets on or off; it would act like a regular power strip when activated. Figure 1: LCD Idle Screen displays the current time and date One possible future hardware improvement was alluded to in the above discussions of the 315MHz RF link circuit modules. As discussed, we found the signal strength between the transmitter and receiver to be unreliable and in serious need of improvement. One way that this signal strength could be improved would be to run the transmitter at a higher source voltage. The following annotated diagram is an extract from the RF transmitter’s datasheet: As can be seen, this transmitter can be run at anywhere from 1.5 to 12 V. Since 5V was well within the specified “typical” supply voltage, we initially used a normal TTL 5V supply line to power the transmitter. Upon finding such a weak signal strength, we moved the supply line of the transmitter on our prototype board from the 5V regulator output to the 9V battery output. However, it was not possible to change the printed-circuit board transmitter supply voltage, since the signal traces are printed immovably onto the board. We were able to observe a very noticeable difference in signal strengths between the two remote control boards running the transmitters at the two different aforementioned supply voltages. While the prototype board typically worked up to a couple meters away from the receiver (still disappointing for RF equipment), the PCB transmitter had to be placed within a centimeter or so of the receiver board in order to get a reasonable transmission. Since the supply voltage seems to have such a drastic effect on signal strength, a future implementation of this project could use a 9V-to-12V “boost” converter to supply the transmitter voltage. In addition, signal strength could be further improved by connecting 315MHz antennas to both receiver and transmitter chips. Another improvement that could be made to the hardware would be to use more robust relays in order to solve the current loading problems detailed in the above “Outlet Outputs” heading of the “Main Module” section of this report. This would eliminate the need for the highpower resistors on our main module board (enabling a lower component count and a smaller footprint), and would also allow more realistic AC current loads that would better mirror real-life current loading situations. Conclusion In conclusion, the ultimate goal of this project was achieved. We were able to construct a device that can successfully “unplug” devices according to times programmed by the user. As expected, the user can simply program the times on the device or use the remote control (when working efficiently) to manually override the programmed times. Even though the final design was very sound, there are always ways that any type of device can be improved in hindsight after taking a step back and taking a look at the project as a whole. Appendix A Schematics C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - Main uC Interface C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - Switch Interface C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - LCD Interface C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - Timing Interface C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - Outlet Interface C:\Documents and Settings\Paul VanWieren\Desktop\My Dropbox\EE459\EE 459L Project Schematics\EE 459L Project Schematic.sch - Remote Control Appendix B Source Code Appendix B: Source Code Source Code for Main Module /********************************************************************* * EE 459 Spring 2009 Team 1 - Duracell * Sara Adkins * Paul VanWieren * Robert Whitley *********************************************************************/ #include <stdio.h> #include <hidef.h> /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ #include <string.h> /* The following puts the dummy interrupt service routine at location MY_ISR_ROM which is defined in the PRM file as the start of the FLASH ROM */ #pragma CODE_SEG MY_ISR_ROM #pragma TRAP_PROC void dummyISR(void) { } /* This prag sets the code storage back to default area of ROM as defined in the PRM file */ #pragma CODE_SEG DEFAULT /* * Port D, bit 1 (0x02) - output to RS (Register Select) input of display * bit 2 (0x04) - output to R/W (Read/Write) input of display * bit 3 (0x08) - output to E (Enable) input of display * Port B, bits 4-7 - Outputs to DB4-DB7 inputs of display. * * The second line of the display starts at address 0x40. * * ---Storage of On/Off times on RTC:--* Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * x2 times per device x7 days x4 devices = 56 bytes (total RAM!) * void LCDMenu(void); void mainLoop(void); void dummyMain(void); //TEST// void testOutlets(void); void fakeLCD(void); void testButtonsLED(void); void testButtonsLCD(void); void testI2Crap(void); void testCLKRegs(void); void testOutlets(void); void testRemote(void); //TEST// /* button input ports */ #define LEFT PTA_PTA1 #define RIGHT PTD_PTD6 #define UP PTD_PTD5 #define DOWN PTD_PTD4 #define SELECT PTD_PTD0 * Device 1: reg 0x08 - 0x15 * Device 2: reg 0x16 - 0x23 * Device 3: reg 0x24 - 0x31 * Device 4: reg 0x32 - 0x3F */ /* The NIBBLE_HIGH condition determines whether PTB bits 4-7 or 0-3 are used to send the four bit nibble to the LCD. If NIBBLE_HIGH is declared, use PTB 4-7. If NIBBLE_HIGH not declared, use PTB 0-3. */ #define NIBBLE_HIGH // Use bits 4-7 for talking to LCD /* function declarations */ void initializeLCD(void); void clearLCD(void); void strout(int, unsigned char *); void iniout(unsigned char); void cmdout(unsigned char); void datout(unsigned char); void nibout(unsigned char); void busywt(void); void del40u(int); void del1m(int); void sci_init(void); void i2c_init(unsigned char); void i2c_write2(unsigned char, unsigned char *, int, unsigned char); void i2c_read2(unsigned char, unsigned char *, int, unsigned char); void clk_init(void); void clkRAM_init(void); void clkRegs_init(void); void blink(int); void manualOn(void); void manualOff(void); unsigned char checkManualOverride(void); unsigned char check_offtime(unsigned char); unsigned char check_ontime(unsigned char); unsigned int qualifyTime(unsigned char, unsigned char); void testCLK(void); void getTime(void); void getDevData(unsigned char); void programCLK(void); void programOutlet(unsigned char); void programDEV(void); void progMenuTime(void); void progMenuOutlets(void); void LCD_Time(void); #define TUEREG 24 #define WEDREG 32 #define THUREG 40 #define FRIREG 48 #define SATREG 56 #define TOTALDEVS 4 //4 devices/outlets total /* This pragma sets the area for allocating variables to the zero page of RAM (0x00 to 0xff) for more efficient access.*/ #pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE unsigned char delay0; unsigned char delay1; unsigned char delay2; /* This pragma sets the area for allocating variables back to the default area of RAM as defined in the PRM file. */ #pragma DATA_SEG DEFAULT /* outlet output ports */ #define OUTLET1 PTB_PTB0 #define OUTLET2 PTB_PTB1 #define OUTLET3 PTB_PTB2 #define OUTLET4 PTB_PTB3 /* LCD */ #define LCD_LINE1 0 #define LCD_LINE2 0x40 /* Addresses for the clock on the I2C bus */ #define CLOCK_WR_ADDR 0xD0 /* clock write address */ #define CLOCK_RD_ADDR 0xD1 /* clock read address */ /* clk reg organized by day of the week */ #define SUNSTART 0x08 //for i2c read/write #define MONSTART 0x10 #define TUESTART 0x18 #define WEDSTART 0x20 #define THUSTART 0x28 #define FRISTART 0x30 #define SATSTART 0x38 #define SUNREG 8 //for clkRegs[] #define MONREG 16 /* Declare these strings as "const" so they are allocated in ROM */ //TEST// #ifdef NIBBLE_HIGH const unsigned char str1[] = "Hi! Press a button"; #else const unsigned char str1[] = "'lo! Press a button"; #endif const unsigned char str2[] = "...if you DARE"; const unsigned char str3[] = "Dare to press another?"; const unsigned char upstr[] = "you pressed UP!"; const unsigned char downstr[] = "you pressed DOWN!"; const unsigned char leftstr[] = "you pressed LEFT!"; const unsigned char rightstr[] = "you pressed RIGHT!"; const unsigned char selectstr[] = "you pressed SELECT!"; //TEST// const unsigned char clearstr[] = " "; const unsigned char strdurasaver[] = "Duracell DuraSaver "; const unsigned char strprogmenu[] = "Programming Menu"; const unsigned char strprogdev[] = "Program Devices"; const unsigned char strsetclk[] = "Set Clock & Date"; const unsigned char strexit[] = "Exit "; const unsigned char stroutlet[] = "Select Outlet"; const unsigned char strprogday[] = "Select Day of the Week"; const unsigned char stroffhour[] = "Select Off Hour"; const unsigned char stroffmin[] = "Select Off Minute"; const unsigned char stronhour[] = "Select On Hour"; const unsigned char stronmin[] = "Select On Minute"; const unsigned char strweekday[] = "Set Day of the Week"; const unsigned char strsun[] = "Sunday "; const unsigned char strmon[] = "Monday "; const unsigned char strtue[] = "Tuesday "; const unsigned char strwed[] = "Wednesday"; const unsigned char strthu[] = "Thursday "; const unsigned char strfri[] = "Friday "; const unsigned char strsat[] = "Saturday "; const unsigned char strmonth[] = "Set Month"; const unsigned char strjan[] = "January "; const unsigned char strfeb[] = "February "; const unsigned char strmar[] = "March "; const unsigned char strapr[] = "April "; const unsigned char strmay[] = "May "; const unsigned char strjun[] = "June "; const unsigned char strjul[] = "July "; const unsigned char straug[] = "August "; const unsigned char strsep[] = "September"; const unsigned char stroct[] = "October "; const unsigned char strnov[] = "November "; const unsigned char strdec[] = "December "; const unsigned char strdate[] = "Set Date (01-31)"; const unsigned char stryear[] = "Set Year (2000-2099)"; const unsigned char strtimehr[] = "Set Hour (01-12 AM/PM)"; const unsigned char strtimemin[] = "Set Minute (00-59)"; const unsigned char strmanon[] = "Manual Override On"; const unsigned char strmanoff[] = "Manual Override Off"; const unsigned char strohnoes[] = "???"; const unsigned char hexCode[] = "0123456789ABCDEF"; const unsigned char one = 1; const unsigned char zero = 0; const unsigned int thousand = 1000; const unsigned char keeppw = 0xF0; const unsigned char keepcode = 0x0F; const unsigned char password = 0xD0; const unsigned char code0 = 0x00; const unsigned char code1 = 0x01; const unsigned char code2 = 0x02; const unsigned char code3 = 0x03; /* global variables */ const unsigned char swDebounce = 1; //1 for software debounce, 0 for hardware only unsigned char PWCODE; unsigned char PW; unsigned char CODE; unsigned char today; //this is for LCD menu; actual current day of the week is stored in dayofweek (against all common sense, I know) unsigned char timesToday; //keeps track of which day of the week's on/off times are stored in the off/on[] variables unsigned char seconds10, seconds09, minutes10, minutes09, hours10, hours09, pm, dayofweek, date10, date09, months10, months09, years10, years09; //time right now get from clock unsigned char off10hr[TOTALDEVS], off09hr[TOTALDEVS], offmin[TOTALDEVS], offpm[TOTALDEVS], //programmed "off" times, 1 per each of 4 devices on10hr[TOTALDEVS], on09hr[TOTALDEVS], onmin[TOTALDEVS], onpm[TOTALDEVS]; //programmed "on" times, 1 per each of 4 devices /* manual override - 0 is off, 1 is on (default is off) */ unsigned char manual[TOTALDEVS]; /* outlets - 0 is off, 1 is on (default is on) */ unsigned char outlet[TOTALDEVS]; unsigned char time[24]; //Day, MO/DD/YR HH:MM xm unsigned char teststr[24]; //to print test statements, variables unsigned char clkRegs[64]; unsigned char dayData[8]; /****************** MAIN ******************/ void main(void) { // EnableInterrupts; /* enable interrupts */ /* include your code here */ CONFIG1_COPD = 1; CONFIG2_IICSEL = 1; // disable COP reset // IIC on PTA2, 3 DDRA_DDRA0 = 1; DDRD_DDRD0 = 0; DDRD_DDRD4 = 0; DDRD_DDRD5 = 0; DDRD_DDRD6 = 0; DDRA_DDRA1 = 0; // Set PTA0 = 1 for output (LED) // clear PTD0 = 0 for input (SELECT button) // clear PTD4 = 0 for input (DOWN button) // clear PTD5 = 0 for input (UP button) // clear PTD6 = 0 for input (RIGHT button) // clear PTA1 = 0 for input (LEFT button) PTA_PTA0 = 1; /* Set baud rate to 38,400. Clock = 9.8304MHz. Divisor = 64. */ i2c_init((unsigned char) 3); // Initialize the IIC port sci_init(); // Initialize the SCI port #ifdef NIBBLE_HIGH DDRB = 0xf0; #else DDRB = 0x0f; #endif DDRD = 0x0e; // Set PTB bits 4-7 for output /********************************************* MAIN LCD MENU *********************************************/ void dummyMain() { del1m(thousand); clearLCD(); del1m(thousand); mainLoop(); } // Set PTB bits 0-3 for output // Set PTD1, 2, and 3 for output initializeLCD(); // Initialize the LCD display //ONLY ONCE//clk_init(); // Initialize the Clock (ONLY HAS TO BE DONE ONCE) //clkRAM_init(); //initialize the clkRegs + initalize the clock RAM (other than time & date) clkRegs_init(); //initialize the clkRegs del1m(thousand); DDRB_DDRB0 = 1; // Set PTB0 = 1 for output (Outlet 1) DDRB_DDRB1 = 1; // Set PTB1 = 1 for output (Outlet 2) DDRB_DDRB2 = 1; // Set PTB2 = 1 for output (Outlet 3) DDRB_DDRB3 = 1; // Set PTB3 = 1 for output (Outlet 4) outlet[0] = 1; OUTLET1 = 1; //Outlet 1 on by default outlet[1] = 1; OUTLET2 = 1; //Outlet 2 on by default outlet[2] = 1; OUTLET3 = 1; //Outlet 3 on by default outlet[3] = 1; OUTLET4 = 1; //Outlet 4 on by default del1m(thousand); timesToday = dayofweek; /* main loop */ while(one) { dummyMain(); } /* please make sure that you never leave this function */ } //LED off void mainLoop() { unsigned char outletNum = TOTALDEVS; strout(LCD_LINE1, (unsigned char *) strdurasaver); testCLK(); while(one) { del1m(thousand); clearLCD(); getTime(); //update time variables // check for RIGHT button press --> program clock if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released progMenuTime(); } // check for LEFT button press --> program outlets else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released progMenuOutlets(); } //check for UP button press --> turn on manual override else if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released manualOn(); } //check for DOWN button press --> turn off manual override else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released manualOff(); } } //end if manual override currently off // check for manual override (on --> off) else if(manual[outletNum-1] == 1) { manual[outletNum-1] = 0; } //end if manual override currently on for(outletNum = TOTALDEVS; outletNum > 0; outletNum--) { //for each device // check for RF remote manual override request if(checkManualOverride() == outletNum) { // check for manual override (off --> on) if(manual[outletNum-1] == 0) { //if manual override currently off manual[outletNum-1] = 1; if(outlet[outletNum-1] == 1) { //outlet 1 is on --> turn it off outlet[outletNum-1] = 0; switch(outletNum) { case 1: OUTLET1 = 0; break; case 2: OUTLET2 = 0; break; case 3: OUTLET3 = 0; break; case 4: OUTLET4 = 0; break; } //end switch //strout(LCD_LINE1, "manv off!"); //del1m(thousand); } else { //outlet 1 is off --> turn it on outlet[outletNum-1] = 1; switch(outletNum) { case 1: OUTLET1 = 1; break; case 2: OUTLET2 = 1; break; case 3: OUTLET3 = 1; break; case 4: OUTLET4 = 1; break; } //end switch //strout(LCD_LINE1, "manv on !"); //del1m(thousand); } case 3: OUTLET3 = 1; //on break; case 4: OUTLET4 = 1; //on break; } //end switch //strout(LCD_LINE1, "time on !"); //del1m(thousand); } } } else { //idle --> display time and date //testCLK(); LCD_Time(); } //end idle } //end for each device } //end while(one) } void LCD_Time() { //getTime(); del1m(2); strout(LCD_LINE1, (unsigned char *) strdurasaver); del1m(2); testCLK(); //del1m(500); } void manualOn() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); } // check if need to turn off outlet if(outlet[outletNum-1] == 1) { if(manual[outletNum-1] == 0) { if(check_offtime(outletNum) == 1) { outlet[outletNum-1] = 0; //OUTLET1 = 0; //OFF switch(outletNum) { case 1: OUTLET1 = 0; //off break; case 2: OUTLET2 = 0; //off break; case 3: OUTLET3 = 0; //off break; case 4: OUTLET4 = 0; //off break; } //end switch //strout(LCD_LINE1, "time off!"); //del1m(thousand); } } } // check if need to turn on outlet else if(outlet[outletNum-1] == 0) { if(manual[outletNum-1] == 0) { if(check_ontime(outletNum) == 1) { outlet[outletNum-1] = 1; //OUTLET1 = 1; //ON switch(outletNum) { case 1: OUTLET1 = 1; //on break; case 2: OUTLET2 = 1; //on break; break; case 1: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN //del1m(thousand); } //end if outlet off --> on strout(LCD_LINE2, "confirmed - another?"); del1m(500); clearLCD(); else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released }//end if choice != 0 if(choice != 0) { manual[choice - 1] = 1; //turn on manual override if(outlet[choice - 1] == 1) { //outlet is on --> turn it off outlet[choice - 1] = 0; switch(choice) { case 1: OUTLET1 = 0; //OFF break; case 2: OUTLET2 = 0; //OFF break; case 3: OUTLET3 = 0; //OFF break; case 4: OUTLET4 = 0; //OFF break; } //end switch //strout(LCD_LINE1, "manv off!"); //del1m(thousand); } //end if outlet is on --> off else if(outlet[choice - 1] == 0) { //outlet is off --> turn it on outlet[choice - 1] = 1; switch(choice) { case 1: OUTLET1 = 1; //ON break; case 2: OUTLET2 = 1; //ON break; case 3: OUTLET3 = 1; //ON break; case 4: OUTLET4 = 1; //ON break; } //end switch //strout(LCD_LINE1, "manv on !"); del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released if(choice != 0) { manual[choice - 1] = 0; //turn on manual override strout(LCD_LINE2, "confirmed - another?"); del1m(500); clearLCD(); }//end if choice != 0 else if(choice == 0) { repeat = '0'; break; } } //end if SELECT } //end repeat } void manualOff() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case 1: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: else if(choice == 0) { repeat = '0'; break; } } //end if SELECT } //end repeat } unsigned int qualifyTime(unsigned char outletNum, unsigned char ontime) { unsigned int qualval, q10hr, q09hr, q10min, q09min, qpm; getTime(); //update time variables getDevData(dayofweek); //update on/off times for current day if(outletNum == 0) { //NOW q10hr = hours10 & 0x01; q09hr = hours09 & 0x0f; q10min = minutes10 & 0x07; q09min = minutes09 & 0x0f; qpm = pm & 0x01; } else if((outletNum != 0) && (ontime == 1)) { q10hr = on10hr[outletNum-1] & 0x01; q09hr = on09hr[outletNum-1] & 0x0f; q10min = onmin[outletNum-1] & 0x07; q09min = 0; qpm = onpm[outletNum-1] & 0x01; } else { q10hr = off10hr[outletNum-1] & 0x01; q09hr = off09hr[outletNum-1] & 0x0f; q10min = offmin[outletNum-1] & 0x07; q09min = 0; qpm = offpm[outletNum-1] & 0x01; } if((q10hr == 1) && (q09hr == 2)) { //12xm is always < anything else xm //qualval = (q10hr * 0) + (q09hr * 0) + (q10min * 10) + (q09min * 1) + (qpm * 1200); qualval = (q10min * 10) + (q09min) + (qpm * 1200); } else { //qualval = (q10hr * 1000) + (q09hr * 100) + (q10min * 10) + (q09min * 1) + (qpm * 1200); qualval = (q10hr * 1000) + (q09hr * 100) + (q10min * 10) + (q09min) + (qpm * 1200); } return qualval; } qNOW = qualifyTime(0, 1); if(qON == qOFF) { //off and on times are the same --> default ON //strout(LCD_LINE1, "qON == qOFF"); //del1m(thousand); return 1; } /* Check Off Time * This function checks if the given outlet * is scheduled to be off right now */ unsigned char check_offtime(unsigned char outletNum){ unsigned int qON, qOFF, qNOW; qON = qualifyTime(outletNum, 1); qOFF = qualifyTime(outletNum, 0); qNOW = qualifyTime(0, 1); if(qOFF < qON) { //turn off then turn on (usually on) if((qNOW < qOFF) || (qNOW >= qON)) { //time now is before off-time or after on-time //strout(LCD_LINE1, "outside off-time"); //del1m(thousand); return 1; } } if(qON == qOFF) { //off and on times are the same --> default ON //strout(LCD_LINE1, "qOFF == qON"); //del1m(thousand); return 0; } if(qOFF < qON) { //turn off then turn on (usually on) if((qNOW >= qOFF) && (qNOW < qON)) { //time now is after off-time but before on-time //strout(LCD_LINE1, "btwn off & on"); //del1m(thousand); return 1; } } if(qON < qOFF) { //turn on then turn off (usually off) if((qNOW < qON) || (qNOW >= qOFF)) { //time now is before on-time or after off-time //strout(LCD_LINE1, "outside on-time"); //del1m(thousand); return 1; } } return 0; } /* Check On Time * This function checks if the given outlet * is scheduled to be on right now */ unsigned char check_ontime(unsigned char outletNum){ unsigned int qON, qOFF, qNOW; qON = qualifyTime(outletNum, 1); qOFF = qualifyTime(outletNum, 0); if(qON < qOFF) { //turn on then turn off (usually off) if((qNOW >= qON) && (qNOW < qOFF)) { //time now is after on-time but before off-time //strout(LCD_LINE1, "btwn off and on"); //del1m(thousand); return 1; } } return '0'; } /* Check for Manual Override * Returns Outlet Number of Outlet Toggling Manual Override * Returns 0 if no Outlet is requesting manual override */ unsigned char checkManualOverride() { if(SCS1_SCRF) { //check flag PWCODE = SCDR; PW = PWCODE&keeppw; if(PW == password) { CODE = PWCODE&keepcode; if(CODE == code0) { return 1; } //end if for code0 check else if(CODE == code1) { return 2; } //end elseif for code1 check else if(CODE == code2) { return 3; } //end else if for code1 check else if(CODE == code3) { return 4; } //end else if for code3 check else { return 0; }//do nothing if code is not valid } //end if for password checking else { return 0; } //do nothing if password is not correct } //end if for serial input data register full check strout(LCD_LINE1, (unsigned char *) strprogmenu); del1m(2); strout(LCD_LINE2, (unsigned char *) strprogdev); while(repeat == '1') { if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released programDEV(); repeat = '0'; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //LCDMenu(); repeat = '0'; } // end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //progMenuTime(); repeat = '0'; } //end if LEFT } //end while repeat } void progMenuTime() { unsigned char repeat = '1'; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strprogmenu); del1m(2); strout(LCD_LINE2, (unsigned char *) strsetclk); while(repeat == '1') { if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released programCLK(); repeat = '0'; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //progMenuOutlets(); repeat = '0'; } // end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //LCDMenu(); repeat = '0'; } //end if LEFT } //end while repeat } void progMenuOutlets() { unsigned char repeat = '1'; clearLCD(); del1m(2); } /********************************************* FETCH DEVICE DATA STORED ON RTC RAM *********************************************/ /* * ---Time & Date--0x00 = clkRegs[0]: Seconds 0x01 = clkRegs[1]: Minutes 0x02 = clkRegs[2]: Hours 0x03 = clkRegs[3]: 0x04 = clkRegs[4]: 0x05 = clkRegs[5]: 0x06 = clkRegs[6]: Year 0x07 = clkRegs[7]: sqwout.... * ---Storage of On/Off times on RTC:--* Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * x2 times per device x7 days x4 devices = 56 bytes (total RAM!) * * Sunday: 0x08 - 0x0F, offset: (deviceNumber - 1) * 2 Device 1: off: 0x08 Device 1: on: 0x09 Device 2: off: 0x0A Device 2: on: 0x0B Device 3: off: 0x0C Device 3: on: 0x0D Device 4: off: 0x0E Device 4: on: 0x0F * Monday: 0x10 - 0x17 * Tuesday: 0x18 - 0x1F * Wednesday: 0x20 - 0x27 * Thursday: 0x28 - 0x2F * Friday: 0x30 - 0x37 * Saturday: 0x38 - 0x3F //for(x = 8; x > 0; x--) { // dayData[x-1] = clkRegs[MONREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, MONSTART); break; case '3': /********** TUESDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[TUEREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, TUESTART); break; case '4': /********** WEDNESDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[WEDREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, WEDSTART); break; case '5': /********** THURSDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[THUREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, THUSTART); break; case '6': /********** FRIDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[FRIREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, FRISTART); break; case '7': /********** SATURDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[SATREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, SATSTART); break; } //end switch * Get Device Data * gets and saves updated on/off times for given day * Reg 1: Off, Reg 2: On * Bit 7 - 4: Hours (1-12 * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM */ void getDevData(unsigned char day) { //day was formerly today, until today was made global unsigned char x; unsigned char offset;// = (deviceNum - 1) * 2; unsigned char i = TOTALDEVS; //clearLCD(); // (1) read data from clock registers switch(hexCode[day]) { case '1': /********** SUNDAY **********/ //for(x = 8; x > 0; x--) { //teststr[0] = hexCode[x]; //teststr[1] = ' '; //teststr[2] = hexCode[SUNREG + x - 1]; //teststr[3] = ' '; //teststr[4] = hexCode[(clkRegs[SUNREG+x-1] >> 4) & 0x0f]; //teststr[5] = hexCode[(clkRegs[SUNREG+x-1]) & 0x0f]; //teststr[6] = '\0'; //strout(LCD_LINE2, teststr); //del1m(thousand); // dayData[x-1] = clkRegs[SUNREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, SUNSTART); break; case '2': /********** MONDAY **********/ // (2a) process "off" time if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'A') { off10hr[i-1] = '1'; off09hr[i-1] = '0'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'B') { off10hr[i-1] = '1'; off09hr[i-1] = '1'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'C') { off10hr[i-1] = '1'; off09hr[i-1] = '2'; } else { off10hr[i-1] = '0'; off09hr[i-1] = hexCode[(dayData[offset] >> 4) & 0x0f]; //up to 9 } offpm[i-1] = hexCode[(dayData[offset] & 0x01)]; offmin[i-1] = hexCode[(dayData[offset] & 0x0e) >> 1]; //all but last bit (bits 3-1) // (2b) process "on" time if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'A') { on10hr[i-1] = '1'; on09hr[i-1] = '0'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'B') { on10hr[i-1] = '1'; on09hr[i-1] = '1'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'C') { on10hr[i-1] = '1'; on09hr[i-1] = '2'; } else { on10hr[i-1] = '0'; on09hr[i-1] = hexCode[(dayData[offset+1] >> 4) & 0x0f]; //up to 9 } onpm[i-1] = hexCode[(dayData[offset+1] & 0x01)]; onmin[i-1] = hexCode[(dayData[offset+1] & 0x0e) >> 1]; //all but last bit (bits 3-1) /*teststr[0] = off10hr[i - 1]; teststr[1] = off09hr[i - 1]; teststr[2] = ':'; teststr[3] = offmin[i - 1]; teststr[4] = '0'; teststr[5] = offpm[i - 1]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[i - 1]; teststr[9] = on09hr[i - 1]; teststr[10] = ':'; // (2) for each device.... for(; i > 0; i--) { //device 4 --> 3 --> 2 --> 1 offset = (i - 1) * 2; //index offset for dayData, based on device # //e.g. dev 4 is stored at 6 and 7 (4 - 1 = 3 * 2 = 6) //e.g. dev 3 is stored at 4 and 5 (3 - 1 = 2 * 2 = 4) //e.g. dev 2 is stored at 2 and 3 (2 - 1 = 1 * 2 = 2) //e.g. dev 1 is stored at 0 and 1 (1 - 1 = 0 * 2 = 0) teststr[11] = onmin[i - 1]; teststr[12] = '0'; teststr[13] = onpm[i - 1]; teststr[14] = 'M'; teststr[15] = '\0'; del1m(thousand); */ } //end for each device timesToday = day; } /********************************************* PROGRAM DEVICE MAIN MENU *********************************************/ void programDEV() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case 1: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //repeat = '0'; if(choice != 0) { repeat = '0'; programOutlet(choice); break; } } //end if SELECT break; case '2': //Monday del1m(2); strout(LCD_LINE2, (unsigned char *) strmon); break; case '3': //Tuesday del1m(2); strout(LCD_LINE2, (unsigned char *) strtue); break; case '4': //Wednesday del1m(2); strout(LCD_LINE2, (unsigned char *) strwed); break; case '5': //Thursday del1m(2); strout(LCD_LINE2, (unsigned char *) strthu); break; case '6': //Friday del1m(2); strout(LCD_LINE2, (unsigned char *) strfri); break; case '7': //Saturday del1m(2); strout(LCD_LINE2, (unsigned char *) strsat); break; default: //unknown?? clearLCD(); del1m(2); strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(dayofweek) else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //repeat = 0; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //repeat = 0; } //end if LEFT } //end repeat } /********************************************* PROGRAM OUTLET ON/OFF TIME ON RTC *********************************************/ /* Program Outlet * User will choose which device to program * prior to calling this function. * This function will go through the LCD menus * to view/change on/off times for outletNum. */ void programOutlet(unsigned char outletNum) { unsigned char repeat = '1', exit = '0'; unsigned char tempvar10, tempvar09, temppm, regOffset, addrOffset, temp; unsigned char tempchars[8]; tempchars[7] = '\0'; /* CHANGE DAY OF THE WEEK */ while(exit == '0') { clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strprogday); today = 0; //start at exit --> user can choose a day of the week from there repeat = '1'; while(repeat == '1') { del1m(100); switch(hexCode[today]) { case '0': //done/exit del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case '1': //Sunday del1m(2); strout(LCD_LINE2, (unsigned char *) strsun); if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = '0'; if(today == 0) { //exit back to choose outlet exit = '1'; //programDEV(); } else { //no exit //del1m(thousand); getDevData(today); //update all the variablesssssss regOffset = (outletNum - 1) * 2; //addrOffset = (regOffset >> 4) & 0x0f; addrOffset = (regOffset) & 0x0f; } break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(today == 7) today = 0; //--> exit else today++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(today == 0) today = 7; else today--; } //end if DOWN else if(SELECT) { if(exit == '1') { break; } /* CHANGE OFF HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stroffhour); tempvar10 = off10hr[outletNum - 1]; tempvar09 = off09hr[outletNum - 1]; if(offpm[outletNum - 1] == '0') temppm = 'A'; else if(offpm[outletNum - 1] == '1') temppm = 'P'; else temppm = '?'; while(repeat == '1') { del1m(100); tempchars[0] = tempvar10; tempchars[1] = tempvar09; tempchars[2] = temppm; tempchars[3] = 'M'; tempchars[4] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } //end if 11 tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 if(tempvar09 == '9') { //9AM --> 10AM, 9PM --> 10PM tempvar09 = '0'; tempvar10 = '1'; } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM tempvar09 = '9'; tempvar10 = '0'; } //end if 10 else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1 else if (tempvar10 == '0') { //its 01-09 if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 off10hr[outletNum - 1] = tempvar10; off09hr[outletNum - 1] = tempvar09; if(temppm == 'A') offpm[outletNum - 1] = '0'; else if(temppm == 'P') offpm[outletNum - 1] = '1'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 // /* del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) /* CHANGE OFF MINUTE */ //choose among: 00, 10, 20, 30, 40, 50 clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; tempvar09 = '0'; del1m(2); strout(LCD_LINE1, (unsigned char *) stroffmin); tempvar10 = offmin[outletNum - 1]; while(repeat == '1') { del1m(100); tempchars[0] = off10hr[outletNum - 1]; tempchars[1] = off09hr[outletNum - 1]; tempchars[2] = ':'; tempchars[3] = tempvar10; tempchars[4] = '0'; if(offpm[outletNum - 1] == '0') tempchars[5] = 'A'; else if(offpm[outletNum - 1] == '1') tempchars[5] = 'P'; else tempchars[5] = '?'; tempchars[6] = 'M'; tempchars[7] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //tempvar10 = (tempvar10 + 1)%6; if(tempvar10 == '5') tempvar10 = '0'; else tempvar10++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //tempvar10 = (tempvar10 - 1)%6; if(tempvar10 == '0') tempvar10 = '5'; else tempvar10--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 offmin[outletNum - 1] = tempvar10; // /* temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday temppm = 'P'; else temppm = '?'; while(repeat == '1') { del1m(100); tempchars[0] = tempvar10; tempchars[1] = tempvar09; tempchars[2] = temppm; tempchars[3] = 'M'; tempchars[4] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } //end if 11 tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 if(tempvar09 == '9') { //9AM --> 10AM, 9PM --> 10PM tempvar09 = '0'; tempvar10 = '1'; } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM tempvar09 = '9'; tempvar10 = '0'; clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) /* CHANGE ON HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; tempchars[4] = ' '; tempchars[5] = ' '; tempchars[6] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stronhour); tempvar10 = on10hr[outletNum - 1]; tempvar09 = on09hr[outletNum - 1]; if(onpm[outletNum - 1] == '0') temppm = 'A'; else if(onpm[outletNum - 1] == '1') } //end if 10 else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1 else if (tempvar10 == '0') { //its 01-09 if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 on10hr[outletNum - 1] = tempvar10; on09hr[outletNum - 1] = tempvar09; if(temppm == 'A') onpm[outletNum - 1] = '0'; else if(temppm == 'P') onpm[outletNum - 1] = '1'; // /* temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 onmin[outletNum - 1] = tempvar10; // /* temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; /* CHANGE ON MINUTE */ //choose among: 00, 10, 20, 30, 40, 50 clearLCD(); repeat = '1'; tempvar09 = '0'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stronmin); tempvar10 = onmin[outletNum - 1]; while(repeat == '1') { del1m(100); tempchars[0] = on10hr[outletNum - 1]; tempchars[1] = on09hr[outletNum - 1]; tempchars[2] = ':'; tempchars[3] = tempvar10; tempchars[4] = '0'; if(onpm[outletNum - 1] == '0') tempchars[5] = 'A'; else if(onpm[outletNum - 1] == '1') tempchars[5] = 'P'; else tempchars[5] = '?'; tempchars[6] = 'M'; tempchars[7] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //tempvar10 = (tempvar10 + 1)%6; if(tempvar10 == '5') tempvar10 = '0'; else tempvar10++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //tempvar10 = (tempvar10 - 1)%6; if(tempvar10 == '0') tempvar10 = '5'; else tempvar10--; } //end if DOWN case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) //TEST// del1m(1); getDevData(today); teststr[0] = off10hr[outletNum - 1]; teststr[1] = off09hr[outletNum - 1]; teststr[2] = ':'; teststr[3] = offmin[outletNum - 1]; teststr[4] = '0'; teststr[5] = offpm[outletNum - 1]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[outletNum - 1]; teststr[9] = on09hr[outletNum - 1]; teststr[10] = ':'; teststr[11] = onmin[outletNum - 1]; teststr[12] = '0'; teststr[13] = onpm[outletNum - 1]; teststr[14] = 'M'; teststr[15] = '\0'; del1m(2); strout(LCD_LINE1, "is this what you saved?"); del1m(2); strout(LCD_LINE2, teststr); while(!SELECT) {} //so can look at while(SELECT) {} //debounce //TEST// repeat = '1'; //go back into choosing day of the week } //while !exit strout(LCD_LINE2, (unsigned char *) strthu); break; case '6': //Friday strout(LCD_LINE2, (unsigned char *) strfri); break; case '7': //Saturday strout(LCD_LINE2, (unsigned char *) strsat); break; default: //unknown?? strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(dayofweek) } /********************************************* PROGRAM THE DATE AND TIME ON RTC *********************************************/ /* Program Clock * This function will go through the LCD menus * to view/change the set time and date. */ void programCLK() { unsigned char repeat = '1'; unsigned char tempvar, tempvar10, tempvar09, temppm; unsigned char tempchars[5] = " "; tempchars[4] = '\0'; getTime(); //get initial values /* CHANGE DAY OF THE WEEK */ clearLCD(); strout(LCD_LINE1, (unsigned char *) strweekday); tempvar = hexCode[dayofweek]; while(repeat == '1') { switch(tempvar) { case '1': //Sunday strout(LCD_LINE2, (unsigned char *) strsun); break; case '2': //Monday strout(LCD_LINE2, (unsigned char *) strmon); break; case '3': //Tuesday strout(LCD_LINE2, (unsigned char *) strtue); break; case '4': //Wednesday strout(LCD_LINE2, (unsigned char *) strwed); break; case '5': //Thursday } //while(repeat) /* CHANGE MONTH */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) strmonth); tempvar10 = hexCode[months10]; tempvar09 = hexCode[months09]; while(repeat == '1') { if(tempvar10 == '1') { switch(tempvar09) { case '0': //10 October strout(LCD_LINE2, (unsigned char *) stroct); break; case '1': //11 November strout(LCD_LINE2, (unsigned char *) strnov); break; case '2': //12 December strout(LCD_LINE2, (unsigned char *) strdec); break; } //end switch(months09) } //end if months10 == 1 else { //months10 == 0 switch(tempvar09) { case '1': //1 January strout(LCD_LINE2, (unsigned char *) strjan); break; case '2': //2 February strout(LCD_LINE2, (unsigned char *) strfeb); break; case '3': //3 March strout(LCD_LINE2, (unsigned char *) strmar); break; case '4': //4 April strout(LCD_LINE2, (unsigned char *) strapr); break; case '5': //5 May strout(LCD_LINE2, (unsigned char *) strmay); break; case '6': //6 June strout(LCD_LINE2, (unsigned char *) strjun); break; case '7': //7 July strout(LCD_LINE2, (unsigned char *) strjul); break; if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar == '7') //saturday tempvar = '1'; //--> sunday else tempvar++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar == '1') //sunday tempvar = '7'; //--> saturday else tempvar--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[3] = ((tempvar) & 0x0f); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[3], 1, 3); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT case '8': //8 August strout(LCD_LINE2, (unsigned char *) straug); break; case '9': //9 September strout(LCD_LINE2, (unsigned char *) strsep); break; default: //unknown?? strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(months09) } //end else months10 == 0 //while(!UP && !DOWN && !SELECT); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { if(tempvar09 == '0' || tempvar09 == '1') tempvar09++; else { //12 December --> 01 January tempvar10 = '0'; tempvar09 = '1'; } //months09 != 0 } //months10 ==1 else { //months10 == 0 if(tempvar09 <= '8') tempvar09++; else { //09 September --> 10 October tempvar10 = '1'; tempvar09 = '0'; } //months09 > 8 } //months10 == 1 } //if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { if(tempvar09 == '2' || tempvar09 == '1') tempvar09--; else { //10 October --> 09 September tempvar10 = '0'; tempvar09 = '9'; } } //months10 ==1 else { if(tempvar09 > '1') tempvar09--; else { //01 January --> 12 December tempvar10 = '1'; tempvar09 = '2'; } //else months09 == 1 } //else months10 == 0 } //if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[5] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[5], 1, 5); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//while(repeat) /* CHANGE DAY OF THE MONTH */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) strdate); tempvar10 = hexCode[date10]; tempvar09 = hexCode[date09]; while(repeat == '1') { tempchars[0] = tempvar10; tempchars[1] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); //while(!UP && !DOWN && !SELECT); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '3') { //31 days: jan (01), march (03), may (05), july (07), oct (10), dec (12); 30 days: april (04), june (06), aug (08), sept (09), nov (11) if(hexCode[months10] == '0') { if(hexCode[months09] == '2' || hexCode[months09] == '4' || hexCode[months09] == '6') { //if february, april, june tempvar10 = '0'; tempvar09 = '1'; } else if(hexCode[months09] == '1' || hexCode[months09] == '3' || hexCode[months09] == '5' || hexCode[months09] == '7') { //january, march, may, july tempvar09++; } } //end if date10 == 1 || 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '0' && tempvar09 == '1') { if(hexCode[months10] == '0') { //months: january-september if(hexCode[months09] == '2') { //february --> max 29 days tempvar10 = '2'; tempvar09 = '9'; } //end if february else if(hexCode[months09] == '1' || hexCode[months09] == '3' || hexCode[months09] == '5' || hexCode[months09] == '7' || hexCode[months09] == '8') { //months with 31 days (jan, mar, may, july, aug) tempvar10 == '3'; tempvar09 == '1'; } //end if month with 31 days else if(hexCode[months09] == '4' || hexCode[months09] == '6' || hexCode[months09] == '9') { //months with 30 days (april, june, sept) tempvar10 == '3'; tempvar09 == '0'; } //end if month with 30 days } //end if months10 = 0 else if(hexCode[months10] == '1') { if(hexCode[months09] == '1') { //november has 30 days tempvar10 = '3'; tempvar09 = '0'; } else if(hexCode[months09] == '0' || hexCode[months09] == '2') { //october and december have 31 days tempvar10 = '3'; tempvar09 = '1'; } } //end if months10 = 1 } //end if date == 01 else if(date09 == 0) { //date != 01, date09 == 0 tempvar10--; tempvar09--; } else { //date != 01, date09 > 0 tempvar09--; } } //if DOWN if(tempvar09 == '1') { tempvar10 = '0'; tempvar09 = '1'; } else if(tempvar09 == '0') { tempvar09 = '1'; } } //end if january, march, may, july } //end if months10 == 0 (january - september except february) else if(hexCode[months10] == '1') { if(hexCode[months09] == '1') { //november tempvar10 = '0'; tempvar09 = '1'; } else if(hexCode[months09] == '0' || hexCode[months09] == '2') { //october or december if(tempvar09 == '1') { tempvar10 = '0'; tempvar09 = '1'; } else if(tempvar09 == '0') { tempvar09 = '1'; } } //end if months10 == 1 (october or november or december) } //end if months10 == 1 } //end if date10 == 3 else if(tempvar10 == '2') { if(tempvar09 == '9') { if(hexCode[months10] == '0' && hexCode[months09] == '2') { //february tempvar10 = '0'; tempvar09 = '1'; } else { //not february tempvar10 = '3'; tempvar09 = '0'; } } //end if date09 == 9 else { //date09 < 9 tempvar09++; } //end if date09 < 9 } //end if date10 == 2 else if(tempvar10 == '1' || tempvar10 == '0') { //date10 = 1 or 0 if(tempvar09 == '9') { tempvar10++; tempvar09 = '0'; } //end if date09 == 9 else { else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[4] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[4], 1, 4); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//while(repeat) /* CHANGE YEAR */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) stryear); tempchars[0] = '2'; tempchars[1] = '0'; tempvar10 = hexCode[years10]; tempvar09 = hexCode[years09]; while(repeat == '1') { tempchars[2] = tempvar10; tempchars[3] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar09 == '9') { tempvar09 = '0'; if(tempvar10 == '9') tempvar10 = '0'; else tempvar10++; } //end years09 == 9 else tempvar09++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar09 == '0') { tempvar09 = '9'; if(tempvar10 == '0') tempvar10 = '9'; else tempvar10--; } //end years09 == 0 else tempvar09--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[6] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[6], 1, 6); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) /* CHANGE HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; strout(LCD_LINE1, (unsigned char *) strtimehr); tempvar10 = hexCode[hours10]; tempvar09 = hexCode[hours09]; tempchars[0] = tempvar10; //NEW// tempchars[1] = tempvar09; if(hexCode[pm] == '1') temppm = 'P'; //NEW// else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM //OLD//if(tempvar10 == '3') tempvar10 = '1'; //OLD//else if(tempvar10 == '1') tempvar10 = '3'; if(temppm == 'A') temppm = 'P'; //NEW// else if(temppm == 'P') temppm = 'A'; //NEW// } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1s else if(tempvar10 == '0') { //its 01-09 //NEW// if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register if(temppm == 'A') pm = 0; else pm = 1; clkRegs[2] = (((0x01 & pm) << 5) | ((0x01 & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[2], 1, 2); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) else temppm = 'A'; //NEW// tempchars[2] = temppm; tempchars[3] = 'M'; while(repeat == '1') { tempchars[0] = tempvar10; //NEW// tempchars[1] = tempvar09; tempchars[2] = temppm; //NEW// tempchars[3] = 'M'; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 //NEW// if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM //OLD//if(tempvar10 == '1') tempvar10 = '3'; //OLD//else if(tempvar10 == '3') tempvar10 = '1'; if(temppm == 'A') temppm = 'P'; //NEW// else if(temppm == 'P') temppm = 'A'; //NEW// } tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 //NEW// if(tempvar09 == '9') { tempvar09 = '0'; tempvar10 = '1'; //9AM --> 10AM, 9PM --> 10PM } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM tempvar09 = '9'; tempvar10 = '0'; } //end if 10 /* CHANGE MINUTE */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; strout(LCD_LINE1, (unsigned char *) strtimemin); tempvar10 = hexCode[minutes10]; tempvar09 = hexCode[minutes09]; while(repeat == '1') { tempchars[0] = tempvar10; tempchars[1] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar09 == '9') { if(tempvar10 == '5') { tempvar10 = '0'; tempvar09 = '0'; } else { //minutes10 < 5 && minutes09 == 9 tempvar10++; tempvar09 = '0'; } } else { //minutes09 < 9 tempvar09++; } } //end UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar09 == '0') { if(tempvar10 == '0') { tempvar10 = '5'; tempvar09 = '9'; } else { //minutes10 > 0 && minutes09 == 0 tempvar10--; tempvar09 = '9'; } } else { //minutes09 > 0 tempvar09--; } } //end DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released del1m(1); i2c_read2(CLOCK_RD_ADDR, clkRegs, 8, 0); //read all 8 main registers // day of the week dayofweek = (clkRegs[3] & 0x07); //only care about 3 lowest bits switch(hexCode[dayofweek]) { case '1': //Sunday time[0] = 'S'; time[1] = 'u'; time[2] = 'n'; break; case '2': //Monday time[0] = 'M'; time[1] = 'o'; time[2] = 'n'; break; case '3': //Tuesday time[0] = 'T'; time[1] = 'u'; time[2] = 'e'; break; case '4': //Wednesday time[0] = 'W'; time[1] = 'e'; time[2] = 'd'; break; case '5': //Thursday time[0] = 'T'; time[1] = 'h'; time[2] = 'u'; break; case '6': //Friday time[0] = 'F'; time[1] = 'r'; time[2] = 'i'; break; case '7': //Saturday time[0] = 'S'; time[1] = 'a'; time[2] = 't'; break; //update the clock register clkRegs[1] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[1], 1, 1); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) strout(LCD_LINE1, "Select to Return Home"); while(!SELECT) { testCLK(); del1m(1000); } while(SELECT){} //debounce } /* This program tests the DS1307 Real Time Clock with I2C interface * An LED on pin 2 of the MC908JL16 will blink every other second * An LED connected to the SQW output of the Clock will blink at 1Hz * The LCD will display the time */ void testCLK() { //unsigned char time[24]; //Day, MO/DD/YR HH:MM xm time[23] = '\0'; default: //unknown?? time[0] = '?'; time[1] = '?'; time[2] = '?'; } time[3] = ','; time[4] = ' '; time[19] = ':'; seconds10 = ((clkRegs[0] >> 4) & 0x07); //only 3 10's bits seconds09 = (clkRegs[0] & 0x0f); time[20] = hexCode[seconds10]; time[21] = hexCode[seconds09]; if(hexCode[pm] == '0') time[22] = 'A'; else if(hexCode[pm] == '1') time[22] = 'P'; else time[22] = '?'; time[23] = 'M'; //month months10 = (clkRegs[5] >> 4) & 0x01; //only 1 10's bit months09 = (clkRegs[5] & 0x0f); time[5] = hexCode[months10]; time[6] = hexCode[months09]; time[7] = '/'; //day of the month date10 = (clkRegs[4] >> 4) & 0x03; //only 2 10's bits date09 = (clkRegs[4] & 0x0f); time[8] = hexCode[date10]; time[9] = hexCode[date09]; time[10] = '/'; //year years10 = (clkRegs[6] >> 4) & 0x0f; years09 = (clkRegs[6] & 0x0f); time[11] = hexCode[years10]; time[12] = hexCode[years09]; time[13] = ' '; //hour /*if((hexCode[(clkRegs[2] >> 4) & 0x0f] == '0') || (hexCode[(clkRegs[2] >> 4) & 0x0f] == '1')) { pm = 'A'; } else if((hexCode[(clkRegs[2] >> 4) & 0x0f] == '2') || (hexCode[(clkRegs[2] >> 4) & 0x0f] == '3')) { pm = 'P'; } */ pm = ((clkRegs[2] >> 5) & 0x01); hours10 = (clkRegs[2] >> 4) & 0x01; //1st bit only - //NEW// hours09 = (clkRegs[2] & 0x0f); time[14] = hexCode[hours10]; //NEW// time[15] = hexCode[hours09]; time[16] = ':'; //minute minutes10 = (clkRegs[1] >> 4) & 0x07; //only 3 10's bits minutes09 = (clkRegs[1] & 0x0f); time[17] = hexCode[minutes10]; time[18] = hexCode[minutes09]; del1m(2); strout(LCD_LINE2, (unsigned char *) time); } /* Get Time * Retrieves Time & Date Register Values * Saves to Global Variables */ void getTime() { i2c_read2(CLOCK_RD_ADDR, clkRegs, 7, 0); seconds10 = ((clkRegs[0] >> 4) & 0x07); //only 3 10's bits seconds09 = (clkRegs[0] & 0x0f); minutes10 = (clkRegs[1] >> 4) & 0x07; //only 3 10's bits minutes09 = (clkRegs[1] & 0x0f); pm = ((clkRegs[2] >> 5) & 0x01); hours10 = (clkRegs[2] >>4) & 0x01; //1st bit only - //NEW// hours09 = (clkRegs[2] & 0x0f); dayofweek = (clkRegs[3] & 0x07); //only care about 3 lowest bits date10 = (clkRegs[4] >> 4) & 0x03; //only 2 10's bits date09 = (clkRegs[4] & 0x0f); months10 = (clkRegs[5] >> 4) & 0x01; //only 1 10's bit months09 = (clkRegs[5] & 0x0f); years10 = (clkRegs[6] >> 4) & 0x0f; years09 = (clkRegs[6] & 0x0f); } /* ----------------------------------------------------------------------- */ /**************************************** Test Functions ****************************************/ /* turn on LED in port A bit 0 for n msec, then turn off */ void blink(int n) { PTA_PTA0 = 0; //turn on LED del1m(n); //leave on n msec PTA_PTA0 = 1; //turn off LED } /* void testOutlets() { del1m(2); while(one) { OUTLET1 = 1; strout(LCD_LINE1, "outlet 1"); del1m(thousand); OUTLET1 = 0; OUTLET2 = 1; strout(LCD_LINE1, "outlet 2"); del1m(thousand); OUTLET2 = 0; OUTLET3 = 1; strout(LCD_LINE1, "outlet 3"); del1m(thousand); OUTLET3 = 0; /* Clear Contents of LCD: * Bring cursor home * Print blanks on line 1 * Print Blanks on line 2 * Bring cursor home */ void clearLCD() { del1m(2); strout(LCD_LINE1, (unsigned char *) clearstr); // clear line 1 del1m(2); strout(LCD_LINE2, (unsigned char *) clearstr); //clear line 2 cmdout(0x02); //cursor home } /* charout - Print the character 'c' at LCD RAM location "x". */ void charout(int x, unsigned char c) { unsigned char ch; cmdout(x | 0x80); // Make A contain a Set Display Address command while ((ch = c) != (unsigned char) NULL) { datout(c); // Output the next character } } /* strout - Print the contents of the character string "s" starting at LCD RAM location "x". The string must be terminated by a zero byte. */ void strout(int x, unsigned char *s) { unsigned char ch; cmdout(x | 0x80); // Make A contain a Set Display Address command OUTLET4 = 1; strout(LCD_LINE1, "outlet 4"); del1m(thousand); OUTLET4 = 0; } }*/ while ((ch = *s++) != (unsigned char) NULL) { datout(ch); // Output the next character } } /**************************************** Test Functions ****************************************/ /**************************************** LCD ****************************************/ /* datout - Output a byte to the LCD display data register (the display) and wait for the busy flag to reset. */ void datout(unsigned char x) { PTD = 0x02; // Set R/W=0, E=0, RS=1 nibout(x); // Put data bits 4-7 in PTB nibout(x << 4); // Put data bits 0-3 in PTB busywt(); // Wait for BUSY flag to reset } iniout(0x30); /* cmdout - Output a byte to the LCD display instruction register and wait for the busy flag to reset. */ void cmdout(unsigned char x) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); // Output command bits 4-7 nibout(x << 4); // Output command bits 0-3 busywt(); // Wait for BUSY flag to reset } /* nibout - Puts bits 4-7 from x into the four bits of Port B that we're using to talk to the LCD. The other bits of Port B are unchanged. Toggle the E control line low-high-low. */ void nibout(unsigned char x) { #ifdef NIBBLE_HIGH PTB = (x & 0xf0) | (PTB & 0x0f); // Use bits 4-7 //PTB_PTB4 = x & 0x10; //PTB_PTB5 = x & 0x20; //PTB_PTB6 = x & 0x30; //PTB_PTB7 = x & 0x80; #else PTB = ((x >> 4) & 0x0f) | (PTB & 0xf0); // Use bits 0-3 //PTB_PTB0 = x & 0x01; //PTB_PTB1 = x & 0x02; //PTB_PTB2 = x & 0x04; //PTB_PTB3 = x & 0x08; #endif PTD_PTD3 = 1; // Set E to 1 PTD_PTD3 = 0; // Set E to 0 } /* initialize - Do various things to force a initialization of the LCD display by instructions, and then set up the display parameters and turn the display on. */ void initializeLCD() { del1m(15); // Delay at least 15ms iniout(0x30); del1m(4); // Send a 0x30 // Delay at least 4msec iniout(0x30); del40u(3); // Send a 0x30 // Delay at least 100usec iniout(0x20); busywt(); // Send a 0x30 // Function Set: 4-bit interface // Wait for BUSY flag to reset cmdout(0x28); // Function Set: 4-bit interface, 2 lines cmdout(0x0f); // Display and cursor on } /* iniout - Output a byte to the LCD control register. Same as the "cmdout" function but it doesn't wait for the BUSY flag since that flag isn't working during initialization. */ void iniout(unsigned char x) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); } /* busywt - Wait for the BUSY flag to reset */ void busywt() { unsigned char bf; //DDRB = 0; // Set PTB for input DDRB_DDRB4 = 0; DDRB_DDRB5 = 0; DDRB_DDRB6 = 0; DDRB_DDRB7 = 0; PTD = 0x04; // Set E=0, R/W=1, RS=0 do { PTD_PTD3 = 1; // Set E=1 #ifdef NIBBLE_HIGH bf = PTB & 0x80; // Read status register bits 4-7 #else bf = PTB & 0x08; // Read status register bits 4-7 #endif PTD_PTD3 = 0; // Set E=0 PTD_PTD3 = 1; // Set E=1, ignore bits 0-3 PTD_PTD3 = 0; // Set E=0 } while (bf != 0); // If Busy (PTB7=1), loop #ifdef NIBBLE_HIGH //DDRB = 0xf0; // Set PTB for output DDRB_DDRB4 = 1; DDRB_DDRB5 = 1; DDRB_DDRB6 = 1; DDRB_DDRB7 = 1; #else //DDRB = 0x0f; // Set PTB for output DDRB_DDRB0 = 1; DDRB_DDRB1 = 1; DDRB_DDRB2 = 1; DDRB_DDRB3 = 1; #endif } //the rest: RAM (on/off times) clkRegs[8] = clkRegs[9] = 0xC0; clkRegs[10] = clkRegs[11] = clkRegs[12] = clkRegs[13] = clkRegs[14] = clkRegs[15] = clkRegs[16] = clkRegs[17] = clkRegs[18] = clkRegs[19] = 0xC0; clkRegs[20] = clkRegs[21] = clkRegs[22] = clkRegs[23] = clkRegs[24] = clkRegs[25] = clkRegs[26] = clkRegs[27] = clkRegs[28] = clkRegs[29] = 0xC0; clkRegs[30] = clkRegs[31] = clkRegs[32] = clkRegs[33] = clkRegs[34] = clkRegs[35] = clkRegs[36] = clkRegs[37] = clkRegs[38] = clkRegs[39] = 0xC0; clkRegs[40] = clkRegs[41] = clkRegs[42] = clkRegs[43] = clkRegs[44] = clkRegs[45] = clkRegs[46] = clkRegs[47] = clkRegs[48] = clkRegs[49] = 0xC0; clkRegs[50] = clkRegs[51] = clkRegs[52] = clkRegs[53] = clkRegs[54] = clkRegs[55] = 0xC0; /**************************************** LCD ****************************************/ i2c_write2(CLOCK_WR_ADDR, clkRegs, 64, 0); } /**************************************** I2C - Real Time Clock ****************************************/ /* i2c_init - Initialize the MMIIC port */ void i2c_init(unsigned char bdiv) { MIMCR_MMBR = bdiv; // Set baud rate divisor MMCR_MMEN = 1; // Enable MMIIC } /* clk_init - Initialize the Clock * The Clock is initialized to 12:00:00 PM Wednesday 04/01/09 * The SQWE pin outputs a 1Hz square wave * * Initialize the RTC RAM for on/off times * Initialize the on/off times in RTC RAM * Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * INIT: 12AM: 1100 000 0 = 0xC0 */ void clk_init() { clkRegs[0] = 0x00; //Seconds: 00 clkRegs[1] = 0x00; //Minutes: 00 clkRegs[2] = 0x72; //Hour: 12pm clkRegs[3] = 0x04; //Day of the week: Wednesday clkRegs[4] = 0x01; //Date: 01 clkRegs[5] = 0x04; //Month: 04 clkRegs[6] = 0x09; //Year: 2009 clkRegs[7] = 0x10; //outputs 1hz square wave from SQWE pin void clkRegs_init() { clkRegs[8] = clkRegs[9] = 0xC0; clkRegs[10] = clkRegs[11] = clkRegs[12] = clkRegs[13] = clkRegs[14] = clkRegs[15] = clkRegs[16] = clkRegs[17] = clkRegs[18] = clkRegs[19] = 0xC0; clkRegs[20] = clkRegs[21] = clkRegs[22] = clkRegs[23] = clkRegs[24] = clkRegs[25] = clkRegs[26] = clkRegs[27] = clkRegs[28] = clkRegs[29] = 0xC0; clkRegs[30] = clkRegs[31] = clkRegs[32] = clkRegs[33] = clkRegs[34] = clkRegs[35] = clkRegs[36] = clkRegs[37] = clkRegs[38] = clkRegs[39] = 0xC0; clkRegs[40] = clkRegs[41] = clkRegs[42] = clkRegs[43] = clkRegs[44] = clkRegs[45] = clkRegs[46] = clkRegs[47] = clkRegs[48] = clkRegs[49] = 0xC0; clkRegs[50] = clkRegs[51] = clkRegs[52] = clkRegs[53] = clkRegs[54] = clkRegs[55] = 0xC0; } void clkRAM_init() { unsigned char clkRAM[56]; clkRAM[0] = clkRAM[1] = clkRAM[2] = clkRAM[3] = clkRAM[4] = clkRAM[5] = clkRAM[6] = clkRAM[7] = clkRAM[8] = clkRAM[9] = 0xC0; clkRAM[10] = clkRAM[11] = clkRAM[12] = clkRAM[13] = clkRAM[14] = clkRAM[15] = clkRAM[16] = clkRAM[17] = clkRAM[18] = clkRAM[19] = 0xC0; clkRAM[20] = clkRAM[21] = clkRAM[22] = clkRAM[23] = clkRAM[24] = clkRAM[25] = clkRAM[26] = clkRAM[27] = clkRAM[28] = clkRAM[29] = 0xC0; clkRAM[30] = clkRAM[31] = clkRAM[32] = clkRAM[33] = clkRAM[34] = clkRAM[35] = clkRAM[36] = clkRAM[37] = clkRAM[38] = clkRAM[39] = 0xC0; clkRAM[40] = clkRAM[41] = clkRAM[42] = clkRAM[43] = clkRAM[44] = clkRAM[45] = clkRAM[46] = clkRAM[47] = clkRAM[48] = clkRAM[49] = 0xC0; clkRAM[50] = clkRAM[51] = clkRAM[52] = clkRAM[53] = clkRAM[54] = clkRAM[55] = 0xC0; del1m(1); i2c_write2(CLOCK_WR_ADDR, clkRAM, 56, 0x08); //ADDR.Address = reg; } MMCR_MMTXAK = 0; // MCU will ACK received data MMADR = CLOCK_WR_ADDR; // Device address -> address reg. //MMDTR = ADDR.Bytes.Address_H; // High byte of data address MMDTR = reg; //data address MIMCR_MMRW = 0; // Set for transmit MIMCR_MMAST = 1; // Initiate transfer /* i2c_write2 - write bytes to an I2C device (two byte address) */ void i2c_write2(unsigned char device_addr, unsigned char *p, int n, byte reg) { //ADDR.Address = reg; // Copy address to struct while (MIMCR_MMBB); // Wait for bus not busy while (!(MMSR_MMTXBE)); // Wait for TX buffer empty////////////////////////////////STUCK HERE: MMSR_MMTXBE never goes to 1 MMADR = device_addr; // Device address -> address reg //MMDTR = ADDR.Bytes.Address_H; // High byte of data address MMDTR = reg; MIMCR_MMRW = 0; // Set for transmit MIMCR_MMAST = 1; // Start transmission //while (!(MMSR_MMTXBE)); // Wait for TX buffer empty //MMDTR = ADDR.Bytes.Address_L; // Low byte of data address //while (MMSR_MMRXAK); // Wait for ACK from slave //while (!(MMSR_MMTXBE)); // Wait for TX buffer empty //MMDTR = ADDR.Bytes.Address_L; // Low byte of data address //while (MMSR_MMRXAK); // Wait for ACK from slave while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = 0xff; // Dummy data to get ACK clock while (MMSR_MMRXAK); // Wait for ACK from slave MMADR = device_addr; // device address -> address reg. //MMDTR = 0xff; // dummy data -> data reg. MIMCR_MMRW = 1; // Set for receive MMCR_REPSEN = 1; // Enable repeated start MIMCR_MMAST = 1; // Initiate transfer while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = 0xff; // Dummy data -> data reg while (MMSR_MMRXAK); // Wait for ACK from slave while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = *p++; // First byte of data to write while (MMSR_MMRXAK); // Wait for ACK from slave while (n > 0) { n--; // Decrement count while (!(MMSR_MMTXBE)); // Wait for TX buffer empty if (n == 0) // Is this the last byte? MMDTR = 0xff; // Yes. dummy data -> DTR else MMDTR = *p++; // No. next data -> DTR while (MMSR_MMRXAK); // Wait for ACK from slave } MIMCR_MMAST = 0; // Generate STOP bit //MMCR_MMEN = 0; //MMCR_MMEN = 1; // Copy address to struct n--; // Loop n-1 times before last read while (n > 0) { // Up to last byte while (!(MMSR_MMRXBF)); // Wait for RX buffer full *p++ = MMDRR; // Get data n--; // Decrement total count } MMCR_MMTXAK = 1; // Don't send ACK for last byte while (!(MMSR_MMRXBF)); // Wait for RX buffer full *p++ = MMDRR; // Get data MIMCR_MMAST = 0; // Generate STOP bit // disable MMIIC // Enable MMIIC } MMCR_MMEN = 0; MMCR_MMEN = 1; /* i2c_read2 - read bytes from an I2C device (two byte address) */ void i2c_read2(unsigned char device_addr, unsigned char *p, int n, byte reg) { unsigned char x; x = MMDRR; // This should clear the MMRXBF flag // disable MMIIC // Enable MMIIC } /**************************************** I2C - Real Time Clock ****************************************/ ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). 95 x .407 usec = 38.7 usec. ; The JSR and RTS instructions will add a bit more. mov #13,delay0 ; 4 cycles u1: dec delay0 ; 4 cycles bne u1 ; 3 cycles /**************************************** SCI Port ****************************************/ /* sci_init - Initialize the SCI port */ void sci_init(void) { SCC1_ENSCI = 1; // Enable SCI /* Set output for 9600 baud. Assumes a 9.8304MHz clock */ SCBR_SCP = 0; // Baud rate prescaler = 1 SCBR_SCR = 2; // Baud rate divisor = 4 SCC2_TE = 1; // Enable transmitter } /* sciout - Output a byte to SCI port */ void sciout(unsigned char ch) { while (SCS1_SCTE == 0); SCDR = ch; } /* sciouts - Print the contents of the character string "s" out the SCI port. The string must be terminated by a zero byte */ void sciouts(unsigned char *s) { unsigned char ch; while ((ch = *s++) != (unsigned char) NULL) sciout(ch); } } } /* del1m - Delay about 1msec times the "d" argument */ void del1m(int d) { while (d--) { asm { ; The following code delays 1 millisecond by looping. ; Total time is 4 + 5 * (4 + 68 * (4 + 3) + 4 + 3) = 2439 cycles ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). Delay is then .993 milliseconds. mov #$5,delay1 ; 4 cycles m1: mov #68,delay0 ; 4 cycles m0: dec delay0 ; 4 cycles bne m0 ; 3 cycles dec delay1 ; 4 cycles bne m1 ; 3 cycles } } } } /**************************************** SCI Port ****************************************/ /**************************************** DELAY ****************************************/ /**************************************** TEST ****************************************/ /***************************************** DELAY ****************************************/ /* Note: these delay routines only work if the the delay0 and delay1 variables are located in the RAM zero page */ /* del40u - Delay about 40usec times the "d" argument */ void del40u(int d) { while (d--) { asm { ; The following code delays about 40 microseconds by looping. ; Total time is 4 + 13 * (4 + 3) = 95 cycles void LCDMenu() { del1m(100); clearLCD(); while(one) { if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released progMenuTime(); } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released progMenuOutlets(); } //end if LEFT else { //DISPLAY TIME del1m(2); strout(LCD_LINE1, (unsigned char *) strdurasaver); del1m(2); testCLK(); del1m(995); } clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) rightstr); // "you pressed right!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) upstr); // "you pressed up!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) downstr); // "you pressed down!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) selectstr); // "you pressed select!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else { // do nothing } } } void testRemote() { while(one) { clearLCD(); if(checkManualOverride() == 1) { strout(0, "manual override 1"); if(outlet[0] == 1) { outlet[0] = 0; OUTLET1 = 0; strout(LCD_LINE2, "turn off"); del1m(thousand); } else if(outlet[0] == 0) { outlet[0] = 1; OUTLET1 = 1; strout(LCD_LINE2, "turn on"); del1m(thousand); } } } } /* Displays confirmation on the LCD of which button is pressed */ void testButtonsLCD() { while(one) { while(!LEFT && !RIGHT && !UP && !DOWN && !SELECT) testCLK(); if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) leftstr); // "you pressed left!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released } } /* This program will test button function, output to an LED. * * LED: PTA0, output * Left Button: LED blink 5x * Right Button: LED blink 4x * Up Button: LED blink 3x * Down Button: LED blink 2x * Select Button: LED blink 1x */ void testButtonsLED() { PTA_PTA0 = 1; //LED off to start while (1) { // Loop forever if (LEFT) { //--> blink 5x if(swDebounce) while(LEFT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(RIGHT) { //--> blink 4x if(swDebounce) while(RIGHT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(UP) { // --> blink 3x if(swDebounce) while(UP) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(DOWN) { //--> blink 2x if(swDebounce) while(DOWN) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(SELECT) { //--> blink 1x if(swDebounce) while(SELECT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); } else PTA_PTA0 = 1; //off } } strout(0x40, "Sunday"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroffhour); del1m(2); strout(0x40, "08AM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroffmin); del1m(2); strout(0x40, "08:30AM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stronhour); del1m(2); strout(0x40, "05PM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); void testI2Crap() { //testCLK(); //do a read strout(0, "before 2nd clkinit"); del1m(thousand); clk_init(); strout(0, "woot woot"); //while(one) { //testCLK(); //del1m(thousand); //} del1m(thousand); programCLK(); } void fakeLCD() { unsigned char repeat = 1; while(repeat) { del1m(2); strout(0, stroutlet); del1m(2); strout(0x40, "Outlet 1"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroutlet); del1m(2); strout(0x40, strexit); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, strprogday); del1m(2); strout(0, stronmin); del1m(2); strout(0x40, "05:20PM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; } void testCLKRegs(void) { unsigned char teststr[24]; unsigned char offset, i, temp, outletNum, today, regOffset, addrOffset; today = 1; outletNum = 1; clkRegs[8] = 0x88; clkRegs[9] = 0x77; clkRegs[10] = 0x66; clkRegs[11] = 0x55; clkRegs[12] = 0x44; clkRegs[13] = 0x33; clkRegs[14] = 0x22; clkRegs[15] = 0x11; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[8], 1, 0x08); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[9], 1, 0x09); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[10], 1, 0x0A); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[11], 1, 0x0B); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[12], 1, 0x0C); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[13], 1, 0x0D); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[14], 1, 0x0E); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[15], 1, 0x0F); del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0, teststr); today = 1; outletNum = 1; regOffset = (outletNum - 1) * 2; addrOffset = (regOffset >> 4) & 0x0f; off10hr[0] = '0'; off09hr[0] = '9'; offpm[0] = '0'; offmin[0] = '0'; on10hr[0] = '0'; on09hr[0] = '6'; onpm[0] = '1'; onmin[0] = '3'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0x40, teststr); del1m(5000); clearLCD(); strout(0, teststr); off10hr[0] = '1'; off09hr[0] = '2'; offpm[0] = '1'; offmin[0] = '2'; on10hr[0] = '1'; on09hr[0] = '0'; onpm[0] = '0'; break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); onmin[0] = '4'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0x40, teststr); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) del1m(5000); del1m(1); //i2c_read2(CLOCK_RD_ADDR, dayData, 8, 0x08); getDevData(1); teststr[0] = hexCode[(dayData[0] >> 4) & 0x0f]; teststr[1] = hexCode[(dayData[0]) & 0x0f]; teststr[2] = hexCode[(dayData[1] >> 4) & 0x0f]; teststr[3] = hexCode[(dayData[1]) & 0x0f]; teststr[4] = hexCode[(dayData[2] >> 4) & 0x0f]; teststr[5] = hexCode[(dayData[2]) & 0x0f]; teststr[6] = hexCode[(dayData[3] >> 4) & 0x0f]; teststr[7] = hexCode[(dayData[3]) & 0x0f]; teststr[8] = hexCode[(dayData[4] >> 4) & 0x0f]; teststr[9] = hexCode[(dayData[4]) & 0x0f]; teststr[10] = hexCode[(dayData[5] >> 4) & 0x0f]; teststr[11] = hexCode[(dayData[5]) & 0x0f]; teststr[12] = hexCode[(dayData[6] >> 4) & 0x0f]; teststr[13] = hexCode[(dayData[6]) & 0x0f]; teststr[14] = hexCode[(dayData[7] >> 4) & 0x0f]; teststr[15] = hexCode[(dayData[7]) & 0x0f]; teststr[16] = '\0'; //strout(0, teststr); del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; //clkRegs[8] = 0xA4; //0001 001 0 = 1:10am, 1010 010 0 = A4 = 10:20am //clkRegs[9] = 0xC9; //0010 010 1 = 2:20pm, 1100 100 1 = C9 = 12:40pm //i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[8], 1, 0x08); //i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[9], 1, 0x09); onmin[i-1] = hexCode[(dayData[offset+1] & 0x0e) >> 1]; //all but last bit (bits 3-1) if(hexCode[(dayData[offset+1] & 0x01)] == '0') //last bit is am/pm onpm[i-1] = 'A'; else if(hexCode[(dayData[offset+1] & 0x01)] == '1') onpm[i-1] = 'P'; else onpm[i-1] = '?'; del1m(1); //i2c_read2(CLOCK_RD_ADDR, dayData, 8, SUNSTART); getDevData(1); i = 1; offset = (i - 1) * 2; //index offset for dayData, based on device # //e.g. dev 4 is stored at 6 and 7 (4 - 1 = 3 * 2 = 6) // (2a) process "off" time if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'A') { off10hr[i-1] = '1'; off09hr[i-1] = '0'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'B') { off10hr[i-1] = '1'; off09hr[i-1] = '1'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'C') { off10hr[i-1] = '1'; off09hr[i-1] = '2'; } else { off10hr[i-1] = '0'; off09hr[i-1] = hexCode[(dayData[offset] >> 4) & 0x0f]; //up to 9 } offmin[i-1] = hexCode[(dayData[offset] & 0x0e) >> 1]; //all but last bit (bits 3-1) if(hexCode[(dayData[offset] & 0x01)] == '0') //last bit is am/pm offpm[i-1] = 'A'; else if(hexCode[(dayData[offset] & 0x01)] == '1') offpm[i-1] = 'P'; else offpm[i-1] = '?'; // (2b) process "on" time if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'A') { on10hr[i-1] = '1'; on09hr[i-1] = '0'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'B') { on10hr[i-1] = '1'; on09hr[i-1] = '1'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'C') { on10hr[i-1] = '1'; on09hr[i-1] = '2'; } else { on10hr[i-1] = '0'; on09hr[i-1] = hexCode[(dayData[offset+1] >> 4) & 0x0f]; //up to 9 } teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; //strout(0x40, teststr); //del1m(5000); } void testOutlets() { del1m(2); DDRB_DDRB0 = 1; DDRB_DDRB1 = 1; DDRB_DDRB2 = 1; DDRB_DDRB3 = 1; while(one) { OUTLET1 = 1; strout(0, "outlet 1"); del1m(thousand); OUTLET1 = 0; OUTLET2 = 1; strout(0, "outlet 2"); del1m(thousand); OUTLET2 = 0; OUTLET3 = 1; strout(0, "outlet 3"); del1m(thousand); OUTLET3 = 0; OUTLET4 = 1; strout(0, "outlet 4"); del1m(thousand); OUTLET4 = 0; } } /* turn on LED in port A bit 0 for n msec, then turn off */ void blink(int n) { PTA_PTA0 = 0; //turn on LED del1m(n); //leave on n msec PTA_PTA0 = 1; //turn off LED } /* test manual override */ void testManOv() { while(one) { switch(checkManualOverride()) { case 1: blink(1000); if(outlet[0] == 1) { outlet[0] = OUTLET1 = 0; } else if(outlet[0] == 0) { outlet[0] = OUTLET1 = 1; } strout(0, "manov 1!"); break; case 2: blink(1000); blink(1000); if(outlet[1] == 1) { outlet[1] = OUTLET2 = 0; /********************************************************************* * EE 459 Spring 2009 Team 1 - Duracell * Sara Adkins * Paul VanWieren * Robert Whitley *********************************************************************/ #include <stdio.h> #include <hidef.h> /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ #include <string.h> /* The following puts the dummy interrupt service routine at location MY_ISR_ROM which is defined in the PRM file as the start of the FLASH ROM */ #pragma CODE_SEG MY_ISR_ROM #pragma TRAP_PROC void dummyISR(void) { } /* This prag sets the code storage back to default area of ROM as defined in the PRM file */ #pragma CODE_SEG DEFAULT /* * Port D, bit 1 (0x02) - output to RS (Register Select) input of display * bit 2 (0x04) - output to R/W (Read/Write) input of display * bit 3 (0x08) - output to E (Enable) input of display * Port B, bits 4-7 - Outputs to DB4-DB7 inputs of display. * * The second line of the display starts at address 0x40. * * ---Storage of On/Off times on RTC:--* Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * x2 times per device x7 days x4 devices = 56 bytes (total RAM!) * * Device 1: reg 0x08 - 0x15 * Device 2: reg 0x16 - 0x23 } else if(outlet[1] == 0) { outlet[1] = OUTLET2 = 1; } strout(0, "manov 2!"); break; case 3: blink(1000); blink(1000); blink(1000); if(outlet[2] == 1) { outlet[2] = OUTLET3 = 0; } else if(outlet[2] == 0) { outlet[2] = OUTLET3 = 1; } strout(0, "manov 3!"); break; case 4: blink(1000); blink(1000); blink(1000); blink(1000); if(outlet[3] == 1) { outlet[3] = OUTLET4 = 0; } else if(outlet[3] == 0) { outlet[3] = OUTLET4 = 1; } strout(0, "manov 4!"); break; default: del1m(2); strout(0, strdurasaver); testCLK(); del1m(1000); } //end switch } //end while(one) } /**************************************** TEST ****************************************/ Source Code for Remote Control * Device 3: reg 0x24 - 0x31 * Device 4: reg 0x32 - 0x3F */ /* The NIBBLE_HIGH condition determines whether PTB bits 4-7 or 0-3 are used to send the four bit nibble to the LCD. If NIBBLE_HIGH is declared, use PTB 4-7. If NIBBLE_HIGH not declared, use PTB 0-3. */ #define NIBBLE_HIGH // Use bits 4-7 for talking to LCD /* function declarations */ void initializeLCD(void); void clearLCD(void); void strout(int, unsigned char *); void iniout(unsigned char); void cmdout(unsigned char); void datout(unsigned char); void nibout(unsigned char); void busywt(void); void del40u(int); void del1m(int); void sci_init(void); void i2c_init(unsigned char); void i2c_write2(unsigned char, unsigned char *, int, unsigned char); void i2c_read2(unsigned char, unsigned char *, int, unsigned char); void clk_init(void); void clkRAM_init(void); void clkRegs_init(void); void blink(int); void manualOn(void); void manualOff(void); unsigned char checkManualOverride(void); unsigned char check_offtime(unsigned char); unsigned char check_ontime(unsigned char); unsigned int qualifyTime(unsigned char, unsigned char); void testCLK(void); void getTime(void); void getDevData(unsigned char); void programCLK(void); void programOutlet(unsigned char); void programDEV(void); void progMenuTime(void); void progMenuOutlets(void); void LCD_Time(void); void LCDMenu(void); void mainLoop(void); void dummyMain(void); //TEST// void testOutlets(void); void fakeLCD(void); void testButtonsLED(void); void testButtonsLCD(void); void testI2Crap(void); void testCLKRegs(void); void testOutlets(void); void testRemote(void); //TEST// /* button input ports */ #define LEFT PTA_PTA1 #define RIGHT PTD_PTD6 #define UP PTD_PTD5 #define DOWN PTD_PTD4 #define SELECT PTD_PTD0 #define THUREG 40 #define FRIREG 48 #define SATREG 56 #define TOTALDEVS 4 //4 devices/outlets total /* This pragma sets the area for allocating variables to the zero page of RAM (0x00 to 0xff) for more efficient access.*/ #pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE unsigned char delay0; unsigned char delay1; unsigned char delay2; /* This pragma sets the area for allocating variables back to the default area of RAM as defined in the PRM file. */ #pragma DATA_SEG DEFAULT /* outlet output ports */ #define OUTLET1 PTB_PTB0 #define OUTLET2 PTB_PTB1 #define OUTLET3 PTB_PTB2 #define OUTLET4 PTB_PTB3 /* LCD */ #define LCD_LINE1 0 #define LCD_LINE2 0x40 /* Addresses for the clock on the I2C bus */ #define CLOCK_WR_ADDR 0xD0 /* clock write address */ #define CLOCK_RD_ADDR 0xD1 /* clock read address */ /* clk reg organized by day of the week */ #define SUNSTART 0x08 //for i2c read/write #define MONSTART 0x10 #define TUESTART 0x18 #define WEDSTART 0x20 #define THUSTART 0x28 #define FRISTART 0x30 #define SATSTART 0x38 #define SUNREG 8 //for clkRegs[] #define MONREG 16 #define TUEREG 24 #define WEDREG 32 const unsigned char stroffhour[] = "Select Off Hour"; const unsigned char stroffmin[] = "Select Off Minute"; const unsigned char stronhour[] = "Select On Hour"; const unsigned char stronmin[] = "Select On Minute"; const unsigned char strweekday[] = "Set Day of the Week"; const unsigned char strsun[] = "Sunday "; const unsigned char strmon[] = "Monday "; const unsigned char strtue[] = "Tuesday "; const unsigned char strwed[] = "Wednesday"; const unsigned char strthu[] = "Thursday "; const unsigned char strfri[] = "Friday "; const unsigned char strsat[] = "Saturday "; const unsigned char strmonth[] = "Set Month"; const unsigned char strjan[] = "January "; const unsigned char strfeb[] = "February "; const unsigned char strmar[] = "March "; const unsigned char strapr[] = "April "; const unsigned char strmay[] = "May "; const unsigned char strjun[] = "June "; const unsigned char strjul[] = "July "; const unsigned char straug[] = "August "; const unsigned char strsep[] = "September"; const unsigned char stroct[] = "October "; const unsigned char strnov[] = "November "; const unsigned char strdec[] = "December "; const unsigned char strdate[] = "Set Date (01-31)"; const unsigned char stryear[] = "Set Year (2000-2099)"; const unsigned char strtimehr[] = "Set Hour (01-12 AM/PM)"; const unsigned char strtimemin[] = "Set Minute (00-59)"; const unsigned char strmanon[] = "Manual Override On"; const unsigned char strmanoff[] = "Manual Override Off"; const unsigned char strohnoes[] = "???"; const unsigned char hexCode[] = "0123456789ABCDEF"; const unsigned char one = 1; const unsigned char zero = 0; const unsigned int thousand = 1000; const unsigned char keeppw = 0xF0; const unsigned char keepcode = 0x0F; const unsigned char password = 0xD0; const unsigned char code0 = 0x00; const unsigned char code1 = 0x01; const unsigned char code2 = 0x02; const unsigned char code3 = 0x03; /* Declare these strings as "const" so they are allocated in ROM */ //TEST// #ifdef NIBBLE_HIGH const unsigned char str1[] = "Hi! Press a button"; #else const unsigned char str1[] = "'lo! Press a button"; #endif const unsigned char str2[] = "...if you DARE"; const unsigned char str3[] = "Dare to press another?"; const unsigned char upstr[] = "you pressed UP!"; const unsigned char downstr[] = "you pressed DOWN!"; const unsigned char leftstr[] = "you pressed LEFT!"; const unsigned char rightstr[] = "you pressed RIGHT!"; const unsigned char selectstr[] = "you pressed SELECT!"; //TEST// const unsigned char clearstr[] = " "; const unsigned char strdurasaver[] = "Duracell DuraSaver "; const unsigned char strprogmenu[] = "Programming Menu"; const unsigned char strprogdev[] = "Program Devices"; const unsigned char strsetclk[] = "Set Clock & Date"; const unsigned char strexit[] = "Exit "; const unsigned char stroutlet[] = "Select Outlet"; const unsigned char strprogday[] = "Select Day of the Week"; const unsigned char swDebounce = 1; //1 for software debounce, 0 for hardware only unsigned char PWCODE; unsigned char PW; unsigned char CODE; unsigned char today; //this is for LCD menu; actual current day of the week is stored in dayofweek (against all common sense, I know) unsigned char timesToday; //keeps track of which day of the week's on/off times are stored in the off/on[] variables unsigned char seconds10, seconds09, minutes10, minutes09, hours10, hours09, pm, dayofweek, date10, date09, months10, months09, years10, years09; //time right now get from clock unsigned char off10hr[TOTALDEVS], off09hr[TOTALDEVS], offmin[TOTALDEVS], offpm[TOTALDEVS], //programmed "off" times, 1 per each of 4 devices on10hr[TOTALDEVS], on09hr[TOTALDEVS], onmin[TOTALDEVS], onpm[TOTALDEVS]; //programmed "on" times, 1 per each of 4 devices /* manual override - 0 is off, 1 is on (default is off) */ unsigned char manual[TOTALDEVS]; /* outlets - 0 is off, 1 is on (default is on) */ unsigned char outlet[TOTALDEVS]; unsigned char time[24]; //Day, MO/DD/YR HH:MM xm unsigned char teststr[24]; //to print test statements, variables unsigned char clkRegs[64]; unsigned char dayData[8]; /****************** MAIN ******************/ void main(void) { // EnableInterrupts; /* enable interrupts */ /* include your code here */ CONFIG1_COPD = 1; CONFIG2_IICSEL = 1; // disable COP reset // IIC on PTA2, 3 DDRA_DDRA0 = 1; DDRD_DDRD0 = 0; DDRD_DDRD4 = 0; DDRD_DDRD5 = 0; DDRD_DDRD6 = 0; DDRA_DDRA1 = 0; // Set PTA0 = 1 for output (LED) // clear PTD0 = 0 for input (SELECT button) // clear PTD4 = 0 for input (DOWN button) // clear PTD5 = 0 for input (UP button) // clear PTD6 = 0 for input (RIGHT button) // clear PTA1 = 0 for input (LEFT button) PTA_PTA0 = 1; /* global variables */ //LED off /* Set baud rate to 38,400. Clock = 9.8304MHz. Divisor = 64. */ i2c_init((unsigned char) 3); // Initialize the IIC port sci_init(); // Initialize the SCI port #ifdef NIBBLE_HIGH DDRB = 0xf0; #else DDRB = 0x0f; #endif DDRD = 0x0e; void dummyMain() { del1m(thousand); clearLCD(); del1m(thousand); mainLoop(); } // Set PTB bits 4-7 for output // Set PTB bits 0-3 for output void mainLoop() { unsigned char outletNum = TOTALDEVS; // Set PTD1, 2, and 3 for output initializeLCD(); // Initialize the LCD display //ONLY ONCE//clk_init(); // Initialize the Clock (ONLY HAS TO BE DONE ONCE) //clkRAM_init(); //initialize the clkRegs + initalize the clock RAM (other than time & date) clkRegs_init(); //initialize the clkRegs del1m(thousand); DDRB_DDRB0 = 1; // Set PTB0 = 1 for output (Outlet 1) DDRB_DDRB1 = 1; // Set PTB1 = 1 for output (Outlet 2) DDRB_DDRB2 = 1; // Set PTB2 = 1 for output (Outlet 3) DDRB_DDRB3 = 1; // Set PTB3 = 1 for output (Outlet 4) outlet[0] = 1; OUTLET1 = 1; //Outlet 1 on by default outlet[1] = 1; OUTLET2 = 1; //Outlet 2 on by default outlet[2] = 1; OUTLET3 = 1; //Outlet 3 on by default outlet[3] = 1; OUTLET4 = 1; //Outlet 4 on by default del1m(thousand); timesToday = dayofweek; /* main loop */ while(one) { dummyMain(); } /* please make sure that you never leave this function */ } /********************************************* MAIN LCD MENU *********************************************/ // check for RF remote manual override request if(checkManualOverride() == outletNum) { // check for manual override (off --> on) if(manual[outletNum-1] == 0) { //if manual override currently off manual[outletNum-1] = 1; if(outlet[outletNum-1] == 1) { //outlet 1 is on --> turn it off outlet[outletNum-1] = 0; switch(outletNum) { case 1: OUTLET1 = 0; break; case 2: OUTLET2 = 0; break; case 3: OUTLET3 = 0; break; case 4: OUTLET4 = 0; break; } //end switch //strout(LCD_LINE1, "manv off!"); //del1m(thousand); } else { //outlet 1 is off --> turn it on outlet[outletNum-1] = 1; switch(outletNum) { case 1: OUTLET1 = 1; break; case 2: OUTLET2 = 1; break; case 3: OUTLET3 = 1; break; case 4: OUTLET4 = 1; break; } //end switch //strout(LCD_LINE1, "manv on !"); //del1m(thousand); } } //end if manual override currently off // check for manual override (on --> off) else if(manual[outletNum-1] == 1) { strout(LCD_LINE1, (unsigned char *) strdurasaver); testCLK(); while(one) { del1m(thousand); clearLCD(); getTime(); //update time variables // check for RIGHT button press --> program clock if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released progMenuTime(); } // check for LEFT button press --> program outlets else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released progMenuOutlets(); } //check for UP button press --> turn on manual override else if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released manualOn(); } //check for DOWN button press --> turn off manual override else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released manualOff(); } for(outletNum = TOTALDEVS; outletNum > 0; outletNum--) { //for each device manual[outletNum-1] = 0; } //end if manual override currently on } // check if need to turn off outlet if(outlet[outletNum-1] == 1) { if(manual[outletNum-1] == 0) { if(check_offtime(outletNum) == 1) { outlet[outletNum-1] = 0; //OUTLET1 = 0; //OFF switch(outletNum) { case 1: OUTLET1 = 0; //off break; case 2: OUTLET2 = 0; //off break; case 3: OUTLET3 = 0; //off break; case 4: OUTLET4 = 0; //off break; } //end switch //strout(LCD_LINE1, "time off!"); //del1m(thousand); } } } // check if need to turn on outlet else if(outlet[outletNum-1] == 0) { if(manual[outletNum-1] == 0) { if(check_ontime(outletNum) == 1) { outlet[outletNum-1] = 1; //OUTLET1 = 1; //ON switch(outletNum) { case 1: OUTLET1 = 1; //on break; case 2: OUTLET2 = 1; //on break; case 3: OUTLET3 = 1; //on break; case 4: OUTLET4 = 1; //on break; } //end switch //strout(LCD_LINE1, "time on !"); //del1m(thousand); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch } } } else { //idle --> display time and date //testCLK(); LCD_Time(); } //end idle } //end for each device } //end while(one) } void LCD_Time() { //getTime(); del1m(2); strout(LCD_LINE1, (unsigned char *) strdurasaver); del1m(2); testCLK(); //del1m(500); } void manualOn() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanon); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case 1: del1m(2); else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN strout(LCD_LINE2, "confirmed - another?"); del1m(500); clearLCD(); else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released }//end if choice != 0 if(choice != 0) { manual[choice - 1] = 1; //turn on manual override if(outlet[choice - 1] == 1) { //outlet is on --> turn it off outlet[choice - 1] = 0; switch(choice) { case 1: OUTLET1 = 0; //OFF break; case 2: OUTLET2 = 0; //OFF break; case 3: OUTLET3 = 0; //OFF break; case 4: OUTLET4 = 0; //OFF break; } //end switch //strout(LCD_LINE1, "manv off!"); //del1m(thousand); } //end if outlet is on --> off else if(outlet[choice - 1] == 0) { //outlet is off --> turn it on outlet[choice - 1] = 1; switch(choice) { case 1: OUTLET1 = 1; //ON break; case 2: OUTLET2 = 1; //ON break; case 3: OUTLET3 = 1; //ON break; case 4: OUTLET4 = 1; //ON break; } //end switch //strout(LCD_LINE1, "manv on !"); //del1m(thousand); } //end if outlet off --> on else if(choice == 0) { repeat = '0'; break; } } //end if SELECT } //end repeat } void manualOff() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case 1: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) strmanoff); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch break; } } //end if SELECT } //end repeat } unsigned int qualifyTime(unsigned char outletNum, unsigned char ontime) { unsigned int qualval, q10hr, q09hr, q10min, q09min, qpm; getTime(); //update time variables getDevData(dayofweek); //update on/off times for current day if(outletNum == 0) { //NOW q10hr = hours10 & 0x01; q09hr = hours09 & 0x0f; q10min = minutes10 & 0x07; q09min = minutes09 & 0x0f; qpm = pm & 0x01; } else if((outletNum != 0) && (ontime == 1)) { q10hr = on10hr[outletNum-1] & 0x01; q09hr = on09hr[outletNum-1] & 0x0f; q10min = onmin[outletNum-1] & 0x07; q09min = 0; qpm = onpm[outletNum-1] & 0x01; } else { q10hr = off10hr[outletNum-1] & 0x01; q09hr = off09hr[outletNum-1] & 0x0f; q10min = offmin[outletNum-1] & 0x07; q09min = 0; qpm = offpm[outletNum-1] & 0x01; } if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released if((q10hr == 1) && (q09hr == 2)) { //12xm is always < anything else xm //qualval = (q10hr * 0) + (q09hr * 0) + (q10min * 10) + (q09min * 1) + (qpm * 1200); qualval = (q10min * 10) + (q09min) + (qpm * 1200); } else { //qualval = (q10hr * 1000) + (q09hr * 100) + (q10min * 10) + (q09min * 1) + (qpm * 1200); qualval = (q10hr * 1000) + (q09hr * 100) + (q10min * 10) + (q09min) + (qpm * 1200); } return qualval; if(choice != 0) { manual[choice - 1] = 0; //turn on manual override strout(LCD_LINE2, "confirmed - another?"); del1m(500); clearLCD(); }//end if choice != 0 } else if(choice == 0) { repeat = '0'; /* Check Off Time * This function checks if the given outlet * is scheduled to be off right now */ unsigned char check_offtime(unsigned char outletNum){ unsigned int qON, qOFF, qNOW; qON = qualifyTime(outletNum, 1); qOFF = qualifyTime(outletNum, 0); qNOW = qualifyTime(0, 1); //strout(LCD_LINE1, "qON == qOFF"); //del1m(thousand); return 1; } if(qOFF < qON) { //turn off then turn on (usually on) if((qNOW < qOFF) || (qNOW >= qON)) { //time now is before off-time or after on-time //strout(LCD_LINE1, "outside off-time"); //del1m(thousand); return 1; } } if(qON == qOFF) { //off and on times are the same --> default ON //strout(LCD_LINE1, "qOFF == qON"); //del1m(thousand); return 0; } if(qOFF < qON) { //turn off then turn on (usually on) if((qNOW >= qOFF) && (qNOW < qON)) { //time now is after off-time but before on-time //strout(LCD_LINE1, "btwn off & on"); //del1m(thousand); return 1; } } if(qON < qOFF) { //turn on then turn off (usually off) if((qNOW < qON) || (qNOW >= qOFF)) { //time now is before on-time or after off-time //strout(LCD_LINE1, "outside on-time"); //del1m(thousand); return 1; } } return 0; } /* Check On Time * This function checks if the given outlet * is scheduled to be on right now */ unsigned char check_ontime(unsigned char outletNum){ unsigned int qON, qOFF, qNOW; qON = qualifyTime(outletNum, 1); qOFF = qualifyTime(outletNum, 0); qNOW = qualifyTime(0, 1); if(qON == qOFF) { //off and on times are the same --> default ON if(qON < qOFF) { //turn on then turn off (usually off) if((qNOW >= qON) && (qNOW < qOFF)) { //time now is after on-time but before off-time //strout(LCD_LINE1, "btwn off and on"); //del1m(thousand); return 1; } } return '0'; } /* Check for Manual Override * Returns Outlet Number of Outlet Toggling Manual Override * Returns 0 if no Outlet is requesting manual override */ unsigned char checkManualOverride() { if(SCS1_SCRF) { //check flag PWCODE = SCDR; PW = PWCODE&keeppw; if(PW == password) { CODE = PWCODE&keepcode; if(CODE == code0) { return 1; } //end if for code0 check else if(CODE == code1) { return 2; } //end elseif for code1 check else if(CODE == code2) { return 3; } //end else if for code1 check else if(CODE == code3) { return 4; } //end else if for code3 check else { return 0; }//do nothing if code is not valid } //end if for password checking else { return 0; } //do nothing if password is not correct } //end if for serial input data register full check while(repeat == '1') { if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released programDEV(); repeat = '0'; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //LCDMenu(); repeat = '0'; } // end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //progMenuTime(); repeat = '0'; } //end if LEFT } //end while repeat } void progMenuTime() { unsigned char repeat = '1'; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strprogmenu); del1m(2); strout(LCD_LINE2, (unsigned char *) strsetclk); while(repeat == '1') { if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released programCLK(); repeat = '0'; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //progMenuOutlets(); repeat = '0'; } // end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //LCDMenu(); repeat = '0'; } //end if LEFT } //end while repeat } void progMenuOutlets() { unsigned char repeat = '1'; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strprogmenu); del1m(2); strout(LCD_LINE2, (unsigned char *) strprogdev); Device 3: on: 0x0D Device 4: off: 0x0E Device 4: on: 0x0F * Monday: 0x10 - 0x17 * Tuesday: 0x18 - 0x1F * Wednesday: 0x20 - 0x27 * Thursday: 0x28 - 0x2F * Friday: 0x30 - 0x37 * Saturday: 0x38 - 0x3F * Get Device Data * gets and saves updated on/off times for given day * Reg 1: Off, Reg 2: On * Bit 7 - 4: Hours (1-12 * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM */ void getDevData(unsigned char day) { //day was formerly today, until today was made global unsigned char x; unsigned char offset;// = (deviceNum - 1) * 2; unsigned char i = TOTALDEVS; //clearLCD(); // (1) read data from clock registers switch(hexCode[day]) { case '1': /********** SUNDAY **********/ //for(x = 8; x > 0; x--) { //teststr[0] = hexCode[x]; //teststr[1] = ' '; //teststr[2] = hexCode[SUNREG + x - 1]; //teststr[3] = ' '; //teststr[4] = hexCode[(clkRegs[SUNREG+x-1] >> 4) & 0x0f]; //teststr[5] = hexCode[(clkRegs[SUNREG+x-1]) & 0x0f]; //teststr[6] = '\0'; //strout(LCD_LINE2, teststr); //del1m(thousand); // dayData[x-1] = clkRegs[SUNREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, SUNSTART); break; case '2': /********** MONDAY **********/ //for(x = 8; x > 0; x--) { // dayData[x-1] = clkRegs[MONREG+x-1]; //} } /********************************************* FETCH DEVICE DATA STORED ON RTC RAM *********************************************/ /* * ---Time & Date--0x00 = clkRegs[0]: Seconds 0x01 = clkRegs[1]: Minutes 0x02 = clkRegs[2]: Hours 0x03 = clkRegs[3]: 0x04 = clkRegs[4]: 0x05 = clkRegs[5]: 0x06 = clkRegs[6]: Year 0x07 = clkRegs[7]: sqwout.... * ---Storage of On/Off times on RTC:--* Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * x2 times per device x7 days x4 devices = 56 bytes (total RAM!) * * Sunday: 0x08 - 0x0F, offset: (deviceNumber - 1) * 2 Device 1: off: 0x08 Device 1: on: 0x09 Device 2: off: 0x0A Device 2: on: 0x0B Device 3: off: 0x0C i2c_read2(CLOCK_RD_ADDR, dayData, 8, MONSTART); break; case '3': /********** TUESDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[TUEREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, TUESTART); break; case '4': /********** WEDNESDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[WEDREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, WEDSTART); break; case '5': /********** THURSDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[THUREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, THUSTART); break; case '6': /********** FRIDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[FRIREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, FRISTART); break; case '7': /********** SATURDAY **********/ //for(x = 8; x > 0; x--) { //dayData[x-1] = clkRegs[SATREG+x-1]; //} i2c_read2(CLOCK_RD_ADDR, dayData, 8, SATSTART); break; } //end switch // (2) for each device.... for(; i > 0; i--) { //device 4 --> 3 --> 2 --> 1 offset = (i - 1) * 2; //index offset for dayData, based on device # //e.g. dev 4 is stored at 6 and 7 (4 - 1 = 3 * 2 = 6) //e.g. dev 3 is stored at 4 and 5 (3 - 1 = 2 * 2 = 4) //e.g. dev 2 is stored at 2 and 3 (2 - 1 = 1 * 2 = 2) //e.g. dev 1 is stored at 0 and 1 (1 - 1 = 0 * 2 = 0) // (2a) process "off" time if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'A') { off10hr[i-1] = '1'; off09hr[i-1] = '0'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'B') { off10hr[i-1] = '1'; off09hr[i-1] = '1'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'C') { off10hr[i-1] = '1'; off09hr[i-1] = '2'; } else { off10hr[i-1] = '0'; off09hr[i-1] = hexCode[(dayData[offset] >> 4) & 0x0f]; //up to 9 } offpm[i-1] = hexCode[(dayData[offset] & 0x01)]; offmin[i-1] = hexCode[(dayData[offset] & 0x0e) >> 1]; //all but last bit (bits 3-1) // (2b) process "on" time if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'A') { on10hr[i-1] = '1'; on09hr[i-1] = '0'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'B') { on10hr[i-1] = '1'; on09hr[i-1] = '1'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'C') { on10hr[i-1] = '1'; on09hr[i-1] = '2'; } else { on10hr[i-1] = '0'; on09hr[i-1] = hexCode[(dayData[offset+1] >> 4) & 0x0f]; //up to 9 } onpm[i-1] = hexCode[(dayData[offset+1] & 0x01)]; onmin[i-1] = hexCode[(dayData[offset+1] & 0x0e) >> 1]; //all but last bit (bits 3-1) teststr[14] = 'M'; teststr[15] = '\0'; del1m(thousand); */ } //end for each device timesToday = day; } /********************************************* PROGRAM DEVICE MAIN MENU *********************************************/ void programDEV() { unsigned char choice = 0; //0 = exit unsigned char repeat = 1; clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); while(repeat) { switch(choice) { case 0: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case 1: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 1"); break; case 2: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 2"); break; case 3: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 3"); /*teststr[0] = off10hr[i - 1]; teststr[1] = off09hr[i - 1]; teststr[2] = ':'; teststr[3] = offmin[i - 1]; teststr[4] = '0'; teststr[5] = offpm[i - 1]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[i - 1]; teststr[9] = on09hr[i - 1]; teststr[10] = ':'; teststr[11] = onmin[i - 1]; teststr[12] = '0'; teststr[13] = onpm[i - 1]; break; case 4: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet 4"); break; default: del1m(2); strout(LCD_LINE1, (unsigned char *) stroutlet); del1m(2); strout(LCD_LINE2, (unsigned char *) "Outlet ?"); break; } //end switch if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //choice = (choice + 1) % 5; if(choice == 4) choice = 0; else choice++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //choice = (choice - 1) % 5; if(choice == 0) choice = 4; else choice--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //repeat = '0'; if(choice != 0) { repeat = '0'; programOutlet(choice); break; } } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released //repeat = 0; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released //repeat = 0; } //end if LEFT } //end repeat } /********************************************* PROGRAM OUTLET ON/OFF TIME ON RTC *********************************************/ /* Program Outlet * User will choose which device to program * prior to calling this function. * This function will go through the LCD menus * to view/change on/off times for outletNum. */ void programOutlet(unsigned char outletNum) { unsigned char repeat = '1', exit = '0'; unsigned char tempvar10, tempvar09, temppm, regOffset, addrOffset, temp; unsigned char tempchars[8]; tempchars[7] = '\0'; /* CHANGE DAY OF THE WEEK */ while(exit == '0') { clearLCD(); del1m(2); strout(LCD_LINE1, (unsigned char *) strprogday); today = 0; //start at exit --> user can choose a day of the week from there repeat = '1'; while(repeat == '1') { del1m(100); switch(hexCode[today]) { case '0': //done/exit del1m(2); strout(LCD_LINE2, (unsigned char *) strexit); break; case '1': //Sunday del1m(2); strout(LCD_LINE2, (unsigned char *) strsun); break; case '2': //Monday del1m(2); strout(LCD_LINE2, (unsigned char *) strmon); break; case '3': //Tuesday del1m(2); strout(LCD_LINE2, (unsigned char *) strtue); break; case '4': //Wednesday del1m(2); strout(LCD_LINE2, (unsigned char *) strwed); break; case '5': //Thursday del1m(2); strout(LCD_LINE2, (unsigned char *) strthu); break; case '6': //Friday del1m(2); strout(LCD_LINE2, (unsigned char *) strfri); break; case '7': //Saturday del1m(2); strout(LCD_LINE2, (unsigned char *) strsat); break; default: //unknown?? clearLCD(); del1m(2); strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(dayofweek) if(today == 0) { //exit back to choose outlet exit = '1'; //programDEV(); } else { //no exit //del1m(thousand); getDevData(today); //update all the variablesssssss regOffset = (outletNum - 1) * 2; //addrOffset = (regOffset >> 4) & 0x0f; addrOffset = (regOffset) & 0x0f; } break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(today == 7) today = 0; //--> exit else today++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(today == 0) today = 7; else today--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = '0'; temppm = 'A'; else if(offpm[outletNum - 1] == '1') temppm = 'P'; else temppm = '?'; while(repeat == '1') { del1m(100); tempchars[0] = tempvar10; tempchars[1] = tempvar09; tempchars[2] = temppm; tempchars[3] = 'M'; tempchars[4] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } //end if 11 tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 if(tempvar09 == '9') { //9AM --> 10AM, 9PM --> 10PM tempvar09 = '0'; tempvar10 = '1'; } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM if(exit == '1') { break; } /* CHANGE OFF HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stroffhour); tempvar10 = off10hr[outletNum - 1]; tempvar09 = off09hr[outletNum - 1]; if(offpm[outletNum - 1] == '0') tempvar09 = '9'; tempvar10 = '0'; } //end if 10 else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1 else if (tempvar10 == '0') { //its 01-09 if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 off10hr[outletNum - 1] = tempvar10; off09hr[outletNum - 1] = tempvar09; if(temppm == 'A') offpm[outletNum - 1] = '0'; else if(temppm == 'P') offpm[outletNum - 1] = '1'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 // /* del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 offmin[outletNum - 1] = tempvar10; // /* temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); } //end if LEFT }//end while(repeat) /* CHANGE OFF MINUTE */ //choose among: 00, 10, 20, 30, 40, 50 clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; tempvar09 = '0'; del1m(2); strout(LCD_LINE1, (unsigned char *) stroffmin); tempvar10 = offmin[outletNum - 1]; while(repeat == '1') { del1m(100); tempchars[0] = off10hr[outletNum - 1]; tempchars[1] = off09hr[outletNum - 1]; tempchars[2] = ':'; tempchars[3] = tempvar10; tempchars[4] = '0'; if(offpm[outletNum - 1] == '0') tempchars[5] = 'A'; else if(offpm[outletNum - 1] == '1') tempchars[5] = 'P'; else tempchars[5] = '?'; tempchars[6] = 'M'; tempchars[7] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //tempvar10 = (tempvar10 + 1)%6; if(tempvar10 == '5') tempvar10 = '0'; else tempvar10++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //tempvar10 = (tempvar10 - 1)%6; if(tempvar10 == '0') tempvar10 = '5'; else tempvar10--; break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) /* CHANGE ON HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; tempchars[4] = ' '; tempchars[5] = ' '; tempchars[6] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stronhour); tempvar10 = on10hr[outletNum - 1]; tempvar09 = on09hr[outletNum - 1]; if(onpm[outletNum - 1] == '0') temppm = 'A'; else if(onpm[outletNum - 1] == '1') temppm = 'P'; else temppm = '?'; while(repeat == '1') { del1m(100); tempchars[0] = tempvar10; tempchars[1] = tempvar09; tempchars[2] = temppm; tempchars[3] = 'M'; tempchars[4] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } //end if 11 tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 if(tempvar09 == '9') { //9AM --> 10AM, 9PM --> 10PM tempvar09 = '0'; tempvar10 = '1'; } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM tempvar09 = '9'; tempvar10 = '0'; } //end if 10 else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) //*/ repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) /* CHANGE ON MINUTE */ if(temppm == 'A') temppm = 'P'; else if(temppm == 'P') temppm = 'A'; } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1 else if (tempvar10 == '0') { //its 01-09 if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 on10hr[outletNum - 1] = tempvar10; on09hr[outletNum - 1] = tempvar09; if(temppm == 'A') onpm[outletNum - 1] = '0'; else if(temppm == 'P') onpm[outletNum - 1] = '1'; // /* temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); //choose among: 00, 10, 20, 30, 40, 50 clearLCD(); repeat = '1'; tempvar09 = '0'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; del1m(2); strout(LCD_LINE1, (unsigned char *) stronmin); tempvar10 = onmin[outletNum - 1]; while(repeat == '1') { del1m(100); tempchars[0] = on10hr[outletNum - 1]; tempchars[1] = on09hr[outletNum - 1]; tempchars[2] = ':'; tempchars[3] = tempvar10; tempchars[4] = '0'; if(onpm[outletNum - 1] == '0') tempchars[5] = 'A'; else if(onpm[outletNum - 1] == '1') tempchars[5] = 'P'; else tempchars[5] = '?'; tempchars[6] = 'M'; tempchars[7] = '\0'; del1m(2); strout(LCD_LINE2, tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released //tempvar10 = (tempvar10 + 1)%6; if(tempvar10 == '5') tempvar10 = '0'; else tempvar10++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released //tempvar10 = (tempvar10 - 1)%6; if(tempvar10 == '0') tempvar10 = '5'; else tempvar10--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register // (1) update clkRegs for this device, day // (2) update RTC regs with i2c_write2 i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) //*/ onmin[outletNum - 1] = tempvar10; // /* temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 del1m(100); switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; while(!SELECT) {} //so can look at while(SELECT) {} //debounce //TEST// repeat = '1'; //go back into choosing day of the week } //while !exit repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) //TEST// del1m(1); getDevData(today); teststr[0] = off10hr[outletNum - 1]; teststr[1] = off09hr[outletNum - 1]; teststr[2] = ':'; teststr[3] = offmin[outletNum - 1]; teststr[4] = '0'; teststr[5] = offpm[outletNum - 1]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[outletNum - 1]; teststr[9] = on09hr[outletNum - 1]; teststr[10] = ':'; teststr[11] = onmin[outletNum - 1]; teststr[12] = '0'; teststr[13] = onpm[outletNum - 1]; teststr[14] = 'M'; teststr[15] = '\0'; del1m(2); strout(LCD_LINE1, "is this what you saved?"); del1m(2); strout(LCD_LINE2, teststr); case '6': //Friday strout(LCD_LINE2, (unsigned char *) strfri); break; case '7': //Saturday strout(LCD_LINE2, (unsigned char *) strsat); break; default: //unknown?? strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(dayofweek) } /********************************************* PROGRAM THE DATE AND TIME ON RTC *********************************************/ /* Program Clock * This function will go through the LCD menus * to view/change the set time and date. */ void programCLK() { unsigned char repeat = '1'; unsigned char tempvar, tempvar10, tempvar09, temppm; unsigned char tempchars[5] = " "; tempchars[4] = '\0'; getTime(); //get initial values /* CHANGE DAY OF THE WEEK */ clearLCD(); strout(LCD_LINE1, (unsigned char *) strweekday); tempvar = hexCode[dayofweek]; while(repeat == '1') { switch(tempvar) { case '1': //Sunday strout(LCD_LINE2, (unsigned char *) strsun); break; case '2': //Monday strout(LCD_LINE2, (unsigned char *) strmon); break; case '3': //Tuesday strout(LCD_LINE2, (unsigned char *) strtue); break; case '4': //Wednesday strout(LCD_LINE2, (unsigned char *) strwed); break; case '5': //Thursday strout(LCD_LINE2, (unsigned char *) strthu); break; if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar == '7') //saturday tempvar = '1'; //--> sunday else tempvar++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar == '1') //sunday tempvar = '7'; //--> saturday else tempvar--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[3] = ((tempvar) & 0x0f); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[3], 1, 3); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //while(repeat) /* CHANGE MONTH */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) strmonth); tempvar10 = hexCode[months10]; tempvar09 = hexCode[months09]; while(repeat == '1') { if(tempvar10 == '1') { switch(tempvar09) { case '0': //10 October strout(LCD_LINE2, (unsigned char *) stroct); break; case '1': //11 November strout(LCD_LINE2, (unsigned char *) strnov); break; case '2': //12 December strout(LCD_LINE2, (unsigned char *) strdec); break; } //end switch(months09) } //end if months10 == 1 else { //months10 == 0 switch(tempvar09) { case '1': //1 January strout(LCD_LINE2, (unsigned char *) strjan); break; case '2': //2 February strout(LCD_LINE2, (unsigned char *) strfeb); break; case '3': //3 March strout(LCD_LINE2, (unsigned char *) strmar); break; case '4': //4 April strout(LCD_LINE2, (unsigned char *) strapr); break; case '5': //5 May strout(LCD_LINE2, (unsigned char *) strmay); break; case '6': //6 June strout(LCD_LINE2, (unsigned char *) strjun); break; case '7': //7 July strout(LCD_LINE2, (unsigned char *) strjul); break; case '8': //8 August strout(LCD_LINE2, (unsigned char *) straug); //update the clock register clkRegs[5] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[5], 1, 5); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//while(repeat) /* CHANGE DAY OF THE MONTH */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) strdate); tempvar10 = hexCode[date10]; tempvar09 = hexCode[date09]; while(repeat == '1') { tempchars[0] = tempvar10; tempchars[1] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); //while(!UP && !DOWN && !SELECT); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '3') { //31 days: jan (01), march (03), may (05), july (07), oct (10), dec (12); 30 days: april (04), june (06), aug (08), sept (09), nov (11) if(hexCode[months10] == '0') { if(hexCode[months09] == '2' || hexCode[months09] == '4' || hexCode[months09] == '6') { //if february, april, june tempvar10 = '0'; tempvar09 = '1'; } else if(hexCode[months09] == '1' || hexCode[months09] == '3' || hexCode[months09] == '5' || hexCode[months09] == '7') { //january, march, may, july if(tempvar09 == '1') { tempvar10 = '0'; break; case '9': //9 September strout(LCD_LINE2, (unsigned char *) strsep); break; default: //unknown?? strout(LCD_LINE2, (unsigned char *) strohnoes); } //end switch(months09) } //end else months10 == 0 //while(!UP && !DOWN && !SELECT); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { if(tempvar09 == '0' || tempvar09 == '1') tempvar09++; else { //12 December --> 01 January tempvar10 = '0'; tempvar09 = '1'; } //months09 != 0 } //months10 ==1 else { //months10 == 0 if(tempvar09 <= '8') tempvar09++; else { //09 September --> 10 October tempvar10 = '1'; tempvar09 = '0'; } //months09 > 8 } //months10 == 1 } //if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { if(tempvar09 == '2' || tempvar09 == '1') tempvar09--; else { //10 October --> 09 September tempvar10 = '0'; tempvar09 = '9'; } } //months10 ==1 else { if(tempvar09 > '1') tempvar09--; else { //01 January --> 12 December tempvar10 = '1'; tempvar09 = '2'; } //else months09 == 1 } //else months10 == 0 } //if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released tempvar09 = '1'; } else if(tempvar09 == '0') { tempvar09 = '1'; } } //end if january, march, may, july } //end if months10 == 0 (january - september except february) else if(hexCode[months10] == '1') { if(hexCode[months09] == '1') { //november tempvar10 = '0'; tempvar09 = '1'; } else if(hexCode[months09] == '0' || hexCode[months09] == '2') { //october or december if(tempvar09 == '1') { tempvar10 = '0'; tempvar09 = '1'; } else if(tempvar09 == '0') { tempvar09 = '1'; } } //end if months10 == 1 (october or november or december) } //end if months10 == 1 } //end if date10 == 3 else if(tempvar10 == '2') { if(tempvar09 == '9') { if(hexCode[months10] == '0' && hexCode[months09] == '2') { //february tempvar10 = '0'; tempvar09 = '1'; } else { //not february tempvar10 = '3'; tempvar09 = '0'; } } //end if date09 == 9 else { //date09 < 9 tempvar09++; } //end if date09 < 9 } //end if date10 == 2 else if(tempvar10 == '1' || tempvar10 == '0') { //date10 = 1 or 0 if(tempvar09 == '9') { tempvar10++; tempvar09 = '0'; } //end if date09 == 9 else { tempvar09++; } } //end if date10 == 1 || 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '0' && tempvar09 == '1') { if(hexCode[months10] == '0') { //months: january-september if(hexCode[months09] == '2') { //february --> max 29 days tempvar10 = '2'; tempvar09 = '9'; } //end if february else if(hexCode[months09] == '1' || hexCode[months09] == '3' || hexCode[months09] == '5' || hexCode[months09] == '7' || hexCode[months09] == '8') { //months with 31 days (jan, mar, may, july, aug) tempvar10 == '3'; tempvar09 == '1'; } //end if month with 31 days else if(hexCode[months09] == '4' || hexCode[months09] == '6' || hexCode[months09] == '9') { //months with 30 days (april, june, sept) tempvar10 == '3'; tempvar09 == '0'; } //end if month with 30 days } //end if months10 = 0 else if(hexCode[months10] == '1') { if(hexCode[months09] == '1') { //november has 30 days tempvar10 = '3'; tempvar09 = '0'; } else if(hexCode[months09] == '0' || hexCode[months09] == '2') { //october and december have 31 days tempvar10 = '3'; tempvar09 = '1'; } } //end if months10 = 1 } //end if date == 01 else if(date09 == 0) { //date != 01, date09 == 0 tempvar10--; tempvar09--; } else { //date != 01, date09 > 0 tempvar09--; } } //if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released if(tempvar09 == '0') { tempvar09 = '9'; if(tempvar10 == '0') tempvar10 = '9'; else tempvar10--; } //end years09 == 0 else tempvar09--; } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[6] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[6], 1, 6); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) /* CHANGE HOUR */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; strout(LCD_LINE1, (unsigned char *) strtimehr); tempvar10 = hexCode[hours10]; tempvar09 = hexCode[hours09]; tempchars[0] = tempvar10; //NEW// tempchars[1] = tempvar09; if(hexCode[pm] == '1') temppm = 'P'; //NEW// else temppm = 'A'; //NEW// tempchars[2] = temppm; //update the clock register clkRegs[4] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[4], 1, 4); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//while(repeat) /* CHANGE YEAR */ clearLCD(); repeat = '1'; strout(LCD_LINE1, (unsigned char *) stryear); tempchars[0] = '2'; tempchars[1] = '0'; tempvar10 = hexCode[years10]; tempvar09 = hexCode[years09]; while(repeat == '1') { tempchars[2] = tempvar10; tempchars[3] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar09 == '9') { tempvar09 = '0'; if(tempvar10 == '9') tempvar10 = '0'; else tempvar10++; } //end years09 == 9 else tempvar09++; } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released tempchars[3] = 'M'; while(repeat == '1') { tempchars[0] = tempvar10; //NEW// tempchars[1] = tempvar09; tempchars[2] = temppm; //NEW// tempchars[3] = 'M'; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 //NEW// if(tempvar09 == '2') { //12AM --> 01AM, 12PM --> 01PM tempvar09 = '1'; tempvar10 = '0'; } //end if 12 else { //its 10 or 11 if(tempvar09 == '1') { //11PM --> 12AM, 11AM --> 12PM //OLD//if(tempvar10 == '1') tempvar10 = '3'; //OLD//else if(tempvar10 == '3') tempvar10 = '1'; if(temppm == 'A') temppm = 'P'; //NEW// else if(temppm == 'P') temppm = 'A'; //NEW// } tempvar09++; } //end if 10 or 11 } //end hour MSB is 1 else if(tempvar10 == '0') { //its 01-09 //NEW// if(tempvar09 == '9') { tempvar09 = '0'; tempvar10 = '1'; //9AM --> 10AM, 9PM --> 10PM } //end if tempvar09 == 9 else { //tempvar09 between 1 and 8 --> just increment by 1 tempvar09++; } } //end hour MSB is 0 } //end if UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar10 == '1') { //its 10, 11, or 12 if(tempvar09 == '0') { //10AM --> 09AM, 10PM --> 09PM tempvar09 = '9'; tempvar10 = '0'; } //end if 10 else { //its 11 or 12 if(tempvar09 == '2') { //12PM --> 11AM, 12AM --> 11PM //OLD//if(tempvar10 == '3') tempvar10 = '1'; //OLD//else if(tempvar10 == '1') tempvar10 = '3'; if(temppm == 'A') temppm = 'P'; //NEW// else if(temppm == 'P') temppm = 'A'; //NEW// } tempvar09--; } //end if 11 or 12 } //end hour MSB is 1s else if(tempvar10 == '0') { //its 01-09 //NEW// if(tempvar09 == '1') { //01AM --> 12AM, 01PM --> 12PM tempvar09 = '2'; //tempvar09++; tempvar10 = '1'; } else { //its between 02 and 09 --> just decrement by 1 tempvar09--; } } //end hour MSB is 0 } //end if DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register if(temppm == 'A') pm = 0; else pm = 1; clkRegs[2] = (((0x01 & pm) << 5) | ((0x01 & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[2], 1, 2); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT }//end while(repeat) } //end DOWN else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released //update the clock register clkRegs[1] = (((0x0f & tempvar10) << 4) | (0x0f & tempvar09)); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[1], 1, 1); repeat = '0'; break; } //end if SELECT else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released repeat = '0'; break; } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released repeat = '0'; break; } //end if LEFT } //end while(repeat) strout(LCD_LINE1, "Select to Return Home"); while(!SELECT) { testCLK(); del1m(1000); } while(SELECT){} //debounce } /* This program tests the DS1307 Real Time Clock with I2C interface * An LED on pin 2 of the MC908JL16 will blink every other second * An LED connected to the SQW output of the Clock will blink at 1Hz * The LCD will display the time */ void testCLK() { //unsigned char time[24]; //Day, MO/DD/YR HH:MM xm time[23] = '\0'; del1m(1); i2c_read2(CLOCK_RD_ADDR, clkRegs, 8, 0); //read all 8 main registers /* CHANGE MINUTE */ clearLCD(); repeat = '1'; tempchars[0] = ' '; tempchars[1] = ' '; tempchars[2] = ' '; tempchars[3] = ' '; strout(LCD_LINE1, (unsigned char *) strtimemin); tempvar10 = hexCode[minutes10]; tempvar09 = hexCode[minutes09]; while(repeat == '1') { tempchars[0] = tempvar10; tempchars[1] = tempvar09; strout(LCD_LINE2, (unsigned char *) tempchars); if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released if(tempvar09 == '9') { if(tempvar10 == '5') { tempvar10 = '0'; tempvar09 = '0'; } else { //minutes10 < 5 && minutes09 == 9 tempvar10++; tempvar09 = '0'; } } else { //minutes09 < 9 tempvar09++; } } //end UP else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released if(tempvar09 == '0') { if(tempvar10 == '0') { tempvar10 = '5'; tempvar09 = '9'; } else { //minutes10 > 0 && minutes09 == 0 tempvar10--; tempvar09 = '9'; } } else { //minutes09 > 0 tempvar09--; } // day of the week dayofweek = (clkRegs[3] & 0x07); //only care about 3 lowest bits switch(hexCode[dayofweek]) { case '1': //Sunday time[0] = 'S'; time[1] = 'u'; time[2] = 'n'; break; case '2': //Monday time[0] = 'M'; time[1] = 'o'; time[2] = 'n'; break; case '3': //Tuesday time[0] = 'T'; time[1] = 'u'; time[2] = 'e'; break; case '4': //Wednesday time[0] = 'W'; time[1] = 'e'; time[2] = 'd'; break; case '5': //Thursday time[0] = 'T'; time[1] = 'h'; time[2] = 'u'; break; case '6': //Friday time[0] = 'F'; time[1] = 'r'; time[2] = 'i'; break; case '7': //Saturday time[0] = 'S'; time[1] = 'a'; time[2] = 't'; break; default: //unknown?? time[0] = '?'; time[1] = '?'; time[2] = '?'; } time[3] = ','; time[4] = ' '; seconds10 = ((clkRegs[0] >> 4) & 0x07); //only 3 10's bits seconds09 = (clkRegs[0] & 0x0f); time[20] = hexCode[seconds10]; time[21] = hexCode[seconds09]; if(hexCode[pm] == '0') time[22] = 'A'; else if(hexCode[pm] == '1') time[22] = 'P'; else time[22] = '?'; time[23] = 'M'; //month months10 = (clkRegs[5] >> 4) & 0x01; //only 1 10's bit months09 = (clkRegs[5] & 0x0f); time[5] = hexCode[months10]; time[6] = hexCode[months09]; time[7] = '/'; //day of the month date10 = (clkRegs[4] >> 4) & 0x03; //only 2 10's bits date09 = (clkRegs[4] & 0x0f); time[8] = hexCode[date10]; time[9] = hexCode[date09]; time[10] = '/'; //year years10 = (clkRegs[6] >> 4) & 0x0f; years09 = (clkRegs[6] & 0x0f); time[11] = hexCode[years10]; time[12] = hexCode[years09]; time[13] = ' '; //hour /*if((hexCode[(clkRegs[2] >> 4) & 0x0f] == '0') || (hexCode[(clkRegs[2] >> 4) & 0x0f] == '1')) { pm = 'A'; } else if((hexCode[(clkRegs[2] >> 4) & 0x0f] == '2') || (hexCode[(clkRegs[2] >> 4) & 0x0f] == '3')) { pm = 'P'; } */ pm = ((clkRegs[2] >> 5) & 0x01); hours10 = (clkRegs[2] >> 4) & 0x01; //1st bit only - //NEW// hours09 = (clkRegs[2] & 0x0f); time[14] = hexCode[hours10]; //NEW// time[15] = hexCode[hours09]; time[16] = ':'; //minute minutes10 = (clkRegs[1] >> 4) & 0x07; //only 3 10's bits minutes09 = (clkRegs[1] & 0x0f); time[17] = hexCode[minutes10]; time[18] = hexCode[minutes09]; time[19] = ':'; /* turn on LED in port A bit 0 for n msec, then turn off */ void blink(int n) { PTA_PTA0 = 0; //turn on LED del1m(n); //leave on n msec PTA_PTA0 = 1; //turn off LED } /* void testOutlets() { del1m(2); while(one) { OUTLET1 = 1; strout(LCD_LINE1, "outlet 1"); del1m(thousand); OUTLET1 = 0; OUTLET2 = 1; strout(LCD_LINE1, "outlet 2"); del1m(thousand); OUTLET2 = 0; OUTLET3 = 1; strout(LCD_LINE1, "outlet 3"); del1m(thousand); OUTLET3 = 0; del1m(2); strout(LCD_LINE2, (unsigned char *) time); } /* Get Time * Retrieves Time & Date Register Values * Saves to Global Variables */ void getTime() { i2c_read2(CLOCK_RD_ADDR, clkRegs, 7, 0); seconds10 = ((clkRegs[0] >> 4) & 0x07); //only 3 10's bits seconds09 = (clkRegs[0] & 0x0f); minutes10 = (clkRegs[1] >> 4) & 0x07; //only 3 10's bits minutes09 = (clkRegs[1] & 0x0f); pm = ((clkRegs[2] >> 5) & 0x01); hours10 = (clkRegs[2] >>4) & 0x01; //1st bit only - //NEW// hours09 = (clkRegs[2] & 0x0f); dayofweek = (clkRegs[3] & 0x07); //only care about 3 lowest bits date10 = (clkRegs[4] >> 4) & 0x03; //only 2 10's bits date09 = (clkRegs[4] & 0x0f); months10 = (clkRegs[5] >> 4) & 0x01; //only 1 10's bit months09 = (clkRegs[5] & 0x0f); years10 = (clkRegs[6] >> 4) & 0x0f; years09 = (clkRegs[6] & 0x0f); } /* ----------------------------------------------------------------------- */ /**************************************** Test Functions ****************************************/ * Print Blanks on line 2 * Bring cursor home */ void clearLCD() { del1m(2); strout(LCD_LINE1, (unsigned char *) clearstr); // clear line 1 del1m(2); strout(LCD_LINE2, (unsigned char *) clearstr); //clear line 2 cmdout(0x02); //cursor home } /* charout - Print the character 'c' at LCD RAM location "x". */ void charout(int x, unsigned char c) { unsigned char ch; cmdout(x | 0x80); // Make A contain a Set Display Address command while ((ch = c) != (unsigned char) NULL) { datout(c); // Output the next character } } /* strout - Print the contents of the character string "s" starting at LCD RAM location "x". The string must be terminated by a zero byte. */ void strout(int x, unsigned char *s) { unsigned char ch; cmdout(x | 0x80); // Make A contain a Set Display Address command OUTLET4 = 1; strout(LCD_LINE1, "outlet 4"); del1m(thousand); OUTLET4 = 0; } }*/ /**************************************** Test Functions ****************************************/ /**************************************** LCD ****************************************/ /* Clear Contents of LCD: * Bring cursor home * Print blanks on line 1 while ((ch = *s++) != (unsigned char) NULL) { datout(ch); // Output the next character } } /* datout - Output a byte to the LCD display data register (the display) and wait for the busy flag to reset. */ void datout(unsigned char x) { PTD = 0x02; // Set R/W=0, E=0, RS=1 nibout(x); // Put data bits 4-7 in PTB nibout(x << 4); // Put data bits 0-3 in PTB busywt(); // Wait for BUSY flag to reset } /* cmdout - Output a byte to the LCD display instruction register and wait for the busy flag to reset. */ void cmdout(unsigned char x) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); // Output command bits 4-7 nibout(x << 4); // Output command bits 0-3 busywt(); // Wait for BUSY flag to reset } /* nibout - Puts bits 4-7 from x into the four bits of Port B that we're using to talk to the LCD. The other bits of Port B are unchanged. Toggle the E control line low-high-low. */ void nibout(unsigned char x) { #ifdef NIBBLE_HIGH PTB = (x & 0xf0) | (PTB & 0x0f); // Use bits 4-7 //PTB_PTB4 = x & 0x10; //PTB_PTB5 = x & 0x20; //PTB_PTB6 = x & 0x30; //PTB_PTB7 = x & 0x80; #else PTB = ((x >> 4) & 0x0f) | (PTB & 0xf0); // Use bits 0-3 //PTB_PTB0 = x & 0x01; //PTB_PTB1 = x & 0x02; //PTB_PTB2 = x & 0x04; //PTB_PTB3 = x & 0x08; #endif PTD_PTD3 = 1; // Set E to 1 PTD_PTD3 = 0; // Set E to 0 } /* initialize - Do various things to force a initialization of the LCD display by instructions, and then set up the display parameters and turn the display on. */ void initializeLCD() { del1m(15); // Delay at least 15ms iniout(0x30); del1m(4); // Send a 0x30 // Delay at least 4msec iniout(0x30); del40u(3); // Send a 0x30 // Delay at least 100usec iniout(0x30); // Send a 0x30 #else //DDRB = 0x0f; // Set PTB for output DDRB_DDRB0 = 1; DDRB_DDRB1 = 1; DDRB_DDRB2 = 1; DDRB_DDRB3 = 1; #endif } iniout(0x20); busywt(); // Function Set: 4-bit interface // Wait for BUSY flag to reset cmdout(0x28); // Function Set: 4-bit interface, 2 lines cmdout(0x0f); // Display and cursor on } /* iniout - Output a byte to the LCD control register. Same as the "cmdout" function but it doesn't wait for the BUSY flag since that flag isn't working during initialization. */ void iniout(unsigned char x) { PTD = 0; // Set R/W=0, E=0, RS=0 nibout(x); } /* busywt - Wait for the BUSY flag to reset */ void busywt() { unsigned char bf; //DDRB = 0; // Set PTB for input DDRB_DDRB4 = 0; DDRB_DDRB5 = 0; DDRB_DDRB6 = 0; DDRB_DDRB7 = 0; PTD = 0x04; // Set E=0, R/W=1, RS=0 do { PTD_PTD3 = 1; // Set E=1 #ifdef NIBBLE_HIGH bf = PTB & 0x80; // Read status register bits 4-7 #else bf = PTB & 0x08; // Read status register bits 4-7 #endif PTD_PTD3 = 0; // Set E=0 PTD_PTD3 = 1; // Set E=1, ignore bits 0-3 PTD_PTD3 = 0; // Set E=0 } while (bf != 0); // If Busy (PTB7=1), loop #ifdef NIBBLE_HIGH //DDRB = 0xf0; // Set PTB for output DDRB_DDRB4 = 1; DDRB_DDRB5 = 1; DDRB_DDRB6 = 1; DDRB_DDRB7 = 1; clkRegs[10] = clkRegs[11] = clkRegs[12] = clkRegs[13] = clkRegs[14] = clkRegs[15] = clkRegs[16] = clkRegs[17] = clkRegs[18] = clkRegs[19] = 0xC0; clkRegs[20] = clkRegs[21] = clkRegs[22] = clkRegs[23] = clkRegs[24] = clkRegs[25] = clkRegs[26] = clkRegs[27] = clkRegs[28] = clkRegs[29] = 0xC0; clkRegs[30] = clkRegs[31] = clkRegs[32] = clkRegs[33] = clkRegs[34] = clkRegs[35] = clkRegs[36] = clkRegs[37] = clkRegs[38] = clkRegs[39] = 0xC0; clkRegs[40] = clkRegs[41] = clkRegs[42] = clkRegs[43] = clkRegs[44] = clkRegs[45] = clkRegs[46] = clkRegs[47] = clkRegs[48] = clkRegs[49] = 0xC0; clkRegs[50] = clkRegs[51] = clkRegs[52] = clkRegs[53] = clkRegs[54] = clkRegs[55] = 0xC0; /**************************************** LCD ****************************************/ i2c_write2(CLOCK_WR_ADDR, clkRegs, 64, 0); } /**************************************** I2C - Real Time Clock ****************************************/ /* i2c_init - Initialize the MMIIC port */ void i2c_init(unsigned char bdiv) { MIMCR_MMBR = bdiv; // Set baud rate divisor MMCR_MMEN = 1; // Enable MMIIC } /* clk_init - Initialize the Clock * The Clock is initialized to 12:00:00 PM Wednesday 04/01/09 * The SQWE pin outputs a 1Hz square wave * * Initialize the RTC RAM for on/off times * Initialize the on/off times in RTC RAM * Bits 7-4: Hour (1-12) * Bits 3-1: Minute (0-5, x10) * Bit 0: AM/PM * INIT: 12AM: 1100 000 0 = 0xC0 */ void clk_init() { clkRegs[0] = 0x00; //Seconds: 00 clkRegs[1] = 0x00; //Minutes: 00 clkRegs[2] = 0x72; //Hour: 12pm clkRegs[3] = 0x04; //Day of the week: Wednesday clkRegs[4] = 0x01; //Date: 01 clkRegs[5] = 0x04; //Month: 04 clkRegs[6] = 0x09; //Year: 2009 clkRegs[7] = 0x10; //outputs 1hz square wave from SQWE pin //the rest: RAM (on/off times) clkRegs[8] = clkRegs[9] = 0xC0; void clkRegs_init() { clkRegs[8] = clkRegs[9] = 0xC0; clkRegs[10] = clkRegs[11] = clkRegs[12] = clkRegs[13] = clkRegs[14] = clkRegs[15] = clkRegs[16] = clkRegs[17] = clkRegs[18] = clkRegs[19] = 0xC0; clkRegs[20] = clkRegs[21] = clkRegs[22] = clkRegs[23] = clkRegs[24] = clkRegs[25] = clkRegs[26] = clkRegs[27] = clkRegs[28] = clkRegs[29] = 0xC0; clkRegs[30] = clkRegs[31] = clkRegs[32] = clkRegs[33] = clkRegs[34] = clkRegs[35] = clkRegs[36] = clkRegs[37] = clkRegs[38] = clkRegs[39] = 0xC0; clkRegs[40] = clkRegs[41] = clkRegs[42] = clkRegs[43] = clkRegs[44] = clkRegs[45] = clkRegs[46] = clkRegs[47] = clkRegs[48] = clkRegs[49] = 0xC0; clkRegs[50] = clkRegs[51] = clkRegs[52] = clkRegs[53] = clkRegs[54] = clkRegs[55] = 0xC0; } void clkRAM_init() { unsigned char clkRAM[56]; clkRAM[0] = clkRAM[1] = clkRAM[2] = clkRAM[3] = clkRAM[4] = clkRAM[5] = clkRAM[6] = clkRAM[7] = clkRAM[8] = clkRAM[9] = 0xC0; clkRAM[10] = clkRAM[11] = clkRAM[12] = clkRAM[13] = clkRAM[14] = clkRAM[15] = clkRAM[16] = clkRAM[17] = clkRAM[18] = clkRAM[19] = 0xC0; clkRAM[20] = clkRAM[21] = clkRAM[22] = clkRAM[23] = clkRAM[24] = clkRAM[25] = clkRAM[26] = clkRAM[27] = clkRAM[28] = clkRAM[29] = 0xC0; clkRAM[30] = clkRAM[31] = clkRAM[32] = clkRAM[33] = clkRAM[34] = clkRAM[35] = clkRAM[36] = clkRAM[37] = clkRAM[38] = clkRAM[39] = 0xC0; clkRAM[40] = clkRAM[41] = clkRAM[42] = clkRAM[43] = clkRAM[44] = clkRAM[45] = clkRAM[46] = clkRAM[47] = clkRAM[48] = clkRAM[49] = 0xC0; clkRAM[50] = clkRAM[51] = clkRAM[52] = clkRAM[53] = clkRAM[54] = clkRAM[55] = 0xC0; del1m(1); i2c_write2(CLOCK_WR_ADDR, clkRAM, 56, 0x08); } MMCR_MMTXAK = 0; // MCU will ACK received data MMADR = CLOCK_WR_ADDR; // Device address -> address reg. //MMDTR = ADDR.Bytes.Address_H; // High byte of data address MMDTR = reg; //data address MIMCR_MMRW = 0; // Set for transmit MIMCR_MMAST = 1; // Initiate transfer /* i2c_write2 - write bytes to an I2C device (two byte address) */ void i2c_write2(unsigned char device_addr, unsigned char *p, int n, byte reg) { //ADDR.Address = reg; // Copy address to struct while (MIMCR_MMBB); // Wait for bus not busy while (!(MMSR_MMTXBE)); // Wait for TX buffer empty////////////////////////////////STUCK HERE: MMSR_MMTXBE never goes to 1 MMADR = device_addr; // Device address -> address reg //MMDTR = ADDR.Bytes.Address_H; // High byte of data address MMDTR = reg; MIMCR_MMRW = 0; // Set for transmit MIMCR_MMAST = 1; // Start transmission //while (!(MMSR_MMTXBE)); // Wait for TX buffer empty //MMDTR = ADDR.Bytes.Address_L; // Low byte of data address //while (MMSR_MMRXAK); // Wait for ACK from slave //while (!(MMSR_MMTXBE)); // Wait for TX buffer empty //MMDTR = ADDR.Bytes.Address_L; // Low byte of data address //while (MMSR_MMRXAK); // Wait for ACK from slave while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = 0xff; // Dummy data to get ACK clock while (MMSR_MMRXAK); // Wait for ACK from slave MMADR = device_addr; // device address -> address reg. //MMDTR = 0xff; // dummy data -> data reg. MIMCR_MMRW = 1; // Set for receive MMCR_REPSEN = 1; // Enable repeated start MIMCR_MMAST = 1; // Initiate transfer while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = 0xff; // Dummy data -> data reg while (MMSR_MMRXAK); // Wait for ACK from slave while (!(MMSR_MMTXBE)); // Wait for TX buffer empty MMDTR = *p++; // First byte of data to write while (MMSR_MMRXAK); // Wait for ACK from slave while (n > 0) { n--; // Decrement count while (!(MMSR_MMTXBE)); // Wait for TX buffer empty if (n == 0) // Is this the last byte? MMDTR = 0xff; // Yes. dummy data -> DTR else MMDTR = *p++; // No. next data -> DTR while (MMSR_MMRXAK); // Wait for ACK from slave } MIMCR_MMAST = 0; // Generate STOP bit //MMCR_MMEN = 0; //MMCR_MMEN = 1; n--; // Loop n-1 times before last read while (n > 0) { // Up to last byte while (!(MMSR_MMRXBF)); // Wait for RX buffer full *p++ = MMDRR; // Get data n--; // Decrement total count } MMCR_MMTXAK = 1; // Don't send ACK for last byte while (!(MMSR_MMRXBF)); // Wait for RX buffer full *p++ = MMDRR; // Get data MIMCR_MMAST = 0; // Generate STOP bit // disable MMIIC // Enable MMIIC } MMCR_MMEN = 0; MMCR_MMEN = 1; /* i2c_read2 - read bytes from an I2C device (two byte address) */ void i2c_read2(unsigned char device_addr, unsigned char *p, int n, byte reg) { unsigned char x; x = MMDRR; //ADDR.Address = reg; // disable MMIIC // Enable MMIIC } /**************************************** I2C - Real Time Clock ****************************************/ // This should clear the MMRXBF flag // Copy address to struct /* sci_init - Initialize the SCI port */ void sci_init(void) { SCC1_ENSCI = 1; // Enable SCI /* Set output for 9600 baud. Assumes a 9.8304MHz clock */ SCBR_SCP = 0; // Baud rate prescaler = 1 SCBR_SCR = 2; // Baud rate divisor = 4 SCC2_TE = 1; // Enable transmitter } /* sciout - Output a byte to SCI port */ void sciout(unsigned char ch) { while (SCS1_SCTE == 0); SCDR = ch; } /* sciouts - Print the contents of the character string "s" out the SCI port. The string must be terminated by a zero byte */ void sciouts(unsigned char *s) { unsigned char ch; while ((ch = *s++) != (unsigned char) NULL) sciout(ch); /**************************************** SCI Port ****************************************/ u1: mov #13,delay0 ; 4 cycles dec delay0 ; 4 cycles bne u1 ; 3 cycles } } } /* del1m - Delay about 1msec times the "d" argument */ void del1m(int d) { while (d--) { asm { ; The following code delays 1 millisecond by looping. ; Total time is 4 + 5 * (4 + 68 * (4 + 3) + 4 + 3) = 2439 cycles ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). Delay is then .993 milliseconds. mov #$5,delay1 ; 4 cycles m1: mov #68,delay0 ; 4 cycles m0: dec delay0 ; 4 cycles bne m0 ; 3 cycles dec delay1 ; 4 cycles bne m1 ; 3 cycles } } } } /**************************************** SCI Port ****************************************/ /**************************************** DELAY ****************************************/ /**************************************** TEST ****************************************/ /***************************************** DELAY ****************************************/ /* Note: these delay routines only work if the the delay0 and delay1 variables are located in the RAM zero page */ /* del40u - Delay about 40usec times the "d" argument */ void del40u(int d) { while (d--) { asm { ; The following code delays about 40 microseconds by looping. ; Total time is 4 + 13 * (4 + 3) = 95 cycles ; A 9.8304MHz external clock gives an internal CPU clock of ; 2.4576MHz (407ns/cycle). 95 x .407 usec = 38.7 usec. ; The JSR and RTS instructions will add a bit more. void LCDMenu() { del1m(100); clearLCD(); while(one) { if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released progMenuTime(); } //end if RIGHT else if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released progMenuOutlets(); } //end if LEFT else { //DISPLAY TIME del1m(2); strout(LCD_LINE1, (unsigned char *) strdurasaver); del1m(2); testCLK(); del1m(995); strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(UP) { if(swDebounce) while(UP) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) upstr); // "you pressed up!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(DOWN) { if(swDebounce) while(DOWN) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) downstr); // "you pressed down!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) selectstr); // "you pressed select!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else { // do nothing } } } } void testRemote() { while(one) { clearLCD(); if(checkManualOverride() == 1) { strout(0, "manual override 1"); if(outlet[0] == 1) { outlet[0] = 0; OUTLET1 = 0; strout(LCD_LINE2, "turn off"); del1m(thousand); } else if(outlet[0] == 0) { outlet[0] = 1; OUTLET1 = 1; strout(LCD_LINE2, "turn on"); del1m(thousand); } } } } /* Displays confirmation on the LCD of which button is pressed */ void testButtonsLCD() { while(one) { while(!LEFT && !RIGHT && !UP && !DOWN && !SELECT) testCLK(); if(LEFT) { if(swDebounce) while(LEFT) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) leftstr); // "you pressed left!" strout(LCD_LINE2, (unsigned char *) str3); //"Dare to press another?" } else if(RIGHT) { if(swDebounce) while(RIGHT) {} //debounce - wait until button is released clearLCD(); //cmdout(0x02); //cursor home strout(LCD_LINE1, (unsigned char *) rightstr); // "you pressed right!" } } /* This program will test button function, output to an LED. * * LED: PTA0, output * Left Button: LED blink 5x * Right Button: LED blink 4x * Up Button: LED blink 3x * Down Button: LED blink 2x * Select Button: LED blink 1x */ void testButtonsLED() { PTA_PTA0 = 1; //LED off to start while (1) { // Loop forever if (LEFT) { //--> blink 5x if(swDebounce) while(LEFT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(RIGHT) { //--> blink 4x if(swDebounce) while(RIGHT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(UP) { // --> blink 3x if(swDebounce) while(UP) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(DOWN) { //--> blink 2x if(swDebounce) while(DOWN) {} //debounce - wait until button is released blink(thousand); del1m(thousand); blink(thousand); del1m(thousand); } else if(SELECT) { //--> blink 1x if(swDebounce) while(SELECT) {} //debounce - wait until button is released blink(thousand); del1m(thousand); } else PTA_PTA0 = 1; //off } } void testI2Crap() { //testCLK(); //do a read strout(0, "before 2nd clkinit"); del1m(thousand); clk_init(); strout(0, "woot woot"); //while(one) { //testCLK(); //del1m(thousand); //} del1m(thousand); programCLK(); } void fakeLCD() { unsigned char repeat = 1; while(repeat) { del1m(2); strout(0, stroutlet); del1m(2); strout(0x40, "Outlet 1"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroutlet); del1m(2); strout(0x40, strexit); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, strprogday); del1m(2); strout(0x40, "Sunday"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroffhour); del1m(2); strout(0x40, "08AM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stroffmin); del1m(2); strout(0x40, "08:30AM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stronhour); del1m(2); strout(0x40, "05PM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; while(repeat) { del1m(2); strout(0, stronmin); del1m(2); strout(0x40, "05:20PM"); if(SELECT) { if(swDebounce) while(SELECT) {} //debounce - wait until button is released repeat = 0; } } clearLCD(); repeat = 1; } teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0, teststr); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) today = 1; outletNum = 1; regOffset = (outletNum - 1) * 2; addrOffset = (regOffset >> 4) & 0x0f; off10hr[0] = '0'; off09hr[0] = '9'; offpm[0] = '0'; offmin[0] = '0'; on10hr[0] = '0'; on09hr[0] = '6'; onpm[0] = '1'; onmin[0] = '3'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; void testCLKRegs(void) { unsigned char teststr[24]; unsigned char offset, i, temp, outletNum, today, regOffset, addrOffset; today = 1; outletNum = 1; clkRegs[8] = 0x88; clkRegs[9] = 0x77; clkRegs[10] = 0x66; clkRegs[11] = 0x55; clkRegs[12] = 0x44; clkRegs[13] = 0x33; clkRegs[14] = 0x22; clkRegs[15] = 0x11; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[8], 1, 0x08); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[9], 1, 0x09); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[10], 1, 0x0A); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[11], 1, 0x0B); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[12], 1, 0x0C); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[13], 1, 0x0D); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[14], 1, 0x0E); i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[15], 1, 0x0F); del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0x40, teststr); del1m(5000); clearLCD(); strout(0, teststr); off10hr[0] = '1'; off09hr[0] = '2'; offpm[0] = '1'; offmin[0] = '2'; on10hr[0] = '1'; on09hr[0] = '0'; onpm[0] = '0'; onmin[0] = '4'; temp = ((((off10hr[outletNum - 1]*10) + off09hr[outletNum - 1]) & 0x0f) << 4) | (((offmin[outletNum - 1] & 0x07) << 1) | (offpm[outletNum - 1] & 0x01)); //1001 0000 = 0x90 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset], 1, SUNSTART + addrOffset); break; case '2': //Monday clkRegs[MONREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset], 1, MONSTART + addrOffset); break; case '3': //Tuesday clkRegs[TUEREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset], 1, TUESTART + addrOffset); break; case '4': //Wednesday clkRegs[WEDREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset], 1, WEDSTART + addrOffset); break; case '5': //Thursday clkRegs[THUREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset], 1, THUSTART + addrOffset); break; case '6': //Friday clkRegs[FRIREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset], 1, FRISTART + addrOffset); break; case '7': //Saturday clkRegs[SATREG + regOffset] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset], 1, SATSTART + addrOffset); break; } //end switch(today) temp = ((((on10hr[outletNum - 1]*10) + on09hr[outletNum - 1]) & 0x0f) << 4) | (((onmin[outletNum - 1] & 0x07) << 1) | (onpm[outletNum - 1] & 0x01)); //0110 0110 = 0x66 switch(hexCode[today]) { case '1': //Sunday clkRegs[SUNREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SUNREG + regOffset + 1], 1, SUNSTART + addrOffset + 0x01); break; case '2': //Monday clkRegs[MONREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[MONREG + regOffset + 1], 1, MONSTART + addrOffset + 0x01); break; case '3': //Tuesday clkRegs[TUEREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[TUEREG + regOffset + 1], 1, TUESTART + addrOffset + 0x01); break; case '4': //Wednesday clkRegs[WEDREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[WEDREG + regOffset + 1], 1, WEDSTART + addrOffset + 0x01); break; case '5': //Thursday clkRegs[THUREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[THUREG + regOffset + 1], 1, THUSTART + addrOffset + 0x01); break; case '6': //Friday clkRegs[FRIREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[FRIREG + regOffset + 1], 1, FRISTART + addrOffset + 0x01); break; case '7': //Saturday clkRegs[SATREG + regOffset + 1] = temp; i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[SATREG + regOffset + 1], 1, SATSTART + addrOffset + 0x01); break; } //end switch(today) teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; strout(0x40, teststr); del1m(5000); del1m(1); //i2c_read2(CLOCK_RD_ADDR, dayData, 8, 0x08); getDevData(1); teststr[0] = hexCode[(dayData[0] >> 4) & 0x0f]; teststr[1] = hexCode[(dayData[0]) & 0x0f]; teststr[2] = hexCode[(dayData[1] >> 4) & 0x0f]; teststr[3] = hexCode[(dayData[1]) & 0x0f]; teststr[4] = hexCode[(dayData[2] >> 4) & 0x0f]; teststr[5] = hexCode[(dayData[2]) & 0x0f]; teststr[6] = hexCode[(dayData[3] >> 4) & 0x0f]; teststr[7] = hexCode[(dayData[3]) & 0x0f]; teststr[8] = hexCode[(dayData[4] >> 4) & 0x0f]; teststr[9] = hexCode[(dayData[4]) & 0x0f]; teststr[10] = hexCode[(dayData[5] >> 4) & 0x0f]; teststr[11] = hexCode[(dayData[5]) & 0x0f]; teststr[12] = hexCode[(dayData[6] >> 4) & 0x0f]; teststr[13] = hexCode[(dayData[6]) & 0x0f]; teststr[14] = hexCode[(dayData[7] >> 4) & 0x0f]; teststr[15] = hexCode[(dayData[7]) & 0x0f]; teststr[16] = '\0'; //strout(0, teststr); del1m(1); getDevData(1); teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; //clkRegs[8] = 0xA4; //0001 001 0 = 1:10am, 1010 010 0 = A4 = 10:20am //clkRegs[9] = 0xC9; //0010 010 1 = 2:20pm, 1100 100 1 = C9 = 12:40pm //i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[8], 1, 0x08); //i2c_write2(CLOCK_WR_ADDR, (unsigned char *) &clkRegs[9], 1, 0x09); del1m(1); //i2c_read2(CLOCK_RD_ADDR, dayData, 8, SUNSTART); getDevData(1); else if(hexCode[(dayData[offset+1] & 0x01)] == '1') onpm[i-1] = 'P'; else onpm[i-1] = '?'; i = 1; offset = (i - 1) * 2; //index offset for dayData, based on device # //e.g. dev 4 is stored at 6 and 7 (4 - 1 = 3 * 2 = 6) // (2a) process "off" time if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'A') { off10hr[i-1] = '1'; off09hr[i-1] = '0'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'B') { off10hr[i-1] = '1'; off09hr[i-1] = '1'; } else if(hexCode[((dayData[offset] >> 4) & 0x0f)] == 'C') { off10hr[i-1] = '1'; off09hr[i-1] = '2'; } else { off10hr[i-1] = '0'; off09hr[i-1] = hexCode[(dayData[offset] >> 4) & 0x0f]; //up to 9 } offmin[i-1] = hexCode[(dayData[offset] & 0x0e) >> 1]; //all but last bit (bits 3-1) if(hexCode[(dayData[offset] & 0x01)] == '0') //last bit is am/pm offpm[i-1] = 'A'; else if(hexCode[(dayData[offset] & 0x01)] == '1') offpm[i-1] = 'P'; else offpm[i-1] = '?'; // (2b) process "on" time if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'A') { on10hr[i-1] = '1'; on09hr[i-1] = '0'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'B') { on10hr[i-1] = '1'; on09hr[i-1] = '1'; } else if(hexCode[((dayData[offset+1] >> 4) & 0x0f)] == 'C') { on10hr[i-1] = '1'; on09hr[i-1] = '2'; } else { on10hr[i-1] = '0'; on09hr[i-1] = hexCode[(dayData[offset+1] >> 4) & 0x0f]; //up to 9 } onmin[i-1] = hexCode[(dayData[offset+1] & 0x0e) >> 1]; //all but last bit (bits 3-1) if(hexCode[(dayData[offset+1] & 0x01)] == '0') //last bit is am/pm onpm[i-1] = 'A'; teststr[0] = off10hr[0]; teststr[1] = off09hr[0]; teststr[2] = ':'; teststr[3] = offmin[0]; teststr[4] = '0'; teststr[5] = onpm[0]; teststr[6] = 'M'; teststr[7] = ' '; teststr[8] = on10hr[0]; teststr[9] = on09hr[0]; teststr[10] = ':'; teststr[11] = onmin[0]; teststr[12] = '0'; teststr[13] = onpm[0]; teststr[14] = 'M'; teststr[15] = '\0'; //strout(0x40, teststr); //del1m(5000); } void testOutlets() { del1m(2); DDRB_DDRB0 = 1; DDRB_DDRB1 = 1; DDRB_DDRB2 = 1; DDRB_DDRB3 = 1; while(one) { OUTLET1 = 1; strout(0, "outlet 1"); del1m(thousand); OUTLET1 = 0; OUTLET2 = 1; strout(0, "outlet 2"); del1m(thousand); OUTLET2 = 0; } strout(0, "manov 2!"); break; OUTLET3 = 1; strout(0, "outlet 3"); del1m(thousand); OUTLET3 = 0; case 3: blink(1000); blink(1000); blink(1000); if(outlet[2] == 1) { outlet[2] = OUTLET3 = 0; } else if(outlet[2] == 0) { outlet[2] = OUTLET3 = 1; } strout(0, "manov 3!"); break; OUTLET4 = 1; strout(0, "outlet 4"); del1m(thousand); OUTLET4 = 0; } } /* turn on LED in port A bit 0 for n msec, then turn off */ void blink(int n) { PTA_PTA0 = 0; //turn on LED del1m(n); //leave on n msec PTA_PTA0 = 1; //turn off LED } /* test manual override */ void testManOv() { while(one) { switch(checkManualOverride()) { case 1: blink(1000); if(outlet[0] == 1) { outlet[0] = OUTLET1 = 0; } else if(outlet[0] == 0) { outlet[0] = OUTLET1 = 1; } strout(0, "manov 1!"); break; case 2: blink(1000); blink(1000); if(outlet[1] == 1) { outlet[1] = OUTLET2 = 0; } else if(outlet[1] == 0) { outlet[1] = OUTLET2 = 1; case 4: blink(1000); blink(1000); blink(1000); blink(1000); if(outlet[3] == 1) { outlet[3] = OUTLET4 = 0; } else if(outlet[3] == 0) { outlet[3] = OUTLET4 = 1; } strout(0, "manov 4!"); break; default: del1m(2); strout(0, strdurasaver); testCLK(); del1m(1000); } //end switch } //end while(one) } /**************************************** TEST ****************************************/ Appendix C Parts List and Cost Analysis Parts Lists and Cost Analysis Main Module - Prototype Supplier Digikey Part Number MC908JL16CPEND Digikey 10KH-ND Digikey 1.0KH-ND Digikey 330H-ND Digikey Digikey Digikey 470H-ND 67-1071-ND 67-1063-ND Digikey P1363-ND Digikey 493-1808-ND Digikey 478-2475-ND Digikey 490-3775-ND Digikey 401-1963-ND Digikey BG Micro 296-1643-5-ND LCD1029 SparkFun WRL-08947 Digikey X114-ND Digikey Digikey DS1307+-ND DS32KHZ/DIPND Digikey Digikey 1N4148DICT-ND 2N3904FS-ND Digikey HE100-ND Digikey Digikey Digikey A98060-ND P138-ND BU2032-1-HD-GND Digikey T977-P6P-ND Total Cost Price Each (Bulk, >1,000) Cost (Per Unit) Quantity Price Each (Individual) 1 $3.23 $1.86 $3.23 $1.86 13 $0.06 $0.01 $0.78 $0.13 4 $0.06 $0.01 $0.24 $0.04 5 $0.06 $0.01 $0.30 $0.05 5 1 4 $0.06 $0.12 $0.09 $0.01 $0.08 $0.06 $0.30 $0.12 $0.36 $0.05 $0.08 $0.24 1 $0.89 $0.28 $0.89 $0.28 5 $0.18 $0.04 $0.90 $0.20 5 $0.27 $0.08 $1.35 $0.40 5 $0.25 $0.08 $1.25 $0.40 6 $0.99 $0.43 $5.94 $2.58 1 1 $0.43 $3.95 $0.14 $3.95 $0.43 $3.95 $0.14 $3.95 1 $5.95 $4.76 $5.95 $4.76 1 $1.88 $1.05 $1.88 $1.05 1 $3.74 $1.66 $3.74 $1.66 1 $5.46 $5.46 $5.46 $5.46 4 4 $0.02 $0.11 $0.02 $0.02 $0.08 $0.44 $0.08 $0.08 4 $1.50 $0.60 $6.00 $2.40 5 1 $2.25 $0.38 $1.35 $0.23 $11.25 $0.38 $6.75 $0.23 Battery Holder 1 $0.63 $0.45 $0.63 $0.45 Power Supply 1 $7.16 $4.77 $7.16 $4.77 $63.01 $38.09 Description MC908JL16 uC Resistor - 10 kOhm Resistor - 1 kOhm Resistor - 330 Ohm Resistor - 470 Ohm LED - Red LED - Green Capacitor 10uF Capacitor 4.7uF Capacitor 0.22uF Capacitor 0.01uF Pushbutton SPST Hex SchmittTrigger Inverter 24x2 LCD RF Receiver 315 MHz 10 MHz Crystal Oscillator Real-Time Clock 32kHz Oscillator Diode 1N4148 NPN BJT Relay SPSTNO Terminal Block - Wire to Board Battery - 3V Cost (Bulk, >1,000 Units) Remote Control Prototype Supplier Digikey Part Number MC908JL16CPEND Digikey 10KH-ND Digikey 401-1963-ND Jameco 321736 Digikey X114-ND SparkFun WRL-08945 Digikey P145-ND Digikey BH9V-W-ND Digikey 67-1898-ND Description MC908JL16 uC Resistor - 10 kOhm Pushbutton SPST Push-Button Debouncer 10 MHz Crystal Oscillator RF Transmitter 315 MHz Quantity Battery - 9V Battery Holder Toggle Switch SPST Price Each (Individual) Price Each (Bulk, >1,000) Cost (Per Unit) Cost (Bulk, >1,000 Units) 1 $3.23 $1.86 $3.23 $1.86 5 $0.06 $0.01 $0.30 $0.05 5 $0.99 $0.43 $4.95 $2.15 1 $5.99 $3.82 $5.99 $3.82 1 $1.88 $1.05 $1.88 $1.05 1 $3.95 $3.16 $3.95 $3.16 1 $2.31 $1.00 $2.31 $1.00 1 $0.86 $0.62 $0.86 $0.62 1 $3.48 $1.54 $3.48 $1.54 $26.95 $15.25 Total Cost Complete Product (Prototype) Item Cost (Per Unit) Cost (Bulk, >1,000 Units) Main Module $63.01 $38.09 Remote Control $26.95 $15.25 Total Cost $89.96 $53.34 Main Module PCB Supplier Digikey Part Number MC908JL16CDWEND Digikey P10KETR-ND Digikey P1.0KETR-ND Digikey P330ETR-ND Digikey Digikey Digikey P470ETR-ND 67-1071-ND 67-1063-ND Digikey PCE3757CT-ND Digikey PCE3021DKR-ND Digikey PCE1012TR-ND Digikey 445-2494-2-ND Digikey 147873-1-ND Digikey BG Micro 296-1212-5-ND LCD1029 SparkFun WRL-08947 Digikey SE2818TR-ND Digikey DS1307Z+-ND Digikey Digikey Digikey DS32KHZS#-ND 1N4148WTDITR-ND 2N3904FS-ND Digikey 374-1039-2-ND Digikey Digikey Digikey Total Cost 1776226-1-ND P022-ND T977-P6P-ND Description MC908JL16 uC Resistor - 10 kOhm Resistor - 1 kOhm Resistor - 330 Ohm Resistor - 470 Ohm LED - Red LED - Green Capacitor 10uF Capacitor 4.7uF Capacitor 0.22uF Capacitor 0.01uF Pushbutton SPST Hex SchmittTrigger Inverter 24x2 LCD RF Receiver 315 MHz 10 MHz Crystal Oscillator Real-Time Clock 32kHz Oscillator Diode - 1N4148 NPN BJT Relay SPSTNO Terminal Block - Wire to Board Battery - 3V Power Supply Quantity Price Each (Bulk, >10,000) Cost to Product (Bulk, >10,000 Units) 1 $1.74 $1.74 13 $0.01 $0.10 4 $0.01 $0.03 5 $0.01 $0.04 5 1 4 $0.01 $0.06 $0.06 $0.04 $0.06 $0.25 1 $0.14 $0.14 5 $0.12 $0.61 5 $0.16 $0.80 5 $0.03 $0.14 6 $0.11 $0.68 1 1 $0.15 $3.95 $0.15 $3.95 1 $4.76 $4.76 1 $1.56 $1.56 1 $1.66 $1.66 1 4 4 $3.29 $0.08 $0.02 $3.29 $0.31 $0.08 4 $3.09 $12.35 5 1 1 $0.50 $0.98 $4.77 $2.48 $0.98 $4.77 $40.94 Remote Control PCB Supplier Digikey Part Number MC908JL16CDW E-ND Digikey P10KETR-ND Digikey 147873-1-ND Elab EDE2008SO Digikey SE2818TR-ND SparkFun Digikey Digikey WRL-08945 P145-ND 1294K-ND Digikey CKN9049TR-ND Quantit y Description MC908JL16 uC Resistor - 10 kOhm Pushbutton SPST Push-Button Debouncer 10 MHz Crystal Oscillator RF Transmitter - 315 MHz Battery - 9V Battery Holder Toggle Switch SPST Price Each (Bulk, >10,000) Cost to Product (Bulk, >10,000 Units) 1 $1.74 $1.74 5 $0.01 $0.04 5 $0.11 $0.56 1 $2.35 $2.35 1 $1.56 $1.56 1 1 1 $3.16 $0.92 $0.74 $3.16 $0.92 $0.74 1 $2.64 $2.64 Total Cost $13.71 Complete Product PCB Item Cost (Bulk, >10,000 Units) Main Module $40.94 Remote Control $13.71 Total Cost $54.66