Information
-
Patent Application
-
20010024095
-
Publication Number
20010024095
-
Date Filed
February 16, 200123 years ago
-
Date Published
September 27, 200123 years ago
-
Inventors
-
Original Assignees
-
CPC
-
US Classifications
-
International Classifications
- H02P001/04
- H02P003/00
- G05B005/00
- H02P007/00
- H02H007/08
Abstract
A movable barrier operator having improved safety and energy efficiency features automatically detects line voltage frequency and uses that information to set a worklight shut-off time. The operator automatically detects the type of door (single panel or segmented) and uses that information to set a maximum speed of door travel. The operator moves the door with a linearly variable speed from start of travel to stop for smooth and quiet performance. The operator provides for full door closure by driving the door into the floor when the DOWN limit is reached and no auto-reverse condition has been detected. The operator provides for user selection of a minimum stop speed for easy starting and stopping of sticky or binding doors.
Description
BACKGROUND OF THE INVENTION
[0001] This invention relates generally to movable barrier operators for operating movable barriers or doors. More particularly, it relates to garage door operators having improved safety and energy efficiency features.
[0002] Garage door operators have become more sophisticated over the years providing users with increased convenience and security. However, users continue to desire further improvements and new features such as increased energy efficiency, ease of installation, automatic configuration, and aesthetic features, such as quiet, smooth operation.
[0003] In some markets energy costs are significant. Thus energy efficiency options such as lower horsepower motors and user control over the worklight functions are important to garage door operator owners. For example, most garage door operators have a worklight which turns on when the operator is commanded to move the door and shuts off a fixed period of time after the door stops. In the United States, an illumination period of 4½ minutes is considered adequate. In markets outside the United States, 4½ minutes is considered too long. Some garage door operators have special safety features, for example, which enable the worklight whenever the obstacle detection beam is broken by an intruder passing through an open garage door. Some users may wish to disable the worklight in this situation. There is a need for a garage door operator which can be automatically configured for predefined energy saving features, such as worklight shut-off time.
[0004] Some movable barrier operators include a flasher module which causes a small light to flash or blink whenever the barrier is commanded to move. The flasher module provides some warning when the barrier is moving. There is a need for an improved flasher unit which provides even greater warning to the user when the barrier is commanded to move.
[0005] Another feature desired in many markets is a smooth, quiet motor and transmission. Most garage door operators have AC motors because they are less expensive than DC motors. However, AC motors are generally noisier than DC motors.
[0006] Most garage door operators employ only one or two speeds of travel. Single speed operation, i.e., the motor immediately ramps up to full operating speed, can create a jarring start to the door. Then during closing, when the door approaches the floor at full operating speed, whether a DC or AC motor is used, the door closes abruptly with a high amount of tension on it from the inertia of the system. This jarring is hard on the transmission and the door and is annoying to the user.
[0007] If two operating speeds are used, the motor would be started at a slow speed, usually 20 percent of full operating speed, then after a fixed period of time, the motor speed would increase to full operating speed. Similarly, when the door reaches a fixed point above/below the close/open limit, the operator would decrease the motor speed to 20 percent of the maximum operating speed. While this two speed operation may eliminate some of the hard starts and stops, the speed changes can be noisy and do not occur smoothly, causing stress on the transmission. There is a need for a garage door operator which opens the door smoothly and quietly, with no aburptly apparent sign of speed change during operation.
[0008] Garage doors come in many types and sizes and thus different travel speeds are required for them. For example, a one-piece door will be movable through a shorter total travel distance and need to travel slower for safety reasons than a segmented door with a longer total travel distance. To accommodate the two door types, many garage door operators include two sprockets for driving the transmission. At installation, the installer must determine what type of door is to be driven, then select the appropriate sprocket to attach to the transmission. This takes additional time and if the installer is the user, may require several attempts before matching the correct sprocket for the door. There is a need for a garage door operator which automatically configures travel speed depending on size and weight of the door.
[0009] National safety standards dictate that a garage door operator perform a safety reversal (auto-reverse) when an object is detected only one inch above the DOWN limit or floor. To satisfy these safety requirements, most garage door operators include an obstacle detection system, located near the bottom of the door travel. This prevents the door from closing on objects or persons that may be in the door path. Such obstacle detection systems often include an infrared source and detector located on opposite sides of the door frame. The obstacle detector sends a signal when the infrared beam between the source and detector is broker,, indicating an obstacle is detected. In response to the obstacle signal, the operator causes an automatic safety reversal. The door stops and begins traveling up, away from the obstacle.
[0010] There are two different “forces” used in the operation of the garage door operator. The first “force” is usually preset or setable at two force levels: the UP force level setting used to determine the speed at which the door travels in the UP direction and the DOWN force level setting used to determine the speed at which the door travels in the DOWN direction. The second “force” is the force level determined by the decrease in motor speed due to an external force applied to the door, i.e., from an obstacle or the floor. This external force level is also preset or setable and is any set-point type force against which the feedback force signal is compared. When the system determines the set point force has been met, an auto-reverse or stop is commanded.
[0011] To overcome differences in door installations, i.e. stickiness and resistance to movement and other varying frictional-type forces, some garage door operators permit the maximum force (the second force) used to drive the speed of travel to be varied manually. This, however, affects the system's auto-reverse operation based on force. The auto-reverse system based on force initiates an auto-reverse if the force on the door exceeds the maximum force setting (the second force) by some predetermined amount. If the user increases the force setting to drive the door through a “sticky” section of travel, the user may inadvertently affect the force to a much greater value than is safe for the unit to operate during normal use. For example, if the DOWN force setting is set so high that it is only a small incremental value less than the force setting which initiates an auto-reverse due to force, this causes the door to engage objects at a higher speed before reaching the auto-reverse force setting. While the obstacle detection system will cause the door to auto-reverse, the speed and force at which the door hits the obstacle may cause harm to the obstacle and/or the door.
[0012] Barrier movement operators should perform a safety reversal off an obstruction which is only marginally higher than the floor, yet still close the door safely against the floor. In operator systems where the door moves at a high speed, the relatively large momentum of the moving parts, including the door, accomplishes complete closure. In systems with a soft closure, where the door speed decreases from full maximum to a small percentage of full maximum when closing, there may be insufficient momentum in the door or system to accomplish a full closure. For example, even if the door is positioned at the floor, there is sometimes sufficient play in the trolley of the operator to allow the door to move if the user were to try to open it. In particular, in systems employing a DC motor, when the DC motor is shut off, it becomes a dynamic brake. If the door isn't quite at the floor when the DOWN travel limit is reached and the DC motor is shut off, the door and associated moving parts may not have sufficient momentum to overcome the braking force of the DC motor. There is a need for a garage door operator which closes the door completely, eliminating play in the door after closure.
[0013] Many garage door operator installations are made to existing garage doors. The amount of force needed to drive the door varies depending on type of door and the quality of the door frame and installation. As a result, some doors are “stickier” than others, requiring greater force to move them through the entire length of travel. If the door is started and stopped using the full operating speed, stickiness is not usually a problem. However, if the garage door operator is capable of operation at two speeds, stickiness becomes a larger problem at the lower speed. In some installations, a force sufficient to run at 20 percent of normal speed is too small to start some doors moving. There is a need for a garage door operator which automatically controls force output and thus start and stop speeds.
SUMMARY OF THE INVENTION
[0014] A movable barrier operator having an electric motor for driving a garage door, a gate or other barrier is operated from a source of AC current. The movable barrier operator includes circuitry for automatically detecting the incoming AC line voltage and frequency of the alternating current. By automatically detecting the incoming AC line voltage and determining the frequency, the operator can automatically configure itself to certain user preferences. This occurs without either the user or the installer having to adjust or program the operator. The movable barrier operator includes a worklight for illuminating its immediate surroundings such as the interior of a garage. The barrier operator senses the power line frequency (typically 50 Hz or 60 Hz) to automatically set an appropriate shut-off time for a worklight. Because the power line frequency in Europe is 50 Hz and in the U.S. is 60 Hz, sensing the power line frequency enables the operator to configure itself for either a European or a U.S. market with no user or installer modifications. For U.S. users, the worklight shut-off time is set to preferably 4½ minutes; for European users, the worklight shut-off time is set to preferably 2½ minutes. Thus, a single barrier movement operator can be sold in two different markets with automatic setup, saving installation time.
[0015] The movable barrier operator of the present invention automatically detects if an optional flasher module is present. If the module is present, when the door is commanded to move, the operator causes the flasher module to operate. With the flasher module present, the operator also delays operation of the motor for a brief period, say ore or two seconds. This delay period with the flasher module blinking before door movement provides an added safety feature to users which warns them of impending door travel (e.g. if activated by an unseen transmitter).
[0016] The movable barrier operator of the present invention drives the barrier, which may be a door or a gate, at a variable speed. After motor start, the electric motor reaches a preferred initial speed of 20 percent of the full operating speed. The motor speed then increases slowly in a linearly continuous fashion from 20 percent to 100 percent of full operating speed. This provides a smooth, soft start without jarring the transmission or the door or gate. The motor moves the barrier at maximum speed for the largest portion of its travel, after which the operator slowly decreases speed from 100 percent to 20 percent as the barrier approaches the limit of travel, providing a soft, smooth and quiet stop. A slow, smooth start and stop provides a safer barrier movement operator for the user because there is less momentum to apply an impulse force in the event of an obstruction. In a fast system, relatively high momentum of the door changes to zero at the obstruction before the system can actually detect the obstruction. This leads to the application of a high impulse force. With the system of the invention, a slower stop speed means the system has less momentum to overcome, and therefore a softer, more forgiving force reversal. A slow, smooth start and stop also provide a more aesthetically pleasing effect to the user, and when coupled with a quieter DC motor, a barrier movement operator which operates very quietly.
[0017] The operator includes two relays and a pair of field effect transistors (FETs) for controlling the motor. The relays are used to control direction of travel. The FET's, with phase controlled, pulse width modulation, control start up and speed. Speed is responsive to the duration of the pulses applied to the FETs. A longer pulse causes the FETs to be on longer causing the barrier speed to increase. Shorter pulses result in a slower speed. This provides a very fine ramp control and more gentle starts and stops.
[0018] The movable barrier operator provides for the automatic measurement and calculation of the total distance the door is to travel. The total door travel distance is the distance between the UP and the DOWN limits (which depend on the type of door). The automatic measurement of door travel distance is a measure of the length of the door. Since shorter doors must travel at slower speeds than normal doors (for safety reasons), this enables the operator to automatically adjust the motor speed so the speed of door travel is the same regardless of door size. The total door travel distance in turn determines the maximum speed at which the operator will travel. By determining the total distance traveled, travel speeds can be automatically changed without having to modify the hardware.
[0019] The movable barrier operator provides full door or gate closure, i.e. a firm closure of the door to the floor so that the door is not movable in place after it stops. The operator includes a digital control or processor, specifically a microcontroller which has an internal microprocessor, an internal RAM and an internal ROM and an external EEPROM. The microcontroller executes instructions stored in its internal ROM and provides motor direction control signals to the relays and speed control signals to the FETs. The operator is first operated in a learn mode to store a DOWN limit position for the door. The DOWN limit position of the door is used as an approximation of the location of the floor (or as a minimum reversal point, below which no auto-reverse will occur). When the door reaches the DOWN limit position, the microcontroller causes the electric motor to drive the door past the DOWN limit a small distance, say for one or two inches. This causes the door to close solidly on the floor.
[0020] The operator embodying the present invention provides variable door or gate output speed, i.e., the user can vary the minimum speed at which the motor starts and stops the door. This enables the user to overcome differences in door installations, i.e. stickiness and resistance to movement and other varying functional-type forces. The minimum barrier speeds in the UP and DOWN directions are determined by the user-configured force settings, which are adjusted using UP and DOWN force potentiometers. The force potentiometers set the lengths of the pulses to the FETs, which translate to variable speeds. The user gains a greater force output and a higher minimum starting speed to overcome differences in door installations, i.e. stickiness and resistance to movement and other varying functional-type forces speed, without affecting the maximum speed of travel for the door. The user can configure the door to start at a speed greater than a default value, say 20 percent. This greater start up and slow down speed is transferred to the linearly variable speed function in that instead of traveling at 20 percent speed, increasing to 100 percent speed, then decreasing to 20 percent speed, the door may, for instance, travel at 40 percent speed to 100 percent speed and back down to 40 percent speed.
BRIEF DESCRIPTION OF THE DRAWINGS
[0021]
FIG. 1 is a perspective view of a garage having mounted within it a garage door operator embodying the present invention;
[0022]
FIG. 2 is an exploded perspective view of a head unit of the garage door operator shown in FIG. 1;
[0023]
FIG. 3 is an, exploded perspective view of a portion of a transmission unit of the garage door operator shown in FIG. 1;
[0024]
FIG. 4 is a block diagram of a controller and motor mounted within the head unit of the garage door operator shown in FIG. 1;
[0025] FIGS. 5A-5D are a schematic diagram of the controller shown in block format in FIG. 4;
[0026] FIGS. 6A-6B are a flow chart of an overall routine that executes in a microprocessor of the controller shown in FIGS. 5A-5D;
[0027] FIGS. 7A-7H are a flow chart of the main routine executed in the microprocessor;
[0028]
FIG. 8 is a flow chart of a set variable light shut-off timer routine executed by the microprocessor;
[0029] FIGS. 9A-9C are a flow chart of a hardware timer interrupt routine executed in the microprocessor;
[0030] FIGS. 10A-10C are a flow chart of a 1 millisecond timer routine executed in the microprocessor;
[0031] FIGS. 11A-11C are a flow chart of a 125 millisecond timer routine executed in the microprocessor;
[0032] FIGS. 12A-12B are a flow chart of a 4 millisecond timer routine executed in the microprocessor;
[0033] FIGS. 13A-13B are a flow chart of an RPM interrupt routine executed in the microprocessor;
[0034]
FIG. 14 is a flow chart of a motor state machine routine executed in the microprocessor;
[0035]
FIG. 15 is a flow chart of a stop in midtravel routine executed in the microprocessor;
[0036]
FIG. 16 is a flow chart of a DOWN position routine executed in the microprocessor;
[0037] FIGS. 17A-17C are a flow chart of an UP direction routine executed in the microprocessor;
[0038]
FIG. 18 is a flow chart of an auto-reverse routine executed in the microprocessor;
[0039]
FIG. 19 is a flow chart of an UP position routine executed in the microprocessor;
[0040] FIGS. 20A-20D are a flow chart of the DOWN direction routine executed in the microprocessor;
[0041]
FIG. 21 is an exploded perspective view of a pass point detector and motor of the operator shown in FIG. 2;
[0042]
FIG. 22A is a plan view of the pass point detector shown in FIG. 21; and
[0043]
FIG. 22B is a partial plan view of the pass point detector shown in FIG. 21.
DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENT
[0044] Referring now to the drawings and especially to FIG. 1, a movable barrier or garage door operator system is generally shown therein and referred to by numeral 8. The system 8 includes a movable barrier operator or garage door operator 10 having a head unit 12 mounted within a garage 14. More specifically, the head unit 12 is mounted to a ceiling 15 of the garage 14. The operator 10 includes a transmission 18 extending from the head unit 12 with a releasable trolley 20 attached. The releasable trolley 20 releasably connects an arm 22 extending to a single panel garage door 24 positioned for movement along a pair of door rails 26 and 28.
[0045] The system 8 includes a hand-held RF transmitter unit 30 adapted to send signals to an antenna 32 (see FIG. 4) positioned on the head unit 12 and coupled to a receiver within the head unit 12 as will appear hereinafter. A switch module 39 is mounted on the head unit 12. Switch module 39 includes switches for each of the commands available from a remote transmitter or from an optional wall-mounted switch (not shown). Switch module 39 enables an installer to conveniently request the various learn modes during installation of the head unit 12. The switch module 39 includes a learn switch, a light switch, a lock switch and a command switch, which are described below. Switch module 39 may also include terminals for wiring a pedestrian door state sensor comprising a pair of contacts 13 and 15 for a pedestrian door 11, as well as wiring for an optional wall switch (not shown).
[0046] The garage door 24 includes the pedestrian door 11. Contact 13 is mounted to door 24 for contact with contact 15 mounted to pedestrian door 11. Both contacts 13 and 15 are connected via a wire 17 to head unit 12. As will be described further below, when the pedestrian door 11 is closed, electrical contact is made between the contacts 13 and 15 closing a pedestrian door circuit in the receiver in head unit 12 and signalling that the pedestrian door state is closed. This circuit must be closed before the receiver will permit other portions of the operator to move the door 24. If circuit is open, indicating that the pedestrian door state is open, the system will not permit door 24 to move.
[0047] The head unit 12 includes a housing comprising four sections: a bottom section 102, a front section 106, a back section 108 and a top section 110, which are held together by screws 112 as shown in FIG. 2. Cover 104 fits into front section 106 and provides a cover for a worklight. External AC power is supplied to the operator 10 through a power cord 112. The AC power is applied to a step-down transformer 120. An electric motor 118 is selectively energized by rectified AC power and drives a sprocket 125 in sprocket assembly 124. The sprocket 125 drives chain 144 (see FIG. 3). A printed circuit board 114 includes a controller 200 and other electronics for operating the head unit 12. A cable 116 provides input and output connections or, signal paths between the printed circuit board 114 and switch module 39. The transmission 18, as shown in FIG. 3, includes a rail 142 which holds chain 144 within a rail and chain housing 140 and holds the chair in tension to transfer mechanical energy from the motor to the door.
[0048] A block diagram or the controller and motor connections is shown in FIG. 4. Controller 200 includes an RF receiver 80, a microprocessor 300 and an EEPROM 302. RF receiver 80 of controller 200 receives a command to move the door and actuate the motor either from remote transmitter 30, which transmits an RF signal which is received by antenna 32, or from a user command switch 250. User command switch 250 can be a switch on switch panel 39, mounted on the head unit, or a switch from an optional wall switch. Upon receipt of a door movement command signal from either antenna 32 or user switch 250, the controller 200 sends a power enable signal via line 240 to AC hot connection 206 which provides AC line current to transformer 212 and power to work light 210. Rectified AC is provided from rectifier 214 via line 236 to relays 232 and 234. Depending on the commanded direction of travel, controller 200 provides a signal to either relay 232 or relay 234. Relays 232 and 234 are used to control the direction of rotation of motor 118 by controlling the direction of current flow through the windings. One relay is used for clockwise rotation; the other is used for counterclockwise rotation.
[0049] Upon receipt of the door movement command signal, controller 200 sends a signal via line 230 to power-control FET 252. Motor speed is determined by the duration or length of the pulses in the signal to a gate electrode of FET 252. The shorter the pulses, the slower the speed. This completes the circuit between relay 232 and FET 252 providing power to motor 118 via line 254. If the door had been commanded to move in the opposite direction, relay 234 would have been enabled, completing the circuit with FET 252 and providing power to motor 118 via line 238.
[0050] With power provided, the motor 118 drives the output shaft 216 which provides drive power to transmission sprocket 125. Gear redaction housing 260 includes an internal pass point system which sends a pass point signal via line 220 to controller 220 whenever the pass point is reached. The pass point signal is provided to controller 200 via current limiting resistor 226 to protect controller 200 from electrostatic discharge (ESD). An RPM interrupt signal is provided via line 224, via current limiting resistor 228, to controller 200. Lead 222 provides a plus five volts supply for the Hall effect sensors in the RPM module. Commanded force is input by two force potentiometers 202, 204. Force potentiometer 202 is used to set the commanded force for UP travel; force potentiometer 204 is used to set the commanded force for DOWN travel. Force potentiometers 202 and 204 provide commanded inputs to controller 200 which are used to adjust the length of the pulsed signal provided to FET 252.
[0051] The pass point for this system is provided internally in the motor 118. Referring to FIG. 22, the pass point module 40 is attached to gear reduction housing 260 of motor 118. Pass point module 40 includes upper plate 42 which covers the three internal gears and switch within lower housing 50. Lower housing 50 includes recess 62 having two pins 61 which position switch assembly 52 in recess 62. Housing 50 also includes three cutouts which are sized to support and provide for rotation of the three geared elements. Outer gear 44 fits rotatably within cutout 64. Outer gear includes a smooth outer surface for rotating within housing 50 and inner gear teeth for rotating middle gear 46. Middle gear 46 fits rotatably within inner cutout 66. Middle gear 46 includes a smooth outer surface and a raised portion with gear teeth for being driven by the gear teeth of outer ring gear 44. Inner gear 48 fits within middle gear 46 and is driven by an extension of shaft 216. Rotation of the motor 118 causes shaft 216 to rotate and drive inner gear 48.
[0052] Outer gear 44 includes a notch 74 in the outer periphery. Middle gear includes a notch 76 in the outer periphery. Referring to FIG. 22A, rotation of inner gear 48 rotates middle gear 46 in the same direction. Rotation of middle gear 46 rotates outer gear 44 in the same direction. Gears 46 and 44 are sized such that pass point indications comprising switch release cutouts 74 and 76 line up only once during the entire travel distance of the door. As seen in FIG. 22A, when switch release cutouts 74 and 76 line up, switch 72 is open generating a pass point presence signal. The location where switch release cutouts 74 and 76 line up is the pass point. At all other times, at least one of the two gears holds switch 72 closed generating a signal indicating that the pass point has not been reached.
[0053] The receiver portion 80 of controller 200 is shown in FIG. 5A. RF signals may be received by the controller 200 at the antenna 32 and fed to the receiver 80. The receiver 80 includes variable inductor L1 and a pair of capacitors C2 and C3 that provide impedance matching between the antenna 32 and other portions of the receiver. An NPN transistor Q4 is connected in common-base configuration as a buffer amplifier. Bias to the buffer amplifier transistor Q4 is provided by resistors R2, R3. The buffered RF output signal is supplied to a second NPN transistor Q5. The radio frequency signal is coupled to a bandpass amplifier 280 to an average detector 282 which feeds a comparator 284. Referring to FIGS. 5C and 5B, the analog output signal A, B is applied to noise reduction capacitors C19, C20 and C21 then provided to pins P32 and P33 of the microcontroller 300. Microcontroller 300 may be a Z86733 microprocessor.
[0054] An external transformer 212 receives AC power from a source such as a utility and steps down the AC voltage to the power supply 90 circuit of controller 200. Transformer 212 provides AC current to full-wave bridge circuit 214, which produces a 28 volt full wave rectified signal across capacitor C35. The AC power may have a frequency of 50 Hz or 60 Hz. An external transformer is especially important when motor 118 is a DC motor. The 28 volt rectified signal is used to drive a wall control switch, a obstacle detector circuit, a door-in-door switch and to power FETs Q11 and Q12 used to start the motor. Zener diode D18 protects against overvoltage due to the pulsed current, in particular, from the FETs rapidly switching off inductive load of the motor. The potential of the full-wave rectified signal is further reduced to provide 5 volts at capacitor C38, which is used to power the microprocessor 300, the receiver circuit 80 and other logic functions.
[0055] The 28 volt rectified power supply signal indicated by reference numeral T in FIG. 5C is voltage divided down by resistors R61 and R62, then applied to an input pin P24 of microprocessor 300. This signal is used to provide the phase of the power line current to microprocessor 300. Microprocessor 300 constantly checks for the phase of the line voltage in order to determine if the frequency of the line voltage is 50 Hz or 60 Hz. This information is used to establish the worklight time-out period and to select the look-up table stored in the ROM in the microcontroller for converting pulse width to door speed.
[0056] When the door is commanded to move, either through a signal from a remote transmitter received through antenna 32 and processed by receiver 80, or through an optional wall switch, the microprocessor 300 commands the work light to turn on. Microprocessor 300 sends a worklight enable signal from pin P07. The worklight enable signal is applied to the base of transistor Q3, which drives relay K3. AC power from a signal U provides power for operating the worklight 210.
[0057] Microprocessor 300 reads from and writes data to an EEPROM 302 via its pins P25, P26 and P27. EEPROM 302 may be a 93C46. Microprocessor 300 provides a light enable signal at pin P21 which is used to enable a learn mode indicator yellow LED D15. LED D15 is enabled or lit when the receiver is in the learn mode. Pin P26 provides double duty. When the user selects switch S1, a learn enable signal is provided to both microprocessor 300 and EEPROM 302. Switch S1 is mounted on the head unit 12 and is part of switch module 39, which is used by the installer to operate the system.
[0058] An optional flasher module provides an additional level of safety for users and is controlled by microprocessor 300 at pin P22. The optional flasher module is connected between terminals 308 and 310. In the optional flasher module, after receipt of a door command, the microprocessor 300 sends a signal from P22 which causes the flasher light to blink for 2 seconds. The door does not move during that 2 second period, giving the user notice that the door has been commanded to move and will start to move in 2 seconds. After expiration of the 2 second period, the door moves and the flasher light module blinks during the entire period of door movement. If the operator does not have a flasher module installed in the head unit, when the door is commanded to move, there is no time delay before the door begins to move.
[0059] Microprocessor 300 provides the signals which start motor 116, control its direction of rotation (and thus the direction of movement of the door) and the speed of rotation (speed of door travel). FETs Q11 and Q12 are used to start motor 118. Microprocessor 300 applies a pulsed output signal to the gates of FETs Q11 and Q12. The lengths of the pulses determine the time the FETs conduct and thus the amount of time current is applied to start and run the motor 118. The longer the pulse, the longer current is applied, the greater the speed of rotation the motor 118 will develop. Diode D11 is coupled between the 28 volt power supply and is used to clean up flyback voltage to the input bridge D4 when the FETs are conducting. Similarly, Zener diode D19 (see FIG. 5A) is used to protect against overvoltage when the FETs are conducting.
[0060] Control of the direction of rotation of motor 118 (and thus direction of travel of the door) is accomplished with two relays, K1 and K2. Relay K1 supplies current to cause the motor to rotate clockwise in an opening direction (door moves UP); relay K2 supplies current to cause the motor to rotate counterclockwise in a closing direction (door moves DOWN). When the door is commanded to move UP, the microprocessor 300 sends an enable signal from pin P05 to the base of transistor Q1, which drives relay K1. When the door is commanded to move DOWN, the microprocessor 300 sends an enable signal from pin P06 to the base of transistor Q2, which drives relay K2.
[0061] Door-in-door contacts 13 and 15 are connected to terminals 304 and 306. Terminals 304 and 306 are connected to relays K1 and K2. If the signal between contacts 13 and 15 is broken, the signal across terminals 304 and 306 is open, preventing relays K1 and K2 from energizing. The motor 118 will not rotate and the door 24 will not move until the user closes pedestrian door 11, making contact between contacts 13 and 15.
[0062] The pass point signal 220 from the pass point module 40 (see FIG. 21) of motor 118 is applied to pin P23 of microprocessor 300. The RPM signal 224 from the RPM sensor module in motor 118 is applied to pin P31 of microprocessor 300. Application of the pass point signal and the RPM signal is described with reference to the flow charts.
[0063] An optional wall control, which duplicates the switches on remote transmitter 30, may be connected to controller 200 at terminals 312 and 314. When the user presses the door command switch 39, a dead short is made to ground, which the microprocessor 300 detects by the failure to detect voltage. Capacitor C22 is provided for RF noise reduction. The dead short to ground is sensed at pins P02 and P03, for redundancy.
[0064] Switches S1 and S2 are part of switch module 39 mounted on head unit 12 and used by the installer for operating the system. As stated above, S1 is the learn switch. S2 is the door command switch. When S2 is pressed, microprocessor 300 detects the dead short at pins P02 and P03.
[0065] Input from an obstacle detector (not shown) is provided at terminal 316. This signal is voltage divided down and provided to microprocessor 300 at pins P20 and P30, for redundancy. Except when the door is moving and less than an inch above the floor, when the obstacle detector senses an object in the doorway, the microprocessor executes the auto-reverse routine causing the door to stop and/or reverse depending on the state of the door movement.
[0066] Force and speed of door travel are determined by two potentiometers. Potentiometer R33 adjusts the force and speed of UP travel; potentiometer R34 adjusts the force and speed of DOWN travel. Potentiometers R33 and R34 act as analog voltage dividers. The analog signal from R33, R34 is further divided down by voltage divider R35/R37, R36/R38 before it is applied to the input of comparators 320 and 322. Reference pulses from pins P34 and P35 of microprocessor 300 are compared with the force input from potentiometers R33 and R34 in comparators 320 and 322. The output of comparators 320 and 322 is applied to pins P01 and P00.
[0067] To perform the A/D conversion, the microprocessor 300 samples the output of the comparators 320 and 322 at pins P00 and P01 to determine which voltage is higher: the voltage from the potentiometer R33 or R34 (IN) or the voltage from the reference pin P34 or P35 (REF). If the potentiometer voltage is higher than the reference, then the microprocessor outputs a pulse. If not, the output voltage is held low. The RC filter (R39, C29/R40, C30) converts the pulses into a DC voltage equivalent to the duty cycle of the pulses. By outputting the pulses in the manner described above, the microprocessor creates a voltage at REF which dithers around the voltage at IN. The microprocessor then calculates the duty cycle of the pulse output which directly correlates to the voltage seen at IN.
[0068] When power is applied to the head unit 12 including controller 200, microprocessor 300 executes a series of routines. With power applied, microprocessor 300 executes the main routines shown in FIGS. 6A and 6B. The main loop 400 includes three basic functions, which are looped continuously until power is removed. In block 402 the microprocessor 300 handles all non-radio EEPROM communications and disables radio access to the EEPROM 302 when communicating. This ensures that during normal operation, i.e., when the garage door operator is not being programmed, the remote transmitter does not have access to the EEPROM, where transmitter codes are stored. Radio transmissions are processed upon receipt of a radio interrupt (see below).
[0069] In block 404, microprocessor 300 maintains all low priority tasks, such as calculating new force levels and minimum speed. Preferably, a set of redundant RAM registers is provided. In the event of an unforeseen event (e.g., an ESD event) which corrupts regular RAM, the main RAM registers and the redundant RAM registers will not match. Thus, when the values in RAM do not match, the routine knows the regular RAM has been corrupted. (See block 504 below.) In block 406, microprocessor 300 tests redundant RAM registers. Several interrupt routines can take priority over blocks 402, 404 and 406.
[0070] The infrared obstacle detector generates an asynchronous IR interrupt signal which is a series of pulses. The absence of the obstacle detector pulses indicates an obstruction in the beam. After processing the IR interrupt, microprocessor 300 sets the status of the obstacle detector as unobstructed at block 416.
[0071] Receipt of a transmission from remote transmitter 30 generates an asynchronous radio interrupt at block 410. At block 418, if in the door command mode, microprocessor 300 parses incoming radio signals and sets a flag if the signal matches a stored code. If in the learn mode, microprocessor 300 stores the new transmitter codes in the EEPROM.
[0072] An asynchronous interrupt is generated if a remote communications unit is connected to an optional RS-232 communications port located on the head unit. Upon receipt of the hardware interrupt, microprocessor 300 executes a serial data communications routine for transferring and storing data from the remote hardware.
[0073] Hardware timer 0 interrupt is shown in block 422. In block 422, microprocessor 300 reads the incoming AC line signal from pin P24 and handles the motor phase control output. The incoming line signal is used to determine if the line voltage is 50 Hz for the foreign market or 60 Hz for the domestic market. With each interrupt, microprocessor 300, at block 426, task switches among three tasks. In block 428, microprocessor 300 updates software timers. In block 430, microprocessor 300 debounces wall control switch signals. In block 432, microprocessor 300 controls the motor state, including motor direction relay outputs and motor safety systems.
[0074] When the motor 118 is running, it generates an asynchronous RPM interrupt at block 434. When microprocessor 300 receives the asynchronous RPM interrupt at pin P31, it calculates the motor RPM period at block 436, then updates the position of the door at block 438.
[0075] Further details of main loop 400 are shown in FIGS. 7A through 7H. The first step executed in main loop 400 is block 450, where the microprocessor checks to see if the pass point has been passed since the last update. If it has, the routine branches to block 452, where the microprocessor 300 updates the position of the door relative to the pass point in EEPROM 302 or non-volatile memory. The routine then continues at block 454. An optional safety feature of the garage door operator system enables the worklight, when the door is open and stopped and the infrared beam in the obstacle detector is broken.
[0076] At block 454, the microprocessor checks if the enable/disable of the worklight for this feature has been changed. Some users want the added safety feature; others prefer to save the electricity used. If new input has been provided, the routine branches to block 456 and sets the status of the obstacle detector-controlled worklight in non-volatile memory in accordance with the new input. Then the routine continues to block 458 where the routine checks to determine if the worklight has been turned on without the timer. A separate switch is provided on both the remote transmitter 30 and the head unit at module 39 to enable the user to switch on the worklight without operating the door command switch. If no, the routine skips to block 470.
[0077] If yes, the routine checks at block 460 to see if the one-shot flag has been set for an obstacle detector beam break. If no, the routine skips to block 470. If yes, the routine checks if the obstacle detector controlled worklight is enabled at block 462. If not, the routine skips to block 470. If it is, the routine checks if the door is stopped in the fully open position at block 464. If no, the routine skips to block 470. If yes, the routine calls the SetVarLight subroutine (see FIG. 8) to enable the appropriate turn off time (4.5 minutes for 60 Hz systems or 2.5 minutes for 50 Hz systems). At block 468, the routine turns on the worklight.
[0078] At block 470, the microprocessor 300 clears the one-shot flag for the infrared beam break. This resets the obstacle detector, so that a later beam break can generate an interrupt. At block 472, if the user has installed a temporary password usable for a fixed period of time, the microprocessor 300 updates the non-volatile timer for the radio temporary password. At block 474, the microprocessor 300 refreshes the RAM registers for radio mode from non-volatile memory (EEPROM 302). At block 476, the microprocessor 300 refreshes I/O port directions, i.e., whether each of the ports is to be input or output. At block 478, the microprocessor 300 updates the status of the radio lockout flag, if necessary. The radio lockout flag prevents the microprocessor from responding to a signal from a remote transmitter. A radio interrupt (described below) will disable the radio lockout flag and enable the remote transmitter to communicate with the receiver.
[0079] At block 480, the microprocessor 300 checks if the door is about to travel. If not, the routine skips to block 502. If the door is about to travel, the microprocessor 300 checks if the limits are being trained at block 482. If they are, the routine skips to block 502. If not, the routine asks at block 484 if travel is UP or DOWN. If DOWN, the routine refreshes the DOWN limit from non-volatile memory (EEPROM 302) at block 486. If UP, the routine refreshes the UP limit from non-volatile memory (EEPROM 302) at block 488. The routine updates the current operating state and position relative to the pass point in non-volatile memory at block 490. This is a redundant read for stability of the system.
[0080] At block 492, the routine checks for completion of a limit training cycle. If training is complete, the routine branches to block 494 where the new limit settings and position relative to the pass point are written to non-volatile memory.
[0081] The routine then updates the counter for the number of operating cycles at block 496. This information can be downloaded at a later time and used to determine when certain parts need to be replaced. At block 498 the routine checks if the number of cycles is a multiple of 256. Limiting the storage of this information to multiples of 256 limits the number of times the system has to write to that register. If yes it updates the history of force settings at block 500. If not, the routine continues to block 502.
[0082] At block 502 the routine updates the learn switch debouncer. At block 504 the routine performs a continuity check by comparing the backup (redundant) RAM registers with the main registers. If they do not match, the routine branches to block 506. If the registers do not match, the RAM memory has been corrupted and the system is not safe to operate, so a reset is commanded. At this point, the system powers up as if power had been removed and reapplied and the first step is a self test of the system (all installation settings are unchanged).
[0083] If the answer to block 504 is yes, the routine continues to block 508 where the routine services any incoming serial messages from the optional wall control (serial messages might be user input start or stop commands). The routine then loads the UP force timing from the ROM look-up table, using the user setting as an index at block 510. Force potentiometers R33 and R34 are set by the user. The analog values set by the user are converted to digital values. The digital values are used as an index to the look-up table stored in memory. The value indexed from the look-up table is then used as the minimum motor speed measurement. When the motor runs, the routine compares the selected value from the look-up table with the digital timing from the RPM routine to ensure the force is acceptable.
[0084] Instead of calculating the force each time the force potentiometers are set, a look-up table is provided for each potentiometer. The range of values based on the range of user inputs is stored in ROM and used to save microprocessor processing time. The system includes two force limits: one for the UP force and one for the DOWN force. Two force limits provide a safer system. A heavy door may require more UP force to lift, but need a lower DOWN force setting (and therefore a slower closing speed) to provide a soft closure. A light door will need less UP force to open the door and possibly a greater DOWN force to provide a full closure.
[0085] Next the force timing is divided by power level of the motor for the door to scale the maximum force timeout at block 512. This step scales the force reversal point based on the maximum force for the door. The maximum force for the door is determined based on the size of the door, i.e. the distance the door travels. Single piece doors travel a greater distance than segmented doors. Short doors require less force to move than normal doors. The maximum force for a short door is scaled down to 60 percent of the maximum force available for a normal door. So, at block 512, if the force setting is set by the user, for example at 40 percent, and the door is a normal door (i.e., a segmented door or multi-paneled door), the force is scaled to 40 percent of 100 percent. If the door is a short door (i.e., a single panel door), the force is scaled to 40 percent of 60 percent, or 24 percent.
[0086] At block 514, the routine loads the DOWN force timing from the ROM look-up table, using the user setting as an index. At block 516, the routine divides the force timing by the power level of the motor for the door to scale the force to the speed.
[0087] At block 518 the routine checks if the door is traveling DOWN. If yes, the routine disables use of the MinSpeed Register at block 524 and loads the MinSpeed Register with the DOWN force setting, i.e., the value read from the DOWN force potentiometer at block 526. If not, the routine disables use of the MinSpeed Register at block 520 and loads the MinSpeed Register with the UP force setting from the force potentiometer at block 522.
[0088] The routine continues at block 528 where the routine subtracts 20 from the MinSpeed value. The MinSpeed value ranges from 0 to 63. The system uses 64 levels of force. If the result is negative at block 530, the routine clears the MinSpeed Register at block 532 to effectively truncate the lower 38 percent of the force settings. If no, the routine divides the minimum speed by 4 to scale 8 speeds to 32 force settings at block 534. At block 536, the routine adds 4 into the minimum speed to correct the offset, and clips the result to a maximum of 12. At block 538 the routine enables use of the MinSpeed Register.
[0089] At block 540 the routine checks if the period of the rectified AC line signal (input to microprocessor 300 at pin P24) is less than 9 milliseconds (indicating the line frequency is 60 Hz). If it is, the routine skips to block 548. If not, the routine checks if the light shut-off timer is active at block 542. If not, the routine skips to block 548. If yes, the routine checks if the light time value is greater than 2.5 minutes at block 544. If no, the routine skips to block 548. If yes, the routine calls the SetVarLight subroutine (see FIG. 8), to correct the light timing setting, at block 546.
[0090] At block 548 the routine checks if the radio signal has been clear for 100 milliseconds or more. If not, the routine skips to block 552. If yes, the routine clears the radio at block 550. At block 552, the routine resets the watchdog timer. At block 554, the routine loops to the beginning of the main loop.
[0091] The SetVarLight subroutine, FIG. 8, is called whenever the door is commanded to move and the worklight is to be turned on. When the SetVarLight subroutine, block 558 is called, the subroutine checks if the period of the rectified power line signal (pin P24 of microprocessor 300) is greater than or equal to 9 milliseconds. If yes, the line frequency is 50 Hz, and the timer is set to 2.5 minutes at block 564. If no, the line frequency is 60 Hz and the timer is set to 4.5 minutes at block 562. After setting, the subroutine returns to the call point at block 566.
[0092] The hardware timer interrupt subroutine operated by microprocessor 300, shown at block 422, runs every 0.256 milliseconds. Referring to FIGS. 9A-9C, when the subroutine is first called, it sets the radio interrupt status as indicated by the software flags at block 580. At block 582, the subroutine updates the software timer extension. The next series of steps monitor the AC power line frequency (pin P24 of microprocessor 300). At step 584, the subroutine checks if the rectified power line input is high (checks for a leading edge). If yes, the subroutine skips to block 594, where it increments the power line high time counter, then continues to block 596. If no, the subroutine checks if the high time counter is below 2 milliseconds at block 586. If yes, the subroutine skips to block 594. If no, the subroutine sets the measured power line time in RAM at block 588. The subroutine then resets the power line high time counter at block 590 and resets the phase timer register in block 592.
[0093] At block 596, the subroutine checks if the motor power level is set at 100 percent. If yes, the subroutine turns on the motor phase control output at block 606. If no, the subroutine checks if the motor power level is set at 0 percent at block 598. If yes, the subroutine turns off the motor phase control output at block 604. If no, the phase timer register is decremented at block 600 and the result is checked for sign. If positive the subroutine branches to block 606; if negative the subroutine branches to block 604.
[0094] The subroutine continues at block 608 where the incoming RPM signal (at pin P31 of microprocessor 300) is digitally filtered. Then the time prescaling task switcher (which loops through 8 tasks identified at blocks 620, 630, 640, 650) is incremented at block 610. The task switcher varies from 0 to 7. At block 612, the subroutine branches to the proper task depending on the value of the task switcher.
[0095] If the task switcher is at value 2 (this occurs every 4 milliseconds), the execute motor state machine subroutine is called at block 620. If the task is value 0 or 4 (this occurs every 2 milliseconds), the wall control switches are debounced at block 630. If the task value is 6 (this occurs every 4 milliseconds), the execute 4 ms timer subroutine is called at block 640. If the task is value 1, 3, 5 or 7, the 1 millisecond timer subroutine is called at block 650. Upon completion of the called subroutine, the 0.256 millisecond timer subroutine returns at block 614.
[0096] Details of the 1 ms timer subroutine (block 650) are shown in FIGS. 10A-10C. When this subroutine is called, the first step is to update the A/D converters on the UP and DOWN force setting potentiometers (P34 and P35 of microprocessor 300) at block 652. At block 654, the subroutine checks if the A/D conversion (comparison at comparators 320 and 322) is complete. If yes, the measured potentiometer values are stored at block 656. Then the stored values (which vary from 0 to 127) are divided by 2 to obtain the 64 level force setting at block 658. If no, the subroutine decrements the infrared obstacle detector timeout timer at block 660. In block 662, the subroutine checks if the timer has reached zero. If no, the subroutine skips to block 672. If yes, the subroutine resets the infrared obstacle detector timeout timer at block 664. The flag setting for the obstacle detector signal is checked at block 666. If no, the one-shot break flag is set at block 668. If yes, the flag is set indicating the obstacle detector signal is absent at block 670.
[0097] At block 672, the subroutine increments the radio time out register. Then the infrared obstacle detector reversal timer is decremented at block 674. The pass point input is debounced at block 676. The 125 millisecond prescaler is incremented at block 678. Then the prescaler is checked if it has reached 63 milliseconds at block 680. If yes, the fault blinking LED is updated at block 682. If no, the prescaler is checked if it has reached 125 ms at block 684. If yes, the 125 ms timer subroutine is executed at block 686. If no, the routine returns at block 688.
[0098] The 125 millisecond timer subroutine (block 690) is used to manage the power level of the motor 118. At block 692, the subroutine updates the RS-232 mode timer and exits the RS-232 mode timer if necessary. The same pair of wires is used for both wall control switches and RS-232 communication. If RS-232 communication is received while in the wall control mode, the RS-232 mode is entered. If four seconds passes since the last RS-232 word was received, then the RS-232 timer times out and reverts to the wall control mode. At block 694 the subroutine checks if the motor is set to be stopped. If yes, the subroutine skips to block 716 and sets the motor's power level to 0 percent. If no, the subroutine checks if the pre-travel safety light is flashing at block 696 (if the optional flasher module has been installed, a light will flash for 2 seconds before the motor is permitted to travel and then flash at a predetermined interval during motor travel). If yes, the subroutine skips to block 716 and sets the motor's power level to 0 percent.
[0099] If no, the subroutine checks if the microprocessor 300 is in the last phase of a limit training mode at block 698. If yes, the subroutine skips to block 710. If no, the subroutine checks if the microprocessor 300 is in another part of the limit training mode at block 700. If no, the subroutine skips to block 710. If yes, the subroutine checks if the minimum speed (as determined by the force settings) is greater than 40 percent at block 704. If no, the power level is set to 40 percent at block 708. If yes, the power level is set equal to the minimum speed stored in MinSpeed Register at block 706.
[0100] At block 710 the subroutine checks if the flag is set to slow down. If yes, the subroutine checks if the motor is running above or below minimum speed at block 714. If above minimum speed, the power level of the motor is decremented one step increment (one step increment is preferably 5% of maximum motor speed) at block 722. If below the minimum speed, the power level of the motor is incremented one step increment (which is preferably 5% of maximum motor speed) to minimum speed at block 720.
[0101] If the flag is not set to slow down at block 710, the subroutine checks if the motor is running at maximum allowable speed at block 712. If no, the power level of the motor is incremented one step increment (which is preferably 5% of maximum motor speed) at block 720. If yes, the flag is set for motor ramp-up speed complete.
[0102] The subroutine continues at block 724 where it checks if the period of the rectified AC power line (pin P24 of microprocessor 300) is greater than or equal to 9 ms. If no, the subroutine fetches the motor's phase control information (indexed from the power level) from the 60 Hz look-up table stored in ROM at block 728. If yes, the subroutine fetches the motor's phase control information (indexed from the power level) from the 50 Hz look-up table stored in ROM at block 726.
[0103] The subroutine tests for a user enable/disable of the infrared obstacle detector-controlled worklight feature at block 730. Then the user radio learning timers, ZZWIN (at the wall keypad if installed) and AUXLEARNSW (radio on air and worklight command) are updated at block 732. The software watchdog timer is updated at block 734 and the fault blinking LED is updated at block 736. The subroutine returns at block 738.
[0104] The 4 millisecond timer subroutine is used to check on various systems which do not require updating as often as more critical systems. Referring to FIGS. 12A and 12B, the subroutine is called at block 640. At block 750, the RPM safety timers are updated. These timers are used to determine if the door has engaged the floor. The RPM safety timer is a one second delay before the operator begins to look for a falling door, i.e., one second after stopping. There are two different forces used in the garage door operator. The first type force are the forces determined by the UP and DOWN force potentiometers. These force levels determine the speed at which the door travels in the UP and DOWN directions. The second type of force is determined by the decrease in motor speed due to an external force being applied to the door (an obstacle or the floor). This programmed or pre-selected external force is the maximum force that the system will accept before an auto-reverse or stop is commanded.
[0105] A block 752 the 0.5 second RPM timer is checked to see if it has expired. If yes, the 0.5 second timer is reset at block 754. At block 756 safety checks are performed on the RPM seen during the last 0.5 seconds to prevent the door from falling. The 0.5 second timer is chosen so the maximum force achieved at the trolley will reach 50 kilograms in 0.5 seconds if the motor is operating at 100 percent of power.
[0106] At block 758, the subroutine updates the 1 second timer for the optional light flasher module. In this embodiment, the preferred flash period is 1 second. At block 760 the radio dead time and dropout timers are updated. At block 762 the learn switch is debounced. At block 764 the status of the worklight is updated in accordance with the various light timers. At block 766 the optional wall control blink timer is updated. The optional wall control includes a light which blinks when the door is being commanded to auto-reverse in response to an infrared obstacle detector signal break. At block 768 the subroutine returns.
[0107] Further details of the asynchronous RPM signal interrupt, block 434, are shown in FIGS. 13A and 13B. This signal, which is provided to microprocessor 300 at pin P31, is used to control the motor speed and the position detector. Door position is determined by a value relative to the pass point. The pass point is set at 0. Positions above the pass point are negative; positions below the pass point are positive. When the door travels to the UP limit, the position detector (or counter) determines the position based on the number of RPM pulses to the UP limit number. When the door travels DOWN to the DOWN limit, the position detector counts the number of RPM pulses to the DOWN limit number. The UP and DOWN limit numbers are stored in a register.
[0108] At block 782 the RPM interrupt subroutine calculates the period of the incoming RPM signal. If the door is traveling UP, the subroutine calculates the difference between two successive pulses. If the door is traveling DOWN, the subroutine calculates the difference between two successive pulses. At block 784, the subroutine divides the period by 8 to fit into a binary word. At block 786 the subroutine checks if the motor speed is ramping up. This is the max force mode. RPM timeout will vary from 10 to 500 milliseconds. Note that these times are recommended for a DC motor. If an AC motor is used, the maximum time would be scaled down to typically 24 milliseconds. A 24 millisecond period is slower than the breakdown RPM of the motor and therefore beyond the maximum possible force of most preferred motors. If yes, the RPM timeout is set at 500 milliseconds (0.5 seconds) at block 790. If no, the subroutine sets the RPM timeout as the rounded-up value of the force setting in block 788.
[0109] At block 792 the subroutine checks for the direction of travel. This is found in the state machine register. If the door is traveling DOWN, the position counter is incremented at block 796 and the pass point debouncer is sampled at block 800. At block 804, the subroutine checks for the falling edge of the pass point signal. If the falling edge is present, the subroutine returns at block 814. If there is a pass point falling edge, the subroutine checks for the lowest pass point (in cases where more than one pass point is used). If this is not the lowest pass point, the subroutine returns at block 814. If it is the only pass point or the lowest pass point, the position counter is zeroed and the subroutine returns at block 814.
[0110] If the door is traveling UP, the subroutine decrements the position counter at block 794 and samples the pass point debouncer at block 798. Then it checks for the rising edge of the pass point signal at block 802. If there is no pass point signal rising edge, the subroutine returns at block 814. If there is, it checks for the lowest pass point at block 806. If no the subroutine returns at block 814. If yes, the subroutine zeroes the position counter and returns at block 814.
[0111] The motor state machine subroutine, block 620, is shown in FIG. 14. It keeps track of the state of the motor. At block 820, the subroutine updates the false obstacle detector signal output, which is used in systems that do not require an infrared obstacle detector. At block 822, the subroutine checks if the software watchdog timer has reached too high a value. If yes, a system reset is commanded at block 824. If no, at block 826, it checks the state of the motor stored in the motor state register located in EEPROM 302 and executes the appropriate subroutine.
[0112] If the door is traveling UP, the UP direction subroutine at block 832 is executed. If the door is traveling DOWN, the DOWN direction subroutine is executed at block 828. If the door is stopped in the middle of the travel path, the stop in midtravel subroutine is executed at block 838. If the door is fully closed, the DOWN position subroutine is executed at block 830. If the door is fully open, the UP position subroutine is executed at block 834. If the door is reversing, the auto-reverse subroutine is executed at block 836.
[0113] When the door is stopped in midtravel, the subroutine at block 838 is called, as shown in FIG. 15. In block 840 the subroutine updates the relay safety system (ensuring that relays K1 and K2 are open). The subroutine checks for a received wall command or radio command. If there is no received command, the subroutine updates the worklight status and returns. If yes, the motor power is set to 20 percent at block 844 and the motor state is set to traveling DOWN at block 846. The worklight status is updated and the subroutine returns at block 850. If the door is stopped in midtravel and a door command is received, the door is set to close. The next time the system calls the motor state machine subroutine, the motor state machine will call the DOWN direction subroutine. The door must close to the DOWN limit before it can be opened to the full UP limit.
[0114] If the state machine indicates the door is in the DOWN position (i.e. the DOWN limit position), the DOWN position subroutine, block 830, at FIG. 16 is called. When the door is in the DOWN position, the subroutine checks if a wall control or radio command has been received. If no, the subroutine updates the light and returns at block 858. If yes, the motor power is set to 20 percent at block 854 and the motor state register is set to show the state is traveling UP at block 856. The subroutine then updates the light and returns at block 858.
[0115] The UP direction subroutine, block 832, is shown in FIGS. 17A-17C. At block 860 the subroutine waits until the main loop refreshes the UP limit from EEPROM 302. Then it checks if 40 milliseconds have passed since closing of the light relay K3 at block 862. If not, the subroutine returns. If yes, the subroutine checks for flashing the warning light prior to travel at block 866 (only if the optional flasher module is installed). If the light is flashing, the status of the blinking light is updated and the subroutine returns at block 868. If not, the flashing is terminated, the motor UP relay is turned on at block 870. Then the subroutine waits until 1 second has passed after the motor was turned on at block 872. If no, the subroutine skips to block 888. If yes, the subroutine checks for the RPM signal timeout. If no, the subroutine checks if the motor speed is ramping up at block 876 by checking the value of the RAMPFLAG register in RAM (i.e., UP, DOWN, FULLSPEED, STOP). If yes, the subroutine skips to block 888. If no, the subroutine checks if the measured RPM is longer than the allowable RPM period at block 878. If no, the subroutine continues at block 888.
[0116] If the RPM signal has timed out at block 874 or the measured time period is longer than allowable at block 878, the subroutine branches to block 880. At block 880, the reason is set as force obstruction. At block 882, if the training limits are being set, the training status is updated. At block 884 the motor power is set to zero and the state is set as stopped in midtravel. At block 886 the subroutine returns.
[0117] At block 888 the subroutine checks if the door's exact position is known. If it is not, the door's distance from the UP limit is updated in block 890 by subtracting the UP limit stored in RAM from the position of the door also stored in RAM. Then the subroutine checks at block 892 if the door is beyond its UP limit. If yes, the subroutine sets the reason as reaching the limit in block 894. Then the subroutine checks if the limits are being trained. If yes, the limit training machine is updated at block 898. If no, the motor's power is set as zero and the motor state is set at the UP position in block 900. Then the subroutine returns at block 902.
[0118] If the door is not beyond its UP limit, the subroutine checks if the door is being manually positioned in the training cycle at block 904. If not, the door position within the slowdown distance of the limit is checked at block 906. If yes, the motor slow down flag is set at block 910. If the door is being positioned manually at block 904 or the door is not within the slow down distance, the subroutine skips to block 912. At block 912 the subroutine checks if a wall control or radio command has been received. If yes, the motor power is set at zero and the state is set at stopped in midtravel as block 916. If no, the system checks if the motor has been running for over 27 seconds at block 914. If yes, the motor power is set at zero and the motor state is set at stopped in midtravel at block 916. Then the subroutine returns at block 918.
[0119] Referring to FIG. 18, the auto-reverse subroutine block 836 is described. (Force reversal is stopping the motor for 0.5 seconds, then traveling UP.) At block 920 the subroutine updates the 0.5 second reversal timer (the force reversal timer described above). Then the subroutine checks at block 922 for expiration of the force-reversal timer. If yes, the motor power is set to 20 percent at block 924 and the motor state is set to traveling UP at block 926 and the subroutine returns at block 932. If the timer has not expired, the subroutine checks for receipt of a wall command or radio command at block 928. If yes, the motor power is set to zero and the state is set at stopped in midtravel at block 930, then the subroutine returns at block 932. If no, the subroutine returns at block 932.
[0120] The UP position routine, block 834, is shown in FIG. 19. Door travel limits training is started with the door in the UP position. At block 934, the subroutine updates the relay safety system. Then the subroutine checks for receipt of a wall command or radio command at block 936 indicating an intervening user command. If yes, the motor power is set to 20 percent at block 938 and the state is set at traveling DOWN in block 940. Then the light is updated and the subroutine returns at block 950. If no wall command has been received, the subroutine checks for training the limits at block 942. If no, the light is updated and the subroutine returns at block 950. If yes, the limit training state machine is updated at block 944. Then the subroutine checks if it is time to travel DOWN at block 946. If no, the subroutine updates the light and returns at block 950. If it is time to travel DOWN, the state is set at traveling DOWN at block 948 and the system returns at block 950.
[0121] The DOWN direction subroutine, block 828, is shown in FIGS. 20A-20D. At block 952, the subroutine waits until the main loop routine refreshes the DOWN limit from EEPROM 302. For safety purposes, only the main loop or the remote transmitter (radio) can access data stored in or written to the EEPROM 302. Because EEPROM communication is handled within software, it is necessary to ensure that two software routines do not try to communicate with the EEPROM at the same time (and have a data collision). Therefore, EEPROM communication is allowed only in the Main Loop and in the Radio routine, with the Main loop having a busy flag to prevent the radio from communicating with the EEPROM at the same time. At block 954, the subroutine checks if 40 milliseconds has passed since closing of the light relay K3. If no, the subroutine returns at block 956. If yes, the subroutine checks if the warning light is flashing (for 2 seconds if the optional flasher module is installed) prior to travel at block 958. If yes, the subroutine updates the status of the flashing light and returns at block 960. If no, or the flashing is completed, the subroutine turns on the DOWN motor relay K2 at block 962. At block 964 the subroutine checks if one second has passed since the motor is first turned on. The system ignores the force on the motor for the first one second. This allows the motor time to overcome the inertia of the door (and exceed the programmed force settings) without having to adjust the programmed force settings for ramp up, normal travel and slow down. Force is effectively set to maximum during ramp up to overcome sticky doors.
[0122] If the one second time has not passed, the subroutine skips to block 984. If the one second time limit has passed, the subroutine checks for the RPM signal time out at block 966. If no, the subroutine checks if the motor speed is currently being ramped up at block 968 (this is a maximum force condition). If yes, the routine skips to block 984. If no, the subroutine checks if the measured RPM period is longer than the allowable RPM period. If no, the subroutine continues at block 984.
[0123] If either the RPM signal has timed out (block 966) or the RPM period is longer than allowable (block 970), this is an indication of an obstruction or the door has reached the DOWN limit position, and the subroutine skips to block 972. At block 972, the subroutine checks if the door is positioned beyond the DOWN limit setting. If it is, the subroutine skips to block 990 where it checks if the motor has been powered for at least one second. This one second power period after the DOWN limit has been reached provides for the door to close fully against the floor. This is especially important when DC motors are used. The one second period overcomes the internal braking effect of the DC motor on shut-off. Auto-reverse is disabled after the position detector reaches the DOWN limit.
[0124] If the motor has been running for one second, at block 990, the subroutine sets the reason as reaching the limit at block 994. The subroutine then checks if the limits are being trained at block 998. If yes, the limit training machine is updated at block 1002. If no, the motor's power is set to zero and the motor state is set at the DOWN position in block 1006. In block 1008 the subroutine returns.
[0125] If the motor has not been running for at least one second at block 990, the subroutine sets the reason as early limit at block 1026. Then the subroutine sets the motor power at zero and the motor state as auto-reverse at block 1028 and returns at block 1030.
[0126] Returning to block 984, the subroutine checks if the door's position is currently unknown. If yes, the subroutine skips to block 1004. If no, the subroutine updates the door's distance from the DOWN limit using internal RAM in microprocessor 300 in block 986. Then the subroutine checks at block 988 if the door is three inches beyond the DOWN limit. If yes, the subroutine skips to block 990. If no, the subroutine checks if the door is being positioned manually in the training cycle at block 992. If yes, the subroutine skips to block 1004. If no, the subroutine checks if the door is within the slow DOWN distance of the limit at block 996. If no, the subroutine skips to block 1004. If yes, the subroutine sets the motor slow down flag at block 1000.
[0127] At block 1004, the subroutine checks if a wall control command or radio command has been received. If yes, the subroutine sets the motor power at zero and the state as auto-reverse at block 1012. If no, the subroutine checks if the motor has been running for over 27 seconds at block 1010. If yes, the subroutine sets the motor power at zero and the state at auto-reverse. If no, the subroutine checks if the obstacle detector signal has beer, missing for 12 milliseconds or more at block 1014 indicating the presence of the obstacle or the failure of the detector. If no, the subroutine returns at block 1018. If yes, the subroutine checks if the wall control or radio signal is being held to override the infrared obstacle detector at block 1016. If yes, the subroutine returns at block 1018. If no, the subroutine sets the reason as infrared obstacle detector obstruction at block 1020. The subroutine then sets the motor power at zero and the state as auto-reverse at block 1022 and returns at block 1024. (The auto-reverse routine stops the motor for 0.5 seconds then causes the door to travel up.)
[0128] The appendix attached hereto includes a source listing of a series of routines used to operate a movable barrier operator in accordance with the present invention.
[0129] While there has been illustrated and described a particular embodiment of the present invention, it will be appreciated that numerous changes and modifications will occur to those skilled in the art, and it is intended in the appended claims to cover all those changes and modifications which followed in the true spirit and scope of the present invention.
1APPENDIX
|
|
PRO7000 DC Motor Operator
Manual forces, automatic limits
New learn switch for learning the limits
Code based on Flex GDO
Notes:
Motor is controlled via two Form C relays to control direction
Motor speed is controlled via a fet (2 IRF540's in parallel) with a
phase control PWM applies.
Wall control (and RS232) are P98 with a redundant smart button and
command button on the logic board
Flex GDO Logic Board
Fixed AND Rolling Code Functionality
Learn from keyless entry transmitter
Posi-lock
Turn on light from broken IR beam (when at up limit)
Keyless entry temporary password based on number of hours or number
of activations. (Rolling code mode only)
GDO is initialized to a ‘clean slate’ mode when the memory is erased.
In this mode, the GDO will receive either fixed or rolling codes.
When the first radio code is learned, the GDO locks itself into that
mode (fixed or rolling) until the memory is again erased.
Rolling code derived from the Leaded67 code
Using the 8K zilog 233 chip
Timer interrupt needed to be 2X faster
Revision history
Revision 1.1:
Changed light from broken IP beam to work in both fixed and rolling
modes.
Changed light from IR beam to work only on beam break, not on beam
block.
Revision 1.2:
Learning rolling code formely erased fixed code. Mode is now
determined by first transmitter learned after radio erase.
Revision 1.3:
Moved radio interrupt disable to reception of 20 bits.
Changed mode of radio switching. Formely toggled upon radio error,
now switches in pseudo-random fashion depending upon value of
125 ms timer.
Revision 1.4:
Optimized portion of radio after bit value is determined. Used
relative addressing to speed code and minimize ROM size.
Revision 1.5:
Changed mode of learning transmitters. Learn command is now
light-command, learn light is now light-lock, and learn open/close/
stop is lock-command. (Command was press light, press command,
release light, release command, worklight was press light, press
command,
release command, release light, o/c/s was press lock, press command,
release command, release lock. This caused DOG2 to reset
Revision 1.6:
Light button and light transmitter now ignored during travel.
Switch data cleared only after a command switch is checked.
Revision 1.7:
Rejected fixed mode (and fixed mode test) when learning light and
open/close/stop transmitters.
Revision 1.8:
Changed learn from wall control to work obly when both switches are
held. Modified force pot. read routine (moved enabling of blank
time and disabling of interrupts. Fixed mode now learns command
with any combination of wall control switches.
Revision 1.9:
Changed PWM output to go from 0-50% duty cycle. This eliminated
the problem of PWM interrupts causing problems near 100% duty cycle.
THIS REVISION REQUIRES A HARDWARE CHANGE.
Revision 1.9A:
Enabled ROM chacksum. Cleaned up documentation.
Revision 2.0:
Blank tire noise immunity,. If noise signal is detected during blank time
the data already received is not thrown out. The data is retained, and the
noise pulse identified as such. The interrupt is enabled to contine to look
for the sync pulse.
Revision 2.0A:
On the event that the noise pulse is of the same duration as the sync
pulse the time between sync and first data pulse (inactive time) is
measured The inactive time is 5.14 ms for billion code and 2.4 ms for
rolling code. If it is determined that the previously received sync is
indeed a noise pulse, the pulse is thrown out and the micro continules to
lock for a sync pulse as in Rev. 2.0.
Revision 2.1:
To make the blank time more impervious to noise, the sync pulses are
differentiated between. Fixed max width is 4.6 ms, roll max width is 2.3
ms.
This is simular to the inactive time check done in Rev. 2.0A.
Revision 2.2:
The worklight function; when the IP beam is broken and the door is at
the up limit the light will turn on for 4.5 min. This revision allows
the worklight function to be enabled and disabled by the user. The
function will come enabled from the factor.
To disable, with the light off press and hold the light button for 7 sec.
The light will come on and after 5 sec. the function is disabled the light
will turn off. To enable the function, turn the light on, release the
button, then press and hold the light button down for 5 sec. The light
will turn off and after the function has been enable in 5 sec.
the light will turn on.
Revision 3.0:
Integrated in functionality for Siminor rolling code transmitter. The
Siminor transmitter may be received whenever a C code transmitter may
be received.
Siminor transmitters are able to perform as a standard command or as a
light control transmitter, but not as an open/close/stop transmitter.
Revision 3.1:
Modified handling of rolling code counter (in mirroring and adding) to
improve efficiency and hopefully kill all short cycles when a radio is
jammed on the
air.
PROD000
Revision 0.1:
Removed physical radio tests
Disabled radio temporarily
Put in sign bit test for limits
Automatic limits working
Revision 0.2:
Provided for traveling up when too close to limit
Revision 0.3:
Changed force pot. read to new routine.
Disabled T1 interrupt and all old force pot. code
Disabled all RS232 output
Revision 0.4:
Added in (veerrrry) rough force into pot. read routine
Revision 0.5:
Changed EEPROM in comments to add in up limit, last operation, and
down limit.
Created OnePass register
Added in limit read from nonvolatile when going to a moving state
Added in limit read on power-up
Created passcounter register to keep track of pass point(s)
Installed basic wake-up routine to restore position based on last state
Revision 0.6:
Changed RPM time read to routine used in P98 to save RAM
Changed operation of RPM forced up travel
Implemented pass point for one-pass-point travel
Revision 0.7:
Changed pass point from single to multiple (no EEPROM support)
Revision 0.8:
Changed all CKIPRADIO loads from 0xFF to NOEECOMM
Installed EEPROM support for multiple pass points
Revision 0.9:
Changed state machine to handle wake-up (i.e. always head towards
the lowest pass point to re-orient the GDO)
Revision 0.10:
Changed the AC line input routine to work off full-wave rectified
AC coming in
Revision 0.11:
Installed the phase control for motor speed control
Revision 0.12:
Installed traveling down if too near up limit
Installed speed-up when starting travel
Installed slow-down when ending travel
Revision 0.13:
Re-activated the C code
Revision 0.14:
Added in conditional assembly for Siminor radio codes
Revision 0.15:
Disabled old wall control code
Changed all pins to conform with new layout
Removed unused constants
Commented out old wall control routine
Changed code to run at 6 MHz
Revision 0.16:
Fixed bugs in Flex radio
Revision 0.17:
Re-enabled old wall control. Changed command charging time to 12 ms
to fix FMEA problems with IR protectors.
Revision 0.18:
Turned on learn switch connected to EEPROM clock line
Revision 0.19
Eliminated unused registers
Moved new registers out of radio group
Re-enabled radio interrupt
Revision 0.20
Changed limit test to account for “lost” position
Re-wrote pass point routine
Revision 0.21
Changed limit tests in state setting routines
Changed criteria for looking for lost position
Changed lost operation to stop until position is known
Revision 0.22:
Added in L_A_C state machine to learn the limits
Installed learn-command to go into LAC mode
Added in command button and learn button jog commands
Disabled limit testing when in learn mode
Added in LED flashing for in learn mode
Added in EVERYTHING with respect to learning limits
Note: LAC still isn't working properly!!!
Revision 0.23:
Added in RS232 functionality over wall control lines
Revision 0.24:
Touched up RS232 over wall control routine
Removed 50 Hz force table
Added in fixes to LAC state machine
Revision 0.25:
Added switch set and release for wall control (NOT smart switch,
into RS232 commands (Turned debouncer set and release in to subs)
Added smart switch into RS232 commands (smart switch is also a sub)
Re-enabled pass point test in ‘:’ RS232 command
Disabled smart switch scan when in RS232 mode
Corrected relative reference in debouncer subroutines
RS232 ‘F’ command still needs to be fixed
Revision 0.26:
Added in max. force operation until motor ramp-up is done
Added in cleaning of slowdown flag in set_any routine
Changed RPM timeout from 30 to 60 ms
Revision 0.27:
Switched phase control to off, then on (was on, then off) inside
each half cycle of the AC line (for noise reduction)
Changed from 40 ms unit max. period to 32 (will need further changes)
Fixed bug in force ignore during ramp (previously jumped from down to
up state machine)
Added in complete force ignore at very slow part of ramp (need to
change this to ignore when very close to limit)
Removed that again
Bug fix -- changed force skip during ramp-up. Before, it kept counting
down the force ignore timer.
Revision 0.28:
Modified the wall control documentation
Installed blinking the wall control on an IP reversal instead of the
worklight
Installed blinking the wall control when a pass point is seen
Revision 0.29:
Changed max. RPM timeout to 100 ms
Fixed wall control blink bug
Raised minimum speed setting
NOTE: Forces still need to be set to accurate levels
Revision 0.30:
Removed ‘er’ before setteing of pcon register
Bypassed slow-down to limit during learn mode
Revision 0.31:
Changed force ramp to a linear FORCE ramp, not a linear time ramp
Installed a look-up table to make the ramp more linear.
Disabled interrupts during radio pointer match
Changed slowdown flag to a up-down-stop ramping flag
Revision 0.32:
Changed down limit to drive lightly into floor
Changed down limit when learning to back off of floor for a few pulses
Revision 0.33:
Changed max. speed to ⅔ when a short door is detected
Revision 0.34:
Changed light timer to 2.5 minutes for a 50 Hz line, 4.5 minutes for
a 60 Hz line. Currently, the light timer is 4.5 minutes WHEN THE
UNIT FIRST POWERS UP.
Fixed problem with learning RP set to and extended group
Revision 0.35:
Changed strting postion of pass point counter to 0x30
Revision 0.36:
Changed algorithm for finding down limit to cure stopping at the floor
during the learn cycle
Fixed bug in learning limits: Up limit was being updated from
EEPROM during the learn cycle
Changed method of checking when limit is reached: calculation for
distance to limit is now ALWAYS performed
Added in skipping of limit test when position is lost
Revision 0.37:
Revised minimum travel distance and short door constants to reflect
approximately 10 RPM pulses/min
Revision 0.38:
Moved slowstart number closer to the limit
Changed backoff number from 10 to 8
Revision 0.39:
Changed backoff number from 8 to 12
Revision 0.40:
Changed task switcher to unburden processor
Consolidated tasks 0 and 4
Took extra unused code out of tasks 1, 3, 5, 7
Moved auz light and 4 ms timer into task 6
Put state machine into task 2 only
Adjusted auto_delay, motdel, rpm_time_out, force_ignore,
motor_timer, obs_count, for new state machine tick
Removed force_pre prescaler (no longer needed with 4 ms state
machine)
Moved updating of obs_count to one ms timer for accuracy
Changed autoreverse delay timer into a byte-wide timer because it was
only storing an 8 bit number anyways . . .
Changed flash delay and light timer constants to adjust for 4 ms tick
Revision 0.41:
Switched back to 4 MHz operation to account for the fact that Zilog's
Z86733 OTP won't run at 6 MHz reliably
Revision 0.42:
Extended RPM timer so that it could measure from 0-524 ms with
a resolution of 8 us
Revision 0.43:
Put in the new look-up table for the force pots (max RPM pulse period
multiplied by 20 to scale it for the various speeds).
Removed taskswitch because it was a redundant register
Removed extra call to the auxlight routine
Removed register ‘temp’ because, as far as I can tell, it does nothing
Removed light_pre register
Eliminated ‘phase’ register because it was never used
Put in preliminary divide for scaling the force and speed
Created speedlevel AND IDEAL speed registers, which are not yet used
Revision 0.47:
Undid the revision of revisions 0.44 through 0.46
Changed ramp-up and ramp-down to an adaptive ramp system
Changed force compare from subtract to a compare
Removed force ignore during ramp (was a kludge)
Changed max. RPM time out to 500 ms static
Put WDT kick in just before main loop
Fixed the word-wise T0EXT register
Set default RPM to max. to fix problem of not ramping up
Revision 0.48:
Took out adaptive ramp
Created look-ahead speed feedback in RPM pulses
Revision 0.49:
Removed speed feedback (again)
NOTE: Speed feedback isn't necessarily impossible, but after all my
efforts, I've concluded that the design time necessary ( a large
amount isn't worth the benefit it gives, especially given the
current time costraints of this project
Revision 0.50:
Fixed the force pot read to actually return a value of 0-64
Set the msx. RPM period time out to be equivalent to the force setting
Revision 0.51:
Added in P2M_SHADOW register to make the following posible:
Added in flashing warning light ‘with auto-detect)
Revision 0.52:
Fixed the variable worklight timer to have the correct value on
power up
Re-enabled the reason register and stackreason
Enabled up limit to back off by one pulse if it appears to be
crashing the up stop port.
Set the door to ignore commands and radio when lost
Changed start of down ramp to 220
Changed backoff from 12 to 9
Changed drive-past of down limit to 9 pulses
Revision 0.53:
Fixed RS232 ‘9’ and ‘F’ commands
Implemented RS232 ‘K’command
Removed ‘M’, ‘P’, and ‘S’ commands
Set the learn LED to always turn off at the end of the
learn limits mode
Revision 0.54:
Reversed the direction of the pot. read to correct the direction
of the min. and max. forces when dialing the pots.
Added in “U” command (currently does nothing)
Aded in “V” command to read force pot. values
Revision 0.55:
Changed number of pulses added in to down limit from 9 to 16
Revision 0.56:
Changed backoff number from 16 back to 9 (not 8!)
Changed minimum force/speed from 4/20 to 10/20
Revision 0.57:
Changed backoff number back to 16 again
Changed minimum force/speed from 10/20 back to 4/20
Changed learning speed from 10/20 to 20/20
Revision 0.58:
Changed learning speed from 20/20 to 12/20 (same as short door)
Changed force to max. during ramp-up period
Changed RPM timeout to a static vlaue of 500 ms
Change drive-past of limit from 1″ to 2″ of trolley travel
(Actually, changed the number from 10 pulses to 20 pulses)
Changed start of ramp-up from 1 to 4 (i.e. the power level)
Changed the alorithm when near the limit - the door will no
longer avoid going toward the limit, even if it is too close
Revision 0.59:
Removed ramp-up bug from auto-reverse of GDO
Revision 0.60:
Added in check for pass point counter if −1 to find position when lost
Change in waking up when lost. GDO now heads toward pass point
only on first operation after a power outage. Heads down on all
subsequent operations.
Created the “limit unknown” fault and prevented the GDO from
traveling whe the limits are not set at a reasonable value
Cleared the fault code on entering learn limits mode
Implemented RS232 ‘H’ command
Revision 0.61:
Changed limit test to look for trolley exactly at the limit position
Changed search for pass point to erase limit memory
Changed setup position to 2″ above the pass point
Set the learn LED to turn off whenever the L_A_C is cleared
Set the learn limits mode to shut off whenever the worklight times out
Revision 0.62:
Removed test for being exactly at down limit (it disabled the drive into
the limit feature
Fixed bug causing the GDO to ignore force when it should autoreverse
Added in ignoring commands when lost and traveling up
Revision 0.63:
Installed MinSpeed register to vary minimum speed with force pot
setting
Created main loop routine to scale the min speed based on force pot.
Changed drive-past of down limit from 20 to 30 pulses 2″ to 3″
Revision 0.64:
Changed learnin algorithm to utilize block. (Changed autoreverse to
add in ½″ to position instead of backing trolley off of the floor)
Enabled ramp-down when nearing the up limit in learn mode
Revision 0.65:
Put special case in speed check to enable slow down near the up limit
Revision 0.66:
Changed ramp-up: Ramping up of speed is now constant - the ramp-
down is the only ramp affected by the force pot. setting
Changed ramp-up and ramp-down tests to ensure that the GDO will get
UP to the minimum speed when we are inside the ramp-down zone,
(The above change necessitated this)
Changed the down limit to add in 0.2″ instead of 0.5″
Revision 0.67:
Removed minimum travel test in set_arev_state
Moved minimum distance of down limit from pass point from 5″ to 2″
Disabled moving pass point when only one pass point has been set
Revision 0.68:
Set error in learn state if no pass point is seen
Revision 0.69:
Added in decrement of pass point counter in learn mode to kill bugs
Fixed bug: Force pots were being ignored in the learn mode
Added in filtering of the RPM (RPM _FILTER register and a routine in
the one ms timer)
Added in check of RPM filter inside RPM interrupt
Added in polling RPM pin inside RPM interrupt
Re-enabled stopping when in learn mode and position is lost
Revision 0.70:
Removed old method of filtering RPM
Added in a “debouncer” to filter the RPM
Revision 0.71:
Changed “debouncer” to automatically vetor low
whenever an RPM pulse is considered valid
Revision 0.72:
Changed number of pulses added in to down limit to 0. Since the actual
down limit test checks for the position to be BEYOND the down limit
this is the equivalent of adding one pulse into the down limit
Revision 0.74:
Undid the work of rev. 0.73
Changed number of pulses added in to down limit to 1. Noting the
comment in rev. 0.72, this mean that we are adding 2 pulses
Changed learning speed to vary between 8/20 and 12/20, depending
upon the force pot. setting
Revision 0.75:
Installed power-up chip ID on P22, P23, P24, and P25
Note : ID is on P24, P23, and P22. P25 is a strobe to signal valid data
First chip ID is 001, with strobe it's 0001.
Changed set_any routine to re-enable the wall control just in case we
stopped while the wall control was being turned off (to avoid disabling
the wall control completely
Changed speed during learn mode to be ⅔ speed for first seven seconds,
then to slow down to the minimum speed to make the limit learning the
same as operation during normal travel.
Revision 0.76:
Restored learning to operate only at 60% speed
Revision 0.77:
Set unit to reverse off of floor and subtract 1″ of travel
Reverted to learning at 40%-60% of full speed
Revision 0.78:
Changed rampflag to have a constant for running at full speed
USed the above change to simplify the force ignore routine
Also used it to change the RPM time out. The time out is now set equal
to the pot setting, except during the ramp up when it is set to 500 ms.
Changed highest force pot setting to be exactly equal to 500 ms.
Revision 0.79:
Changed setup routine to reverse off block (yet again). Added in one
pulse.
Enabled RS232 version number return
Enabled ROM checksum. Cleaned up ducumentation
Revision 1.1:
Tweaked light times for 8.192 ms prescale instead of 8.0 ms prescale
Changed compare statement inside setvarlight to ‘uge’ for consistency
Changed one-shot low time to 2 ms for power line
Changed one-shot low time to truly count falling-edge-to-falling-edge.
Revision 1.2:
Eliminated testing for lost GDO in set_up_dir_state (is already taken
care of by set_on_dir_state.
Created special time for max. run motor timer in learn mode: 50
seconds
Revision 1.3:
Fixed bug in set_any to fix stack imbalance
Changed short door discrimination point to 78″
Revision 1.4:
Changed second ‘di’ to ‘ei’ in KnowSimCode
Changed IR protector to ignore for first 0.5 second before travel
Changed blinking time constant to take it back to 2 seconds before
travel
Changed blinking code to ALWAYS flash during travel, with pre-travel
flash when module is properly detected
Put in bounds checking on pass point counter to keep it in line
Changed driving into down limit to consider the system list if floor not
seen
Revision 1.5:
Changed blinking of wall control at pass point to be a one-shot timer
to correct problems with bad passpoint connections and stopping at pass
point to cause wall control ignore.
Revision 1.6:
Fixed blinking of wall control when indicating IP protector recersal
to give the blink a true 50% duty cycle
Changed blinker output to output a constant high instead of pulsing
Changed P2S_POR to 1010 Indicate Siminor unit;
Revision 1.7:
Disabled Siminor Radio
Changed P2S_POR to 1011 Indicate Lift-Master unit,
Added in one more conditional assembly point to avoid use of simradio
label
Revision 1.8:
Re-enabled Siminor Radio
Changed P2S_POR back to 1010 Siminor
Re-fixed blinking of wall control LED for protector reversal
Changed blinking of wall control LED for indicating pass point
Fixed error in calculating highest pass point value
Fixed error in calculating lowest pass point value
Revision 1.9:
Lengthened blink time for indicating pass point
Installed a max. travel distance when lost
Removed skipping up limit test when lost
Reset the position when lost and force reversing
Installed sample of pass point signal when changing states
Revision 2.0:
Moved main loop test for max. travel distance (was causing a memory
fault before)
Revision 2.1:
Changed limit test to use 11000000b instead of 10000000b to ensure
only setting up of limit when we're actually close
Revision 2.2:
Changed minimum speed scanning to move it further down the pot.
rotation. Formula is now \\force − 24/41 + 4, truncated to 12
Changed max. travel test to be inside motor state mahine. Max travel
test calculates for limit position differently when system is lost.
Reverted limit test to use 10000000b
Changed some jp's to jr's to conserve code space
Changed loading of reason byte with 0 to clearing if reason byte (very
desperate for space)
Revision 2.3:
Disabled Siminor Radio
Changed P2S_POR to 1011 (Lift-Master)
Revision 2.4:
Re-enabled Siminor Radio
Changed P2S_POR to 1010 (Siminor)
Changed wall control LED to also flash during learn mode
Changed reaction to single pass point near floor. If only one pass point
is seen during the learn cycle, and it is too close to the floor, the
learn cycle will now fail.
Removed an ei from pass point when learning to avoid a race condition
Revision 2.5:
Changed backing off of up limit to only occur during learn cycle. Backs
off by {fraction (1/2 )}″ if learn cycle force stops within ½″ of stop bolt.
Removed considering system lost if floor not seen.
Changed drive-past of down limit to 36 pulses (3″)
Added in clearing of power level whenever motor gets stopped (to turn
off the FET's sooner)
Added in a 40 ms delay (using the same MOTDEL register as for the
traveling states to delay the shut-off of the motor relay. This should
enable the motor to discharge some energy before the relay has to break
the current flow
Created STOPNOFLASH label - it looks like it should have been there
all along
Moved incrementing MOTDEL timer into head of state machine to
conserve space
Revision 2.6:
Fixed back-off of up limit to back off in the proper direction.
Added in testing for actual stop state in back-off (before was always
backing off the limit)
Simplified testing for light being on in ‘set any’ routine; eliminated
lights register
Revision 2.7: (Test-only revision)
Moved ei when testing for down limit
Eliminated testing for negative number in radio time calculation
Installed a primitive debouncer for the pass point (out of paranoia
Changed a pass point in the down direction to correspond to a position
of 1
Installed a temporary echo of the RPM signal on the blinker pin
Temporarily disabled POM checksum
Moved three subroutines before address 0101 to save space (2.2B)
Framed lock up using upforce and dnforce registers with di and ei to
prevent corruption of upforce or dnforce while doing math (2.7C)
Fixed error in definition of pot_count register (2.7C)
Disabled actual number check of RPM perdod for debug (2.7D)
Added in di at test_up_sw and test_dn_sw for ramping up period
(2.7D)
Set RPM_TIME_OUT to always be loaded to max value for debug
(2.7E)
Set RPM_TIME_OUT to round up by two instead of one (2.7F)
Removed 2.7E revision (2.7F)
Fixed RPM_TIME_OUT to round up in both the up and down
direction(2.7G)
Installed constant RS232 output of RPM_TIME_OUT register (2.7H)
Enabled RS232 ‘U’ and ‘V’ commands (2.7I)
Disabled constant output of 2.7H (2.7I)
Set PS232 ‘U’ to output RPM_TIME_OUT (2.7I)
Removed disable of actual RPM number check (2.7J)
Removed pulsing to indicate RPM interrupt (2.7J)
2.7J note -- need to remove ‘u’ command function
Revision 2.8:
Remove interrupt enable before resetting rpm_time_out. This will
introduce roughly 30us of extra delay in time measurement, but should
take care of
nuisance stops.
Removed push-ing and pop-ing of RP in tasks 2 and 6 to save stack
space (2.8B)
Removed temporary functionality for ‘u’ command (2.8 Release)
Re-enabled ROM checksum (2.8 Release)
|
[0130]
2
|
|
L_A_C State Machine
|
73
77
|
*******
****
|
*
*
|
72
74*
76*
|
Back to
*
*
|
70
Up Lim
----
----
|
71
----
----
|
Error
******
|
75
|
Position
|
the limit
|
|
NON-VOL MEMORY MAP
|
00
A0
D0
Multi-function transmitters
|
01
A0
D0
|
02
A1
D0
|
03
A1
D0
|
04
A2
D1
|
05
A2
D1
|
06
A3
D1
|
07
A3
D1
|
08
A4
D2
|
09
A4
D2
|
0A
A5
D2
|
0B
A5
D2
|
0C
A6
D3
|
0D
A6
D3
|
0E
A7
D3
|
0F
A7
D3
|
10
A8
D4
|
11
A8
D4
|
12
A9
D4
|
13
A9
D4
|
14
A10
D5
|
15
A10
D5
|
16
A11
D5
|
17
A11
D5
|
18
B
D6
|
19
B
D6
|
1A
C
D6
|
1B
C
D6
|
1C
unused
D7
|
1D
unused
D7
|
1E
unused
D7
|
1F
unused
D7
|
20
unused
DTCP
Keyless permanent 4 digit code
|
21
unused
DTCID
Keyless ID code
|
22
unused
DTCR1
Keyless Roll value
|
23
unused
DTCR2
|
24
unused
DTCT
Keyless temporary 4 digit code
|
25
unused
Duration
Keyless temporary duration
|
Upper byte = Mode; hours activations
|
Lower byte = # of hours activations
|
26
unused
Radio type
|
77665544 33221100
|
00 = CMD 01 = LIGHT
|
10 = OPEN/CLOSE/STOP
|
27
unused
Fixed/roll
|
Upper word = fixed/roll byte
|
Lower word = unsed
|
28
CYCLE COUNTER 1ST 16 BITS
|
29
CYCLE COUNTER 2ND 16 BITS
|
2A
VACATION FLAG
|
Vacation Flag , Last Operation
|
0000
XXXX
in vacation
|
1111
XXXX
out of vacation
|
2B
A MEMORY ADDRESS LAST WRITTEN
|
2C
IRLIGHHTADDR 4-22-97
|
2D
Up Limit
|
2E
Pass point counter / Last operating state
|
2F
Down Limit
|
3C-3F
Force Back trace
|
RS232 DATA
|
REASON
|
00
COMMAND
|
10
RADIO COMMAND
|
20
FORCE
|
30
AUX OBS
|
40
A REVERSE DELAY
|
50
LIMIT
|
60
EARLY LIMIT
|
70
MOTOR MAX TIME, TIME OUT
|
80
MOTOR COMMANDED OFF RPM CAUSING AREV
|
90
DOWN LIMIT WITH COMMAND HELD
|
A0
DOWN LIMIT WITH THE RADIO HELD
|
B0
RELEASE OF COMMAND OR RADIO AFTER A FORCED
|
UP MOTOR ON DUE TO RPM PULSE WITHG MOTOR OFF
|
STATE
|
00
AUTOREVERSE DELAY
|
01
TRAVELING UP DIRECTION
|
02
AT THE UP LIMIT AND STOPES
|
03
ERROR RESET
|
04
TRAVELING DOWN DIRECTION
|
05
AT THE DOWN LIMIT
|
06
STOPPED IN MID TRAVEL
|
DIAG
|
1) AOBS SHORTED
|
2) AOBS OPEN / MISS ALIGNED
|
3) COMMAND SHORTED
|
4) PROTECTOR INTERMITTENENT
|
5) CALL DEALER
|
NO RPM IN THE FIRST SECOND
|
6) RPM FORCED A REVERSE
|
7) LIMITS NOT LEAPNET YET
|
DOG 2
|
DOG 2 IS A SECONDARY WATCHDOG USED TO
|
RESET THE SYSTEM IF THE LOWEST LEVEL “MAINLOOP”
|
IS NOT REACHED WITHIN A 3 SECOND
|
Conditional Assembly
|
GLOBALS ON
; Enable a symbol file
|
Yes
.equ 1
|
No
.equ 0
|
TwoThirtyThree
.equ Yes
|
UseSiminor
.equ Yes
|
EQUATE STATEMENTS
|
check_sum_value
.equ
065H
; CRC checksum for ROM code
|
TIMER_I_EN
.equ
0CH
; TMR mask to start timer 1
|
MOTORTIME
.equ
.27000 / 4
; Max. run for otor = 22 sec (4 ms tick,
|
LACTIME
.equ
(500 / 4;
; Delay before learning limits is 0.5 seconds
|
LEARNTIME
.equ
(50000 / 4
; Max. run for motor in learn mode
|
PWM_CHARGE
.equ
0CH
; PWM state for old force pots.
|
LIGHT
.equ
0FFH
; Flag for light on constantly
|
LIGHT_ON
.equ
10000000B
; P0 pin turning on worklight
|
MOTOR_UP
.equ
01000000B
; P0 pin turning on the up motor
|
MOTOR_DN
.equ
00100000B
; P0 pin turning on the down motor
|
UP_OUT
.equ
00110000B
; P3 pin otput for up force pot.
|
DOWN_OUT
.equ
001000000B
; P3 pin output for down force pot.
|
DOWN_COMP
.equ
00000001B
; P0 pin input for down force pot.
|
UP_COMP
.equ
00000010B
; P0 pin input for up force pot.
|
FALSEIR
.equ
00000001B
; P2 pin for false AOBS output
|
LINSINFIN
.equ
00010000B
; P2 pin for reading in AC line
|
PPoint Port
.equ
p2
; Port for pass point input
|
PassPoint
.equ
00011000B
; B_t mask for pass point input
|
PhasePrt
.equ
p0
; Port for phase control output
|
PhaseHigh
.equ
00010000B
; Pin for controlling FET's
|
CHARGE_SW
.equ
10000000B
; P3 Pin for charging the wall control
|
DIS_SW
.equ
01000000B
; P3 Pin for discharging the wall control
|
SWITCHES1
.equ
00001000B
; PC Pin for first wall control input
|
SWITCHES2
.equ
00000100B
; P0 Pin for second wall control input
|
P01M_INIT
.equ
00000101B
; set mode p00-p03 in p04-p07 out
|
P2M_INIT
.equ
01011100B
; P2M initialization for operation
|
P2M_POP
.equ
01000000B
; P2M initialization of output of onip ID
|
P3M_INIT
.equ
00000011B
; set port3 p30-p33 input ANALOG mode
|
P01S_INIT
.equ
10000000B
; Set init. state as worklight on, motor off
|
P2S_INIT
.equ
00000110B
; Init p2 to have LED off
|
P2S_POR
.equ
00101010B
; P2 init to output a chip ID (P25, P24, P23, P22;
|
P3S_INIT
.equ
00000000B
; Init p3 to have everything off
|
BLINK_PIN
.equ
00000000B
; Pin which controls flasher module
|
P2M_ALLOUTS
.equ
01111100B
; Pins which need to be refreshed to outputs
|
P2M_ALLINS
.equ
01011000B
; Pins which need to be refreshed to inputs
|
RsPerHalf
.equ
104
; RS232 period 1200 Baud half time 416uS
|
RsPer Full
.equ
208
; RS232 period full time 832us
|
RsPer1P22
.equ
00
; RS232 period 1.22 unit times 1.025ms (00 = 256)
|
FLASH
.equ
0FFH
;
|
WORKLIGHT
.equ
LIGHT_ON
; Pin for toggling state of worklight
|
PPOINTPULSES
.equ
897
; Number of RPM pulses between pass points
|
SetupPos
.equ
(65535-20)
; Setup position -- 2” above pass point
|
CMD_TEST
.equ
00
; States for old wall control routine
|
WL_TEST
.equ
01
|
VAC_TEST
.equ
02
|
CHARGE
.equ
03
|
RSSTATUS
.equ
04
; Hold wall control okt. in RS232 mode
|
WALLOFF
.equ
05
; Turn off wall control LED for blinks
|
AUTO_REV
.equ
00H
; States for GDO state machine
|
UP_DIRECTION
.equ
01H
|
UP_POSITION
.equ
02H
|
DN_DIRECTION
.equ
04H
|
DN_POSITION
.equ
05H
|
STOP
.equ
06H
|
CMD_SW
.equ
01H
; Flags for switches hit
|
LIGHT_SW
.equ
02H
|
VAC_SW
.equ
04H
|
TRUE
.equ
0FFH
; Generic constants
|
FALSE
.equ
00H
|
FIXED_MODE
.equ
10101010b
;Fixed mode radio
|
ROLL_MODE
.equ
01010101b
;Rolling mode radio
|
FIXED_TEST
.equ
00000000b
;Unsure of mode -- test fixed
|
ROLL_TEST
.equ
00000001b
;Unsure of mode -- test roll
|
FIXED_MASK
.equ
FIXED_TEST
;Bit mask for fixed mode
|
ROLL_MASK
.equ
ROLL_TEST
;Bit mask for rolling mode
|
FIXTHR
.equ
03H
;Fixed code decision threshold
|
DTHR
.equ
02H
;Rolling code decision threshold
|
FIXSYNC
. equ
08H
;Fixed code sync threshold
|
DSYNC
.equ
04h
;Rolling code sync threshold
|
FIXBITS
.equ
11
;Fixed code number of bits
|
DBITS
.equ
21
;Polling code number of bits
|
EQUAL
.equ
00
;Counter compare result constants
|
BACKWIN
.equ
FH
;
|
FWDWIN
.equ
80H
|
OUTOFWIN
.equ
0FFH
|
AddressCounter
.equ
27H
|
AddressAPointer
.equ
2BH
|
CYCCOUNT
.equ
28H
|
TOUCHID
.equ
21H
;Touch code ID
|
TOUCHROLL
.equ
22H
;Touch code roll value
|
TOUCHPERM
.equ
20H
;Touch code permanent password
|
TOUCHTEMP
.equ
24H
;Touch code temporary password
|
DURAT
.equ
25H
;Touch code temp. duration
|
VERSIONNUM
.equ
088H
;Version: PRO7000 V2.8
|
;4-22-97
|
IRLIGHTADDR
.EQU
20H
;work light feature on or off
|
DISABLE
.EQU
00H
;00 = disabled, FF = enabled
|
;
|
RTYPEADDR
.equ
26h
;Radio transmitter type
|
VACATIONADDR
.equ
2AH
|
MODEADDR
.equ
20H
;Rolling/Fixed mode in EEPROM
|
;High byte = don't care (now)
|
;Low byte = RadioMode flag
|
UPLIMADDR
.equ
2DH
;Address of up limit
|
LASTSTATEADDR
.equ
2EH
;Address of last state
|
DNLIMADDR
.equ
2FH
;Address of down limit
|
NOEECOMM
.equ
01111111b
;Flag: skip radio read/write
|
NOINT
.equ
10000000b
;Flag: skip radio interrupts
|
RDROPTIME
.equ
125
;Radio drop-out time: 0.5s
|
LRNOCS
.equ
0AAH
;Learn open/close/stop
|
BRECEIVED
.equ
077H
;B code received flag
|
LRNLIGHT
.equ
0BBH
;Light command trans.
|
LRNTEMP
.equ
0CCH
;Learn touchcode temporary
|
LRNDURTN
.equ
0DDH
;Learn t.c. temp. duration
|
REGLEARN
.equ
0EEH
;Regular learn mode
|
NORMAL
.equ
00H
;Normal command trans.
|
ENTER
.equ
00H
;Touch code ENTER key
|
POUND
.equ
01H
;Touch code # key
|
STAR
.equ
02H
;Touch code * key
|
ACTIVATIONS
.equ
0AAH
;Number of activations mode
|
HOURS
.equ
055H
;Number of hours mode
|
;Flags for Ramp Flag Register
|
STILL
.equ
00h
; Motor not moving
|
RAMPUP
.equ
0AAH
; Ramp speed up to maximum
|
RAMPDOWN
.equ
0FFH
; Slow down the motor to minimum
|
FULLSPEED
.equ
0CCH
; Running at full speed
|
UPSLOWSTART
.equ
200
; Distance (in pulses) from limit when slow-
|
down
|
DNSLOWSTART
.equ
220
; of GDO motor starts (for up and down
|
direction)
|
BACKOFF
.equ
16
; Distance (in pulses) to back trolley off of
|
floor
|
; when learning limits by reversing off of
|
floor
|
SHORTDOOR
.equ
936
; Travel distance (in pulses) that
|
discriminates a
|
; one piece door (slow travel) from a normal
|
door
|
; (normal travel) (Roughly 76″
|
PERIODS
|
AUTO_REV_TIME
.equ
124
; (4 ms prescale)
|
MIN_COUNT
.equ
02H
; pwm start point
|
TOTAL_PWM_COUNT
.equ
03FH
; pwm end = start + 2*total − 1
|
FLASH_TIME
.equ
61
; 0.25 sec flash time
|
; 4.5 MINUTE USA LIGHT TIMER
|
USA_LIGHT_HI
.equ
080H
; 4.5 MIN
|
USA_LIGHT_LO
.equ
0BEH
; 4.5 MIN
|
; 2.5 MINUTE EUROPEAN LIGHT TIMEP
|
EURO_LIGHT_HI
.equ
047H
; 2.5 MIN
|
EURO_LIGHT_LO
.equ
086H
; 2.5 MIN
|
ONE_SEC
.equ
0F4H
; WITH A /4 IN FRONT
|
CMD_MAKE
.equ
8
; cycle count *10mS
|
CMD_BREAK
.equ
(255-8)
|
LIGHT_MAKE
.equ
8
; cycle count *11mS
|
LIGHT_BREAK
.equ
(255-8)
|
VAC_MAKE_OUT
.equ
4
; cycle cound *100mS
|
VAC_BREAK_OUT
.equ
(255-4)
|
VAC_MAKE_IN
.equ
2
|
VAC_BREAK_IN
.equ
(255-2)
|
VAC_DEL
.equ
8
; Delay 16 ms for vacation
|
CMD_DEL_EX
.equ
6
; Delay 12 ms ( 5*2 + 2)
|
VAC_DEL_EX
.equ
50
; Delay 100 ms
|
PREDEFINED REG
|
ALL_ON_IMR
.equ
00111101b
; turn on int for timers rpm auxobs radio
|
RETURN_IMR
.equ
00111100b
; return on the IMR
|
RadioImr
.equ
00000001b
; turn on the radio only
|
GLOBAL REGISTERS
|
STATUS
.equ
04H
; CMD_TEST 00
|
; WL_TEST 01
|
; VAC_TEST 02
|
; CHARGE 03
|
STATE
.equ
05H
; state register
|
LineCtr
.equ
06H
;
|
RampFlag
.equ
0−H
; Ramp up, ramp down, or stop
|
AUTO_DELAY
.equ
08H
|
LinePer
.equ
09H
; Period of AC line coming in
|
MOTOR_TIMER_HI
.equ
0AH
|
MOTOR_TIMER_LO
.equ
0BH
|
MOTOR_TIMER
.equ
0AH
|
LIGHT_TIMER_HI
.equ
0CH
|
LIGHT_TIMER_LO
.equ
0DH
|
LIGHT_TIMER
.equ
0CH
|
AOBSF
.equ
0EH
|
PrevPass
.equ
0FH
|
CHECK_GRP
.equ
10H
|
check_sum
.equ
r0
; check sum pointer
|
rom_data
.equ
r1
|
test_adr_hi
.equ
r2
|
test_adr_lo
.equ
r3
|
test_adr
.equ
rr2
|
CHECK_SUM
.equ
CHECK_GRP+0
; check sum reg for por
|
ROM_DATA
.equ
CHECK_GRP+1
; data read
|
LIM_TEST_HI
.equ
CHECK_GRP−0
; Compare registers for measuring
|
LIM_TEST_LO
.equ
CHECK_GRP−1
; distance to limit
|
LIM_TEST
.equ
CHECK_GRP+0
:
|
AUXLEARNSW
.equ
CHECK_GRP+2
;
|
RRTO
.equ
CHECK_GRP+3
;
|
RPM_ACOUNT
.equ
CHECK_GRP+4
; to test for active rpm
|
RS_COUNTEP
.equ
CHECK_GRP+5
; rs232 byte counter
|
RS232DAT
.equ
CHECK_GRP+6
; rs232 data
|
RADIO_CMI
.equ
CHECK_GRP+7
; radio command
|
R_DEAD_TIME
.equ
CHECK_GRP+8
;
|
FAULT
.equ
CHECK_GRP+9
;
|
VACFLAG
.equ
CHECK_GRP+10
; VACATION mode flag
|
VACFLASH
.equ
CHECK_GRP+11
|
VACCHANGE
.equ
CHECK_GRP+12
|
FAULTTIME
.equ
CHECK_GRP+13
|
FORCE_IGNORE
.equ
CHECK_GRP+14
|
FAULTCODE
.equ
CHECK_GRP+15
|
TIMER_GROUP
.equ
20H
|
position_hi
.equ
r0
|
position_lo
.equ
r1
|
position
.equ
rr0
|
up_limit_hi
.equ
r2
|
up_limit_lo
.equ
r3
|
up_limit
.equ
rr2
|
switch_delay
.equ
r4
|
obs_count
.equ
r6
|
rscommand
.equ
r9
|
rs_temp_hi
.equ
r10
|
rs_temp_lo
.equ
r11
|
rs_temp
.equ
rr10
|
POSITION_HI
.equ
TIMER_GROUP+0
|
POSITION_LO
.equ
TIMER_GROUP+1
|
POSITION
.equ
TIMER_GROUP+2
|
UP_LIMIT_HI
.equ
TIMER_GROUP+2
|
UP_LIMIT_LO
.equ
TIMER_GROUP+3
|
UP_LIMIT
.equ
TIMER_GROUP−2
|
SWITCH_DELAY
.equ
TIMER_GROUP+4
|
OnePass
.equ
TIMER_GROUP+5
|
OBS_COUNT
.equ
TIMER_GROUP+6
|
RsMode
.equ
TIMER_GROUP+7
|
Divisor
.equ
TIMER_GROUP+8
; Number to divide by
|
RSCOMMAND
.equ
TIMER_GROUP+9
|
RS_TEMP_HI
.equ
TIMER_GROUP+10
|
RS_TEMP_LO
.equ
TIMER_GROUP+11
|
RS_TEMP
.equ
TIMER_GROUP+10
|
PowerLevel
.equ
TIMER_GROUP+12
; Current step in 20-step phase ramp-up
|
PhaseTMR
.equ
TIMER_GROUP+13
; Timer for turning on and off phase control
|
PhaseTime
.equ
TIMER_GROUP+14
; Current time reload value for phase timer
|
MaxSpeed
.equ
TIMER_GROUP+15
; Maximum speed for this kind of door
|
LEARN EE GROUP FOR LOOPS ECT
|
LEARNEE_GRP
.equ
30H
;
|
TEMPH
.equ
LEARNEE_GRP
;
|
TEMPL
.equ
LEARNEE_GRP+1
;
|
PSM_SHADOW
.equ
LEARNEE_GRP+2
; Readable shadow of P2M register
|
LEARNDB
.equ
LEARNEE_GRP+3
; learn debouncer
|
LEARNT
.equ
LEARNEE_GRP+4
; learn timer
|
ERASET
.equ
LEARNEE_GRP+5
; erase timer
|
MTEMPH
.equ
LEARNEE—GRP+6
; memory temp
|
MTEMPL
.equ
LEARNEE_GRP+7
; memory temp
|
MTEMP
.equ
LEARNEE_GRP+8
; memory temp
|
SERIAL
.equ
LEARNEE_GRP+9
; data to & from nonvol memory
|
ADDRESS
.equ
LEARNEE_GRP+10
; address for the serial nonvol memory
|
ZZWIN
.equ
LEARNEE_GRP+11
; radio 00 code window
|
T0_OFLOW
.equ
LEARNEE_GRP+12
; Third byte of T0 counter
|
T0EXT
.equ
LEARNEE_GRP+13
; t0 extend dec'd every t0 int
|
T0ENTWORD
.equ
LEARNEE_GRP+12
; Word-wide t0 extension
|
T125MS
.equ
LEARNEE_GRP+14
; 125mS counter
|
SKIPRADIO
.equ
LEARNEE_GRP+15
; flag to skip radio read, write if
|
; learn or vacation talking to it
|
temph
.equ
r0
;
|
temp1
.equ
r1
;
|
learndb
.equ
r3
; learn debouncer
|
learnt
.equ
r4
; learn timer
|
eraset
.equ
r5
; erase timer
|
mtemph
.equ
r6
; memory temp
|
mtemp1
.equ
r7
; memory temp
|
mtemp
.equ
r8
; memory temp
|
serial
.equ
r9
; data to and from nonvol mem
|
address
.equ
r10
; addr for serial nonvol memory
|
zzwin
.equ
r11
;
|
t0_oflow
.equ
r12
; Overflow counter for T0
|
t0ext
.equ
r13
; t0extend dec'd every t0 int
|
t0extword
.equ
rr12
; Word-wide T0 extension
|
t125ms
.equ
r14
; 125mS counter
|
skipradio
.equ
r15
; flag to skip radio read, write if
|
; learn or vacation talking to it
|
FORCE_GROUP
.equ
40H
|
dnforce
.equ
r0
|
upforce
.equ
r1
|
loopreg
.equ
r3
|
up_force_hi
.equ
r4
|
up_force_lo
.equ
r5
|
up_force
.equ
rr4
|
dn_force_hi
.equ
r6
|
dn_force_lo
.equ
r7
|
dn_force
.equ
rr6
|
force_add_hi
.equ
r8
|
force_add_lo
.equ
r9
|
force_add
.equ
rr8
|
up_temp
.equ
r10
|
dn_temp
.equ
r11
|
pot_count
.equ
r12
|
force_temp_of
.equ
r13
|
force_temp_hi
.equ
r14
|
force_temp_lo
.equ
r15
|
DNFORCE
.equ
40H
|
UPFORCE
.equ
41H
|
AOBSTEST
.equ
42H
|
LoopReg
.equ
43H
|
UP_FORCE_HI
.equ
44H
|
UP_FORCE_LO
.equ
45H
|
DN_FORCE_HI
.equ
46H
|
DN_FORCE_LO
.equ
47H
|
UP_TEMP
.equ
4AH
|
ON_TEMP
.equ
4BH
|
POT_COUNT
.equ
40H
|
FORCE_TEMP_OF
.equ
40H
|
FORCE_TEMP_HI
.equ
4EH
|
FORCE_TEMP_LO
.equ
4FH
|
RPM_GROUP
.equ
50H
|
rtypes2
.equ
r0
|
stackflag
.equ
r1
|
rpm_temp_of
.equ
r2
|
rpm_temp_hi
.equ
r3
|
rpm_temp_hiword
.equ
rr2
|
rpm_temp_lo
.equ
r4
|
rpm_past_hi
.equ
r5
|
rpm_past _lo
.equ
r6
|
rpm_period_hi
.equ
r7
|
rpm_period_lo
.equ
r8
|
divcounter
.equ
r11
; Counter for dividing RPM time
|
rpm_count
.equ
r12
|
rpm_time_out
.equ
r13
|
RTypes2
.equ
RPM_GROUP+2
|
STACKFLAG
.equ
RPM_GROUP+1
|
RPM_TEMP_OF
.equ
RPM_GROUP+2
; Overflow for RPM Time
|
RPM_TEMP_HI
.equ
RPM_GROUP+2
;
|
RPM_TEMP_HWORD
.equ
RPM_GROUP+2
; High word of RPM Time
|
RPM_TEMP_LO
.equ
RPM_GROUP+4
|
RPM_PAST_HI
.equ
RPM_GROUP+5
|
RPM_PAST_LO
.equ
RPM_GROUP+6
|
RPM_PERIOD_HI
.equ
RPM_GROUP+7
|
RPM_PERIOD_LO
.equ
RPM_GROUP+8
|
DN_LIMIT_HI
.equ
RPM_GROUP+9
;
|
DN_LIMIT_LO
.equ
RPM_GROUP+10
;
|
DIVCOUNTER
.equ
RPM_GROUP+11
; Counter for divinding RPM time
|
RPM_FILTER
.equ
RPM_GROUP+11
; DOUBLE MAPPED register for filtering signal
|
RPM_COUNT
.equ
RPM_GROUP+12
|
RPM_TIME_OUT
.equ
RPM_GROUP+13
|
BLINK_HI
.equ
RPM_GROUP+14
; Blink timer for flashing the
|
BLINK_LO
.equ
RPM_GROUP+15
; about-to-travel warning light
|
BLINK
.equ
RPM_GROUP+14
; Word-wise blink timer
|
RADIO GROUP
|
RadioGroup
.equ
60H
;
|
RTemp
.equ
RadioGroup
; radio temp storage
|
RTempH
.equ
RadioGroup+1
; radio temp storage high
|
RTempL
.equ
RadioGroup+2
; radio temp storage low
|
RTimeAH
.equ
RadioGroup+3
; radio active time high byte
|
RTimeAL
.equ
RadioGroup+4
; radio active time low byte
|
RTimeIH
.equ
RadioGroup+5
; radio inactive time high byte
|
RTimeIL
.equ
RadioGroup+6
; radio inactive time low byte
|
Radio1H
.equ
RadioGroup+7
; sync 1 code storage
|
Radio1L
.equ
RadioGroup+8
; sync 1 code storage
|
RadioC
.equ
RadioGroup+9
; radio word count
|
PointerH
.equ
RadioGroup+10
;
|
PointerL
.equ
RadioGroup+11
;
|
AddValueH
.equ
RadioGroup+12
;
|
AddValueL
.equ
RadioGroup+13
;
|
Radio3H
.equ
RadioGroup+14
; sync 3 code storage
|
Radio3L
.equ
RadioGroup+15
; sync 3 code storage
|
rtemp
.equ
r0
; radio temp storage
|
rtemph
.equ
r1
; radio temp storage high
|
rtemp1
.equ
r2
; radio temp storage low
|
rtimeh
.equ
r3
; radio active time high byte
|
rtimea1
.equ
r4
; radio active time low byte
|
rtimeih
.equ
r5
; radio inactive time high byte
|
rtimei1
.equ
r6
; radio inactive time low byte
|
radio1h
.equ
r7
; sync 1 code storage
|
radio11
.equ
r8
; sync 1 code storage
|
radioc
.equ
r9
; radio word count
|
pointerh
.equ
r10
;
|
pointer1
equ
r11
;
|
pointer
.equ
rr11
; Overall pinter for ROM
|
addvalueh
.equ
r12
;
|
addvalue1
.equ
r13
;
|
radio3h
.equ
r14
; sync 3 code storage
|
radio31
.equ
r15
; sync 3 code storage
|
w2
.equ
rr14
; For Siminor revision
|
CounterGroup
.equ
070h
; counter group
|
TestReg
.equ
CounterGroup
; Test area when dividing
|
BitMask
.equ
CounterGroup+01
; Mask for transmitters
|
LastMatch
.equ
CounterGroup+02
; last matching code address
|
LoopCount
.equ
CounterGroup+03
; loop counter
|
CounterA
.equ
CounterGroup+04
; counter translation MSB
|
CounterB
.equ
CounterGroup+05
;
|
CounterC
.equ
CounterGroup+06
;
|
CounterD
.equ
CounterGroup+07
; countr translation LSB
|
MirrorA
.equ
CounterGroup+08
; back translation MSB
|
MirrorB
.equ
CounterGroup+09
;
|
MirrorC
.equ
CounterGroup+010
;
|
MirrorD
.equ
CounterGroup+011
; back translation LSB
|
COUNT1H
.equ
CounterGroup+012
; received count
|
COUNT1L
.equ
CounterGroup+013
|
COUNT3H
.equ
CounterGroup+014
|
COUNT3L
.equ
CounterGroup+015
|
loopcount
.equ
r3
;
|
countera
.equ
r4
;
|
counterb
.equ
r5
;
|
counterc
.equ
r6
;
|
counterd
.equ
r7
;
|
mirrora
.equ
r8
;
|
mirrorb
.equ
r9
;
|
mirrorc
.equ
r10
;
|
mirrord
.equ
r11
;
|
Radio2Group
.equ
080H
|
PREVFIX
.equ
Radio2Group + 0
|
PREVTMP
.equ
Radio2Group + 1
|
ROLLBIT
.equ
Radio2Group + 2
|
RTimeDH
.equ
Radio2Group + 3
|
RTimeDL
.equ
Radio2Group + 4
|
RTimePH
.equ
Radio2Group + 5
|
RTimePL
.equ
Radio2Group + 6
|
ID13 B
.equ
Radio2Group + 7
|
SW_B
.equ
Radio2Group + 8
|
RADIOBIT
.equ
Radio2Group + 9
|
RadioTimeOut
.equ
Radio2Group + 10
|
RadioMode
.equ
Radio2Group + 11
;Fixed or rolling mode
|
BitThresh
.equ
Radio2Group + 12
;Bit decision threshold
|
SyncThresh
.equ
Radio2Group + 13
;Sync pulse decision threshold
|
MaxBits
.equ
Radio2Group + 14
;Maximum number of bits
|
RFlag
.equ
Radio2Group + 15
;Radio flags
|
prevfix
.equ
r0
|
prevtmp
.equ
r1
|
rollbit
.equ
r2
|
id_b
.equ
r7
|
sw_b
.equ
r8
|
radiobit
.equ
r9
|
radiotimeout
.equ
r10
|
radiomode
.equ
r11
|
rflag
.equ
r15
|
OriginalGroup
.equ
90H
|
SW_DATA
.equ
OrginalGroup+0
|
ONEP2
.equ
OrginalGroup+1
; 1.2 SEC TIMER TICK .125
|
LAST_CMD
.equ
OrginalGroup+2
; LAST COMMAND FROM
|
; = 55 WALL CONTROL
|
; = 00 RADIO
|
CodeFlag
.equ
OrginalGroup+3
; Radio code type flag
|
; FF = Learning open/close/stop
|
; 77 = b code
|
; AA = open/close/stop code
|
; 55 = Light control trasnmitter
|
; 00 = Command or unknown
|
RPMONES
.equ
OrginalGroup+4
; RPM Pulse One Sec. Disable
|
RPMCLEAR
.equ
OrginalGroup+5
; RPM PULSE CLEAR & TEST TIMEP
|
FAREVFLAG
.equ
OrginalGroup+6
; RPM FORCED AREV FLAG
|
; 88H FOR A FORCED REVERSE
|
FLASH_FLAG
.equ
OrginalGroup+7
|
FLASH_DELAY
.equ
OrginalGroup+8
|
REASON
.equ
OrginalGroup-30 9
|
FLASH_COUNTER
.equ
OrginalGroup+10
|
RadioTypes
.equ
OrginalGroup+11
; Types for one page of tx's
|
LIGHT_FLAG
.equ
OrginalGroup+12
|
CMD_DEB
.equ
OrginalGroup+13
|
LIGHT_DEB
.equ
OrginalGroup+14
|
VAC_DEB
.equ
OrginalGroup+15
|
NextGroup
.equ
0A0H
|
SDISABLE
.equ
NextGroup+0
; system disable timer
|
PRADIO3H
.equ
NextGroup+1
; 3 mS code storage high byte
|
PRADIO3L
.equ
NextGroup+2
; 3 mS code storage low byte
|
PRADIO1H
.equ
NextGroup+3
; 1 mS code storage high byte
|
PRADIO1L
.equ
NextGroup+4
; 1 mS code storage low byte
|
RTO
.equ
NextGroup+5
; radio time out
|
;RFlag
.equ
NextGroup+6
; radio flags
|
EnableWorkLight
.equ
NextGroup+6
; 4-22-97 work light function on or off?
|
RINFILTER
.equ
NextGroup+7
; radio input filter
|
LIGHT1S
.equ
NextGroup+8
; light timer for 1second flash
|
DOG2
.equ
NextGroup+9
; second watchdog
|
FAULTFLAG
.equ
NextGroup+10
; flag for fault blink, no rad. blink
|
MOTDEL
.equ
NextGroup+11
; motor time delay
|
PPOINT_DEB
.equ
NextGroup+12
; Pass Point debouncer
|
DELAYC
.equ
NextGroup+13
; for the time delay for command
|
L_A_C
.equ
NextGroup+14
; Limits are changing register
|
CMP
.equ
NextGroup+15
; Counter compare result
|
BACKUP_GRP
.equ
0B0H
|
PCounterA
.equ
BACKUP_GRP
|
PCounterB
.equ
BACKUP_GRP+1
|
PCounterC
.equ
BACKUP_GRP+2
|
PCounterD
.equ
BACKUP_GRP+3
|
HOUR_TIMER
.equ
BACKUP_GRP+4
|
HOUR_TIMES_HI
.equ
BACKUP_GRP+4
|
HOUR_TIMER_LO
.equ
BACKUP_GRP+5
|
PassCounter
.equ
BACKUP_GRP+6
|
STACKREASON
.equ
BACKUP_GRP+7
|
FirstRun
.equ
BACKUP_GRP+8
; Flag for first operation after power-up
|
MinSpeed
.equ
BACKUP_GRP+9
|
BRPM_COUNT
.equ
BACKUP_GRP+10
|
BRPM_TIME_OUT
.equ
BACKUP_GRP+11
|
BFORCE_IGNORE
.equ
BACKUP_GRP+12
|
BAUTC_DELAY
.equ
BACKUP_GRP+13
|
BCMD_DEB
.equ
BACKUP_GRP+14
|
BSTATE
.equ
BACKUP_GRP+15
|
; Double-mapped registers for M6800 test
|
COUNT_HI
.equ
BRPM_COUNT
|
COUNT_LO
.equ
BRPM_TIME_OUT
|
COUNT
.equ
BFORCE_IGNORE
|
REGTEMP
.equ
BAUTO_DELAY
|
REGTEMP2
.equ
BCM2_DEB
|
; Double-mapped registers for Siminor Code Reception
|
CodeT0
.equ
COUNT1L
; Binary radio code received
|
CodeT1
.equ
Radio1L
|
CodeT2
.equ
MirrorC
|
CodeT3
.equ
MirrorD
|
CodeT4
.equ
COUNT3H
|
CodeT5
.equ
COUNT3L
|
Ix
.equ
COUNT1H
; Index per Siminor's code
|
W1High
.equ
AddValueH
; Word 1 per Siminor's code
|
W1Low
.equ
AddValueL
; description
|
w1high
.equ
addvalueh
|
w1low
.equ
addvaluel
|
W2High
.equ
Radio3H
; Word 2 per Siminor's code
|
W2Low
.equ
Radio3L
; description
|
w2high
.equ
radio3h
|
w2low
.equ
radio3l
|
STACKTOP
.equ
238
; start of the stack
|
STACKEND
.equ
0C0H
; end of the stack
|
RS2321P
.equ
P0
; RS232 input port
|
RS232IM
.equ
SWITCHES1
; RS232 mask
|
csh
.equ
10000000B
; chip select high for the 93c46
|
csl
.equ
˜csh
; chip select low for 93c46
|
clockh
.equ
01000000B
; clock high for 93c46
|
clockl
.equ
˜clockh
; clock low for 93c46
|
doh
.equ
00100000B
; data out high for 93c46
|
dol
.equ
˜doh
; data out low for 93c46
|
ledh
.equ
00000010B
; turn the led pin high “off
|
ledl
.equ
˜ledh
;turn the led pin low “on
|
psmask
.equ
01000000B
; mask for the program switch
|
csport
.equ
P2
; chip select port
|
dioport
.equ
P2
; data i/o port
|
clkport
.equ
P2
; clock port
|
ledport
.equ
P2
; led port
|
psport
.equ
P2
; program switch port
|
WATCHDOG_GROUP
.equ
0FH
|
pcon
.equ
r0
|
smr
.equ
r11
|
wdtmr
.equ
r15
|
;
.IF
TwoThirtyThree
|
;
|
;WDT
.macro
|
;
.byte
5fH
|
;
.endm
|
;
|
;
.ELSE
|
;
|
;MDT
.macro
|
;
xcr
F1, #00101101b
; Kick external watchdog
|
;
.endm
|
;
|
;
.ENDIF
|
FILL
.macro
|
.byte
0ffh
|
.endm
|
FILL10
.macro
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
.endm
|
FILL100
.macro
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
.endm
|
FILL1000
.macro
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
FILL100
|
.endm
|
TRAP
.macro
|
jp
start
|
jp
start
|
jp
start
|
jp
start
|
jp
start
|
.endm
|
TRAP10
.macro
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
TRAP
|
.endm
|
SetRpToRadio2Group
.macro
|
.byte
031H
|
.byte
08CH
|
.endm
|
Interrupt Vector Table
|
.org
0000H
|
.IF
TwoThirtyThree
|
.word
RADIO_INT
;IRQ0
|
.word
000CH
;IRQ1, P3.3
|
.word
RPM
;IRQ2, P3.1
|
.word
AUX_OBS
;IRQ3, P3.0
|
.word
TIMEPVD
;IRQ4, T0
|
.word RS232
;IRQ5, T1
|
.ELSE
|
.word
RADIO_INT
;IRQ0
|
.word
RADIO_INT
;IRQ1, P3.3
|
.word
RPM
;IRQ2, P3.1
|
.word
AUX_OBS
;IRQ3, P3.0
|
.word
TIMERUD
;IRQ4, T0
|
.word
000CH
;IRQ5, T1
|
.ENDIF
|
.page
|
.org
000CH
|
jp
Start
;jmps to start at location 0101, 0202 etc
|
RS232 DATA ROUTINES
|
RS_COUNTER REGISTER:
|
0000XXXX - 0011XXXX Input byte counter (inputting bytes 1-4)
|
00XX0000
Waiting for a start bit
|
00XX0001 -XXXX1001 Input bit counter (Bits 1-9, including stop)
|
00XX1111
Idle -- whole byte received
|
1000XXXX - 1111XXXX Output byte counter (outputting bytes 1-8)
|
1XXX0000
Tell the routine to output a byte
|
1XXX0001 - 1XXX1001 Outputting a byte (Bits 1-9, including stop)
|
1XXX1111
Idle -- whole byte output
|
OutputMode:
|
tm
RS_COUNTER, #00001111B
; Check for outputting start bit
|
jr
z, OutputStart
;
|
tcm
RS_COUNTER, #00001001B
; Check for outputting stop bit
|
jr
z, OutputStop
; (bit 9), if so, don't increment
|
OutputData:
|
scf
; Set carry to ensure high stop bit
|
rrc
RS232DAT
;Test the bit for output
|
jr
c, OutputHigh
;
|
OutputLow:
|
and
p3, *˜CHAPSE_SW
; Turn off the pull-up
|
cr
P3, *DIS_SW
; Turn on the pull-down
|
jr
DataBitDone
;
|
OutputStart:
|
ld
T1,#RsPerFull
; Set the timer to a full bit period
|
ld
TMR, #00001110B
; Load the full time period
|
and
p3, #˜CHARGE_SW
; Send a start bit
|
or
P3, #DIS_SW
;
|
inc
RS_COUNTER
; Set the counter to first bit
|
iret
;
|
OutputHigh:
|
and
p3, #˜DIS_SW
; Turn off the pull-down
|
or
P3, #CHARGE_SW
; Turn on the pull-up
|
DataBitDone:
|
inc
RS_COUNTER
; Advance to the next data bit
|
iret
;
|
OutputStop:
|
and
p3, #˜DIS_SW
; Output a stop (high) bit
|
or
P3, #CHARGE_SW
;
|
or
RS_COUNTER, #00001111B
; Set the flag for word being done
|
cp
RS_COUNTER, #11111111B
; Test for last output byte
|
jr
nz, MoreOutput
; If not, wait for more output
|
clr
RS_COUNTER
; Start waiting for input bytes
|
MoreOutput:
|
RSExit:
|
iret
;
|
RS232:
|
cp
RsMode, #00
; Check for in RS232 mode,
|
jr
nz, InRsMode
; If so, keep receiving data
|
cp
STATUS, #CHARGE
; Else, only receive data when
|
jr
nz, WallModeBad
; charging the wall control
|
InRsMode:
|
tcm
RS_COUNTER, #00001111B
; Test for idle state
|
jr
z, RSExit
; If so, don't do anything
|
tm
RS_COUNTER, #11000000B
; test for input or output mode
|
jr
nz, OutputMode
|
RSInput:
|
tm
RS_COUNTER, #00001111B
; Check for waiting for start
|
jr
z, WaitForStart
; If so, test for start bit
|
tcm
RS_COUNTER, #00001001B
; Test for receiving the stop bit
|
jr
z, StopBit
; If so, end the word
|
scf
; Initially set the data in bit
|
tm
RS232IP, #RS232IM
; Check for high or low bit at input
|
jr
nz, GotRsBit
; If high, leave carry high
|
rcf
; Input bit was low
|
GotRsBit:
|
rrc
RS232DAT
; Shift the bit into the byte
|
inc
RS_COUNTER
; Advance to the next bit
|
iret
|
Stopbit:
|
tm
RS232IP,#RS232IM
; Test for a valid stop bit
|
jr
z, DataBad
; If invalid, throw out the word
|
DataGood:
|
tm
RS_COUNTER, #11110000B
; If we're not reading the first word,
|
jr
nz, IsData
; then this is not a command
|
ld
RSCOMMAND, RS232DAT
; Load the new command word
|
IsData:
|
or
RS_COUNTER, #00001111B
; Indicate idle at end of word
|
iret
|
WallModeBad:
|
clr
RS_COUNTER
; Reset the RS232 state
|
DataBad:
|
and
RS_COUNTER, #00110000B
; Clear the byte counter
|
iret
|
WaitForStart:
|
tm
RS232IP,#RS232IM
; Check for a start bit
|
jr
nz, NoStartBit
; If high, keep waiting
|
inc
RS_COUNTER
; Set to receive bit 1
|
ld
T1, #RsPer1P22
; Long time until next sample
|
ld
TMR, #00001110B
; Load the timer
|
ld
T1, #RsPerFull
; Sample at 1X afterwords
|
iret
;
|
NoStartBit:
|
ld
T1, #RsPerHalf
; Sample at 2X for start bit
|
iret
|
Set the worklight timer to 4.5 minutes for 60Hz line
|
and 2.5 minutes for 50 Hz line
|
SetVarLight:
|
cp
LinePer, #36
; Test for 50Hz or 60Hz
|
jr
uge, EuroLight
; Load the proper table
|
USALight:
|
ld
LIGHT_TIMER_HI,#USA_LIGHT_HI
; set the light period
|
ld
LIGHT_TIMER_LO,#USA_LIGHT_LO
;
|
ret
; Return
|
EuroLight:
|
ld
LIGHT_TIMER_HI,#EURO_LIGHT_HI
; set the light period
|
ld
LIGHT_TIMER_LO,#EURO_LIGHT_LO
;
|
ret
; Return
|
THIS THE AUXILARY OBSTRUCTION INTERRUPT ROUTINE
|
AUX_OBS:
|
ld
OBS_COUNT, #11
; reset pulse counter (no obstruction)
|
and
imr,#11110111b
; turn off the interupt for up to 500uS
|
ld
AOBSTEST,#11
; reset the test timer
|
or
AOBSF,#00000010B
; set the flag for got a aobs
|
and
AOBSF,#11011111B
; Clear the bad aobs flag
|
iret
; return from int
|
Test for the presence of a blinker module
|
LookForFlasher:
|
and
P2M_SHADOW, #˜BLINK_PIN
;Set high for autolatch test
|
ld
P2M, P2M_SHADOW
;
|
or
P2, #BLINK_PIN
;
|
or
P2M_SHADOW, #BLINK_PIN
;Look for Flasher module
|
ld
P2M, P2M_SHADOW
;
|
ret
|
; Full 41 bytes of unused memory
|
FILL10
|
FILL10
|
FILL10
|
FILL10
|
FILL
|
REGISTER INITILISATION
|
.org
0011H
; address has both bytes the same
|
start:
|
START: di
; turn off the interrupt for init
|
.IF
TwoThirtyThree
|
ld
RP,#WATCHDOG_GROUP
|
ld
wdtmr,#00001111B
; rc dog 100mS
|
.ELSE
|
clr
p1
|
.ENDIF
|
WDT
; kick the dog
|
clr
RP
; clear the register pointer
|
PORT INITILIZATION
|
ld
p0,#P01S_INIT
; RESET all ports
|
ld
P2,#P2S_POR
; Output the chip ID code
|
ld
P3,#P3S_INIT
;
|
ld
P01M,#P01M_INIT
; set mode p00-p03 out p04-p07in
|
ld
P3M,#P3M_INIT
; set port3 p30-p33 input analog mode
|
; p34-p37 outputs
|
ld
P2M,#P2M_POR
; set port 2 mode for chip ID out
|
Internal RAM Test and Reset All RAM = mS
|
srp
#0F0h
; point to control group use stack
|
ld
r15,#4
;r15= pointer (minimum of RAM)
|
write_again:
|
WDT
; KICK THE DOG
|
ld
r14,#1
|
write_again1:
|
ld
@r15,r14
;write 1,2,4,8,10,20,40,80
|
cp
r14,@r15
;then compare
|
jr
ne,system_error
|
rl
r14
|
jr
nc,write_again1
|
clr
Εr15
;write RAM(r5)=0 to memory
|
inc
r15
|
cp
r15,#240
|
jr
ult,write_again
|
Checksum Test
|
CHECKSUMTEST:
|
srp
#CHECK_GRP
|
ld
test_adr_hi,#01FH
|
ld
test_adr_lo,#0FFH
;maximum address=fffh
|
add_sum:
|
WDT
; KICK THE DOG
|
idc
rom_data,@test_adr
;read ROM code one by one
|
add
checkp_sum,rom_dat
;add it to checksum register
|
decw
test_addr
;increment ROM address
|
jr
nz,add_sum
;address=0 ?
|
cp
check_sum,#check_sum_value
|
jr
z,system_ok
;check final checksum = 00 ?
|
system_error:
|
and
ledport,#ledl
; turn on the LED to indicate fault
|
jr
system_error
|
.byte
256-check_sum_value
|
system_ok
|
WDT
; kick the dog
|
ld
STACKEND,#STACKTOP
; start at the top of the stack
|
SETSTACKLOOP:
|
ld
@STACKEND,#01H
; set the value for the stack vector
|
dec
STACKEND
; next address
|
cp
STACKEND,#STACKEND
; test for the last address
|
jr
nz,SETSTACKLOOP
; loop till done
|
CLEARDONE:
|
ld
STATE,#06
; set the state to stop
|
ld
BSTATE,#06
;
|
ld
OnePass,STATE
; Set the one-shot
|
ld
STATUS,#CHARGE
; set start to charge
|
ld
SWITCH_DELAY,#CMD_DEL_EX
; set the delay time to cmd
|
ld
LIGHT_TIMER_HI,#USA_LIGHT_HI
; set the light period
|
ld
LIGHT_TIMER_LO,#USA_LIGHT_LO
; for the 4.5 min timer
|
ld
RPMONES,#244
; set the hold off
|
srp
#LEARNEE_GRP
;
|
ld
learndb,#0FFH
; set the learn debouncer
|
ld
zzwin,learndb
; turn off the learning
|
ld
CMD_DEE,learnoo
; in case of shorted switches
|
ld
BCMD_DEB,learndb
; in case of shorted switches
|
ld
VAC_DEB,learndb
;
|
ld
LIGHT_DEB,learndb
;
|
ld
ERASET,learndb
; set the erase timer
|
ld
learnt,learndb
; set the learn timer
|
ld
RTO,learndb
; set the radio time out
|
ld
AUXLEARNSW,learndb
; turn off the aux learn switch
|
ld
RRTO,learndb
; set the radio timer
|
STACK INITILIZATION
|
clr
254
|
1D
255,#238
; set the start of the stack
|
.IF
TwoThirtyThree
|
.ELSE
|
clr
P1
|
.ENDIF
|
TIMER INITILIZATION
|
ld
pre0,#00000101b
; set the prescaler to /1 for 4MHz
|
ld
PRE1,#00010011B
; set the prescaler to /4 for 4MHz
|
clr
T0
; set the counter to count FF through 0
|
ld
T1,#RsPerHalf
; set the period to rs232 period for start bit sample
|
ld
TMR,#00001111B
; turn on the timers
|
PORT INITILIZATION
|
lD
P0,#P01S_INIT
; RESET all ports
|
ld
P2,#P2S_INIT
;
|
ld
P3,#P3S_INIT
;
|
ld
P01M,#P01M_INIT
; set mode p00-p03 out p04-p07in
|
ld
P3M,#P3M_INIT
; set port3 p30-p33 input analog mode
|
; p34-p37 outputs
|
ld
P2M_SHADOW,#P2M_INIT
; Shadow P2M for read ability
|
ld
P2M,#P2M_INIT
; set port 2 mode
|
.IF
TwoThirtyThree
|
.ELSE
|
clr
p1
|
.ENDIF
|
READ THE MEMORY 2X AND GET THE VACFLAG
|
ld
SKIPRADIO,#NOEECOMM
;
|
ld
ADDRESS,#VACTIONADDR
; set non vol address to the VAC flag
|
call READMEMORY
; read the value 2X 1X INIT 2ND read
|
call READMEMORY
; read the value
|
ld
VACFLAG,MTEMPH
; save into volital
|
WakeUpLimits:
|
ld
ADDRESS, #UPLIMADDR
; Read the up and down limits into memory
|
call
READMEMORY
;
|
ld
UP_LIMIT_HI, MTEMPH
;
|
ld
UP_LIMIT_LO, MTEMPL
;
|
ld
ADDRESS, #DNLIMADDR
;
|
call
READMEMORY
;
|
ld
DN_LIMIT_HI, MTEMPH
;
|
ld
DN_LIMIT_LO, MTEMPL
;
|
WDT
; Kick the dog
|
WakeUpState:
|
ld
ADDRESS, #LASTSTATEADDR
; Read the previous operating state into memory
|
call
READMEMORY
;
|
ld
STATE, MTEMPL
; Load the state
|
ld
PassCounter, MTEMPH
; Load the pass point couter
|
cp
STATE, #UP_POSITION
; If at up limit, set position
|
jr
z, WakeUpLimit
;
|
cp
STATE, #DN_POSITION
; If at down limit, set position
|
jr
z, WakeOnLimit
;
|
WakeUpLost:
|
ld
STATE, #STOP
; Set state as stopped in mid travel
|
ld
POSITION_HI, #07FH
; Set position as lost
|
ld
POSITION_LO, #080H
;
|
jr
GotWakeUp
;
|
WakeUpLimit:
|
ld
POSITION_HI, UP_LIMIT_HI
; Set position as at the up limit
|
ld
POSITION_LO, UP_LIMIT_LO
;
|
jr
GotWakeUp
|
WakeDnLimit:
|
ld
POSITION_HI, DN_LIMIT_HI
; Set position as at the down limit
|
ld
POSITION_LO, DN_LIMIT_LO
;
|
GotWakeUp:
|
ld
BSTATE, STATE
; Back up the state and
|
ld
OnePass, STATE
; clear the one-shot
|
SET ROLLING/FIXED MODE FROM NON-VOLATILE MEMORY
|
call
SetRadioMode
; Set the radio mode
|
jr
SETINTEPPUPTS
; Continue on
|
SetRadioMode:
|
ld
SKIPRADIO, #NCEECOMM
; Set skip radio flag
|
ld
ADDRESS, #MODEADDR
; Point to the radio mode flag
|
call
READMEMORY
; REad the radio mode
|
ld
RadioMode, MTEMPL
; Set the proper radio mode
|
clr
SKIPRADIO
; Re-enable the radio
|
tm
RadioMode, #ROLL_MASK
; Do we want rolling numbers
|
jr
nz, StartRoll
|
call
FixedNums
|
ret
|
StartRoll:
|
call
RollNums
|
ret
|
INITERRUPT INITILIZATION
|
SETINTERRUPTS:
|
ld
IPR,#00011010B
; set the priority to timer
|
ld
IMR,#ALL_ON_IMR
; turn on the interrupt
|
.IF
TwoThirtyThree
|
ld
IRQ,#01000000B
; set the edge clear int
|
.ELSE
|
ld
IRQ,#00000000b
; Set the edge, clear ints
|
.ENDIF
|
ei
; enable interrupt
|
RESET SYSTEM REG
|
.IF TwoThirtyThree
|
ld
RP,#WATCHDOG_GROUP
|
ld
smr,#00100010B
; reset the xtal / number
|
ld
pcon,#01111110B
; reset the pcon no comparator output
|
; no low emi mode
|
clr
RP
; Reset the RP
|
.ENDIF
|
ld
PRE0,#00000101B
; set the prescaler to / 1 for 4Mhz
|
WDT
; Kick the dog
|
MAIN LOOP
|
MAINLOOP:
|
cp
PrevPass, PassCounter
;Compare pass point counter to backup
|
jr
z, PassPointCurrent
;If equal, EEPROM is up to date
|
PassPointChanged:
|
ld
SKIPRADIO, #NOEECOMM
; Disable radio EEPROM communications
|
ld
ADDRESS, #LASTSTATEADDR
; Point to the pass point storage
|
call
READMEMORY
; Get the current GDO state
|
di
; Lock in the pass point state
|
ld
MTEMPH, PassCounter
; Store the current pass point state
|
ld
PrevPass, PassCounter
; Clear the one-shot
|
ei
:
|
call
WRITEMEMORY
; Write it back to the EEPROX
|
clr
SKIPRADIO
|
PassPointCurrent:
|
;
|
;4-22-97
|
CP
EnableWorkLight, #10000000B
;is the debouncer set? if so write and
|
; give feedback
|
JR
NE,LightOpen
|
TM
p0,#LIGHT_ON
|
JR
NZ,GetRidOfIt
|
LD
MTEMPL,#0FFH
;turn on the IR beam work light function
|
LD
MTEMPH,#0FFH
|
JR
CommitToMem
|
GetRidOfIt:
|
LD
MTEMPL,#00H
;turn off the IR beam work light function
|
LD
MTEMPH,#00H
|
CommitToMem:
|
LD
SKIPRADIO,#NOEECOMM
;write to memory to store if enabled or not
|
LD
ADDRESS,#IRLIGHTADDR
;set address for write
|
CALL
WRITEMEMORY
|
CLR
SKIPRADIO
|
XOR
p0,#WORKLIGHT
; toggle current state of work light for feedback
|
LD
EnableWorklight,#01100000B
|
LightOpen:
|
cp
LIGHT_TIMER_HI,#0FFH
; if oight timer not done test beam break
|
jr
nz,TestBeamBreak
|
tm
p0,#LIGHT_ON
; if the light is off test beam break
|
jr
nz,LightSkip
|
TestBeamBreak:
|
tm
AOBSF,#10000000b
; Test for broken beam
|
jr
z,LightSkip
; if no pulses Staying blocked
|
; else we are intermittent
|
;4-22-97
|
LD
SKIPRADIO,#NOEECOMM
;Turn off radio interrupt to read from e2
|
LD
ADDRESS,#IRLIGHTADDR
;
|
CALL
READMEMORY
|
CLR
SKIPRADIO
; don't forget to zero the one shot
|
CP
MTEMPL,#DISABLED
;Does e2 report that IR work light function
|
EQ,LightSkip
;is Disabled? If so jump over light on and
|
CP
STATE,#2
; test for the up limit
|
JR
nz,LightSkip
; if not goto output the code
|
call
SetVarLight
; Set worklight to proper time
|
or
p0,#LIGHT_ON
; turn on the light
|
LightSkip:
|
;4-22-97
|
AND
AOBSF,#01111111B
;Clear the one shot,for IR beam
|
;break detect.
|
cp
HOUR_TIMER_HI, #010H
; If and hour has passed,
|
jr
ult, NoDecrement
; then decrement the
|
cp
HOUR_TIMER_LO, #020H
; temporary password timer
|
jr
ult, NoDecrement
;
|
clr
HOUR_TIMER_HI
; Reset hour timer
|
clr
HOUR_TIMER_LO
;
|
ld
SKIPRADIO, #NOEECOMM
; Disable radio EE read
|
ld
ADDRESS, #DURAT
; Load the temporary password
|
call
READMEMORY
; duration from non-volatile
|
cp
MTEMPH, #HOURS
; If not in timer mode,
|
jr
nz, NoDecrement2
; then don't update
|
cp
MTEMPL, #00
; If timer is not done,
|
jr
z, NoDecrement2
; decrement it
|
dec
MTEMPL
; Update the number of hours
|
call
WRITEMEMORY
;
|
NoDecrement:
|
tm
AOBSF, #01000000b
; If the poll radio mode flag is
|
jr
z, NoDecrement2
; set, poll the radio mode
|
call
SetRadioMode
; Set the radio mode
|
and
AOBSF, #10111111b
; Clear the flag
|
NoDecrement2:
|
clr
SKIPRADIO
; Re-enable radio reads
|
and
AOBSF,#00100011b
; Clear the single break flag
|
clr
DOG2
; clear the second watchdog
|
ld
P01M,#P01M_INIT
; set mode p00-p03 out p04-p07in
|
ld
P3M,#P3M_INIT
; set port3 p30-p33 input analog mode
|
; p34-p37 outputs
|
or
P2M_SHADOW,#P2M_ALLINS
; Refresh all the P2M pins which have are
|
and
P2M_SHADOW,#P2M_ALLOTS
; always the same when we get here
|
ld
P2M,P2M_SHADOW
; set port 2 mode
|
cp
VACCHANGE,#0AAH
; test for the vacation change flag
|
jr
nz,NOVACCHG
; if no change the skip
|
cp
VACFLAG,#0FFH
; test for in vacation
|
jr
z,MCLEARVAC
; if in vac clear
|
ld
VACFLAG,#0FFH
; set vacation
|
jr
SETVACCHANGE
; set the change
|
MCLEARVAC:
|
clr
VACFLAG
; clear vacation mode
|
SETVACCHANGE:
|
clr
VACCHANGE
; one shot
|
ld
SKIPRADIO,#NOEECOMM
; set skip flag
|
ld
ADDRESS,#VACATIONADDR
; set the non vol address to the VAC flag
|
ld
MTEMPH,VACFLAG
; store the vacation flag
|
ld
MTEMPL,VACFLAG
;
|
call
WRITEMEMORY
; write the value
|
clr
SKIPRADIO
; clear skip flag
|
NOVACCHG:
|
cp
STACKFLAG,#0FFH
; test for the change flag
|
jr
nz,NOCHANGEST
; if no change skip updating
|
cp
L_A_C, #070H
; If we're in learn mode
|
jr
uge, SkipReadLimits
; then don't refresh the limits!
|
cp
STATE, #UP_DIRECTION
; If we are going to travel up
|
jr
z, ReadUpLimit
; then read the up limit
|
cp
STATE, #DN_DIRECTION
; If we are going to travel down
|
jr
z, ReadDnLimit
; then read the down limit
|
jr
SkipReadLimits
; No limit on this travel . . .
|
ReadUpLimit:
|
ld
SKIPRADIO, #NOEECOMM
; Skip radio EEPROM reads
|
ld
ADDRESS, #UPLIMADDR
; Read the up limit
|
call
READMEMORY
;
|
di
;
|
ld
UP_LIMIT_HI, MTEMPH
;
|
ld
UP_LIMIT_LO, MTEMPL
;
|
clr
FirstRun
; Calculate the highest possible value for pass count
|
add
MTEMPL, #10
; Bias back by 1” to provide margin of error
|
adc
MTEMPH, #00
;
|
CalcMaxLoop:
|
inc
FirstRun
;
|
add
MTEMPL, #LOW(PPOINTPULSES)
;
|
adc
MTEMPH, #HIGH(PPOINTPULSES)
;
|
jr
nc, CalcMaxLoop
; Count pass points until value goes positive
|
GotMaxPPoint:
|
ei
;
|
clr
SKIPRADIO
;
|
tm
PassCounter, #01000000b
; Test for a negative pass point counter
|
jr
z, CounterGood1
; If not, no lower bounds check needed
|
cp
DN_LIMIT_HI, #HIGHT(PPOINTPULSES - 35)
; If the down limit is low enough,
|
jr
ugt, CounterIsNeg1
; then the counter can be negative
|
jr
ult, ClearCount
; Else, it should be zero
|
cp
DN_LIMIT_LO, #LOW(PPOINTPULSES - 35)
|
jr
uge, CounterIsNeg1
;
|
ClearCount:
|
and
PassCounter, #10000000b
; Reset the pass point counter to zero
|
jr
CounterGood1
;
|
CounterIsNeg1:
|
or
PassCounter, #01111111b
; Set the pass point counter to −1
|
CounterGood1:
|
cp
UP_LIMIT_HI, #0FFH
; Test to make sure up limit is at a
|
jr
nz, TestUpLimit2
; a learned and legal value
|
cp
UP_LIMIT_LO, #0FFH
;
|
jr
z, LimitIsBad
;
|
jr
LimitsAreDone
;
|
TestUpLimit2:
|
cp
UP_LIMIT_HI, #0D0H
; Look for up limit set to illegal value
|
jr
ule, LimitIsBad
; If so, set the limit fault
|
jr
LimitsAreDone
;
|
ReadDnLimit:
|
ld
SKIPRADIO, #NOEECOMM
; Skip radio EEPROM reads
|
ld
ADDRESS, #DNLIMADDR
; Read the down limit
|
call
READMEMORY
;
|
di
;
|
ld
DN_LIMIT_HI, MTEMPH
;
|
ld
DN_LIMIT_LO, MTEMPH
;
|
ei
;
|
clr
SKIPRADIO
;
|
cp
DN_LIMIT_HI, #00H
; Test to make sure down limit is at a
|
jr
nz, TestDownLimit2
; a learned and legal value
|
cp
DN_LIMIT_LO, #00H
;
|
jr
z, LimitIsBad
;
|
jr
LimitsAreDone
;
|
TestDownLimit2:
|
cp
DN_LIMIT_HI, #020H
; Look for down limit set to illegal value
|
jr
ult, LimitsAreDone
; If not, proceed as normal
|
LimitIsBad:
|
ld
FAULTCODE, #
; Set the “no limits” fault
|
call
SET_STOP_STATE
; Stop the GDO
|
jr
LimitsAreDone
;
|
SkipReadLimits:
|
LimitsAreDone:
|
ld
SKIPRADIO, #NOEECOMM
; Turn off the radio read
|
ld
ADDRESS, #LASTSTATEADDR
; Write the current state and pass count
|
call
READMEMORY
;
|
ld
MTEMPH, PassCounter
; DON'T update the pass point here!
|
ld
MTEMPL, STATE
;
|
call
WRITEMEMORY
;
|
clr
SKIPRADIO
;
|
ld
OnePass, STATE
; Clear the one-shot
|
cp
L_A_C, #077H
; Test for successful learn cycle
|
jr
nz, DontWriteLimits
; If not, skip writing limits
|
WriteNewLimits:
|
cp
STATE, #STOP
;
|
jr
nz, WriteUpLimit
;
|
cp
LIM_TEST_HI, #00
; Test for (force) stop witin 0.5″ of
|
jr
nz, WriteUpLimit
; the original up limit position
|
cp
LIM_TEST_LO, #16
;
|
jr
ugt, WriteUpLimit
;
|
BackOffUpLimit:
;
|
add
UP_LIMIT_LO, #
; Back off the up limit by 0.5″
|
add
UP_LIMIT_HI, #00
;
|
WriteUpLimit:
|
ld
SKIPRADIO, #NOEECOMM
; Skip radio EEPROM reads
|
ld
ADDRESS, #UPLIMADDR
; Read the up limit
|
di
;
|
ld
MTEMPH, UP_LIMIT_HI
;
|
ld
MTEMPL, UP_LIMIT_LO
;
|
ei
;
|
call
WRITEMEMORY
;
|
WriteDnLimit:
|
ld
ADDRESS, #DNLIMADDR
; Read the up limit
|
di
;
|
ld
MTEMPH, DN_LIMIT_HI
;
|
ld
MTEMPL, DN_LIMIT_LO
;
|
ei
;
|
call
WRITEMEMORY
;
|
WritePassCount:
|
ld
ADDRESS, #LASTSTATEADDR
; Write the current state and pass count
|
ld
MTEMPH, PassCounter
; Update the pass point
|
ld
MTEMPL, STATE
;
|
call
WRITEMEMORY
;
|
clr
SKIPRADIO
;
|
clr
L_A_C
; Leave the learn mode
|
or
ledport,#ledh
; turn off the LED for program mode
|
DontWriteLimits:
|
srp
#LEARNEE_GRP
; set the register pointer
|
clr
STACKFLAG
; clear the flag
|
ld
SKIPRADIO, #NOEECOMM
; set skip flag
|
ld
address,#CYCCOUNT
; set the non vol address to the cycle c
|
call
READMEMORY
; read the value
|
inc
mtemp1
; increase the counter lower byte
|
jr
nz,COUNTER1DONE
;
|
inc
mtemph
; increase the counter high byte
|
jr
nz,COUNTER2DONE
;
|
call
WRITEMEMORY
; store the value
|
inc
address
; get the next bytes
|
call
READMEMORY
; read the data
|
inc
mtemp1
; increase the counter low byte
|
jr
nz,COUNTER2DONE
;
|
inc
mtemph
; increase the vounter high byte
|
COUNTER2DONE:
|
call
WRITEMEMORY
; save the value
|
ld
address,#CYCCOUNT
;
|
call
READMEMORY
; read the data
|
and
mtemph,#00001111B
; find the force address
|
or
mtemph,#30H
;
|
ld
ADDRESS,MTEMPH
; set the address
|
ld
mtemp1,DNFORCE
; read the forces
|
ld
mtemph,UPFORCE
;
|
call
WRITEMEMORY
; write the value
|
jr
CDONE
; done set the back trace
|
COUNTER1DONE:
|
call
WRITEMEMORY
; got the new address
|
CDONE:
|
clr
SKIPRADIO
; clear skip flag
|
NOCHANGEST:
|
call
LEARN
; do the learn switch
|
di
|
cp
BRPM_COUNT_RPM_COUNT
|
jr
z,TESTRPM
|
RESET:
|
jp
START
|
TESTRPM:
|
cp
BRPM_TIME_OUT,RPM_TIME_OUT
|
jr
nz,RESET
|
cp
BFORCE_IGNORE,FORCE_IGNORE
|
jr
nz,RESET
|
ei
|
di
|
cp
BAUTO_DELAY,AUTO_DELAY
|
jr
nz,REESET
|
cp
BCMD_DEB,CMD_DEB
|
jr
nz,RESET
|
cp
BSTATE,STATE
|
jr
nz,RESET
|
ei
|
TESTRS232:
|
SRP
#TIMER_GROUP
|
tcm
RS_COUNTER, #00001111B
; If we are at the end of a word,
|
jp
nz, SIPRS232
; then handle the RS232 word
|
cp
rscommand,#‘V’
;
|
jp
ugt,ClearRS232
;
|
cp
rscommand,#‘0’
; test for in range
|
jp
ult,ClearRS232
; if out of range skip
|
cp
rscommand,#‘<’
; If we are reading
|
jr
nz,NotRs3C
; go straight there
|
call
GotRs3C
;
|
jp
SIPRS232
;
|
NotRs3C:
|
cp
rscommand,#‘>’
; If we are writing EEPROM
|
jr
nz,NotRs3E
; go straight there
|
call
GotRs3E
;
|
jp
SKIPRS232
;
|
NotRs3E:
|
ld
rs_temp_hi,#HIGH (RS232JumpTable-(3*‘0’))
; address pointer to table
|
ld
rs_temp_lo,#LOW (RS232JumpTable-(3*‘0’))
; Offset for ASCII adjust
|
add
rs_temp_lo,rscommand
; look up the jump 3x
|
adc
rs_temp_hi,#00
;
|
add
rs_temp_lo,rscommand
; look up the jump 3x
|
adc
rs_temp_hi,·00
;
|
add
rs_temp_lo,rscommand
; look up the jump 3x
|
adc
rs_temp_hi,#00
;
|
call
@rs_temp
; call this address
|
jp
SKIPRS232
; done
|
RS232JumpTable:
|
jp
GotRs30
|
jp
GotRs31
|
jp
GotRs32
|
jp
GotRs33
|
jp
GotRs34
|
jp
GotRs35
|
jp
GotRs36
|
jp
GotRs37
|
jp
GotRs38
|
jp
GotRs39
|
jp
GotRs3A
|
jp
GotRs3B
|
jp
GotRs3C
|
jp
GotRs3D
|
jp
GotRs3E
|
jp
GotRs3F
|
jp
GotRs40
|
jp
GotRs41
|
jp
GotRs42
|
jp
GotRs43
|
jp
GotRs44
|
jp
GotRs45
|
jp
GotRs46
|
jp
GotRs47
|
jp
GotRs48
|
jp
GotRs49
|
jp
GotRs4A
|
jp
GotRs4B
|
jp
GotRs4C
|
jp
GotRs4D
|
jp
GotRs4E
|
jp
GotRs4F
|
jp
GotRs50
|
jp
GotRs51
|
jp
GotRs52
|
jp
GotRs53
|
jp
GotRs54
|
jp
GotRs55
|
jp
GotRs56
|
ClearRS232:
|
and
RS_COUNTER, #11110000b
; Clear the RS232 state
|
SKIPRS232:
|
UpdateForceAndSpeed:
|
; Update the UP force from the look-up table
|
srp
#FORCE_GROUP
; Point ot the proper registers
|
ld
force_add_hi, #HIGH(force_table)
; Fetch the proper unscaled
|
ld
force_add_lo, #LOW(force_table)
; value from the ROM table
|
di
;
|
add
force_add_lo, upforce
; Offset to point to the
|
adc
force_add_hi, #00
; proper place in the table
|
add
force_add_lo, upforce
; x2
|
adc
force_add_hi, #00
;
|
add
force_add_lo, upforce
; x3 (three bytes wide)
|
adc
force_add_hi, #00
;
|
ei
;
|
ldc
force_temp_of, @force_add
; Fetch the ROM bytes
|
incw
force_add
;
|
ldc
force_temp_hi, @force_add
;
|
incw
force_add
;
|
ldc
force_temp_lo, @force_add
;
|
ld
Divisor, PowerLevel
; Divide by our current force level
|
call
ScaleTheSpeed
; Scale to get our proper force number
|
di
; Update the force registers
|
ld
UP_FORCE_HI, force_temp_hi
;
|
ld
UP_FORCE_LO, force_temp_lo
;
|
ei
;
|
; Update the DOWN force from the look-up table
|
ld
force_add_hi, #HIGH(force_table)
; Fetch the proper unscaled
|
ld
force_add_lo, #LOW(force_table)
value from the ROM table
|
di
;
|
add
force_add_lo, dnforce
; Offset to point to the
|
adc
force_add_hi, #00
; proper place in the table
|
add
force_add_lo, dnforce
; x2
|
adc
force_add_hi, #00
;
|
add
force_add_lo, dnforce
; x3 (three bytes wide)
|
adc
force_add_hi, #00
;
|
ei
;
|
ldc
force_temp_of, @force_add
; Fetch the ROM bytes
|
incw
force_add
;
|
ldc
force_temp_hi, @force_add
;
|
incw
force_add
;
|
ldc
force_temp_lo, @force_add
;
|
ld
Divisor, PowerLevel
; Divide by our current force level
|
call
ScaleTheSpeed
; Scale to get our proper force number
|
di
; Update the force registers
|
ld
DN_FORCE_HI, force_temp_hi
;
|
ld
DN_FORCE_LO, force_temp_lo
;
|
ei
;
|
; Scale the minumum speed based on force setting
|
cp
STATE, #DN_DIRECTION
; If we're traveling down,
|
jr
z, SetDownMinSpeed
; then use the down force pot for min. speed
|
SetUpMinSpeed:
|
di
; Disable interrupts during update
|
ld
MinSpeed, UPFORCE
; Scale up force pot
|
jr
MinSpeedMath
;
|
SetDownMinSpeed:
|
di
;
|
ld
MinSpeed, DNFORCE
; Scale down force pot
|
MinSpeedMath:
|
sub
MinSpeed, #24
; pot level - 24
|
jr
nc, UpStep2
; truncate off the negative number
|
clr
MinSpeed
;
|
UpStep2:
|
rcf
; Divide by four
|
rrc
MinSpeed
;
|
rcf
;
|
rrc
MinSpeed
;
|
add
MinSpeed, #4
; Add four to find the minimum speed
|
cp
MinSpeed, #12
; Perform bounds check on minium speed
|
jr
ule, MinSpeedOkay
; Truncate if necessary
|
ld
MinSpeed, #12
;
|
MinSpeedOkay:
|
ei
; Re-enable interrupts
|
; Make sure the worklight is at the proper time on power-up
|
cp
LinePer, #36
; Test for a 50 Hz system
|
jr
ult, TestRadioDeadTime
; if not, we don't have a problem
|
cp
LIGHT_TIMER_HI, #0FFH
; If the light timer is running
|
jr
z, TestRadioDeadTime
; and it is greater than
|
cp
LIGHT_TIMER_HI, #EURO_LIGHT_HI
; the European time, fix it
|
jr
ule, TestRadioDeadTime
;
|
call
SetVarLight
;
|
TestRadioDeadTime:
|
cp
R_DEAD_TIME, #25
; test for too long dead
|
jp
nz,MAINLOOP
; if not loop
|
clr
RadioC
; clear the radio counter
|
clr
RFlag
; clear the radio flag
|
jp
MAINLOOP
; loop forever
|
Speed scaling (i.e. Division) routine
|
ScaleTheSpeed:
|
clr
TestReg
|
ld
loopreg, #24
; Loop for all 24 bits
|
DivideLoop:
|
rcf
; Rotate the next bit into
|
rlc
force_temp_lo
; the test field
|
rlc
force_temp_hi
;
|
rlc
force_temp_of
;
|
rlc
TestReg
;
|
cp
TestReg, Divisor
; Test to see if we can subtract
|
jr
ult, BitIsDone
; If we can't, we're all done
|
sub
TestReg, Divisor
; Subtract the divisor
|
or
force_temp_lo, #00000001b
; Set the LSB to mark the subtract
|
BitIsDone:
|
djnz
loopreg, DivideLoop
; Loop for all bits
|
DivideDone:
|
; Make sure the result is under our 500 ms limit
|
cp
force_temp_of, #00
; Overflow byte must be zero
|
jr
nz, ScaleDown
;
|
cp
force_temp_hi, #0F4H
;
|
jr
ugt,ScaleDown
;
|
jr
ult, DivideIsGood
; If we're less, then we're okay
|
cp
force_temp_lo, #024H
; Test low byte
|
jr
ugt,ScaleDown
; if low byte is okay,
|
DivideIsGood:
|
ret
; Number is good
|
ScaleDown:
|
ld
force_temp_hi, #0F4H
; Overflow is never used anyway
|
ld
force_temp_lo, #024H
;
|
ret
|
RS232 SUBROUTINES
|
“0”
|
Set Command Switch
|
GotRs30:
|
ld
LAST_CMD,#0AaH
; set the last command as rs wall cmd
|
call
CmdSet
; set the command switch
|
jp
NoPos
|
“1”
|
Clear Command Switch
|
GotRs31:
|
call
CmdRel
; release the command switch
|
jp
NoPos
|
“2”
|
Set Worklight switch
|
GotRs32:
|
call
LightSet
; set the light switch
|
jp
NoPos
|
“3”
|
Clear Worklight Switch
|
GotRs33:
|
clr
LIGHT_DEB
; Release the light switch
|
jp
NoPos
|
“4”
|
Set Vacation Switch
|
GotRs34:
|
call
VacSet
; Set the vacation switch
|
jp
NoPos
|
“5”
|
Clear Vacation Switch
|
GotRs35:
|
clr
VAC_DEB
; release the vacation switch
|
jp
NoPos
|
“6”
|
Set smart switch
|
GotRs36:
|
call
SmartSet
|
jp
NoPos
|
“7”
|
Clear Smart switch set
|
GotRs37:
|
call
SmartRelease
|
jp
NoPos
|
“8”
|
Return Present state and reason for that state
|
GotRs38:
|
ld
RS232DAT,STATE
|
or
RS232DAT,STACKREASON
|
jp
LastPos
|
“9”
|
Return Force Adder and Fault
|
GotRs39:
|
ld
RS232DAT,FAULTCODE
; insert the fault code
|
jp
LastPos
|
“:”
|
Status Bits
|
GotRs3A:
|
clr
RS232DAT
; Reset data
|
tm
P2, #01000000b
; Check the strap
|
jr
z, LookForBlink
; If none, next check
|
or
RS232DAT, #00000001b
; Set flag for strap high
|
LookForBlink:
|
call
LookForFlasher
;
|
tm
P2, #BLINK_PIN
; If flasheer is present,
|
jr
nz, ReadLight
;
|
or
RS232DAT,#00000010b
; then idicate it
|
ReadLight:
|
tm
P0,#00000010B
; read the light
|
jr
z,C3ADone
|
or
RS232DAT,#00000100b
|
C3ADone:
|
cp
CodeFlag, #REGLEARN
; Test for being in a learn mode
|
jr
ult, LookForPass
; If so, set the bit
or
RS232DAT,#00010000b
;
|
or
RS232DAT,#000100000b
;
|
LookForPass:
|
tm
PassCounter,#01111111b
; Check for above pass point
|
jr
z, LookForProt
; If so, set the bit
|
tcm
PassCounter,#01111111b
;
|
jr
z, LookForProt
;
|
or
RS232DAT,#00100000b
;
|
LookForProt:
|
tm
ACBSF, #10000000b
; Check for protector break/block
|
jr
nz, LookForVac
; If blocked, don't set the flag
|
or
RS232DAT,#01000000b
; Set flag for protector signal good
|
LookForVac:
|
cp
VACFLAG,#00B
; test for the vacation mode
|
jp
nz,LastPos
|
or
RS232DAT,#00001000b
|
jp
LastPos
|
“;”
|
Return L_A_C
|
GotRs3B:
|
ld
RS232DAT,L_A_C
; read the L_A_C
|
jr
LastPos
|
“<”
|
Read a word of data from an EEPROM address input by the user
|
GotRs3C:
|
cp
RS_COUNTER, #010H
; If we have only received the
|
jr
ult, FirstByte
; first word, wait for more
|
cp
RS_COUNTER, #080H
; If we are outputting,
|
jr
ugt, OutputSecond
; output the second byte
|
SecondByte:
|
ld
SKIPRADIO, #0FFH
; Read the memory at the specified
|
ld
ADDRESS, RS232DAT
; address
|
call
READMEMORY
;
|
ld
RS232DAT, MTEMPH
; Store into temporary registers
|
ld
RS_TEMP_LO, MTEMPL
;
|
clr
SKIPRADIO
;
|
jp
MidPos
;
|
OutputSecond:
|
ld
RS232DAT, RS_TEMP_LO
; Output the second byte of the read
|
jp
LastPos
;
|
FirstByte:
|
inc
RS_COUNTER
; Set to receive second word
|
ret
;
|
“=”
|
Exit learn limits mode
|
GotRs3D:
|
cp
L_A_C, #00
; If not in learn mode,
|
jp
z, NoPos
; then don't touch the learn LED
|
clr
L_A_C
; Reset the learn limits state machine
or
leaport,#ledn
; turn off the LED for program mode
|
or
ledport,#ledh
; turn off the LED for program mode
|
jp
NoPos
;
|
“>”
|
Write a word of dat ato the address input by the user
|
GotRs3E:
|
cp
RS_COUNTER, #01FH
;
|
jr
z, SecondByteW
;
|
cp
RS_COUNTER, #02FH
;
|
jr
z, ThirdByteW
;
|
cp
RS_COUNTER, #03FH
;
|
jr
z, FourthByteW
;
|
FirstByteW:
|
DataDone:
|
inc
RS_COUNTER
; Set to receive next byte
|
ret
|
SecondByteW:
|
ld
RS_TEMP_HI, RS232DAT
; Store the address
|
jr
DataDone
;
|
ThirdByteW:
|
ld
RS_TEMP_LO, RS232DAT
; Store the high byte
|
jr
DataDone
;
|
FourthByteW:
|
cp
RS_TEMP_HI, #03FH
; Test for illegal address
|
jr
ugt, FailedWrite
; If so, don't write
|
ld
SKIPRADIO, #0FFH
; Turn off radio reads
|
ld
ADDRESS, RS_TEMP_HI
; Load the address
|
ld
MTEMPH, RS_TEMP_LO
; and the data for the
|
ld
MTEMPL, RS232DAT
; EEPROM write
|
call
WRITEMEMORY
;
|
clr
SKIPRADIO
; Re-enable radio reads
|
ld
RS232DAT, #00H
; Flag write okay
|
jp
LastPos
;
|
FailedWrite:
|
ld
RS232DAT, #0FFH
; Flag bad write
|
jp
LastPos
|
“?”
|
; Suspend all communication for 30 seconds
|
GotRs3F:
|
clr
RSCOMMAND
; Throw out any command currently
|
;running
|
jp
NoPos
; Ignore all RS232 data
|
“@”
|
; Force Up State
|
GotRs40:
|
cp
STATE, #DN_DIRECTION
; If traveling down, make sure that
|
jr
z, dontup
; the door autoreverses first
|
cp
STATE, #AUTO_REV
; If the door is autoreversing or
|
jp
z, NoPos
; at the up limit, don't let the
|
cp
STATE, #UP_POSITION
; up direction state be set
|
jp
z, NoPos
;
|
ld
REASON, #00H
; Set the reason as command
|
call
SET_UP_DIR_STATE
|
jp
NoPos
|
dontup:
|
ld
REASON, #00H
; Set the reason as command
|
call
SET_AREV_STATE
; Autoreverse the door
|
jp
NoPos
;
|
“A”
|
Force Down State
|
GotRs41:
|
cp
STATE, #5h
; test for the down position
|
jp
z,NoPos
;
|
clr
REASON
; Set the reason as command
|
call
SET_DN_DIR_STATE
|
jp
NoPos
|
“B”
|
Force Stop State
|
GotRs42:
|
clr
REASON
; Set the reason as command
|
call
SET_STOP_STATE
|
jp
NoPos
|
“C”
|
Force Up Limit State
|
GotRs43:
|
clr
REASON
; Set the reason as command
|
call
SET_UP_POS_STATE
|
jp
NoPos
|
“D”
|
Force Down Limit State
|
GotRs44:
|
clr
REASON
; Set the reason as command
|
call
SET_DN_POS_STATE
|
jp
NoPos
|
“E”
|
Return min. force during travel
|
GotRs45:
|
ld
RS232DAT,MIN_RPM_HI
; Return high and low
|
cp
RS_COUNTER,#090h
; bytes of min. force read
|
jp
ult,MidPos
;
|
ld
RS232DAT,MIN_RPM_LO
;
|
jp
LastPos
;
|
“F”
|
Leave RS232 mode -- go back to scanning for wall control switches
|
GotRs46:
|
clr
RsMode
; Exit the rs232 mode
|
ld
STATUS, #CHARGE
; Scan for switches again
|
clr
RS_COUNTER
; Wait for input again
|
ld
rscommand,#0FFH
; turn off command
|
ret
|
“G”
|
(No Function)
|
GotRs47:
|
jp
NoPos
|
“H”
|
45 Second search for pass point the setup for the door
|
GotRs48:
|
ld
SKIPRADIO, #0FFH
; Disable radio EEPROM reads / writes
|
ld
MTEMPH, #0FFH
; Erase the up limit and down limit
|
ld
MTEMPL, #0FFH
; in EEPROM memory
|
ld
ADDRESS, #UPLIMADDR
;
|
call
WRITEMEMORY
;
|
ld
ADDRESS, #DNLIMADDR
;
|
call
WRITEMEMORY
;
|
ld
UP_LIMIT_HI, #HIGH(SetupPos)
; Set the dorr to travel
|
ld
UP_LIMIT_LO, #LOW SetupPos)
; to the setup position
|
ld
POSITION_HI, #040H
; Set the current position to unknown
|
and
PassCounter, #10000000b
; Reset to activate on first pass point seen
|
call
SET_UP_DIR_STATE
; Force the door to travel
|
ld
OnePass, STATE
; without a limit refresh
|
jp
NoPos
|
“I”
|
Return radio drop-out timer
|
GotRs49:
|
clr
RS232DAT
; Initially say no radio on
|
cp
RTO,#RDROPTIME
; If there's no radio on,
|
jp
uge, LastPos
; then broadcast that
|
com
RS232DAT
; Set data to FF
|
jp
LastPos
|
“J”
|
Return current position
|
GotRs4A:
|
ld
RS232DAT,POSITION_HI
|
cp
RS_COUNTER,#090H
; Test for no words out yet
|
jp
ult, MidPos
; If not, transmit high byte
|
ld
RS232DAT,POSITION_LO
|
jp
LastPos
|
“K”
|
Set radio Received
|
GotRs4B:
|
cp
L_A_C, #070H
; If we were positioning the up limit,
|
jr
ult, NormalRSRadio
; then start the learn cycle
|
jr
z, FirstRSLearn
;
|
cp
L_A_C, #071H
; If we had an error,
|
jp
nz, NoPos
; re-learn, otherwise ignore
|
ReLearnRS:
|
ld
L_A_C, #072H
; Set the re-learn state
|
call
SET_UP_DIR_STATE
;
|
jp
NoPos
;
|
FirstRSLearn:
|
ld
L_A_C, #073H
; Set the learn state
|
call
SET_UP_POS_STATE
; Start from the “up limit”
|
jp
NoPos
|
NormalRSRadio:
|
clr
LAST_CMD
; mark the last command as radio
|
ld
RADIO_CMD,#0AAH
; set the radio command
|
jp
NoPos
; return
|
“L”
|
Direct-connect sensitivity test -- toggle worklight for any code
|
GotRs4C:
|
clr
RTO
; Reset the drop-out timer
|
ld
CodeFlag, #SENS_TEST
; Set the flag to test sensitivity
|
jp
NoPos
|
“M”
|
GotRs4D:
|
jp
NoPos
|
“N”
|
If we are within the first 4 seconds and RS232 mode is not yet enabled,
|
then echo the nybble on P30 - P33 on all other nybbles
|
(A.K.A. The 6800 test)
|
GotRs4E:
|
cp
SDISABLE, #32
; If the 4 second init timer
|
jp
ult, ExitNoTest
; is done, don't do the test
|
di
; Shut down all other GDO operations
|
ld
COUNT_HI, #002H
; Set up to loop for 512 iterations,
|
clr
COUNT_LO
; totaling 13.056 milliseconds
|
ld
P01M, #00000100b
; Set all possible pins or micro.
|
ld
P2M, #00000000b
; to outputs for testing
|
ld
P3M, #00000001b
;
|
WDT
; Kick the dog
|
TimingLoop:
|
clr
REGTEMP
; Create a byte of identical nybbles
|
ld
REGTEMP2, P3
; from P30 - P33 to write to all ports
|
and
REGTEMP2, #00001111b
;
|
or
REGTEMP, REGTEMP2
;
|
swap
REGTEMP2
;
|
or
REGTEMP, REGTEMP2
;
|
ld
P0, REGTEMP
; Echo the nybble to all ports
|
ld
P2, REGTEMP
;
|
ld
P3, REGTEMP
;
|
decw
COUNT
; Loop for 512 iterations
|
jr
nz, TimingLoop
;
|
jp
START
; When done, reset the system
|
“O”
|
Return max, force during travel
|
GotRs4F:
|
ld
RS232DAT,P32_MAX_HI
; Return high and low
|
cp
RS_COUNTER,#090h
; bytes of max. force read
|
jp
ult,MidPos
;
|
ld
RS232DAT,P32_MAX_LO
;
|
jp
LastPos
;
|
“P”
|
Return the measured temperature range
|
GotRs50:
|
jr
NoPos
|
“Q”
|
Return address of last memory matching
|
radio code received
|
GotRs51:
|
ld
RS232DAT, RTEMP
; Send back the last matching address
|
jr
LastPos
;
|
“R”
|
Set Rs232 mode -- No ultra board present
|
Return Version
|
GotRs52:
|
clr
UltraBrd
; Clear flag for ultra board present
|
SetIntoRs232:
|
ld
RS232DAT,#VERSIONNUM
; Initially return the version
|
cp
RsMode,#00
; If this is the first time we're
|
jr
ugt, LockedInNoCR
l looking RS232, signal it
|
ld
RS232DAT,#0BBH
; Return a flag for initial RS232 lock
|
LockedInNoCR:
|
ld
RsMode,#32
|
jr
LastPos
|
“S”
|
Set Rs232 mode -- Ultra board present
|
Return Version
|
GotRs53:
|
jr
NoPos
|
“T”
|
Range test -- toggle worklight whenever a good memory-matching code
|
is received
|
GotRs54:
|
clr
RTO
; Reset the drop-out timer
|
ld
CodeFlag, #RANGETEST
; Set the flag to test sensitivity
|
jr
NoPos
|
“U”
|
(No Function)
|
GotRs55:
|
jr
NoPos
|
“V”
|
Return current values of up and down force pots
|
GotRs56:
|
ld
RS232DAT,UPFORCE
; Return values of up and down
|
cp
PS_COUNTER,#090h
; force pots.
|
jp
ult,MidPos
;
|
ld
RS232DAT,DNFORCE
;
|
jr
LastPos
|
MidPos:
|
cr
RS_COUNTER, #10000000B
; Set the output mode
|
inc
RS_COUNTER
; Transmit the next byte
|
jr
RSDone
; exit
|
LastPos:
|
ld
RS_COUNTER, #11110000B
; set the start flag for last byte
|
ld
rscommand,#0FFH
; Clear the command
|
jr
RSDone
; Exit
|
ExitNoTest:
|
NoPos:
|
clr
RS_COUNTER
; Wait for input again
|
ld
rscommand,#0FFH
; turn off command
|
RSDone:
|
ld
RsMode,#32
;
|
ld
STATUS, #RSSTATUS
; Set the wall control to RS232
|
or
P3, #CHARGE_SW
; Turn on the pull-ups
|
and
P3, #˜DIS_SW
;
|
ret
|
Radio interrupt from a edge of the radio signal
|
RADIO_INT:
|
push
RP
; save the radio pair
|
srp
#RadioGroup
; set the register pointer
|
ld
rtemph,T0EXT
; read the upper byte
|
ld
rtemp1,T0
; read the lower byte
|
tm
IRQ,#00010000B
; test for pending int
|
jr
z,RTIMEOK
; if not then ok time
|
tm
rtemp1,#10000000B
; test for timer reload
|
jr
z,RTIMEOK
; if not reloaded then ok
|
dec
rtemph
; if reloaded then dec high for sync
|
RTIMEOK:
|
clr
R_DEAD_TIME
; clear the dead time
|
.IF
TwoThirtyThree
|
and
IMR,#11111110B
; turn off the radio interrupt
|
.ELSE
|
and
IMR,#11111100B
; Turn off the radio interrupt
|
.ENDIF
|
ld
RTimeDH,PTimePH
; find the difference
|
ld
RTimeDL,RTimePL
;
|
sub
RTimeDL,rtemp1
;
|
sbc
RTimeDH,rtemph
; in past time and the past time in temp
|
RTIMEDONE:
|
tm
P3,#00000100B
; test the port for the edge
|
jr
nz,ACTIVETIME
; if it was the active time then branch
|
INACTIVETIME:
|
cp
RINFILTER,#0FFH
; test for active last time
|
jr
z,GOINACTIVE
; if so continue
|
jp
RADIO_EXIT
; if not the return
|
GOINACTIVE:
|
.IF
TwoThirtyThree
|
or
IRQ,#01000000B
; set the bit setting direction to pos edge
|
.ENDIF
|
clr
RINFILTER
; set flag to inactive
|
ld
rtimeih,RTimeDH
; transfer difference to inactive
|
ld
rtimeil,RTimeDL
;
|
ld
RTimePH,rtemph
; transfer temp into the past
|
ld
RTimePL,rtempl
;
|
CP
radioc,#01H
;inactive time after sync bit
|
JP
Z,RADIO_EXIT
;exit if it was not sync
|
TM
RadioMode, #ROLL_MASK
;If in fixed mode,
|
JR
z, FixedBlank
;no number counter exists
|
CP
rtimeih,#0AH
;s.56ms for rolling code mode
|
JP
ULT,RADIO_EXIT
;pulse ok exit as normal
|
CLR
radioc
;if pulse is longer, bogus sync, restart sync search
|
jp
RADIO_EXIT
; return
|
FixedBlank:
|
CP
rtimeih,#014H
; test for the max width 5.16ms
|
JP
ULT,RADIO_EXIT
;pulse ok exit as normal
|
CLR
radioc
;if pulse is longer, bogus sync, restart sync search
|
jp
RADIO_EXIT
; return
|
ACTIVETIME:
|
cp
RINFILTER,#00H
; test for active last time
|
jr
z,GOACTIVE
; if so continue
|
jr
RADIO_EXIT
; if not the return
|
GOACTIVE:
|
.IF
TwoThirtyThree
|
and
IRQ,#00111111B
; clear bit setting direction to neg edge
|
.ENDIF
|
ld
RINFILTER,#0FFH
;
|
ld
rtimeah,RTimeDH
; transfer difference to active
|
ld
rtimeal,RTimeDL
;
|
ld
RTimePH,rtemph
; transfer temp into the past
|
ld
RTimePL,rtempl
;
|
GotBothEdges:
|
ei
; enable the interrupts
|
cp
radioc,#1
; test for the blank timing
|
jp
ugt,INSIG
; if not then in the middle of signal
|
.IF UseSiminor
|
JP
z, CheckSiminor
; Test for a Siminor tx on the first bit
|
.ENDIF
|
inc
radioc
; set the counter to the next number
|
TM
RFlag,#001000000B
;Has a valid blank time occured
|
JR
NZ,BlankSkip
|
cp
RadioTimeOut,#10
; test for the min 10 ms blank time
|
jr
ult,ClearJump
; if not then clear the radio
|
OP
RFlag,#00100000B
;blank time valid! no need to check
|
BlankSkip:
|
cp
rtimeah,#00h
; test first the min sync
|
pr
z,JustNoise
; if high byte 0 then clear the radio
|
SyncOk:
|
TM
RadioMode,#ROLL_MASK
;checking sync pulse with,fix or Roll
|
JR
z,Fixedsync
|
CP
rtimeah,#09h
;time for roll 1/2 fixed, 2.3ms
|
JR
uge,JustNoise
|
JR
SET1
|
Fixedsync:
cp
rtimeah,#012h
; test of the max time 4.6mS
|
jr
uge,JustNoise
; if not clear
|
SET1:
|
clr
PREVFIX
;Clear the previous “fixed” bit
|
cp
rtimeah, SyncThresh
; test for 1 or three time units
|
jr
uge,SYNC3FLAG
; set the sync 3 flag
|
SYNCLFLAG:
|
tm
RFlag, #01000000b
;Was a sync 1 word the last received?
|
jr
z, SETADCODE
; if not, then this is an A (or D code
|
SETBCCODE:
|
ld
radio3h, radio1h
;Store the last sync 1 word
|
ld
radio31, radio11
|
or
RFlag, #00000110b
;Set the B/C Code flags
|
and
RFlag, #11110111b
;Clear the A/D Code Flag
|
jr
BCCODE
|
JustNoise:
|
CLR
radioc
;Edge was noise keep waiting for sync bit
|
JP
RADIO_EXIT
|
SETADCODE:
|
or
RFlag, #00001000b
|
BCCODE:
|
or
RFlag,#01000000b
; set the sync 1 memory flag
|
clr
radio1h
; clear the memory
|
clr
radio11
;
|
clr
COUNT1H
; clear the memory
|
clr
COUNT1L
;
|
jr
DONESET1
; do the 2X
|
SYNC3FLAG:
|
and
RFlag,#10111111b
; set the sync 3 memory flag
|
clr
radio3h
; clear the memory
|
clr
radio3l
;
|
clr
COUNT3H
; clear the memory
|
clr
COUNT3L
;
|
clr
ID_B
; Clear the ID bits
|
DONESET1:
|
RADIO_EXIT:
|
and
SKIPRADIO, # LOW:˜NOINT)
;Re-enable radio ints
|
pop
rp
|
iret
; done return
|
ClearJump:
|
or
P2,#10000000b
; turn of the flag bit for clear radio
|
jp
ClearRadio
; clear the radio signal
|
.IF
UseSiminor
|
SimRadio:
|
tm
rtimeah, #10000000b
; Test for inactive greater than active
|
jr
nz, SimBitZero
; If so, binary zero received
|
SimBitOne:
|
scf
; Set the bit
|
jr
RotateInBit
;
|
SimBitZero:
|
rcf
|
RotateInBit:
|
rrc
CodeT0
; Shift the new bit into the
|
rrc
CodeT1
; radio word
|
rrc
CodeT2
;
|
rrc
CodeT3
;
|
rrc
CodeT4
;
|
rrc
CodeT5
;
|
inc
radioc
; increase the counter
|
cp
radioc, # 49 - 129
; Test for all 48 bits received
|
jp
ugt, CLEARRADIO
;
|
jp
z, KnowSimCode
;
|
jp
RADIO_EXIT
;
|
CheckSiminor:
|
tm
RadioMode, #ROLL_MASK
; If not in a rolling mode,
|
jr
z, INSIG
; then it can't be a Siminor transmitter
|
cp
RadioTimeOut, #35
; If the blank time is linger than 35 ms,
|
jr
ugt, INSIG
; then it can't be a Siminor unit
|
or
RadioC, #10000000b
; Set the flag for a Siminor signal
|
clr
ID_B
; No ID bits for Siminor
|
.ENDIF
|
INSIG:
|
AND
RFlag,#11011111B
;clear blank time good flag
|
cp
rtimeih,#014H
; test for the max width 5.16
|
jr
uge,ClearJump
; if too wide clear
|
cp
rtimeih,#00h
; test for the min width
|
jr
z,ClearJump
; if high byte is zero, pulse too narrow
|
ISigOk:
|
cp
rtimeah,#014H
; test for the max width
|
jr
uge,ClearJump
; if too wide clear
|
cp
rtimeah,#00h
; if greater then 0 then signal ok
|
jr
z,ClearJump
; if too narrow clear
|
ASigOk:
|
sub
rtimeal,rtimeil
; find the difference
|
sbc
rtimeah,rtimeih
|
.IF
UseSiminor
|
tm
RadioC, #10000000b
; If this is a Siminor code,
|
jr
nz, SimRadio
; then handle it appropriately
|
.ENDIF
|
tm
rtimeah,#10000000b
; find out if neg
|
jr
nz,NEGDIFF2
; use 1 for ABC or D
|
jr
POSDIFF2
|
POSDIFF2:
|
cp
rtimeah, BitThresh
; test for 3/2
|
jr
ult,BITIS2
; mark as a 2
|
jr
BITIS3
|
NEGDIFF2:
|
com
rtimeah
; invert
|
cp
rtimeah, BitThresh
; test for 2/1
|
jr
ult,BIT2COMP
; mark as a 2
|
jr
BITIS1
|
BITIS3:
|
ld
RADIOBIT,#2h
; set the value
|
jr
GOTRADBIT
|
BIT2COMP:
|
com
rtimeah
; invert
|
BITIS2:
|
ld
RADIOBIT,#1h
; set the value
|
jr
GOTRADBIT
|
BITIS1:
|
com
rtimeah
; invert
|
ld
RADIOBIT, #0h
; set the value
|
GOTRADBIT:
|
clr
rtimeah
; clear the time
|
clr
rtimeal
|
clr
rtimeih
|
clr
rtimeil
|
ei
; enable interrupts --REDUNDANT
|
ADDRADBIT:
|
SetRpToRadio2Group
;Macro for assembler error
|
srp
#Radio2Group
; -- this is what it does
|
tr
rflag,#01000000b
; test for radio 1 / 3
|
jr
nz,ROLING
;
|
RC3INC:
|
tm
RadioMode, #ROLL_MASK
;If in fixed mode,
|
jr
z, Radio3F
; no number counter exists
|
tm
RadioC,#00000001b
; test for even odd number
|
jr
nz,COUNT3INC
; if EVEN number counter
|
Radio3INC:
; else radio
|
call
GETTRUEFIX
;Get the true fixed bit
|
cp
RadioC,#14
; test the radio coutner for the specials
|
jr
uge,SPECIAL_BITS
; save the special bits seperate
|
Radio3R:
|
Radio3F:
|
srp
#RadioGroup
|
di
; Disable interrupts to avoid pointer collision
|
ld
pointerh,#Radio3H
; get the pointer
|
ld
pointerl,#Radio3L
;
|
jr
AddAll
|
SPECIAL_BITS:
|
cp
RadioC,#20
; test for the switch id
|
jr
z,SWITCHID
; if so then branch
|
ld
RTempH,id_b
; save the special bit
|
add
id_b,RTempH
; *3
|
add
id_b,RTempH
; *3
|
add
id_b,radiobit
; add in the new value
|
jr
Radio3R
|
SWITCHID:
|
cp
id_b,#18
; If this was a touch code,
|
jr
uge, Radio3R
; then we already have the ID bit
|
ld
sw_b,radiobit
; save the switch ID
|
jr
Radio3R
|
RC1INC:
|
tm
RadioMode, #ROLL_MASK
;If in fixed mode, no number counter
|
jr
z, Radio1F
|
tm
RadioC,#00000001b
; test for even odd number
|
jr
nz,COUNT1INC
; if odd number counter
|
Radio1INC:
; else radio
|
call
GETRUEFIX
;Get the real fixed code
|
cp
RadioC, #02
;If this is bit 1 of the 1ms code,
|
jr
nz, Radio1F
;then see if we need the switch ID bit
|
tm
rflag, #00010000b
;If this is the first word received,
|
jr
z, SwitchBit1
;then save the switch bit regardless
|
cp
id_b, #16
;If we have a touch code,
|
jr
ult, Radio1F
;then this is our switch ID bit
|
SwitchBit1:
|
ld
sw_b, radiobit
;Save touch code ID bit
|
Radio1F:
|
srp
#RadioGroup
|
di
; Disable interrupts to avoid pinter collision
|
ld
pinterh,#Radio1H
; get the pointer
|
ld
pointer1,#Radio1L
;
|
jr
AddAll
|
GETTRUEFIX:
|
; Chamberlain proprietary fixed code
|
; bit decryption algorithm goes here
|
ret
|
COUNT3INC:
|
ld
rollbit, radiobit
;Store the rolling bit
|
srp
#RadioGroup
|
di
; Disable interrupts to avoid pinter collision
|
ld
pointerh,#COUNT3H
; get the pointer
|
ld
pointer1,#COUNT3L
;
|
jr
AddAll
|
COUNT1INC:
|
ld
rollbit, radiobit
;Store the rolling bit
|
srp
#RadioGroup
|
di
; Disable interrupts to avoid pointer collision
|
ld
pointerh,#COUNT1H
; get the pointers
|
ld
pointer1,#COUNT1L
;
|
jr
AddAll
|
AddAll:
|
ld
addvalueh,@pointerh
; get the value
|
ld
addvaluel,@pointerl
;
|
add
addvaluel,@pointerl
; addx2
|
adc
addvalueh,@pointerh
;
|
add
addvaluel,@pointerl
; add x3
|
adc
addvalueh,@pointerh,
;
|
add
addvalue1,RADIOBIT
; add in new number
|
adc
addvalueh,#00h
;
|
ld
@pointerh,addvalueh
; save the value
|
ld
@pointerl,addvaluel
;
|
ei
; Re-enable interrupts
|
ALLADDED:
|
inc
radioc
; increase the counter
|
FULLWORD?:
|
cp
radioo, MaxBits
; test for full (10/20 bit) word
|
jp
nz,RRETURN
; if not then return
|
;;;;;Disable interrupts until word is handled
|
or
SKIPRADIO, #NOINT
; Set the flag to disable radio interrupts
|
.IF
TwoThirtyThree
|
nad
IMR,#11111110B
; turn off the radio interrupt
|
.ELSE
|
and
IMR,#11111100B
; Turn off the radio interrupt
|
.ENDIF
|
clr
RadioTimeOut
; Reset the blank time
|
cp
RADIOBIT, #00H
; If the last bit is zero,
|
jp
z, ISCCODE
; then the code is the obsolete C code
|
and
RFlag,#11111101B
; Last digit isn't zero, clear B code flag
|
ISCCODE:
|
tm
RFlag,#00010000B
; test flag for previous word receiverd
|
jr
nz,KNOWCODE
; If the second word received
|
FIRST20:
|
or
RFlag,#00010000B
; set the flag
|
clr
radioo
; clear the radio counter
|
jp
RRETURN
; return
|
.IF UseSiminor
|
KnowSimCode:
|
; Siminor proprietary rolling code decryption algorithm goes here
|
ld
radiolh, #0FFH
; Set the code to be incompatible with
|
clr
MirrorA
; the Chamberlain rolling code
|
clr
MirrorB
;
|
jp
CounterCorrected
;
|
.ENDIF
|
KNOWCODE:
|
tm
RadioMode, #ROLL_MASK
;If not in rolling mode,
|
jr
z, CounterCorrected
; forget the number counter
|
; Chamberlain proprietary counter decryption algorithm goes here
|
CounterCorrected:
|
srp
#RadioGroup
;
|
clr
RRTO
; clear the got a radio flag
|
tm
SKIPRADIO,#NOEECOMM
; test for the skip flag
|
jp
nz,CLEARRADIO
; if skip flag is active then donot look at EE mem
|
cp
ID_B, #18
;If the ID bits total more than 18,
|
jr
ult, NoTCode
;
|
or
RFlag, #00000100b
;then indicate a touch code
|
NoTCode:
|
ld
ADDRESS,#VACATIONADDR
; set the non vol address to the VAC flag
|
call
READMEMORY
; read the value
|
ld
VACFLAG,MTEMPH
; save into volital
|
cp
CodeFlag,#REGLEARN
; test for in learn mode
|
jp
nz,TESTCODE
; if out of learn mode then test for matching
|
STORECODE:
|
tm
RadioMode, #ROLL_MASK
;If we are in fixed mode,
|
jr
z, FixedOnly
;then don't compare the counters
|
CompareCounters:
|
cp
PCounterA, MirrorA
; Test for counter match to previous
|
jp
nz, STORENOTMATCH
; if no match, try again
|
cp
PCounterB, MirrorB
; Test for counter match to previous
|
jp
nz, STORENOTMATCH
; if no match, try again
|
cp
PCounterC, MirrorC
; Test for counter match to previous
|
jp
nz, STORENOTMATCH
; if no match, try again
|
cp
PCounterD, MirrorD
; Test for counter match to previous
|
jp
nz, STORENOTMATCH
; if no match, try again
|
FixedOnly:
|
cp
PRADIO1H,radiolh
; test for the match
|
jp
nz,STORENOTMATCH
; if not a match then loop again
|
cp
PRADIO1Lradioll
; test for the match
|
jp
nz,STORENOTMATCH
; if not a match then loop again
|
cp
PRADIO3H,radio3h
; test for the match
|
jp
nz,STORENOTMATCH
; if not a match then loop again
|
cp
PRADIO3L,radio3l
; test for the match
|
jp
nz,STORENOTMATCH
; if not a match then loop again
|
cp
AUXLEARNSW, #116
; If learn was not from wall control,
|
jr
ugt, CMDONLY
; then learn a command only
|
CmdNotOpen:
|
tm
CMD_DEB, #10000000b
; If the command switch is held,
|
jr
nz, CmdOrOOS
; then we are learning command or o/c/s
|
CheckLight:
|
tm
LIGHT_DEB, #10000000b
; If the light switch and the lock
|
jp
z, CLEARRADIO2
; switch are being held,
|
tm
VAC_DEB, #10000000b
; then learn a light trans.
|
jp
z, CLEARRADIO2
;
|
LearningLight:
|
tm
RadioMode, #ROLL_MASK
; Only learn a light trans. if we are in
|
jr
z, CMDONLY
; the rolling mode.
|
ld
CodeFlag, #LRNLIGHT
;
|
ld
BitMask, #01010101b
;
|
jr
CMDONLY
|
CmdOrOCS:
|
tm
LIGHT_DEB, #10100000b
; If the light switch isn't being held,
|
jr
nz, CMDONLY
; then see if we are learning o/c/s
|
CheckOCS:
|
tm
VAC_DEB, #10000000b
; If the vacation switch isn't held,
|
jp
z, CLEARRADIO222
; then it must be a normal command
|
tm
RadioMode, #ROLL_MASK
; Only learn an o/c/s if we are in
|
jr
z, CMDONLY
; the rolling mode.
|
tm
RadioC, #10000000b
; If the bit for siminor is et,
|
jr
nz, CMDONLY
; then don't learn as an o/c/s Tx
|
ld
CodeFlag, #LRNOCS
; Set flag to learn o/c/s
|
ld
BitMask, #10101010b
;
|
CMDONLY:
|
call
TESTCODES
; test the code to see if in memory now
|
cp
ADDRESS, #0FFh
; If the code isn't in memory
|
jr
z, STOREMATCH
;
|
WriteOverOCS:
|
dec
ADDRESS
;
|
jp
READYTOWRITE
;
|
STOREMATCH:
|
cp
RadioMode, #ROLL_TEST
; If we are not testing a new mode,
|
jr
ugt, SameRadioMode
; then don't switch
|
ld
ADDRESS, #MODEADDR
; Fetch the old radio mode,
|
call
READMEMORY
; change only the low order
|
tm
RadioMode, #ROLL_MASK
; byte, andd write in its new value.
|
jr
nz, SetAsRoll
;
|
SetAsFixed:
|
ld
RadioMode, #FIXED_MODE
;
|
call
FixedNums
; Set the fixed thresholds permanetly
|
jr
WriteMode
|
SetAsRoll:
|
ld
RadioMode, #ROLL_MODE
;
|
call
RollNums
; Set the rolling thresholds permanently
|
WriteMode:
|
ld
MTEMPL, RadioMode
;
|
call
WRITEMEMORY
;
|
SameRadioMode:
|
tm
RFlag, #00000010B
; If the flag for the C code is set,
|
jp
nz, CCODE
; then set the C Code address
|
tm
RFlag,#00100100B
; test for the b code
|
jr
nz,BCODE
; if a B code jump
|
ACODE:
|
ld
ADDRESS,#2BH
; set the address to read the last written
|
call
READMEMORY
; read the memory
|
inc
MTEMPH
; add 2 to the last written
|
inc
MTEMPH
;
|
tr
RadioMode, #ROLL_MASK
; If the radio is in fixed mode,
|
jr
z, FixedMem
; then handle the fixed mode memory
|
RollMem:
|
inc
MTEMPH
; Add another 2 to the last written
|
inc
MTEMPH
|
and
MTEMPH,#11111100B
; Set to a multiple of four
|
cp
MTEMPH,#1FH
; test for the last address
|
jr
ult, GOTAADDRESS
; If not the last address jump
|
jr
AddressZero
; Address is now zero
|
FixedMem:
|
and
MTEMPH,#11111110B
; set the address on a even number
|
cp
MTEMPH,#17H
; test for the last address
|
jr
ult,GOTAADDRESS
; if not the last address jump
|
AddressZero:
|
ld
MTEMPH,#00
; set the address to 0
|
GOTAADDRESS:
|
ld
ADDRESS,#2BH
; set the address to write the last written
|
ld
RTemp,MTEMPH
; save the address
|
LD
MTEMPL,MTEMPH
; both bytes same
|
call
WRITEMEMORY
; write it
|
ld
ADDRESS,rtemp
; set the address
|
jr
READYTOWRITE
;
|
CCODE:
|
tm
RadioMode, #ROLL_MASK
; If in rolling code mode,
|
jp
nz, CLEARRADIO
; then HOW DID WE GET A C CODE?
|
ld
ADDRESS, #01AH
; Set the C code address
|
jr
READYTOWRITE
; Store the C code
|
BCODE:
|
tm
RadioMode, #ROLL_MASK
; If in fixed mode,
|
jr
z, BFixed
; handle normal touch code
|
BRoll:
|
cp
SW_B, #ENTER
; If the user is trying to learn a key
|
jp
nz, CLEARRADIO
; other than enter, THROW IT OUT
|
ld
ADDRESS, #20H
; Set the address for the rolling touch code
|
jr
READYTOWRITE
|
BFixed:
|
cp
radio3h,#90H
; test for the 00 code
|
jr
nz,BCODEOK
;
|
cp
radio3l,#29H
; test for the 00 code
|
jr
nz,BCODEOK
;
|
jp
CLEARRADIO
; SKIP MAGIC NUMBER
|
BCODEOK:
|
ld
ADDRESS,#18H
; set the address for the B code
|
READYTOWRITE:
|
call
WRITECODE
; write the code in radio1 and radio3
|
NOFIXSTORE:
|
tm
RadioMode, #ROLL_MASK
; If we are in fixed mode,
|
jr
z, NOWRITESTORE
; then we are done
|
inc
ADDRESS
; point to the counter address
|
ld
Radio1H, MirrorA
; Store the counter into the radio
|
ld
Radio1L, MirrorB
; for the writecode
routine
|
ld
Radio3H, MirrorC
;
|
ld
Radio3L, MirroD
;
|
call
WRITECODE
|
call
SetMask
|
com
BitMask
|
ld
ADDRESS, #RTYPEADDR
; Fetch the radio types
|
call
READMEMORY
|
tm
RFlag, #10000000b
; Find the proper byte of the type
|
jr
nz, UpByte
|
LowByte:
|
and
MTEMPL, BitMask
; Wipe out the proper bits
|
jr
MaskDone
;
|
UpByte:
|
and
MTEMPH, BitMask
;
|
MaskDone:
|
com
BitMask
;
|
cp
CodeFlag, #LRNLIGHT
; If we are learing a light
jr
z, LearnLight
; set eh appropriate bits
|
cp
CodeFlag, #LRNOCS
; If we are learning an o/c/s,
|
jr
z, LearnOCS
; set the appropriate bits
|
Normal:
|
clr
BitMask
; Set the proper bits as command
|
jr
BMReady
|
LearnLight:
|
and
BitMask, #01010101b
; Set the proper bits as worklight
|
jr
BMReady
; Bit mask is ready
|
LearnOCS:
|
cp
SW_B, #02H
; If ‘open’ switch is not being held,
|
jp
nz, CLEARRADIO2
; then don't accept the transmitter
|
and
BitMask,#10101010b
; Set the proper bits as open/close/stop
|
BMReady:
|
tm
RFlag, #10000000b
; Find the proper byte of the type
|
jr
nz, UpByt2
;
|
LowByt2:
|
or
MTEMPL, BitMask
; Write the transmitter type in
|
jr
MaskDon2
;
|
UpByt2:
|
or
MTEMPH, BitMask
; Write the transmitter type in
|
MaskDon2:
|
call
WRITEMEMORY
; Store the transmitter types
|
NOWRITESTORE:
|
xor
p0,#WORKLIGHT
; toggle light
|
or
leadport,#ledh
; turn off the LED for program mode
|
ld
LIGHT1S,#244
; turn on the 1 second blink
|
ld
LEARNT,#0FFH
; set learnmode timer
|
clr
RTO
; disallow cmd from learn
|
clr
CodeFlag
; Clear any learning flags
|
jp
CLEARRADIO
|
STORENOTMATCH:
|
ld
PRADIO1H,radio1h
; transfer radio into past
|
ld
PRADIO1L,radio1l
;
|
ld
PRADIO3H,radio3h
;
|
ld
PRADIO3L,radio3l
;
|
tm
RadioMode, #ROLL_MASK
; If we are in fixed mode,
|
jp
z, CLEARRADIO
; get the next code
|
ld
PCounterA, MirrorA
; transfer counter into past
|
ld
PCounterB, MirrorB
;
|
ld
PCounterC, MirrorC
;
|
ld
PCounterD, MirrorD
;
|
jp
CLEARRADIO
|
TESTCODE:
|
cp
ID_B, #18
; If this was a touch code,
|
jp
uge, TCReceived
; handle appropriately
|
tm
RFlag, #00000100b
; If we have received a B code,
|
jr
z, AorDCode
; then check for the learn mode
|
cp
ZZWIN, #64
; Test 0000 learn window
|
jr
ugt, AorDCode
; if out of window no learn
|
cp
Radio1H, #90H
;
|
jr
nz, AorDCode
;
|
cp
Radio1L, #29H
;
|
jr
nz, AorDCode
;
|
ZZLearn:
|
push
RP
|
srp
#LEARNEE_GRP
|
call
SETLEARN
|
pop
RP
|
jp
CLEARRADIO
|
AorDCode:
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
uge, FS1
; If so, don't blink the LED
|
cp
FAULTFLAG,#0FFH
; test for a active fault
|
jr
z,FS1
; if a avtive fault skip led set and reset
|
and
ledport,#ledl
; turn on the LED for flashing from signal
|
FS1:
|
call
TESTCODES
; test the codes
|
cp
+T+L,15 L_A_C, #070H
; Test for in learn limits mode
|
jr
uge, FS2
; If so, don't blink the LED
|
cp
FAULTFLAG,#0FFH
; test for a active fault
|
jr
z,FS2
; if a avtive fault skip led set and reset
|
cr
ledport,#ledh
; turn off the LED for flashing from signal
|
FS2:
|
cp
ADDRESS,#0FFH
; test for the not matching state
|
jr
nz,GOTMATCH
; if matching the send a command if needed
|
jp
CLEARRADIO
; clear the radio
|
SimRollCheck:
|
inc
ADDRESS
; Point to the rolling code
|
; (note: High word always zero)
|
inc
ADDRESS
; Point to rest of the counter
|
call
READMEMORY
; Fetch lower word of counter
|
ld
CounterC, MTEMPH
;
|
ld
CounterD, MTEMPL
;
|
cp
CodeT2, CounterC
; If the two counters are equal,
|
jr
nz, UpdateSCode
; then don't activate
|
cp
CodeT3, Counter D
;
|
jr
nz, UpdateSCode
;
|
jp
CLEARRADIO
; Counters equal -- throw it out
|
UpdateSCode:
|
ld
MTEMPH, CodeT2
; Always update the counter if the
|
ld
MTEMPL, CodeT3
; fixed portions match
|
call
WRITEMEMORY
|
sub
CodeT3, CounterD
; Compare the two codes
|
sbc
CodeT2, CounterC
;
|
tm
CodeT2, #10000000b
; If the result is negative,
|
jp
nz, CLEARRADIO
; then don't activate
|
jp
MatchGoodSim
; Match good -- handle normally
|
GOTMATCH:
|
tm
RadioMode, #ROLL_MASK
; If we are in fixed mode,
|
jr
z, MatchGood2
; then the match is already valid
|
tm
RadioC, #10000000b
; If this was a Siminor transmitter,
|
jr
nz, SimRollCheck
; then test the roll in its own way
|
tm
BitMask, #10101010b
; If this was NOT an open/close/stop trans,
|
jr
z, RollCheckB
; then we must check the rolling value
|
cp
SW_B, #02
; If the o/c/s had a key other than ‘2’
|
jr
nz, MatchGoodOCS
; then don't check / update the roll
|
RollCheckB:
|
call
TestCounter
; Rolling mode -- compare the counter values
|
cp
CMP, #EQUAL
; If the code is equal,
|
jp
z, NOTNEWMATCH
; then just keep it
|
cp
CMP, #FWDWIN
; If we are not in forward window,
|
jp
nz, CheckPast
; then forget the code
|
MatchGood:
|
ld
Radio1H, MirrorA
; Store the coutner into memory
|
ld
Radio1L, MirrorB
; to keep the roll current
|
ld
Radio3H, MirrorC
;
|
ld
Radio3L, MirrorD
;
|
dec
ADDRESS
; Line up the address for writing
|
call
WRITECODE
|
MatchGoodOCS:
|
MatchGoodSim:
|
or
RFlag,#00000001B
; set the flag for recieving without error
|
cp
RTO,#RDPOPTIME
; test for the timer time out
|
jp
ult,NOTNEWMATCH
; if the timer is active then donor reissure cma
|
cp
ADDRESS, #23H
; If the code was the rolling touch code,
|
jr
z, MatchGood2
; then we already know the transmitter type
|
call
SetMask
; Set the mask bits properly
|
ld
ADDRESS, #RTYPEADDR
; Fetch the transmitter config. bits
|
call
READMEMORY
;
|
tm
RFlag, #10000000b
; If we are in the upper word,
|
jr
nz, Upper D
; check the upper transmitters
|
LowerD:
|
and
BitMask, MTEMPL
; Isolate out transmitter
|
jr
TransType
; Check out transmitter type
|
UpperD:
|
and
BitMask, MTEMPH
; Isolate our transmitter
|
TransType:
|
tm
BitMask, #01010101b
; Test for light transmitter
|
jr
nz, LightTrans
; Execute light transmitter
|
tm
BitMask, #10101010b
; Test for Open/Close/Stop Transmitter
|
jr
nz, OCSTrans
; Execute open/close/stop transmitter
|
; Otherwise, standard command transmitter
|
MatchGood2:
|
or
RFlag, #00000001B
; set the flag for recieving without error
|
cp
RTO,#RDROPTIME
; test fro the timer time out
|
jp
ult, NOTNEWMATCH
; if the timer is active then donot reissure cmd
|
TESTVAC:
|
cp
VACFLAG,#00B
; test for the vacation mode
|
jp
z,TSTSDISABLE
; if not in vacation mode test the system disable
|
tm
RadioMode, #ROLL_MASK
;
|
jr
z, FixedB
|
cp
ADDRESS,#23H
; If this was a touch code,
|
jp
nz, NOTNEWMATCH
; then do a command
|
jp
TSTSDISABLE
;
|
FixedB:
|
cp
ADDRESS,#19H
; test for the B code
|
jp
nz,NOTNEWMATCH
; if not a B not a match
|
TSTSDISABLE:
|
cp
SDISABLE,#32
; test for 4 second
|
jp
ult,NOTNEWMATCH
; if 6 s ot up not a new code
|
clr
RTO
; clear the radio timeout
|
cp
ONEP2,#10
; test for the 1.2 second time out
|
jp
nz,NOTNEWMATCH
; if the timer is active then skip the command
|
RADIOCOMMAND:
|
clr
RTO
; clear the radio timeout
tm
RFlag,#00000100b
; test for a B code
|
jr
z,BDONTSET
; if not a b code donot set flag
|
zzwinclr:
|
clr
ZZWIN
; flag got matching B code
|
ld
CodeFlag,#BRECEIVED
; flag for aobs bypass
|
BDONTSET:
|
cp
L_A_C, #070H
; If we were positioning the up limit,
|
jr
ult, NormalRadio
; then start the learn cycle
|
jr
z, FirstLearn
;
|
cp
L_A_C, #071H
; If we had an error,
|
jp
nz, CLEARRADIO
; re-learn, otherwise ignore
|
ReLearning:
|
ld
L_A_C, #072H
; Set the re-learn state
|
call
SET_UP_DIR_STATE
;
|
jp
CLEARRADIO
;
|
FirstLearn:
|
ld
L_A_C, #073H
; Set the learn state
|
call
SET_UP_POS_STATE
; Start from the “up limit”
|
jp
CLEARRADIO
;
|
NormalRadio:
|
clr
LAST_CMD
; mark the last command as radio
|
ld
RADIO_CMD,#0AAH
; set the radio command
|
jp
CLEARRADIO
; return
|
LightTrans:
|
clr
RTO
; Clear the radio timeout
|
cp
ONEP2,#00
; Test for the 1.2 sec. time out
|
jp
nz, NOTNEWMATCH
; If it isn't timed out, leave
|
ld
SW_DATA, #LIGHT_SW
; Set a light command
|
jp
CLEARRADIO
; return
|
OCSTrans:
|
cp
SDISABLE, #32
; Test for 4 second system disable
|
jp
ult, NOTNEWMATCH
; if not done not a new code
|
cp
VACFLAG, #00H
; If we are in vacation mode,
|
jp
nz, NOTNEWMATCH
; don't obey the transmitter
|
clr
RTO
; Clear the radio timeout
|
cp
ONEP2, #00
; test for the 1.2 second timeout
|
jp
nz, NOTNEWMATCH
; If the timer is active the skip command
|
cp
SW_B, #02
; If the open button is pressed,
|
jr
nz, CloseOrSTop
; then process it
|
OpenButton:
|
cp
STATE, #STOP
; If we are stopped of
|
jr
z, OpenUp
; at the down limit, then
|
cp
STATE, #DN_POSITION
; begin to move up
|
jr
z, OpenUp
;
|
cp
STATE, #DN_DIRECTION
; If we are moving down,
|
jr
nz, OCSExit
; then autoreverse
|
ld
REASON, #010H
; Set the reason as radio
|
call
SET_ARVE_STATE
;
|
jr
OCSExit
;
|
OpenUp:
|
ld
REASON, #010H
; Set the reason as radio
|
call
SET_UP_DIR_STATE
;
|
OCSExit:
|
jp
CLEARRADIO
;
|
CloseOrSTop:
|
cp
SW_B, #01
; If the stop button is pressed,
|
jr
no, CloseButton
; then process it
|
StopButton:
|
cp
STATE, #UP_DIRECTION
; If we are moving or in
|
jr
z, StopIt
; the autoreverse state,
|
cp
STATE, #DN_DIRECTION
; then stop the door
|
jr
z, StopIt
;
|
cp
STATE, #AUTO_REV
;
|
jr
z, StopIt
|
jr
OCSExit
|
StopIt:
|
ld
REASON, #010H
; Set the reason as radio
|
call
SET_STOP_STATE
|
jr
OCSExit
|
CloseButton:
|
cp
STATE, #UP_POSITION
; If we are at the up limit
|
jr
z, CloseIt
; or stopped in travel,
|
cp
STATE, #STOP
; then send the door down
|
jr
z, CloseIt
;
|
jr
OCSExit
|
CloseIt:
|
ld
REASON, #010H
; Set the reason as radio
|
call
SET_DN_DIR_STATE
|
jr
OCSExit
|
SetMask:
|
and
RFlag, #01111111bv
; Reset the page 1 bit
|
tm
ADDRESS, #11110000b
; If our address is on page 1,
|
jr
z, InLowerByte
; then set the proper flag
|
or
RFlag, #10000000b
;
|
InLowerByte:
|
tm
ADDRESS, #00001000b
; Binary search to set the
|
jr
z, ZeroOrFour
; proper bits in the bit mask
|
EightOrTwelve:
|
ld
BitMask, #11110000b
|
jr
LSNybble
|
ZeroOrFour:
|
ld
BitMask, #00001111b
;
|
LSNybble:
|
tm
ADDRESS, #00000100b
|
jr
z, ZeroOrEight
|
FourOrTwelve:
|
and
BitMask, #11001100b
;
|
ret
|
ZeroOrEight:
|
and
BitMask, #00110011b
;
|
ret
|
TESTCODES:
|
ld
ADDRESS, #RTYPEADDR
; Get the radio types
|
call
READMEMORY
;
|
ld
RadioTypes, MTEMPL
;
|
ld
RTypes2, MTEMPH
;
|
tm
RadioMode, #ROLL_MASK
;
|
jr
nz, RollCheck
;
|
clr
RadioTypes
;
|
clr
RTypes2
|
RollCheck:
|
clr
ADDRESS
; start address is 0
|
NEXTCODE:
|
call
SetMask
; Get the approprite bit mask
|
and
+T+L,15 BitMask, RadioTypes
; Isolate the current transmitter types
|
HAVEMASK:
|
call
READMEMORY
; read the word at this address
|
cp
MTEMPH, radioln
; test for the match
|
jr
nz,NOMATCH
; if not matching then do next address
|
cp
MTEMPL,radioll
; test for the match
|
jr
nz,NOMATCH
; if not matching then do next address
|
inc
ADDRESS
; set the second half of the code
|
call
READMEMORY
; read the word at this address
|
tm
BitMask, #10101010b
; If this is an Open/Close/Stop trans.,
|
jr
nz/ CheckOCS1
; then do the different check
|
cp
CodeFlag, #LRNOCS
; If we are in open/clsoe/stop learn mode,
|
jr
z, CheckOCS1
; then do the different check
|
cp
MTEMPH,radio3h
; test for the match
|
jr
nz,NOMATCH2
; if not matching then do the next address
|
cp
MTEMPL,radio3;
; test for the match
|
jr
nz,NOMATCH2
; if not matching then do the next address
|
ret
; return with the address of the match
|
CheckOCS1:
|
sub
MTEMPL, radio3l
; Subtract the radio from the memory
|
sbc
MTEMPH, radio3h
;
|
cp
CodeFlag, #LRNOCS
; If we are trying to learn open/close/stop,
|
jr
nz, Positive
; then we must complement to be postitive
|
com
MTEMPL
;
|
com
MTEMPH
;
|
add
MTEMPL, #1
; Switch from ones complement to 2's
|
adc
MTEMPH, #0
; complement
|
Positive:
|
cp
MTEMPH, #00
; We must be within 2 to match properly
|
jr
nz, NOMATCH2
;
|
cp
MTEMPL, #02
;
|
jr
ugt, NOMATCH2
;
|
ret
; Return with the address of the match
|
NOMATCH:
|
inc
ADDRESS
; set the address to the next code
|
NOMATCH2:
|
inc
ADDRESS
; set the address to the next code
|
tm
RadioMode, #ROLL_MASK
; If we are in fixed mode,
|
jr
z, AtNextAdd
; then we are at the next address
inc
ADDRESS
; Roll mode -- advance past the counter
|
inc
ADDRESS
; Roll mode -- advance past the counter
|
inc
ADDRESS
;
|
cp
ADDRESS, #10H
; If we are on the second page
|
jr
nz, AtNextAdd
; then get the other tx. types
|
ld
RadioTypes, RTypes2
;
|
AtNextAdd:
|
cp
ADDRESS,#22H
; test for the last address
|
jr
ult,NEXTCODE
; if not the last address then try again
|
GOTNOMATCH:
|
ld
ADDRESS,#0FFH
; set the no match flag
|
ret
; and return
|
NOTNEWMATCH:
|
clr
RTO
; reset the radio time out
|
and
RFlag,#00000001B
; clear radio flags leaving recieving w/o error
|
clr
radioc
; clear the radio bit counter
|
ld
LEARNT,#0FFH
; set the learn timer “turn off” and backup
|
jp
RADIO_EXIT
; return
|
CheckPast:
|
; Proprietary algorithm for maintaining
|
; rolling code counter
|
; Jumps to either MatchGood, UpdatePast or CLEARRADIO
|
UpdatePast:
|
ld
LastMatch, ADDRESS
; Store the last fixed code received
|
ld
PCounterA, MirrorA
; Store the last counter received
|
ld
PCounterB, MirrorB
;
|
ld
PCounterC, MirrorC
;
|
ld
PCounterD, MirrorD
;
|
CLEARRADIO2:
|
ld
LEARNT, #0FFH
; Turn off the learn mode timer
|
clr
CodeFlag
|
CLEARRADIO:
|
.IF
TwoThirtyThree
|
and
IRQ,#00111111B
; clear the bit setting directio to neg edge
|
.ENDIF
|
ld
PINFILTER,#0FFH
; set flag to active
|
CLEARRADIOA:
|
tm
RFlag,#00000001B
; test for receiving without error
|
jr
z,SKIPRTO
; if flag not se then donot clear timer
|
clr
RTO
; clear radio timer
|
SKIPRTO:
|
clr
radioc
; clear the radio counter
|
clr
RFlag
; clear the radio flag
|
clr
ID_B
; Clear the ID bits
|
jp
RADIO_EXIT
; return
|
TCReceived:
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
uge, TestTruncate
; If so, don't blink the LED
|
cp
FAULTFLAG, #0FFH
; If no fault
|
jr
z, TestTruncate
; turn on the led
|
and
ledport, #ledl
;
|
jr
TestTruncate
; Truncate off most significant digit
|
TruncTC:
|
sub
RadiolL, #0E3h
; Subtract out 3ˆ 9 to truncate
|
sbc
RadiolH, #04Ch
;
|
TestTruncate:
|
cp
RadiolH, #04Ch
; If we are greater than 3ˆ 9,
|
jr
ugt, TruncT0
; truncate down
|
jr
ult, GotT0
;
|
cp
Radio1L, #0E3h
;
|
jr
uge, TruncT0
;
|
GotTC:
|
ld
ADDRESS, #TOUCHID
; Check to make sure the ID code is good
|
call
READMEMORY
;
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
uge, CheckID
; If so, don't blink the LED
|
cp
FAULTFLAG, #0FFH
; If no fault,
|
jr
z, CheckID
; turn off the LED
|
or
ledport, #ledh
;
|
CheckID:
|
cp
MTEMPH, Radio3H
;
|
jr
nz, CLEARRADIO
;
|
cp
MTEMPL, Radio3L
;
|
jr
nz, CLEARRADIO
;
|
call
TestCounter
; Test the rolling code counter
|
cp
CMP, #EQUAL
; If the counter is equal,
|
jp
z, NOTNEWMATCH
; then call it the same code
|
cp
CMP, #FWDWIN
;
|
jr
nz, CLEARRADIO
;
|
; Counter good -- update it
|
ld
COUNT1H, Radiolh
; Back up radio code
|
ld
COUNT1L, RadiolL
;
|
ld
RadioH, MirrorA
;Write the counter
|
ld
RadioL, MirrorB
;
|
ld
Radio3H, MirrorC
;
|
ld
Radio3L, MirrorD
;
|
dec
ADDRESS
|
call
WRITECODE
|
ld
Radio1H, COUNT1H
; Restore the radio code
|
ld
Radio1L, COUNT1L
;
|
cp
CodeFlag, #NORMAL
; Find and jump to current mode
|
jr
z, NormT0
;
|
cp
CodeFlag, #LRNTEMP
;
|
jp
z, LearnTMP
;
|
cp
CodeFlag, #LPNDUPIN
;
|
jp
z, LearnDur
;
|
jp
CLEARRADIO
;
|
NormTC:
|
ld
ADDRESS, #TOUCHPERM
; Compare the four-digit touch
|
call
READMEMORY
; code to our permanent password
|
cp
Radio1H, MTEMPH
;
|
jr
nz, CheckTCTemp
;
|
cp
Radio1L, MTEMPL
;
|
jr
nz, CheckTCTemp
;
|
cp
SW_B, #ENTER
; If the ENTER key was pressed,
|
jp
z, RADIOCOMMAND
; issue a B code radio command
|
cp
SW_B, #POUND
; If the user pressed the pound key,
|
jr
z, TCLearn
; enter the learn mode
|
; Star key pressed -- start 30 s timer
|
clr
LEARNT
;
|
ld
FLASH COUNTER, #06h
; Blink the worklight three
|
ld
FLASH_DELAY, #FLASH_TIME
; times quickly
|
ld
FLASH_FLAG, #0FFH
;
|
ld
CodeFlag, #LRNTEMP
; Enter learn temporary mode
|
jp
CLEARRADIO
;
|
TCLearn:
|
ld
FLASH_COUNTER, #04h
; Blink the worklight two
|
ld
FLASH_DELAY, #FLASH TIME
; times quickly
|
ld
FLASH FLAG, #0FFH
;
|
push
RP
; Enter learn mode
|
srp
#LEARNEE_GRP
|
call
SETLEARN
|
pop
RP
|
jp
CLEARADIO
|
CheckTCTemp:
|
ld
ADDRESS, #TOUCHTEMP
; Compare the four-digit touch
|
call
READMEMORY
; code to our temporary password
|
cp
Radio1H, MTEMPH
;
|
jp
nz, CLEARRADIO
;
|
cp
Radio1L, MTEMPL
;
|
jp
nz, CLEARRADIO
;
|
cp
STATE, #DN_POSITION
; If we are not at the down limit,
|
jp
nz, RADIOCOMMAND
; issue a command regardless
|
ld
ADDRESS, #DUPAT
; If the duration is at zero,
|
call
READMEMORY
; then don't issue a command
|
cp
MTEMPL, #00
;
|
jp
z, CLEARRADIO
;
|
cp
MTEMPH, #ACTIVATIONS
; If we are in number of activations
|
jp
nz, RADIOCOMMAND
; mode, then decrement the
|
dec
MTEMPL
; number of activations left
|
call
WRITEMEMORY
;
|
jp
RADIOCOMMAND
|
LearnTMP:
|
cp
SW_B, #ENTER
; If the user pressed a key other
|
jp
nz, CLEARRADIO
; then enter, reject the code
|
ld
ADDRESS, #TOUCHPERM
; If the code entered matches the
|
call
READMEMORY
; permanent touch code,
|
cp
Radio1H, MTEMPH
; then reject the code as a
|
jp
nz, TempGood
; temporary code
|
cp
Radio1L, MTEMPL
;
|
jp
z, CLEARRADIO
;
|
TempGood:
|
ld
ADDRESS, #TOUCHTEMP
; Write the code into temp.
|
ld
MTEMPH, Radio1H
; code memory
|
ld
MTEMPL, Radio1L
;
|
call
WRITEMEMORY
;
|
ld
FLASH COUNTER, #08h
; Blink the worklight four
|
ld
FLASH_DELAY, #FLASH_TIME
; times quickly
|
ld
FLASH_FLAG, #0FFH
;
|
; Start 30 s timer
|
clr
LEARNT
|
ld
CodeFlag, #LRNDURTN
; Enter learn duration mode
|
jp
CLEARRADIO
;
|
LearnDur:
|
cp
Radio1H, #00
; If the duration was > 255,
|
jp
nz, CLEARRADIO
; reject the duration entered
|
cp
SW_B, #POUND
; If the user pressed the pound
|
jr
z, NumDuration
; key, number of activations mode
|
cp
SW_B, #STAR
; If the star key was pressed,
|
jr
z, HoursDur
; enter the timer mode
|
jp
CLEARRADIO
; Enter pressed -- reject code
|
NumDuration:
|
ld
MTEMPH, #ACTIVATIONS
; Flag number of activations mode
|
jr
DurationIn
;
|
HoursDur:
|
ld
MTEMPH, #HOURS
; Flag number of hours mode
|
DurationIn:
|
ld
MTEMPL, Radio1l
; Load on duration
|
ld
ADDRESS, #DURAT
; Write duration and mode
|
call
WRITEMEMORY
; into nonvolatile memory
|
; Give worklight one long blink
|
xcr
P0, #WORKLIGHT
; Give the light one blink
|
ld
LIGHTS, #244
; Lasting one second
|
clr
CodeFlag
; Clear the learn flag
|
jp
CLEARRADIO
|
Test Rolling Code Counter Subroutine
|
Note: CounterA-D will be used as temp registers
|
TestCounter:
|
push
RP
|
srp
#CounterGroup
|
inc
ADDRESS
Point to the rolling code counter
|
call
READMEMORY
; Fetch lower word of counter
|
ld
countera, MTEMPH
|
ld
counterb, MTEMPL
|
inc
ADDRESS
; Point to rest of the counter
|
call
READMEMORY
; Fetch upper word of counter
|
ld
countero, MTEMPH
|
ld
countera, MTEMPL
|
Subtract old counter (countera-d) from current
|
counter (mirrora-d) and store in countera-d
|
com
countera
; Obtain twos complement of counter
|
com
counterb
|
com
counterc
|
com
counterd
|
add
counterd, #01H
|
adc
counterc, #00H
|
adc
counterb, #00H
|
adc
countera, #00H
|
add
counterd, mirrord
; Subtract
|
adc
counterc, mirrorc
|
adc
counterb, mirrorb
|
adc
countera, mirrora
|
If the msb of counterd is negative, check to see
|
if we are inside the negative window
|
tm
counterd, #10000000B
|
jr
z, ChecckFwdWin
|
CheckBackWin:
|
cp
countera, #0FFH
; Check to see if we are
|
jr
nz, OutOfWindow
; less than −0400H
|
cp
counterb, #0FFH
; (i.e. are we greater than
|
jr
nz, OutOfWindow
; 0xFFFFFC00H
|
cp
counterd, #0FCH
;
|
jr
ult, OutOfWindow
;
|
InBacKWin:
|
ld
CMP, #BACKWN
; Return in back window
|
jr
CompDone
|
CheckFwdWin:
|
cp
countera, #00H
; Check to see if we are less
|
jr
nz, Out Of Window
; than 0O00 32″1 = 1024
|
cp
counterb, #00h
; activations
|
jr
nz, OutOf Window
;
|
cp
counterd, #0CH
;
|
jr
uge, OufOfWindow
|
cp
counterd, #00H
|
jr
nz, InFwdWin
|
cp
counterd, #00H
|
jr
nz, InFwdwin
|
CountersEqual:
|
ld
CMP, #EQUAL
;Return equal counters
|
jr
CompDone
|
InFwdWin:
|
ld
CMP, #FWDWN
;Return in forward window
|
jr
CompDone
|
OutOfWindow
|
ld
CMP, #OUTOFWIN
;Return out of any window
|
CompDone:
|
pop
RP
|
ret
|
Clear interrupt
|
ClearRadio:
|
cp
RadioMode, #ROLL_TEST
;If in fixed or rolling mode,
|
jr
ugt, MODEDONE
; then we cannot switch
|
tm
T125MS, #00000001b
; If our ‘coin toss’ was a zero,
|
jr
z, SETROLL
; set as the rolling mode
|
SETFIXED:
|
ld
RadioMode, #FIXED_TEST
|
call
FixedNums
|
jp
MODEDONE
|
SETROLL:
|
ld
RadioMode, ROLL_TEST
|
call
RollNums
|
MODEDONE:
|
clr
RadioTimeOut
; clear radio timer
|
clr
RadioC
; clear the radio counter
|
clr
RFlag
; clear the radio flags
|
RRETURN:
|
pop
RP
; reset the RP
|
iret
; return
|
FixedNums:
|
ld
BitThresn, #FIXTHH
|
ld
SyncThresh, #FIXSYNC
|
ld
MaxBits, #FIXBITS
|
ret
|
RollNums:
|
ld
BitThresh, #DTHP
|
ld
SyncThresh, #DSYNC
|
ld
MaxBits, #DBITS
|
ret
|
rotate mirror LoopCount * 2 then add
|
RotateMirrorAdd:
|
rcf
; clear the carry
|
rlc
mirrord
;
|
rlc
mirrorc
;
|
rlc
mirrorb
;
|
rlc
mirrora
;
|
djnz
loopcount,RotateMirrorAdd
; loop till done
|
Add mirror to counter
|
AddMirrorToCounter:
|
add
counterd,mirrord
;
|
adc
counterc,mirrorc
;
|
adc
counterb,mirrorb
;
|
adc
countera,mirrora
;
|
ret
|
LEARN DEBOUNCES THE LEARN SWITCH 80mS
|
TIMES OUT THE LEARN MODE 30 SECONDS
|
DEBOUNCES THE LEARN SWITCH FOR ERASE 6 SECONDS
|
LEARN:
|
srp
#LEARNEE_GRP
; set the register pointer
|
cp
STATE, *DN_POSITION
; test for motor stoped
|
jr
z,TESTLEARN
;
|
cp
STATE, #UP_POSITION
; test for motor stoped
|
jr
z,TESTLEARN
;
|
cp
STATE,#STOP
; test for motor stoped
|
jr
z,TESTLEARN
;
|
cp
L_A_C,#074H
; Test for traveling
|
jr
z,TESTLEARN
;
|
ld
learnt,#0FFH
; set the learn timer
|
cp
learnt,#240
; test for the learn 30 second timeout
|
jr
nz,ERASETEST
; if not then test erase
|
jr
learnoff
; if 30 seconds then turn off the learn mode
|
TESTLEARN:
|
cp
learndb,#236
; test for the debounced release
|
jr
nz,LEARNNOTRELEASED
; if debouncer not released then jump
|
LEARNRELEASED:
|
SmartRelease:
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
nz, NormLearnBreak
; If not, treat the break as normal
|
ld
REASON, #00H
; Set the reason as command
|
call
SET_STOP_STATE
;
|
NormLearnBreak:
|
clr
LEARNDB
; clear the debouncer
|
ret
; return
|
LEARNNOTRELEASED:
|
cp
CodeFlag,#LRNTEMP
;test for learn mode
|
jr
uge,INLEARN
; if in learn jump
|
cp
learndb,#20
; test for debounce period
|
jr
nz,ERASETEST
; if not then test the erase period
|
SETLEARN:
|
call
SmartSet
;
|
ERASETEST:
|
cp
LA_C, #070H
; Test for in learn limits mode
|
jr
uge,ERASERELEASE
; If so, DON'T ERASE THE MEMORY
|
cp
learndb,#0FFH
; test for learn button active
|
jr
nz,ERASERELEASE
; if button released set the erase timer
|
cp
eraset,#0FFH
; test for timer active
|
jr
nz,ERASETIMING
; if the timer active jump
|
clr
eraset
; clear the erase timer
|
ERASETIMING:
|
cp
eraset,#48
; test for the erase period
|
jr
z,ERASETIME
; if timed out the erase
|
ret
; else we return
|
ERASETIME:
|
or
ledport,#ledh
; turn off the led
|
ld
Skipradio,#NOEECOMM
; set the flag to skip the radio read
|
call
CLEARCODES
; clear all codes in memory
|
clr
skipradio
; reset the flag to skip radio
|
ld
learnt,#0FFH
; set the learn timer
|
clr
CodeFlag
|
ret
; return
|
SmartSet:
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
nz, NormLearnMake1
; If not, treat normally
|
ld
REASON, #00H
; Set the reason as command
|
call
SET_DN_NOBLINK
;
|
jr
LearnMakeDone
;
|
NormlearnMake1:
|
cp
L_A_C, #074H
; Test for traveling down
|
jr
nz, NormLearnMake2
; If not, treat normally
|
ld
L_A_C, #075H
; Reverse off false floor
|
ld
REASON, #00H
; Set the reason as command
|
call
SET_AREV_STATE
;
|
jr
LearnMakeDone
;
|
NormLearnMake2:
|
clr
LEARNT
; clear the learn timer
|
ld
CodeFlag, #REGLEARN
; Set the learn flag
|
and
ledport,#ledl
; turn on the led
|
clr
VACFLAG
; clear vacation mode
|
ld
ADDRESS,#VACATIONADDR
; set the non vol address for vacation
|
clr
MTEMPH
; clear the data for cleared vacation
|
clr
MTEMPL
;
|
ld
SKIPRADIO,#NOEECOMM
; set the flag
|
call
WRITEMEMORY
; write the memory
|
clr
SKIPRADIO
; clear the flag
|
LearnMakeDone:
|
ld
LEARNDB,#0FFH
; set the debouncer
|
ret
|
ERASERELEASE:
|
ld
eraset,#0FFH
; turn off the erase timer
|
cp
learndb,#236
; test for the debounced release
|
jr
z,LEARNRELEASE:
; if debouncer not released then jump
|
ret
; return
|
INLEARN:
|
cp
learndb,#20
; test for the debounce period
|
jr
nz,TESTLEARNTIMER
; if not then test the learn timer for.time 0ut
|
ld
learnd,#0FFH
; set the learn db
|
TESTLEARNTIMER:
|
cp
learnt,#240
; test for the learn 30 second timeout
|
jr
nz, ERASETEST
; if not then test erase
|
learnoff:
|
or
ledport,#ledh
; turn off the led
|
ld
learnt,#0FFh
; set the learn timer
|
ld
learndb,#0FFH
; set the learn debounce
|
clr
CodeFlag
; Clear ANY code types
|
jr
ERASETEST
; test the erase timer
|
WRITE WORD TO MEMORY
|
ADDRESS IS SET IN REG ADDRESS
|
DATA IS IN REG MTEMPH AND MTEMPL
|
RETURN ADDRESS IS UNCHANGED
|
WRITEMEMORY:
|
push
RP
; SAVE THE RP
|
srp
#LEARNEE_GRP
; set the register pointer
|
call
STARTB
; output the start bit
|
ld
serial,#11110000B
; set byte to enable write
|
call
SERIALOUT
; output the byte
|
and
csport,#osl
; reset the chip select
|
call
STARTB
; output the start bit
|
ld
serial,#01000000B
; set the byte for write
|
or
serial,address
; or in the address
|
call
SERIALOUT
; output the byte
|
ld
serial,mtemph
; set the first byte to write
|
call
SERIALOUT
; output the byte
|
ld
serial,mtempl
; set the second byte to write
|
call
SERIALOUT
; output the byte
|
call
ENDWRITE
; wait for the ready status
|
call
STARTB
; output the start bit
|
ld
serial,#00000000B
; set byte to disable write
|
call
SERIALOUT
; output the byte
|
and
csport,#csl
; reset the chip select
|
or
P2M_SHADOW,#clockh
; Change program switch back to read
|
ld
P2M,P2M_SHADOW
;
|
pop
RP
; reset the RP
|
ret
|
READ WORD FROM MEMORY
|
ADDRESS IS SET IN REG ADDRESS
|
DATA IS RETURNED IN REG MTEMPH AND MTEMPL
|
ADDRESS IS UNCHANGED
|
READMEMORY:
|
push
RP
;
|
srp
#LEARNEE_GRP
; set the register pointer
|
call
STARTB
; output the start bit
|
ld
serial,#1000000DB
; preamble for read
|
or
serial,address
; or in the address
|
call
SERIALOUT
; output the byte
|
call
SERIALIN
; read the first byte
|
ld
mtemph,serial
; save the value in mtemph
|
call
SERIALIN
; read the second byte
|
ld
mtempl,serial
; save the value in mtempl
|
and
csport,#csl
; reset the chip select
|
or
P2M_SHADOW,#clockh
; Change program switch back to read
|
ld
P2M, P2M_SHADOW
;
|
pop
RP
|
ret
|
WRITE CODE TO 2 MEMORY ADDRESS
|
CODE IS IN RADIO1H RADIO1L RADIO3H RADIO3L
|
WRITECODE:
|
push
RP
;
|
srp
#LEARNEE_GRP
; set the register pointer
|
ld
mtemph,Radio1H
; transfer the data from radio 1 to the temps
|
ld
mtemp1,Radio1L
;
|
call
WRITEMEMORY
; write the temp bits
|
inc
address
; next address
|
ld
mtemph,Radio3H
; transfer the data from radio 3 to the temps
|
ld
mtempl,Radio3L
;
|
call
WRITEMEMORY
; write the temps
|
pop
RP
;
|
ret
; return
|
CLEAR ALL RADIO CODES IN THE MEMORY
|
CLEARCODES:
|
push
RP
;
|
srp
#LEARNEE_GRP
; set the register pointer
|
ld
MTEMPH,#0FFH
; set the codes to illegal codes
|
ld
MTEMPL,#0FFH
;
|
ld
address,#00H
; clear address 0
|
CLEARC:
|
call
WRITEMEMORY
; “A0”
|
inc
address
; set the next address
|
cp
address,#(AddressCounter - 1)
; test for the last address of radio
|
jr
ult,CLEARC
|
clr
mtemph
; clear data
|
clr
mtempl
|
call
WRITEMEMORY
; Clear radio types
|
ld
address,#AddressAPointer
; clear address F
|
call
WRITEMEMORY
;
|
ld
address,#MODEADDR
;Set EEPROM memcry as fixed test
|
call
WRITEMEMORY
;
|
ld
RadioMode, #FIXED TEST
;Revert to fixed mode testing
|
ld
BitThresh, #FIXTHR
|
ld
SyncThresh, #FIXSYNC
|
ld
MaxBits, #FIXBITS
|
CodesCleared:
|
pop
RP
;
|
ret
; return
|
START BIT FOR SERIAL NONVOL
|
ALSO SETS DATA DIRECTION AND AND CS
|
STARTB:
|
and
P2M_SHADOW, #(clockl & dol)
; Set output mode for clock line and
|
ld
P2M,P2M_SHADOW
; I/O lines
|
and
csport,#csl
;
|
and
clkport,#clockl
; start by clearing the bits
|
and
dioport,#dol
;
|
or
csport,#csn
; set the chip select
|
or
dioport,#doh
; set the data out high
|
cr
clkport,#clockh
; set the clock
|
and
clkport,#clockl
; reset the clock low
|
and
dioport,#dol
; set the data low
|
ret
; return
|
END OF CODE WRITE
|
ENDWRITE:
|
and
csport,#csl
; reset the chip select
|
nop
; delay
|
cr
csport,#csn
; set the chip select
|
P2M_SHADOW, #con
; Set the data line to input
|
ld
P2M,P2M_SHADOW
; set port 2 mode forcing input mode data
|
ENDWRITELOOP:
|
ld
temph,dioport
; read the port
|
and
temph,#aoh
; mask
|
jr
z,ENDWRITELOOP
; if the bit is low then loop until done
|
and
csport,#csl
; reset the chip select
|
or
P2M_SHADOW, #clockh
; Reset the clock line to read smart button
|
and
P2M_SHADOW, #dol
; Set the data line back to output
|
ld
P2M,P2M_SHADOW
; set port 2 mode forcing output mode
|
ret
|
SERIAL OUT
|
OUTPUT THE BYTE IN SERIAL
|
SERIALOUT:
|
and
P2M_SHADOW,#(dol & clockl)
; Set the clock and data lines to outputs
|
ld
P2M,P2M_SHADOW
; set port 2 mode forcing output mode data
|
ld
templ,#8H
; set the count for eight bits
|
SERIALOUTLOOP:
|
rcl
serial
; get the bit to output into the carry
|
jr
nc,ZEROOUT
; output a zero if no carry
|
ONEOUT:
|
or
dioport,#doh
; set the data out high
|
or
clkport,#clockh
; set the clock high
|
and
clkport,#clockl
; reset the clock low
|
and
dioport,#dol
; reset the data out low
|
djnz
texnpl,SERIALOUTLOOP
|
; loop till done
|
ret
; return
|
ZEROOUT:
|
and
dioport,#dol
; reset the data out low
|
or
clkport,#clockh
; set the clock high
|
and
clkport,#clockl
; reset the clock low
|
and
dioport,#dol
; reset the data out low
|
djnz
templ,SERIALOUTLOOP
|
; loop till done
|
ret
; return
|
SERIAL IN
|
INPUTS A BYTE TO SERIAL
|
SERIALIN:
|
or
P2M_SHADOW, #doh
; Force the data line to input
|
ld
P2M,P2M_SHADOW
; set port 2 mode forcing input mode data
|
ld
templ,#8H
; set the count for eight bits
|
SERIALINLOOP:
|
or
clkport,#clockh
; set the clock high
|
rcf
; reset the carry flag
|
ld
temph,dioport
; read the port
|
and
temph,#doh
; mask out the bits
|
jr
z,DONTSET
|
scf
; set the carry flag
|
DONTSET:
|
rlc
serial
; get the bit into the byte
|
and
clkport,#clockl
; reset the clock low
|
djnz
temp1,SERIALINLOOP
|
; loop till done
|
ret
; return
|
TIMER UPDATE FROM INTERUPT EVERY 0.256mS
**
|
SkipPulse:
|
tm
SKIPRADIO, #NOINT
;If the ‘no radio interrupt’
|
jr
nz, NoPulse
;flag is set, just leave
|
or
IMR,#RadioImr
; turn on the radio
|
NoPulse:
|
iret
|
TIMERUD:
|
tm
SKIPRADIO, #NOINT
;If the ‘no radio interrupt’
|
jr
nz, NoEnable
;flag is set, just leave
|
or
IMR,#RadioImr
; turn on the radio
|
NoEnable:
|
decw
TOEXITWORD
; decrement the T0 extension
|
T0ExtDone:
|
tm
P2, #LINEINPIN
; Test the AC line in
|
jr
z, LowAC
; If it's low, mark zero crossing
|
HighAC:
|
inc
LineCtr
; Count the high time
|
jr
LineDone
;
|
LowAC:
|
cp
LineCtr, #08
; If the line was low before
|
jr
ult, HighAC
; then one-shot the edge of the line
|
ld
LinePer, LineCtr
; Store the high time
|
clr
LineCtr
; Reset the counter
|
ld
PhaseTMR, PhaseTime
; Reset the timer for the phase control
|
LineDone:
|
cp
PowerLevel, #20
; Test for at full wave of phase
|
jr
uge, PhaseOn
; If not, turn off at the start of the phase
|
cp
PowerLevel, #00
; If we're at the minimum,
|
jr
z, PhaseOff
; then never turn the phase control on
|
dec
PhaseTMR
; Update the timer for phase control
|
jr
mi, PhaseOn
; If we are past the zero point, turn on the line
|
PhaseOff:
|
and
PhasePrt, #˜PhaseHigh
; Turn off the phase control
|
jr
PhaseDone
|
PhaseOn:
|
cr
PhasePrt, #PhaseHigh
; Turn on the phase control
|
PhaseDone:
|
tm
P3, #0000010b
; Test the RPM in pin
|
jr
nz, IncRPMDB
; If we're high, increment the filter
|
DecRPMDB:
|
cp
RPM_FILTER, #00
; Decrement the value of the filter if
|
jr
z, RPMFiltered
; we're not already at zero
|
dec
RPM_FILTER
;
|
jr
RPMFiltered
;
|
IncRPMDB:
|
inc
RPM_FILTER
; Increment the value of the filter
|
jr
nz, RPMFiltered
; and back turn if necessary
|
dec
RPM_FILTER
;
|
RPMFiltered:
|
cp
RPM_FILTER, #12
; If we've seen 2.5 ms of high time
|
jr
z, VectorRPMHigh
; then vector high
|
cp
RPM_FILTER, #255 - 12
; If we've seen 2.5 ms of low time
|
jr
nz, TaskSwitcher
; then vector low
|
VectorRPMLow:
|
clr
RPM_FILTER
;
|
jr
TaskSwitcher
;
|
VectorRPMHigh:
|
ld
RPM_FILTER, #0FFH
;
|
TaskSwitcher
|
tm
T0EXT, #00000001b
; skip everyother pulse
|
jr
nz,SkipPulse
|
tm
T0EXT,#00000010b
; Test for odd numbered task
|
jr
nz,TASK1357
; If so do the 1ms timer undate
|
tm
T0EXT,#00000100b
; Test for task 2 or 6
|
jr
z, TASK04
; If not, then go to Tasks 0 and 4
|
tm
T0EXT,#00001000b
; Test for task 6
|
jr
nz, TASK6
; If so, jump
|
; Otherwise, we must be in task 2
|
TASK2:
|
or
IMP,#RETURN_IMR
; turn on the interrupt
|
ei
|
call
STATEMACHINE
; do the motor function
|
iret
|
TASK04:
|
or
IMR,#RETURN_IMR
; turn on the interrupt
|
ei
|
push
rp
; save the rp
|
srp
#TIMER_GROUP
; set the rp for the switches
|
call
switches
; test the switches
|
pop
rp
|
iret
|
TASK6:
|
or
IMR,#RETURN_IMR
; turn on the interrupt
|
ei
|
call
TIMER4MS
; do the four ms timer
|
iret
|
TASK1357:
|
push
RP
|
or
IMR,#RETURN_IMR
; turn on the interrupt
|
ei
|
ONEMS:
|
tm
p0,#DOWN_COMP
; Test down force pot.
|
jr
nz,HigherDn
Average too low -- output pulse
|
LowerDn:
|
and
p3,#(˜DOWN_OUT)
; take pulse output low
|
jr
DnPotDone
|
HigherDn:
|
or
p3,#DOWN_OUT
; Output a high pulse
|
inc
DN_TEMP
; Increase measured duty cycle
|
DnPotDone:
|
tm
p0,#UP_COMP
; Test the up force pot.
|
jr
nz,HigherUp
; Average too low -- output pulse
|
LowerUp:
|
and
P3,#(˜UP_OUT)
; Take pulse output low
|
jr
UpPotDone
;
|
HigherUp:
|
or
P3,#UP_OUT
; Output a high pulse
|
inc
UP_TEMP
; Increase measured duty cycle
|
UpPotDone:
|
inc
POT_COUNT
; Incremet the total period for
|
jr
nz, GoTimer
; duty cycle measurement
|
rcf
; Divide the pot values by two to obtain
|
rrc
UP_TEMP
; a 64-level force range
|
rcf
;
|
rrc
DN_TEMP
;
|
cr
; Subtract from 63 to reverse the direction
|
ld
UPFORCE, #63
; Calculate pot. values every 255
|
sub
UPFORCE, UP_TEMP
; counts
|
ld
DNFORCE, #63
;
|
sub
DNFORCE, DN_TEMP
;
|
ei
;
|
clr
UP_TEMP
; counts
|
clr
DN_TEMP
;
|
GoTimer:
|
srp
#LEARNEE_GRP
; set the register pointer
|
dec
AOBSTEST
; decrease the aobs test timer
|
jr
nz,NOFAIL
; if the timer not at 0 then it didnot fail
|
ld
AOBSTEST,#11
; if it failed reset the timer
|
tm
AOBSF,#00100000b
; If the aobs was blocked before,
|
jr
nz, BlockedBeam
; don't turn on the light
|
or
AOBSF,#100000001b
; Set the break edge flag
|
BlockedBeam:
|
or
AOBSF,#00000000b
; Set the single break flag
|
NOFAIL:
|
inc
RadioTimeOut
|
cp
OBS_COUNT, #00
; Test for protector timed out
|
jr
z, TEST125
; If it has failed, then don't decrement
|
dec
OBS_COUNT
; Decrement the timer
|
PPointDeb:
|
di
; Disable ints while debouncer being modified (16us)
|
tm
PPointPort, #PassPoint
; Test for pass point being seen
|
jr
nz, IncPPDeb
; If high, increment the debouncer
|
DecPPDeb:
|
and
PPOINT_DEB,#00000011b
; Debounce 3-0
|
jr
z, PPDebDone
; If already zero, don't decrement
|
dec
PPOINT_DEB
; Decrement the debouncer
|
jr
PPDebDone
;
|
IncPPDeb:
|
inc
PPOINT_DEB
; Increment 0-3 debouncer
|
and
PPOINT_DEB, #00000011B
;
|
jr
nz, PPDebDone
; If rolled over,
|
ld
PPOINT_DEB, #00000011B
; keep it at the max.
|
PPDebDone:
|
ei
; Re-enable interrupts
|
TEST125:
|
inc
t125ms
; increment the 125 mS timer
|
cp
t125ms,#125
; test for the time out
|
jr
z,ONE25MS
; if true the jump
|
cp
t125ms,#63
; test for the other timeout
|
jr
nz,N125
|
call
FAULTS
|
N125:
|
pop
RP
|
iret
|
ONE25MS:
|
cp
RsMode, #00
; Test for not in RS232 mode
|
jr
z, CheckSpeed
; If not, don't update RS timer
|
dec
RsMode
; Count down RS232 time
|
jr
nz, CheckSpeed
; If not done yet, don't clear wall
|
ld
STATUS, #CHARGE
; Revert to charging wall control
|
CheckSpeed:
|
cp
RampFlag, #STILL
; Test for still motor
|
jr
z, StopMotor
; If so, turn off the FET's
|
tm
BLINK_HI, #10000000b
; If we are flashing the warning light,
|
jr
z, StopMotor
; then don't ramp up the motor
|
cp
L_A_C, #076H
; Special case -- use the ramp-down
|
jr
z, NormalRampFlag
; when we're going to the learned up limit
|
cp
L_A_C, #070H
; If we're learning limits,
|
jr
uge, RunReduced
; then run at a slow speed
|
NormalRampFlag:
|
cp
RampFlag, #RAMPDOWN
; Test for slowing down
|
jr
z, SlowDown
; If so, slow to minimum speed
|
SpeedUp:
|
cp
PowerLevel, MaxSpeed
; Test for at max. speed
|
jr
uge, SetAtFull
; If so, leave the duty cycle alone
|
RampSpeedUp:
|
inc
PowerLevel
; Increase the duty cycle of the phase
|
jr
SpeedDone
;
|
Slowdown:
|
cp
PowerLevel, MinSpeed
; Test for at min. speed
|
jr
ult, RampSpeedup
; If we're below the minimum, ramp up to it
|
jr
z, SpeedDone
; If we're at the minimum, stay there
|
dec
PowerLevel
; Increase the duty cycle of the phase
|
jr
SpeedDone
|
RunReduced:
|
ld
RampFlag, #FULLSPEED
; Flag that we're not ramping up
|
cp
MinSpeed, #8
; Test for high minimum speed
|
jr
ugt, PowerAtMin
;
|
ld
PowerLevel, #8
; Set the speed at 40%
|
jr
SpeedDone
|
PowerAtMin:
|
ld
PowerLevel, MinSpeed
; Set power at higher minimum
|
jr
SpeedDone
;
|
StopMotor:
|
clr
PowerLevel
; Make sure that the motor is stopped (FMEA
|
protection)
|
jr
SpeedDone
;
|
SetAtFull:
|
ld
RampFlag, #FULLSPEED
; Set flag for done with ramp-up
|
SpeedDone:
|
cp
LinePer, #36
; Test for 50Hz or 60Hz
|
jr
uge, FiftySpeed
; Load the proper table
|
SixtySpeed:
|
di
; Disable interrupts to avoid pointer collizion
|
srp
#RadioGroup
; Use the radio pointers to do a ROM fetch
|
lc
pointerh, ##HIGH SPEED_TABLE_60)
; Point to the force look-up table
|
ld
pointerl, #LOW(SPEED_TABLE_60)
;
|
add
pointerl, PowerLevel
; Offset for current phase step
|
adc
pointerh, #00H
;
|
ldc
addvalueh, @pointer
; Fetch the ROM data for phase control
|
ld
PhaseTime, addvalueh
; Transfer to the proper register
|
ei
; Re-enable interrupts
|
jr
WorkCheck
; Check the worklight toggle
|
FiftySpeed:
|
ai
; Disable interrupts to avoid pointer collision
|
src
#RadioGroup
; Use the radio pointers to do a ROM fetch
|
ld
pointerh, #HIGH (SPEED_TABLE_50)
; Point to the force look-up table
|
ld
pointerl, #LOW(SPEED_TABLE_50)
;
|
add
pointerl, PowerLevel
; Offset for current phase step
|
adc
pointerh, #00H
;
|
ldc
addvalueh, @pointer
; Fetch the ROM data for phase control
|
ld
PhaseTime, addvalueh
; Transfer to the proper register
|
ei
; Re-enable interrupts
|
WorkCheck:
|
srp
#LEARNEE_GRP
; Re-set the RP
|
;4-22-97
|
CP
EnableWorkLight,#01100000B
|
JR
EQ,DontInc
;Has the button already been held for 10s?
|
INC
EnableWorkLight
;Work light function is added to every
|
;125ms if button is light button is held
|
;for 10s will iniate change, if not held
|
;down will be cleared in switch routine
|
DontINC:
cp
AUXLEARNSW,#0FFh
; test for the rollover postion
|
jr
z,SKIPAUXLEARNSW
; if so then skip
|
inc
AUXLEARNSW
; increase
|
SKIPAUXLEARNSW:
|
cp
ZZWIN,#0FFH
; test for the roll position
|
jr
z,TESTFA
; if so skip
|
inc
ZZWIN
; if not increase the counter
|
TESTFA:
|
call
; call the fault blinker
|
clr
T125MS
; reset the timer
|
inc
DOG2
; incrwease the second watch dog
|
di
|
inc
SDISABLE
; count off the systen disable timer
|
jr
nz,D012
; if not rolled over then do the 1.2 sec
|
dec
SDISABLE
; else reset to FF
|
D012:
|
cp
ONEP2,#00
; test for 0
|
jr
z,INCLEARN
; if counted down then increment learn
|
dec
ONEP2
; else down count
|
INCLEARN:
|
inc
learnt
; increase the learn timer
|
cp
learnt,#0H
; test for overflow
|
jr
nn,LEARNTOK
; if not 0 skip back turning
|
dec
learnt
;
|
LEARNTOK:
|
ei
|
inc
eraset
; increase the erase timer
|
cp
eraset,#0H
; test for overflow
|
jr
nz,ERASETOK
; if not 0 skip back turning
|
dec
eraset
:
|
ERASETOK:
|
pop
RP
|
iret
|
fault blinker
|
FAULTB:
|
inc
FAULTTIME
; increase the fault timer
|
op
L_A_C, #070H
; Test for in learn limits mode
|
jr
ult, DoFaults
; If not, handle faults normally
|
cp
L_A_C, #071H
; Test for failed learn
|
jr
z, FastFlash
; If so, blink the LED fast
|
RegFlash:
|
tm
FAULTIME, #00000100b
; Toggle the LED every 250ms
|
jr
z, FlashOn
;
|
FlashOff:
|
or
ledport, #ledh
; Turn of f the LED for blink
|
jr
NOFAULT
; Don't test for faults
|
FlashOn:
|
and
ledport,#ledl
; Turn on the LED for blink
|
jr
NOFAULT
;
|
FastFlash:
|
tm
FAULTIME; #00000010b
; Toggle the LED every 125ms
|
jr
z, FlasnOn
;
|
jr
FlashOff
|
DoFaults:
|
cp
FAULTTIME, #80h
; test for the end
|
jr
nz,FIRSTFAULT
; if not timed out
|
clr
FAULTTIME
; reset the clock
|
clr
FAULT
; clear the last
|
cp
FAULTCODE,#05h
; test for call dealer code
|
jr
UGE,GOTFAULT
; set the fault
|
cp
CMD_DEB,#0FFH
; test the debouncer
|
jr
nz,TESTAOBSM
; if not set test aobs
|
cp
FAULTCODE,#03h
; test for command shorted
|
jr
z,GOTFAULT
; set the error
|
ld
FAUTCODE,#03h
; set the code
|
jr
FIRSTFAULT
;
|
TESTAOBSM:
|
tm
AOBSF,#00000001b
; test for the skiped aobs pulse
|
jr
z,NOAOBSFAULT
if no skips then no faults
|
tm
AOBSF,#00000000b
; test for any pulses
|
jr
z, NOPULSE
; if no pulses find if hi or low
|
; else we are intermittent
|
ld
FAULTCODE,#04h
; set the fault
|
jr
GOTFAULT
; if same got fault
|
cp
FAULTCODE,#04h
; test the last fault
|
jr
z,GOTFAULT
; if same got fault
|
ld
FAULTCODE,#04h
; set the fault
|
jr
FIRSTFC
;
|
NOPULSE:
tm
P3,#00000001b
; test the input pin
|
jr
z,AOBSSH
; jump if aobs is stuck hi
|
cp
FAULTCODE,#01h
; test for stuck low in the past
|
jr
z,GOTFAULT
; set the fault
|
ld
FAULTCODE,#01h
; set the fault code
|
jr
FIRSTFC
;
|
AOBSSH:
cp
FAULTCODE,#02h
; test for stuck high in past
|
jr
z,GOTFAULT
; set the fault
|
ld
FAULTCODE.#02h
; set the code
|
jr
FIRSTFC
;
|
GOTFAULT:
ld
FAULT,FAULTCODE
; set the cone
|
swap
FAULT
;
|
jr
FIRSTFC
;
|
NOAOBSFAULT:
|
clr
FAULTCODE
; clear the fault code
|
FIRSTFC:
and
AOBSF, #11111100b
; clear flags
|
FIRSTFAULT:
|
tm
FAULTTIME, #00000111b
; If one second has passed,
|
jr
nz, RegularFault
; increment the 60min
|
incw
HOUR_TIMER
; Increment the 1 hour timer
|
tcm
HOUR_TIMER_LO, #00011111b
; If 32 seconds have passed
|
jr
nz, RegularFault
; poll the radio mode
|
or
AOBSF, #01000000b
; Set the ‘poll radio’ flag
|
RegularFault:
|
cp
FAULT,#00
; test for no fault
|
jr
z,NOFAULT
|
ld
FAULTFLAG,#0FFH
; set the fault flag
|
cp
CodeFlag,#REGLEARN
; test for not in learn mode
|
jr
z,TESTSDI
; if in learn then skip setting
|
cp
FAULT, FAULTTIME
;
|
jr
ULE,TESTSDI
|
tm
FAULTTIME,#00001000b
; test the 1 sec bit
|
jr
nz,BITONE
|
and
ledport,#ledl
; turn on the led
|
ret
|
BITONE:
|
or
ledport,#ledh
; turn off the led
|
TESTSDI:
|
ret
|
NOFAULT: clr
FAULTFLAG
; clear the flag
|
ret
|
Four ms timer tick routines and aux light function
|
TIMER4MS:
|
cp
RPMONES,#00H
; test for the end of the one sec timer
|
jr
z,TESTPERIOD
; if one sec over then test the pulses
|
; over the period
|
aec
RPMONES
; else decrease the timer
|
di
|
clr
RPM_COUNT
; start with a count of 0
|
clr
BRPM_COUNT
; start with a count of 0
|
ei
|
jr
RPMTDONE
|
TESTPERIOD:
|
cp
RPMCLEAR,#00H
; test the clear test timer for 0
|
jr
nz,RPMTDONE
; if not timed out then skip
|
ld
RPMCLEAR,#122
; set the clear test time for next cycle .5
|
cp
RPM_COUNT,#50
; test the count for too many pulses
|
jr
ugt,FAREV
; if too man pulses then reverse
|
di
|
clr
RPM_COUNT
; clear the counter
|
clr
BRPM_COUNT
; clear the counter
|
ei
|
clr
FAREVFLAG
; clear the flag temp test
|
jr
RPMTDONE
; continue
|
FAREV:
|
ld
FAULTCODE,#06h
; set the fault flag
|
ld
FAREVFLAG,#088H
; set the forced up flag
|
and
p),#LOW ˜WORKLIGHT
; turn off light
|
ld
REASON,#80H
; rpm forcing up motion
|
call
SET_AREV_STATE
; set the autorev state
|
RPMTDONE:
|
dec
RPMCLEAR
; decrement the timer
|
cp
LIGHT1S,#00
; test for the end
|
jr
z,SKIPLIGHTE
|
dec
LIGHT1S
; down count the light time
|
SKIPLIGHTE:
|
inc
R_DEAD_TIME
|
cp
RTO,#RDROPTIME
; test for the radio time out
|
jr
ult,DONOTCB
; if not timed out donot clear b
|
cp
CodeFlag, #LRNOCS
; If we are in a special learn mode,
|
jr
uge,DONOTCB
; then don't clear the code flag
|
clr
CodeFlag
; else clear the b code flag
|
DONOTCB:
|
inc
+L,15 RTO
; increment the radio time out
|
jr
nz,RTOOK
; if the radio timeout Ok then skip
|
dec
RTO
; back turn
|
RTOOK:
|
cp
RRTO,#0FFH
; test for roll
|
jr
z,SKIPRRTO
; if so then skip
|
inc
RRTO
|
SKIPRRTO:
;
|
cp
SKIPRADIO, #00
; Test for EEPROM communication
|
jr
nz, LEARNDBOK
; If so, skip reading program switch
|
cp
RsMode, #00
; Test for in RS232 mode,
|
jr
nz, LEARNDBOK
; if so don't update the debouncer
|
tm
psport,#psmaks
; Test for program switch
|
jr
z,PRSWOLOSED
; if the switch is closed count up
|
cp
LEARNDB,#00
; test for the non decrement point
|
jr
z, LEARNDBOK
; if at end skip dec
|
dec
LEARNDB
;
|
jr
LEARNBOK
;
|
PHSWCLOSE:
|
cp
LEARNDB,#0FFH
; test for debouncer at max.
|
jr
z,LEARNDBOK
; if not at max increment
|
inc
LEARNDB
; increase the learn debounce timer
|
LEARNDBOK
|
AUX OBSTRUCTION OUTPUT AND LIGHT FUNCTION
|
AUXLIGHT:
|
test_light_on:
|
cp
LIGHT_FLAG,#LIGHT
;
|
jr
z,ado_light
;
|
cp
LIGHT1s,#00
; test for no flash
|
jr
z,NO1S
; if not skip
|
cp
LIGHTS,#1
; test for timeout
|
jr
nz,NO1S
; if not skip
|
xor
p0,#WORKLIGHT
; toggle light
|
clr
LIGHT1S
; onesnoted
|
NO1S:
|
cp
FLASH_FLAG,#FLASH
|
jr
nz,dec_light
;
|
clr
VACFLASH
; Keep the vacation flash timer off
|
dec
FLASH_DELAY
; 250 ms period
|
jr
nz,dec_light
;
|
cp
STATUS, #RSSTATUS
; Test for in RS232 mode
|
jr
z,BlinkDone
; If so, don't blink the LED
|
; Toggle the wall control LED
|
cp
STATUS, #WALLOFF
; See if the LED is off or on
|
jr
z, TurnItOn
;
|
TurnItOff:
|
ld
STATUS, #WALLOFF
; Turn the light off
|
jr
BlinkDone
;
|
TurnItOn:
|
ld
STATUS, #CHARGE
; Turn the light on
|
ld
SWITCH_DELAY, #CMD_DEL_EX
; Reset the delay time for charge
|
BlinkDone:
|
ld
FLASH_DELAY,#FLASH_TIME
|
dec
FLASH_COUNTER
;
|
jr
nz,dec light
|
clr
FLASH_FLAG
;
|
dec_light:
|
cp
LIGHT_TIMER_HI,#0FFH
; test for the timer ignore
|
jr
z,exit_light
; if set then ignore
|
tm
T0EXT, #00010000b
; Decrement the light every 8 ms
|
jr
nz,exit_light
; (Use T0Ext to prescale)
|
decw
LIGHT_TIMER
;
|
jr
nz,exit_light
; if timer 0 turn off the light
|
and
p0,#˜LIGHT_ON
; turn off the light
|
cp
L_A_C, #00
; Test for in a learn mode
|
jr
z, exit_light
; If not, leave the LED alone
|
clr
L_A_C
; Leave the learn mode
|
or
ledport,#ledh
; turn off the LED for program mode
|
exit_light:
|
ret
; return
|
MOTOR STATE MACHINE
|
STATEMACHINE:
|
cp
MOTDEL, #0FFH
; Test for max. motor delay
|
jr
z, MOTDELDONE
; if do, don't increment
|
inc
MOTDEL
; update the motor delay
|
MOTDELDONE:
|
xor
p2,#FALSEIR
; toggle aux output
|
cp
DOG2,#8
; test the 2nd watchdog for problem
|
jp
ugt,START
; if problem reset
|
cp
STATE,#6
; test for legal number
|
jp
ugt,start
; if not the reset
|
jp
z,stop
; step motor 6
|
cp
STATE,#3
; test for legal number
|
jp
z,start
; if not the reset
|
cp
STATE,#0
; test for autorev
|
jp
z,auto_rev
; auto reversing 0
|
cp
STATE,#1
; test for up
|
jp
z,up_direction
; door is going up 1
|
cp
STATE,#2
; test for autorev
|
jp
z,up_position
; door is up 2
|
cp
STATE,#4
; test for autorev
|
jp
z,dn_direction
; door is going down 4
|
jp
dn_position
; door is down 5
|
AUTO_REV ROUTINE
|
auto_rev:
|
cp
FAREVFLAG,#088H
; test for the forced up flag
|
jr
nz,LEAVEREV
|
and
p0,#LOW(˜WORKIGHT)
; turn off light
|
clr
FAREVFLAG
; one shot temp test
|
LEAVEREV:
|
cp
MOTDEL, #10
; Test for 40 ms passed
|
jr
ult, AREVON
; If not, keep the relay on
|
AREVOFF:
|
and
p0,#LOW(˜MOTOR_UP & ˜MOTOR_DN)
; disable motor
|
AREVON
|
WDT
; kick the dog
|
call
HOLDREV
; hold off the force reverse
|
ld
LIGHT_FLAG,#LIGHT
; force the Light on no blink
|
di
|
dec
AUTO_DELAY
; wait for .5 second
|
dec
BAUTO_DELAY
; wait for .5 second
|
ei
|
jr
nz,arswitch
; test switches
|
or
p2,#FALSEIR
; set aux output for FEMA
|
;LOOK FOR LIMIT HERE (No)
|
ld
REASON,#40H
; set the reason for the change
|
cp
L_A_C, #075H
; Check for learning limits,
|
jp
nz, SET_UP_NOBLINK
; If not, proceed normally
|
ld
L_A_C, #076H
;
|
jp
SET_UP_NOBLINK
; set the state
|
arswitch:
|
ld
REASON,#00H
; set the reason to command
|
di
|
cp
SW_DATA,#CMD_SW
; test for a command
|
clr
SW_DATA
|
ei
|
jp
z,SET_STOP_STATE
; if so then stop
|
ld
REASON,#10H
; set the reason as radio command
|
cp
RADIO_CMD,#0AAH
; test for a radio command
|
jp
z,SET_STOP_STATE
; if so the stop
|
exit_auto_rev:
|
ret
; return
|
HOLDFREV:
|
ld
RPMONES,#244
; set the hold off
|
ld
RPMCLEAR,#122
; clear rpm reverse .5 sec
|
di
|
clr
RPM_COUNT
; start with a count of 0
|
clr
BRPM_COUNT
; start with a count of 0
|
ei
|
ret
|
DOOR GOING UP
|
up_direction:
|
WDT
; kick the dog
|
cp
OnePass, STATE
; Test for the memory read one-shot
|
jr
z, UpReady
; If so, continue
|
ret
; Else wait
|
UpReady:
|
call
HOLDFREV
; hold off the force reverse
|
ld
LIGHT_FLAG,#LIGHT
; force the light on no blink
|
and
p0,#LOW ˜MOTOR_DN
; disable down relay
|
or
p0,#LIGHT ON
; turn on the light
|
cp
MOTDEL,#10
; test for 40 milliseconds
|
jr
ule,UPOFF
; if not timed
|
CheckUpBlink:
|
and
P2M_SHADOW, #˜BLINK_PIN
; Turn on the blink output
|
ld
P2M, P2M_SHADOW
;
|
cr
P2, #BLINK_PIN
; Turn on the blinker
|
decw
BLINK
; Decrement blink time
|
tm
BLINK_HI, #10000000b
; Test for pre-travel blinking done
|
jp
z, NotUpSlow
; If not, delay normal motor travel
|
UPON:
|
or
p0,#(MOTOR_UP | LIGHT_ON)
; turn on the motor and light
|
UPOFF:
|
cp
FORCE_IGNORE,#1
; test fro the end of the force ignore
|
jr
nz,SKIPUPRPM
; if not donot test rpmcount
|
cp
RPM_ACCOUNT,#12h
; test for less the 2 pulses
|
jr
ugt,SKIPUPRPM
;
|
ld
FAULTCODE,#05h
|
SKIPUPRPM:
|
cp
FORCE_IGNORE, #00
; test timer for done
|
jr
nz,test_UP_SW_pre
; if timer not up do not test force
|
TEST_UP_FORCE:
|
di
|
dec
RPM_TIME_OUT
; decrease the timeout
|
dec
BRPM_TIME_OUT
; decrease the timeout
|
ei
|
jr
z,failed_up_rpm
|
cp
RampFlag, #RAMPUP
; Check for ramping up the force
|
jr
z, test_up_sw
; If not, always do full force check
|
TestUpForcePot:
|
di
; turn off the interrupt
|
cp
RPM_PERIOD_HI, UP_FORCE_HI
; Test the RPM against the force setting
|
jr
ugt, failed_up rpm
;
|
jr
ult, test_up_sw
;
|
cp
RPM_PERIOD_LO, UP_FORCE_LO
;
|
jr
ult, test_up_sw
;
|
failed_up_rpm:
|
ld
REASON, #20H
; set the reason as force
|
cp
L_A_C, #076H
; If we're learning limits,
|
jp
nz, SET_STOP_STATE
; then set the flag to store
|
ld
L_A_C, #077H
;
|
jp
SET_STOP_STATE
|
test_up_sw_pre:
|
di
|
dec
FORCE_IGNORE
|
dec
BFORCE_IGNORE
|
test_up_sw:
|
di
|
ld
LIM_TEST_HI, POSITION_HI
; Calculate the distance from the up limit
|
ld
LIM_TEST_LO, POSITION_LO
;
|
sub
LIM_TEST_LO, UP_LIMIT_LO
;
|
sbc
LIM_TEST_HI, UP_LIMIT_HI
;
|
cp
POSITION_HI, #0B0H
; Test for lost door
|
jr
ugt, UpPosKnown
; If not lost, limit test is done
|
cp
POSITION_HI, #050H
|
jr
ult, UpPosKnown
;
|
ei
;
|
UPosUnknown:
|
sub
LIM_TEST_LO, #062H
; Calculate the total travel distance allowed
|
sbc
LIM_TEST_HI, #07FH
; from the floor when lost
|
add
LIM_TEST_LO, DN_LIMIT_LO
;
|
adc
LIM_TEST_HI, DN_LIMIT_HI
;
|
UpPosKnown:
;
|
ei
;
|
cp
L_A_C, #070H
; If we're positioning the door, forget the limit
|
jr
z, test_up_time
; and the wall control and radio
|
cp
LIM_TEST_HI, #11
; Test for exactly at the limit
|
jr
nz, TestForPastUp
; If not, see if we've passed the limit
|
cp
LIM_TEST_LO, #00
;
|
jr
z, AtUpLimit
;
|
TestForPastUp:
|
tm
LIM_TEST HI, #10000000b
; Test for a negative result (past the limit, but
|
close)
|
jr
z, get_sw
; If so, set the limit
|
AtUpLimit:
|
ld
REASON,#50H
; set the reason as limit
|
cp
L_A_C, #072H
; If we're re-learning limits,
|
jr
z, ReLearnLim
; jump
|
cp
L_A_C, #076H
; If we're learning limits,
|
jp
nz, SET_UP_POS_STATE
; then set the flag to store
|
ld
L_A_C, #077H
;
|
jp
SET_UP_POS_STATE
;
|
ReLearnLim:
|
ld
L_A_C, #073H
;
|
jp
SET_UP_POS_STATE
;
|
get_sw:
|
cp
L_A_C, #070H
; Test for positioning the up limit
|
jr
z,NotUpSlow
; If so, don't slow down
|
TestUpSlow:
|
cp
LIM_TEST_HI, #HIGH(UPSLOWSTART)
; Test for start of slowdown
|
jr
nz, NotUpSlow
; (Cheating -- the high byte of the number is zero)
|
cp
LIM_TEST_LO, #LOW(UPSLOWSTART)
;
|
jr
ugt, NotUpSlow
;
|
UpSlow:
|
ld
RampFlag, #RAMPDOWN
; Set the slowdown flag
|
NotUpSlow:
|
ld
REASON, #10H
; set the radio command reason
|
cp
RADIO_CMD,#0AAH
; test for a radio command
|
jp
z,SET_STOP_STATE
; if so stop
|
ld
REASON,#00H
; set the reason as a command
|
di
|
cp
SW_DATA, #CMD_SW
; test for a command condition
|
clr
SW_DATA
|
ei
|
jr
ne,test_up_time
;
|
jp
SET_STOP_STATE
;
|
test_up_time:
|
ld
REASON,#70H
; set the reason as a time out
|
decw
MOTOR_TIMER
; decrement motor timer
|
jp
z,SET_STOP_STATE
;
|
exit_up_dir:
|
ret
; return to caller
|
DOOR UP
|
up_position:
|
WDT
; kick the dog
|
cp
FAREVFLAG,#088E
; test for the forced up flag
|
jr
nz, LEAVELIGHT
|
and
p0,#LOW(˜WORKLIGHT)
; turn off light
|
jr
UPNOFLASH
; skip clearing the flash flag
|
LEAVELIGHT:
|
ld
LIGHT_FLAG,#00H
; allow blink
|
UPNOFLASH:
|
cp
MOTDEL, #10
; Test for 40 ms passed
|
jr
ult, UPLIMON
; If not, keep the relay on
|
UPLIMOFF:
|
and
p0,#LOW(˜MOTOR UP & ˜MOTOR_DN)
; disable motor
|
UPLIMON:
|
cp
L_A_C, #073H
; If we've begun the learn limits cycle,
|
jr
z,LAOUPPOS
; then delay before traveling
|
cp
SW_DATA, #LIGHT_SW
; light sw debounced
|
jr
z,work_up
;
|
ld
REASON, #10H
; set the reason as a radio command
|
cp
RADIO_CMD,#0AAH
; test for a radio cmd
|
jr
z,SETDNDIRSTATE
; if so start down
|
ld
REASON, #00H
; set the reason as a command
|
di
|
cp
SW_DATA,#CMD_SW
; command sw debounced?
|
clr
SW_DATA
|
ei
|
jr
z,SETDNDIRSTATE
; if command
|
ret
|
SETDNDIRSTATE:
|
ld
ONEP2,#10
; set the 1.2 sec timer
|
jp
SET_DN_DIR_STATE
|
LACUPPOS:
|
cp
MOTOR_TIMER_HI, #HIGH(LACTIME)
; Make sure we're set to the proper time
|
jr
ule, UpTimeOx
|
ld
MOTOR_TIMER_HI, #HIHG(LACTIME)
|
ld
MOTOR_TIMER_LO, #LOW(LACTIME)
|
UpTimeOk:
|
decw
MOTOR_TIMER
; Count down more time
|
jr
nz, up_pos_ret
; If nor timed out, leave
|
StartLACDown:
|
ld
L_A_C, #074H
; Set state as traveling down in LAC
|
clr
UP_LIMIT_HI
; Clear the up limit
|
clr
UP_LIMIT_LO
; and the position for
|
clr
POSITION_HI
; determining the new up
|
clr
POSITION_LO
; limit of travel
|
ld
PassCounter, #030H
; Set pass points at max.
|
jp
SET_DN_DIR_STATE
; Start door traveling down
|
work_up:
|
xor
p0,#WORKLIGHT
; toggle work light
|
ld
LIGHT_TIMER_HI,#0FFH
; set the timer ignore
|
and
SW_DATA, #LOW(˜LIGHT_SW)
; Clear the worklight bit
|
up_pos_ret:
|
ret
; return
|
DOOR GOING DOWN
|
dn_direction:
|
WDT
; kick the dog
|
cp
OnePass, STATE
; Test for the memory read one-shot
|
jr
z, DownReady
; If so, continue
|
ret
; else wait
|
DownReady:
|
call
HOLDFREV
; hold off the force reverse
|
clr
FLASH_FLAG
; turn off the flash
|
ld
LIGHT_FLAG,#LIGHT
; force the light on no blink
|
and
p0,#LOW(˜MOTOR_UP
; turn off motor up
|
or
p0,#LIGHT_ON
; turn on the light
|
cp
MOTDEL,#10
; test for 40 milliseconds
|
jr
ule,DNOFF
; if not timed
|
CheckDnBlink:
|
and
P2M_SHADOW, #˜BLINK_PIN
; Turn on the blink output
|
ld
P2M, P2M_SHADOW
;
|
or
P2, #BLINK_PIN
; Turn on the blinker
|
decw
BLINK
; Decrement blink time
|
tm
BLINK_HI, #10000000b
; Test for pre-travel blink done
|
jr
z, NotOnSlow
; If not, don't start the motor
|
DNON:
|
or
p0,#(MOTOR_DN LIGHT_ON
; turn on the motor and Light
|
DNOFF:
|
cp
FORCE_IGNORE,#01
; test fro the end of the force ignore
|
jr
nz,SKIPDNRPM
; if not donot test rpmcount
|
cp
RPM_ACOUNT,·02H
; test for less the 2 pulses
|
jr
ugt,SKIPDNRPM
;
|
ld
FAULTCODE,#05h
|
SKIPDNRPM:
|
cp
FORCE_IGNORE,#00
; test timer for done
|
jr
nz,test_on_sw_pre
; if timer not up do not test force
|
TEST_DOWN_FORCE:
|
di
|
dec
RPM_TIME_OUT
; decrease the timeout
|
dec
BRPM_TIME_OUT
; decrease the timeout
|
ei
|
jr
z,failed_dn_rpm
|
cp
RampFlag, #RAMPUP
; Check for ramping up the force
|
jr
z, test_dn_sw
; If not, always do full force check
|
TestDownForcePot:
|
di
; turn off the interrupt
|
cp
RPM_PERIOD_HI, DN_FORCE_HI
; rest the RPM against the force setting
|
jr
ugt, failed_dn_rpm
; if too slow then force reverse
|
jr
ult, test_dn_sw
; if faster then we're fine
|
cp
RPM_PERIOD_LO, DN_FORCE_LO
;
|
jr
ult, test_dn_sw
;
|
failed_dn_rpm:
|
+T+L,12 cp
L_A_C, #074H
; Test for learning limits
|
jp
z, DnLearnRev
; If not, set the state normally
|
tm
POSITION_HI, #11000000b
; Test for below last pass point
|
jr
nz, DnRPMRev
; if not, we're nowhere near the limit
|
tm
LIM_TEST_HI, #10000000b
; Test for beyond the down limit
|
jr
nz, DoDownLimit
; If so, we've driven into the down limit
|
DnRPMRev:
|
ld
REASON, #0B0H
; set the reason as force
|
cp
POSITION_HI, #0B0H
; Test for lost,
|
jp
ugt, SET_AREV_STATE
; if not, autoreverse normally
|
cp
POSITION_HI, #050H
;
|
jp
ult, SET_AREV_STATE
;
|
di
; Disable interrupts
|
ld
POSITION_HI, #07FH
; Reset lost position for max. travel up
|
ld
POSITION_LO, #080H
;
|
ei
; Re-enable interrupts
|
jp
SET_AREV_STATE
;
|
DnLearnRev:
|
ld
L_A_C, #075H
; Set proper LAC
|
jp
SET_AREV_STATE
;
|
test_dn_sw_pre:
|
di
|
dec
FORCE_IGNORE
|
dec
BFORCE_IGNORE
|
test_dn_sw:
|
di
;
|
cp
POSITION_HI, #050H
; Test for lost in mid travel
|
jr
ult, TestDnLimGood
;
|
cp
POSITION_HI, #0B0H
; If so, don't test for limit until
|
jr
ult, NotDnSlow
; a proper pass point is seen
|
TestDnLimGood:
|
ld
LIM_TEST_HI, DN_LIMIT_HI
; Measure the distance to the down limit
|
ld
LIM_TEST_LO, DN_LIMIT_LO
;
|
sub
LIM_TEST_LO, POSITION_LO
;
|
sbc
LIM_TEST_HI, POSITION_HI
;
|
ei
;
|
cp
L_A_C, #070H
If we're in the learn cycle, forget the limit
|
jr
uge, test_dn_time
; and ignore the radio and wall control
|
tm
LIM_TEST_HI, #10000000b
; Test for a ngegative result (past the down limit)
|
jr
z, call_sw_dn
; If so, set the limit
|
cp
LIM_TEST_LO, #255 36
; Test for 36 pulses (3″) beyond the limit
|
jr
ugt, NotDnSlow
; if not, then keep driving onto the floor
|
DoDownLimit:
|
ld
REASON,#50H
; set toe reason as a limit
|
cp
CMD_DEB,#0FFH
; test for the switch still held
|
jr
nz,TESTRADIO
;
|
ld
REASON,#90H
; closed with the control held
|
jr
TESTFORCEIG
|
TESTRADIO:
|
cp
LAST_CMD,#00
; test for the last command being radio
|
jr
nz,TESTFORCEIG
; if not test force
|
cp
CodeFlag,#BRECEIVED
; test for the b code flag
|
jr
nz,TESTFORCEIG
;
|
ld
REASON,#0A0H
; set the reason as b code to limit
|
TESTFORCEIG:
|
cp
FORCE_IGNORE,#00H
; test the force ignore for done
|
jr
z,NOAREVDN
; a rev if limit before force enabled
|
ld
REASON,#60h
; early limit
|
jp
SET_AREV_STATE
; set autoreverse
|
NOAREVDN:
|
and
p0,#LOW(˜MOTOR_DN
;
|
jp
SET_DN_POS_STATE
; set the state
|
call_sw_dn:
|
cp
LIM_TEST_HI, #HIGH(DNSLOWSTART,
; Test for start of slowdown
|
jr
nz, NotDnSlow
; (Cheating -- the high byte is zero)
|
cp
LIM_TEST_LO, #LOW(DNSLOWSTART)
;
|
jr
ugt, NotDnSlow
;
|
DnSlow:
|
ld
RampFlag, #RAMPDOWN
; Set the slowdown flag
|
NotDnSlow:
|
ld
REASON, #10H
; set the reason as radio command
|
cp
RADIO_CMD,#0AAH
; test for a radio command
|
jp
z,SET_AREV_STATE
; if so arev
|
ld
REASON,#00H
; set the reason as command
|
di
|
cp
SW_DATA,#CMD_SW
; test for command
|
clr
SW_DATA
|
ei
|
jp
z,SET_AREV_STATE
;
|
test_dn_time:
|
ld
REASON,#70H
; set the reason as timeout
|
decw
MOTOR_TIMER
; decrement motor timer
|
jp
z,SET_AREV_STATE
;
|
test_obs_count:
|
cp
OBS_COUNT,#00
; Test the obs count
|
jr
nz, exit_dn_dir
; if not done, don't reverse
|
cp
FORCE_IGNORE, #(ONE_SEC / 2)
; Test for 0.5 second passed
|
jr
ugt, exit_an_dir
; if within first 0.5 sec, ignore it
|
cp
LAST_CMD,#00
; test for the last command from radio
|
jr
z,OBSTESTB
; if last command was a radio test b
|
cp
CMD_DEB,#0FFH
; test for the command switch holding
|
jr
nz,OBSAREV
; if the command switch is not holding
|
; do the autorev
|
jr
exit_dn_dir
; otherwise skip
|
OBSAREV:
|
ld
FLASH_FLAG, #0FFH
; set flag
|
ld
FLASH_COUNTER, #20
; set for 10 flashes
|
ld
FLASH_DELAY,#FLASH_TIME
; set for .5 Hz period
|
ld
REASON,#30E
; set the reason as autoreverse
|
jp
SET_AREV_STATE
;
|
OBSTESTB:
|
cp
CodeFlag,#BRECEIVED
; test for the b code flag
|
jr
nz,OBSAREV
; if not b code then arev
|
exit_dn_dir:
|
ret
; return
|
DOOR DOWN
|
dn_position:
|
WDT
; kick the doa
|
cp
FAREVFLAG,#088H
; test for the forced up flag
|
jr
nz,DNLEAVEL
;
|
and
p0,#LOW(˜WORKLIGHT)
; turn off light
|
jr
DNNOFLASH
; skip clearing the flash flag
|
DNLEAVEL:
|
ld
LIGHT_FLAG,#00H
; allow blink
|
DNNOFLASH:
|
cp
MOTDEL, #10
; Test for 40 ms passed
|
jr
ult, DNLIMON
; If not, keep the relay on
|
DNLIMOFF:
|
and
p0,#LOW(˜MOTOR_UP & ˜MOTOR_DN)
; disable motor
|
DNLIMON:
|
cp
SW_DATA,#LIGHT_SW
; debounced? light
|
jr
z,work_an
;
|
ld
REASON,#10H
; set the reason as a radio command
|
cp
RADIO_CMD,#0AAH
; test for a radio command
|
jr
z,SETUPDIRSTATE
; if so go up
|
ld
REASON,#00H
; set the reason as a command
|
di
|
cp
SW_DATA,#CMD_SW
; command sw pressed?
|
clr
SW_DATA
|
ei
|
jr
z,SETUPDIRSTATE
; if so go up
|
ret
|
SETUPDIRSTATE:
|
ld
ONEP2,#10
; set the 1.2 sec timer
|
jp
SET_UP_DIR_STATE
|
work_dn:
|
xor
p0,#WORKLIGMT
; toggle work light
|
ld
LIGHT_TIMER_HI,#0FFH
; set the timer ignore
|
and
SW_DATA, #LOW(˜LIGHT_SW)
; Clear the worklight bit
|
dn_pos_ret:
|
ret
; return
|
STOP
|
stop:
|
WDT
; kick the dog
|
cp
FAREVFLAG,#066H
; test for the forced up flag
|
jr
nz,LEAVESTOP
|
and
p0,#LOW˜WORKLIGHT
; turn off light
|
jr
STOPNOFLASH
;
|
LEAVESTOP:
|
ld
LIGHT_FLAG,#00H
; allow blink
|
STOPNOFLASH:
|
cp
MOTDEL, #10
; Test for 40 ms passed
|
jr
ult, STOPMIDON
; If not, keep the relay on
|
STOPMIDOFF:
|
and
p0,#LOW(˜MOTOR_UP & ˜MOTOR_DN
; disable motor
|
STOPMIDON:
|
cp
SW_DATA,#LIGHT_SW
; debounced? light
|
jr
z,work_stop
;
|
ld
REASON,#10H
; set the reason as radio command
|
cp
RADIO_CMD,#0AAH
; test for a radio command
|
jp
z,SET_DN_DIR_STATE
; if so go down
|
ld
REASON,#00H
; set the reason as a command
|
di
|
cp
SW_DATA,#CMD_SW
; command sw pressed?
|
clr
SW_DATA
|
ei
|
jp
z,SET_DN_DIR_STATE
; if so go down
|
ret
|
work_stop:
|
xor
p0,#WORKLIGHT
; toggle work light
|
ld
LIGHT_TIMER_HI,#0FFH
; set the timer ignore
|
and
SW_DATA, #LOW,˜LIDHT_SW
; Clear the worklight bit
|
stop_ret:
|
ret
; return
|
SET THE AUTOREV STATE
|
SET_ARVE_STATE:
|
di
;
|
cp
L_A_C, #070H
; Test for learning limits,
|
jt
uge, LearningRev
; If not, do a normal autoreverse
|
cp
POSITION_HI, #020H
; Look for lost postion
|
jr
ult, DoTheArev
; If not, Proceed as normal
|
cp
POSITION_HI, #0D0H
; Look for lost position
|
jr
ugt, DoTheArev
; If not, proceed as normal
|
;Otherwise, we're list -- ignore commands
|
cp
REASON, #020H
Don't respond to command or radio
|
jf
uge, DoTheArev
;
|
clr
RADIO_CMD
; Throw out the radio command
|
ei
; Otherwise, just ignore it
|
ret
;
|
DoTheArev:
|
ld
STATE,#AUTO_REV
; if we got here, then reverse motor
|
ld
RampFlag, #STILL
; Set the FET's to off
|
clr
PowerLevel
;
|
jr
SET_ANY
; Done
|
LearningRev:
|
ld
STATE,#AUTO_REV
; if we got here, then reverse motor
|
ld
RampFlag, #STILL
; Set the FET's to off
|
clr
PowerLevel
;
|
cp
L_A_C, #075H
; Check for proper reversal
|
jr
nz, ErrorLearnArev
; If not, stop the learn cycle
|
cp
PassCounter, #030H
; If we haven't seen a pass point,
|
jr
z, ErrorLearnArev
; then flag an error
|
GoodLearnArev:
|
cp
POSITION_HI, #00
; Test for down limit at least
|
jr
nz, DnLimGood
; 20 pulses away from pass point
|
cp
POSITION_LO, #20
;
|
jr
ult, MovePassPoint
; If not, use the upper pass point
|
DnLimGood:
|
and
PassCounter, #10100000b
; Set at lowest pass point
|
GotDnLim:
|
di
|
ld
DN_LIMIT_HI, POSITION_HI
; Set the new down limit
|
ld
DN_LIMIT_LO, POSITION_LO
;
|
add
DN_LIMIT_LO, #01
; Add in a pulse to guarantee reversal off the block
|
adc
DN_LIMIT_HI, #00
;
|
jr
SET_ANY
;
|
ErrorLearnArev:
|
ld
L_A_C, #071H
; Set the error in learning state
|
jr
SET_ANY
|
MovePassPoint:
|
cp
PassCounter, #02FH
; If we have only one pass point,
|
jr
z, ErrorLearnArev
; don't allow it to be this close to the floor
|
di
|
add
POSITION_LO, #LOW(PPOINTPULSES)
; Use the next pass point up
|
adc
POSITION_HI, #HIGH(PPOINTPULSES)
;
|
add
UP_LIMIT_LO, #LOW PPOINPULSES
;
|
adc
UP_LIMIT_HI, #HIGH PPOINTPULSES
;
|
ei
;
|
or
PassCounter, #01111111b
; Set pass counter at −1
|
jr
GotDmLim
;
|
SET THE STOPPED STATE
|
SET_STOP_STATE:
|
di
|
cp
L_A_C, #070H
; If we're in the learn mode,
|
jr
uge, DoTheStop
; Then don't ignore anything
|
cp
POSITION_HI, #020H
; Look for lost postion
|
jr
ult, DoTheStop
; If not, proceed as normal
|
cp
POSITION_HI, #0D0H
; Look for lost postion
|
jr
ugt, DoTheStop
; If not, proceed as normal
|
;Otherwtse, we're lost -- ignore commands
|
cp
REASON, #020H
; Don't respond to command or radio
|
jr
uge, DoTheStop
;
|
clr
RADIO_CMD
; Throw out the radio command
|
ei
; Otherwise, just ignore it
|
ret
|
DoTheStop:
|
ld
STATE,#STOP
;
|
ld
RampFlag, #STILL
; Stop the motor at the FET's
|
clr
PowerLevel
;
|
jr
SET_ANY
|
SET THE DOWN DIRECTION STATE
|
SET_DN_DIR_STATE:
|
ld
BLINK_HI, #0FFH
;Initially disable pre-travel blink
|
call
LookForFlasher
;Test to see if flasher present
|
tm
P2, #BLINK PIN
;If the flasher is not present,
|
jr
nz, SET_DN_NOBLINK
;don't flash it
|
ld
BLINK_LO, #0FFH
;Turn on the blink timer
|
ld
BLINK_HI, #01H
;
|
SET_DN_NOBLINK:
|
di
|
ld
RampFlag, #RAMPUP
; Set the flag to accelerate motor
|
ld
PowerLevel, #4
; Set speed at minimum
|
ld
STATE,#DN_DIRECTION
; energize door
|
clr
FAREVFLAG
; one shot the forced reverse
|
cp
L_A_C, #070H
; If we're learning the limits,
|
jr
uge, SET_ANY
; Then don't bother with testing anything
|
cp
POSITION_HI, #020H
; Look for lost postion
|
jp
ult, SET_ANY
; If not, proceed as normal
|
cp
POSITION_HI, #0D0H
; Lock for lost postion
|
jp
ugt, SET_ANY
; If not, proceed as normal
|
LostDn:
|
cp
FirstRun, #0C
; If this isn't our first operation when lost,
|
jr
nz, SET_ANY
; then ALWAYS head down
|
tm
PassCounter, #01111111b
; If we are below the lowest
|
jr
z, SET_UP_DIR_STATE
; pass point, head up to see it
|
tcm
PassCounter, #01111111b
; If our pass point number is set at −1,
|
jr
z, SET_UP_DIR_STATE
; then go up to find the position
|
jr
SET_ANY
; Otherwise, proceed normally
|
SET THE DOWN POSITION STATE
|
SET_DN_POS_STATE:
|
di
|
ld
STATE,#DN_POSITION
; load new state
|
ld
RampFlag, #STILL
; Stop the motor at the FET's
|
clr
PowerLevel
;
|
jr
SET_ANY
|
SET THE UP DIRECTION STATE
|
SET_UP_DIR_STATE:
|
ld
BLINK_HI, #0FFH
;Initially turn off blink
|
call
LookForFlasher
;Test to see if flasher present
|
tm
P2, #BLINK_PIN
;If the flasher is not present,
|
jr
nz, SET_UP_NOBLINK
;don't flash it
|
ld
BLINK_LO, #0FFH
;Turn on the blink timer
|
ld
BLINK_HI, #01H
;
|
SET_UP_NOBLINK
|
di
|
ld
RampFlag,#RAMPUP
; Set the flag to accelerate to max.
|
ld
PowerLevel, #4
; Start speed at minimum
|
ld
STATE, #UP_DIRECTION
;
|
jr
SET_ANY
;
|
SET THE UP POSITION STATE
|
SET_UP_POS_STATE:
|
di
|
ld
STATE,#UP_POSITION
;
|
ld
RampFlag, #STILL
; Stop the motor at the FET's
|
clr
PowerLevel
;
|
SET ANY STATE
|
SET_ANY:
|
and
P2M_SHADOW, #˜BLINK_PIN
; Turn on the blink output
|
ld
P2M, P2M_SHADOW
:
|
and
P2, #˜BLINK_PIN
; Turn off the light
|
cp
PPOINT_DEB, #2
; Test for pass point being seen
|
jr
ult, NoPrePPoint
; If signal is low, none seen
|
PrePPoint:
|
or
PassCounter, #0000000b
; Flag pass point signal high
|
jr
PrePPointDone
;
|
NoPrePPoint:
|
and
PassCounter, #01111111b
; Flag pass point signal low
|
PrePPointDone:
|
ld
FirstRun, #0FFH
; One-shot the first run flag DONE IN MAIN
|
ld
BSTATE,STATE
; set the backup state
|
di
|
clr
RPM_COUNT
; clear the rpm counter
|
clr
BRPM_COUNT
;
|
ld
AUTO_DELAY,#AUTO_REV_TIME
; set the .5 second auto rev timer
|
ld
BAUTO_DELAY, #AUTO_REV_TIME
;
|
ld
FORCE_IGNORE,#ONE_SEC
; set the force ignore timer to one sec
|
ld
BFORCE_IGNORE,#ONE_SEC
; set the force ignore timer to one sec
|
ld
RPM_PERIOD_HI, #0FFH
; Set the RPM period to max. to start
|
ei
; Flush out any pending interrupts
|
di
;
|
cp
L_A_C, #070H
; If we are in learn mode,
|
jr
uge, LearnModeMotor
; don't test the travel distance
|
push
LIM_TEST_HI
; Save the limit tests
|
push
LIM_TEST_LO
;
|
ld
LIM_TEST_HI, DN_LIMIT_HI
+T+L,28 Test the door travel distance to
|
ld
LIM_TEST_LO, DN_LIMIT_LO
; see if we are shorter than 2.3M
|
sub
LIM_TEST_L0, UP_LIMIT_LO
;
|
sbc
LIM_TEST_HI, UP_LIMIT_HI
;
|
cp
LIM_TEST_HI, #HIGH(SHORTDOOR)
; If we are shorter than 2.3M,
|
jr
ugt, DoorIsNorm
; then set the max. travel speed to 2/3
|
jr
ult, DoorIsShort
; Else, normal speed
|
cp
LIM_TEST_LO, #LOW(SHORTDOOR)
;
|
jr
ugt, DoorIsNorm
;
|
DoorIsShort:
|
ld
MaxSpeed, #12
; Set the max. speed to 2/3
|
jr
DoorSet
;
|
DoorIsNorm:
|
ld
MaxSpeed, #20
;
|
DoorSet:
|
pop
LIM_TEST_LO
; Restore the limit tests
|
pop
LIM_TEST HI
;
|
ld
MOTOR_TIMER_HI,#HIGH(MOTORTIME)
|
ld
MOTOR_TIMER_LO,#LOW(MOTORTIME)
|
MotorTimeSet:
|
ei
|
clr
RADIO_CMD
; one shot
|
clr
RPM_ACOUNT
; clear the rpm active counter
|
ld
STACKREASON,REASON
; save the temp reason
|
ld
STACKFLAG,#0FFH
; set the flag
|
TURN_ON_LIGHT:
|
call
SetVarLight
; Set the worklight to the proper value
|
tm
P0, *LIGHT_ON
; If the light is on skip clearing
|
jr
nz,lighton
;
|
lightoff:
|
clr
MOTDEL
; clear the motor delay
|
lighton:
|
ret
|
LearnModeMotor:
|
ld
MaxSpeed, #12
; Default to slower max. speed
|
ld
MOTOR_TIMER_HI,#HIGH(LEARNTIME)
|
ld
MOTOR_TIMER_LO,#LOW(LEARNTIME)
|
jr
MotorTimeSet
; Set door to longer run for learn
|
THIS IS THE MOTOR RPM INTERRUPT ROUTINE
|
RPM:
|
push
rp
; save current pointer
|
srp
#RPM_GROUP
;point to these reg
|
ld
rpm_temp_of,T0_0FLOW
; Read the 2nd extension
|
ld
rpm_temp_hi,T0EXT
; read the timer extension
|
ld
rpm_temp_lo,T0
; read the timer
|
tm
IRQ,#00010000B
; test for a pending interrupt
|
jr
z,RPMTIMEOK
; if not then time ok
|
RPMTIMEERROR:
|
tm
rpm_temp_lo, #10000000B
; test for timer reload
|
jr
z,RPMTIMEOK
; if no reload time is ok
|
decw
rpm_temp_hiword
; if reloaded then dec the hi to resync
|
RPMTIMEOK:
|
cp
RPM_FILTER, #128
; Signal must have been high for 3 ms before
|
jr
ult, RejectTheRPM
; the pulse is considered legal
|
tm
P3, #00000010B
; If the line is sitting high,
|
jr
nz, RejectTheRPM
; then the falling edge was a noise pulse
|
RPMIsGood:
|
and
imr,#11111011b
; turn off the interupt for up to 500uS
|
ld
divcounter, #03
; Set to divide by 8 (destroys value in RPM_FILTER)
|
DivideRPMLoop:
|
rcf
; Reset the carry
|
rrc
rpm_temp_of
; Divide the number by 8 so that
|
rrc
rpm_temp hi
; it will always fit within 16 bits
|
rrc
rpm_temp_lo
;
|
djnz
divcounter, DivideRPMLoop
; Loop three times (Note: This clears RPM FILTER)
|
ld
rpm_period_lo, rpm_past_lo
;
|
ld
rpm_period_hi, rpm_past_hi
;
|
sub
rpm_period_lo, rpm_temp_lo
; find the period of the last pulse
|
sbc
rpm_period_hi, rpm_temp_hi
;
|
ld
rpm_past_lo, rpm_temp_lo
; Store the current time for the
|
ld
rpm_past_hi, rpm_temp_hi
; next edge capture
|
cp
rpm_period_hi,#12
; test for a period of at least 6.144mS
|
jr
ult,SKIPC
; if the period is less then skip counting
|
TULS:
|
INCRPM:
|
inc
RPM_COUNT
; increase the rpm count
|
inc
BRPM_COUNT
; increase the rpm count
|
SKIFC:
|
inc
RPM_ACOUNT
; increase the rpm count
|
cp
RampFlag, #RAMPUP
; If we're ramping the speed up,
|
jr
z, MaxTimeOut
; then set the timeout at max.
|
cp
STATE, #DN_DIRECTION
; If we're traveling down,
|
jr
z, DownTimeOut
; then set the timeout from the down force
|
UpTimeOut:
|
ld
rpm_time_out,UP_FORCE_HI
; Set the RPM timeout to be equal to the up force setting
|
rcf
; Divide by two to account
|
rrc
rpm_time_out
; for the different prescalers
|
add
rpm_time_out, #2
; Round up and account for free-running prescale
|
jr
GotTimeOut
|
MaxTimeOut:
|
ld
rpm_time_out, #125
; Set the RPM timeout to be 500mns
|
jr
GotTimeOut
;
|
DownTimeOut:
|
ld
rpm_time_out,DN_FORCE_HI
; Set the RPM timeout to be equal to the down force setting
|
rcf
; Divide by two to account
|
rrc
rpm_time_out
; for the different prescalers
|
add
rpm_time_out, #2
; Round up and account for free-running prescale
|
GotTimeOut:
|
ld
BRPM_TIME_OUT, rpm_time_out
; Set the backup to the same value
|
ei
|
Position Counter
|
Position is incremented when going down and decremented when
|
going up. The zero position is taken to be the upper edge of the pass
|
point signal (i.e. the falling edge in the up direction, the rising edge in
|
the down direction)
|
cp
STATE, #UP_DIRECTION
; Test for the proper direction of the counter
|
jr
z, DecPos
;
|
cp
STATE, #STOP
;
|
jr
z, DecPos
;
|
+T+L,12 cp
STATE, #UP_POSITION
;
|
jr
z, DecPos
;
|
IncPos:
|
incw
POSITION
;
|
cp
PPOINT_DEB, #2
; Test for pass point being seen
|
jr
ult, NoDNPPoint
; If signal is low, none seen
|
DnPPoint:
|
or
PassCounter, #10000000b
+T+L,32 ; Mark pass point as currently high
|
jr
CtrDone
;
|
NoDnPPoint:
|
tm
PassCounter, #10000000b
; Test for pass point seen before
|
jr
z, PastDnEdge
; If not, then we're past the edge
|
AtDnEdge
|
cp
L_A_C, #074H
; Test for learning limits
|
jr
nz, NormalDownEdge
; if not, treat normally
|
LearnDownEdge:
|
di
|
sub
UP_LIMIT_LO, POSITION_LO
; Set the up position higher
|
sbc
UP_LIMIT_HI, POSTION_HI
;
|
dec
PassCounter
; Count pass point as being seen
|
jr
Lowest1
; Clear the position counter
|
NormalDownEdge:
|
dec
PassCounter
; Mark as one pass point closer to floor
|
tm
PassCounter, #01111111b
; Test for lowest pass point
|
jr
nz, NotLowest1
; If not, don't zero the position counter
|
Lowest1:
|
di
|
clr
POSITION_HI
; Set the position counter back to zero
|
ld
POSITION_LO, #1
;
|
ei
;
|
NotLowest1:
|
cp
STATUS, #PSSTATUS
; Test for in R5232 mode
|
jr
z, DontResetWall3
; If so, don't blink the LED
|
ld
STATUS, #WALLOFF
; Blink the LED for pass point
|
clr
VACFLASH
; Set the turn-off timer
|
DontResetWall3.
|
PastDnEdge:
|
NoUpPPoint:
|
and
PassCounter, #01111111b
; Clear the flag for pass point high
|
jr
CtrDone
;
|
DecPos:
|
decw
POSITION
;
|
cp
PPOINT_DEB, #2
; Test for pass point being seen
|
jr
ult, NoUpPPoint
; If signal is low, none seen
|
UpPPoint:
|
tm
PassCounter, #10000000b
+T+L,32 ; Test for pass point seen before
|
jr
nz, PastUpEdge
; If so, then we're past the edge
|
AtUpEdge:
|
tm
PassCounter, #01111111b
; Test for lowest pass point
|
jr
nz, NotLowest2
; If not, don't zero the position counter
|
Lowest2:
|
di
|
clr
POSITION_HI
; Set the position counter back to zero
|
clr
POSITION_LO
;
|
ei
|
NotLowest2:
|
cp
STATUS, #RSSTATUS
; Test for in R5232 mode
|
jr
z, DontResetWall2
; If so, don't blink the LED
|
ld
STATUS, #WALLOFF
; Blink the LED for pass point
|
clr
VACFLASH
; Set the turn-off timer
|
DontResetWall2:
|
inc
PassCounter
; Mark as one pass point higher above
|
cp
PassCounter, FirstRun
; Test for pass point above max. value
|
jr
ule, PastUpEdge
; If not, we're fine
|
ld
PassCounter, FirstRun
; Otherwise, correct the pass counter
|
PastUpEdge:
|
or
PassCounter, #10000000b
; Set the flag for pass point high before
|
CtrDone:
|
RejectTheRPM:
|
pop
rp
; return the rp
|
iret
; return
|
THIS IS THE SWITCH TEST SUBROUTINE
|
STATUS
|
0 => COMMAND TEST
|
1 => WORKLIGHT TEST
|
2 => VACATION TEST
|
3 => CHARGE
|
4 => RSSTATUS -- RS232 mode, don't scan for switches
|
5 => WALLOFF -- Turn off the wall control LED
|
SWITCH DATA
|
0 => OPEN
|
1 => COMMAND CMD_SW
|
2 => WORKLIGET LIGHT_SW
|
4 => VACATION VAC_SW
|
switches:
|
ei
|
4-22-97
|
CP
LIGHT_DEB,#0FFH
;is the light button being held?
|
JR
NZ,NotHeldDown
;if not debounced, skip long hold
|
CP
EnableWorkLight,#01100000B
;has the 10 sec. already passed?
|
JR
GE,HeldDon
|
CP
EnableWorkLight,#01010000B
|
JR
LT,HeldDown
|
LD
EnableWorkLight,#10010000B
;when debounce occurs, set register
|
;to initiate e2 write in mainloop
|
JR
HeldDown
|
NotHeldDown:
|
CLR
EnableWorkLight
|
HeldDown:
|
and
SW_DATA, #LIGHT_SW
; Clear all switches excect for worklrght
|
cp
STATUS, #WALLOFF
; Test for illegal status
|
jp
ugt, start
; if so reset
|
jr
z, NoWallCtrl
; Turn off wall control state
|
cp
STATUS, #RSSTATUS
; Check for in RS232 mode
|
jr
z, NOTFLASHED
; If so, skip the state machine
|
cp
STATUS,#3
; test for illegal number
|
jp
z,charge
; if it is 3 then goto charge
|
cp
STATUS,#2
; test for vacation
|
jp
z,VACATION_TEST
; if so then jump
|
cp
STATUS,#1
; test for worklight
|
jp
z,WORKLIGHT_TEST
; if so then jump
|
; else it id command
|
COMMAND_TEST:
|
cp
VACFLAC,#00H
; test for vacation mode
|
jr
z,COMMAND_TEST1
; if not vacation skip flash
|
inc
VACFLASH
; increase the vacation flash timer
|
cp
VACFLASH,#10
; test the vacation flash period
|
jr
ult,COMMMAND_TEST1
; if lower period skip flash
|
and
p3,#˜CHARGE_SW
; turn off wall switch
|
or
p3,#DIS_SW
; enable discharoe
|
cp
VACFLASH,#60
; test the time delay for max
|
jr
nz,NOTFLASHED
; if the flash is not done jump and ret
|
clr
VACFLASH
; restart the timer
|
NOTFLASHED
|
ret
; return
|
NoWallCtrl:
|
and
P3, #˜CHARGE_SW
; Turn off the circuit
|
or
P3, #DIS_SW
;
|
inc
VACFLASH
; Update the off time
|
cp
VACFLASH, #81
; If off tine hasn't expired,
|
jr
ult, KeepOff
; keep the LED off
|
ld
STATUS, #CHARGE
; Reset the wall control
|
ld
SWITCH_DELAY, #CMD_DEL_EX
; Reset the charce timer
|
KeepOff:
|
ret
;
|
COMMAND_TEST1:
|
tm
p0,#SWTCHES1
; command sw pressed?
|
jr
nz,CMDOPEN
; open command
|
tm
P0,#SWITCHES2
; test the second command input
|
jr
nz,CMDOPEN
|
CMDCLOSE1:
; closed command
|
call
DECVAC
; decrease vacation debounce
|
call
DECLIGHT
; decrease light debounce
|
cp
CMD_DEB,#0FFH
; test for the max number
|
jr
z,SKIPCMDINO
; if at the max skip inc
|
di
|
inc
CMD_DEB
; increase the debouncer
|
inc
BCMD_DEB
increase the debouncer
|
SKIPCMDINC:
|
cp
CMD_DEB,#CMD_MAFE
;
|
jr
nz,CMDEXIT
; if not made then exit
|
call
CmdSet
; Set the command switch
|
CMDEXIT:
|
or
p3,#CHARGE_SW
; turn on the charge system
|
and
p3,#˜DIS_SW
;
|
ld
SWITCH_DELAY,#CMD_DEL_EX
; set the delay time to 8mS
|
ld
STATUS,#CHARGE
; charge time
|
CMDDELEXIT:
|
ret
;
|
CmdSet:
|
cp
L_A_C, #070H
; Test for in learn limits mode
|
jr
ult, RegCmdMake
; If not, treat as normal command
|
jr
ugt, LeaveLAC
; If learning, command button exits
|
call
SET_UP_NOBLINK
; Set the up direction state
|
jr
CMDMAXEDONE
;
|
RegCmdMake:
|
cp
LEARNDB, #0FFH
; Test for learn button held
|
jr
z, GoIntoLAC
; If so, enter the learn mode
|
NormalCmd:
|
di
|
ld
LAST_CMD,#055H
; set the last command as command
|
cmd:
ld
SW_DATA,#CMD_SW
; set the switch data as command
|
cp
AUXLEARNSW,#100
; test the time
|
jr
ugt,SKIP_LEARN
|
push
RP
|
srp
#LEARNEE_GRP
|
call
SETLEARN
; set the learn mode
|
dr
SW_DATA
; clear the cmd
|
pop
RP
|
or
p0,#LIGHT_ON
; turn on the light
|
call
TURN_ON_LIGHT
; turn on the light
|
CMDMAKEDONE:
|
SKIP_LEARN:
|
ld
CMD_DEB,#0FFH
; set the debouncer to ff one shot
|
ld
BCMD_DEB,#0FFH
; set the debouncer to ff one shot
|
ei
|
ret
|
LeaveLAC:
|
clr
L_A_C
; Exit the learn mode
|
or
ledport,#ledn
; turn off the LED for program mode
|
call
SET_STOP_STATE
;
|
jr
CMDMAKEDONE
;
|
GoIntoLAC:
|
ld
L_A_C, #170H
; Start the learn limits mode
|
clr
FAULTCODE
; Clear any faults that exist
|
clr
CodeFlag
; Clear the reoular learn mode
|
ld
LEARNT, #0FFH
; Turn off the learn timer
|
ld
ERASET, #OFFH
; Turn off the erase timer
|
jr
CMDMAKEDONE
;
|
CMDOPEN:
; command switch open
|
and
p3,#˜CHARGE_SW
; turn off charging sw
|
or
p3,#DIS_SW
; enable discharge
|
ld
DELAYC,#16
; set the time delay
|
DELLOOP:
|
dec
DELAYC
|
jr
nz,DELLOOP
; loop till delay is up
|
tm
p0,#SWITCHES1
; command line still high
|
jr
nz,TESTWL
; if so return later
|
call
DECVAC
; if not open line dec all debouncers
|
call
DECLIGHT
;
|
call
DECCMD
;
|
ld
AUXLEARNSW,#0FfH
; turn off the aux learn switch
|
jr
CMDEXIT
; and exit
|
TESTWL:
|
ld
STATUS,#WL_TEST
; set to test for a worklight
|
ret
; return
|
WORKLIGHT_TEST:
|
tm
p0,#SWITCHES
; command line still high
|
jr
nz,TESTVAC2
; exit setting to test for vacation
|
call
DECVAC
; decrease the vacation debouncer
|
call
DECCMD
; and the command debouncer
|
cp
LIGHT_DEB,#0FFH
; test for the max
|
jr
z,SKIPLIGHTING
; if at the max skip inc
|
inc LIGHT_DEB
; inc debouncer
|
SKIPLIGHTING:
|
cp
LIGHT_DEB,#LIGHT_MAKE
; test for the light make
|
jr
nz,CMDEXIT
; if not then recharge delay
|
call
LightSet
; Set the light debouncer
|
jr
CMDEXIT
; then recharge
|
LightSet:
|
ld
LIGHT_DEB,#0FFH
; set the debouncer to max
|
ld
SW_DATA,#LIGHT_SW
; set the data as worklight
|
cp
RRTO,#RDROPTIME
; test for code reception
|
jr
ugt,CMDEXT
; if not then skip the seting of flag
|
clr
AUXLEARNSW
; start the learn timer
|
ret
|
TESTVAC2:
|
ld
STATUS,#VAC_TEST
; set the next test as vacation
|
ld
switch_delay,#VAC_DEL
; set the delay
|
LIGHTDELEXIT:
|
ret
; return
|
VACATION_TEST:
|
djnz
switch_delay,VACDELEXIT
;
|
tm
p0,#SWITCHES1
; command line still high
|
jr, EXIT_ERROR
; exit with a error setting open state
|
call
DECLIGHT
; decrease the light debouncer
|
call
DECCMD
; decrease the command debouncer
|
cp
VAC_DEB,#0FFH
; test for the max
|
jr
z,VACINCSKIP
; skip the incrementing
|
VACINCSKIP:
|
or
VACFLAG,#00H
; test for vacation mode
|
jr
z,VACOUT
; if not vacation use out time
|
VACIN:
|
or
VAC_DEB,#VAC_MAKE_IN
; test for the vacation make point
|
jr
nz,VACATION_EXIT
; exit of not made
|
call
VacSet
;
|
jr
VACATION_EXIT
;
|
VACOUT:
|
cp
VAC_DEB,#VAC_MAKE_OUT
; test for the vacation make count
|
jr
nz,VACATION_EXIT
; exit if not made
|
call
VacSet
;
|
jr
VACATION_EXIT
; Forget vacatoon mode
|
VacSet:
|
ld
VAC_DEB,#0FFH
; set vacation debouncer to max
|
cp
AUXLEARNSW,#100
; test the time
|
jr
ugt,SKIP_LEARNV
|
push
RP
|
srp
#LEARNEE_GRP
|
call
SETLEARN
; set the learn mode
|
pop
RP
|
cr
p0, #LIGHT_ON
; Turn on the worklight
|
call
TURN_ON_LIGHT
;
|
ret
|
SKIP_LEARNT:
|
ld
VACCHANGE,#0AAH
; set the toggle data
|
cp
RRTO,#RDROPTIME
; test for code reception
|
jr
ugt,VACATION_EXIT
; if not then skip the seting of flag
|
clr
AUXLEARNSW
; start the learn timer
|
VACATION_EXIT:
|
ld
SWITCH_DELAY,#VAC_DEL_EX
; set the delay
|
ld
STATUS,#CHARGE
; set the next test as charge
|
VACDELEXIT:
|
ret
|
EXIT_ERROR:
|
call
DECCMD
; decrement the debouncers
|
call
DECVAC
;
|
call
DECLIGHT
;
|
ld
SWITCH_DELAY,#VAC_DEL_EX
; set the delay
|
ld
STATUS,#CHANGE
; set the next test as charge
|
ret
|
charge:
|
or
p3,#CHARGE_SW
;
|
and
p3,#˜DIS_SW
;
|
dec
SWITCH_DELAY
;
|
jr
nz,charge_ret
;
|
ld
STATUS,#CMD_TEST
;
|
charge_ret:
|
ret
|
DECOMD:
|
cp
CMD_DEB,#00H
; test for the min number
|
jr
z,SKIPCMDDEC
; if at the min skip dec
|
di
|
dec
CMD_DEB
; decrement debouncer
|
dec
BCMD_DEB
decrement debouncer
|
ei
|
SKIPCMDDEC:
|
cp
CMD_DEB,#CMD_BREAK
; if not at break then exit
|
jr
nz,DECMDEXIT
; if not break then exit
|
call
CmdRel
;
|
DECCMDEXIT:
|
ret
; and exit
|
CmdRel:
|
cp
L_A_C, #070h
; Test for in learn mode
|
jr
nz, NormCmdBreak
; If not, treat normally
|
call
SET_STOP_START
; Stop the door
|
NormCmdBreak:
|
di
|
clr
CMD_DEB
; reset the debouncer
|
clr
BCMD_DEB
; reset the debouncer
|
ei
|
ret
|
DECLIGHT:
|
cp
LIGHT_DEB,#00H
; test for the min number
|
jr
z,SKIPLIGHTDEC
; if at the min skip dec
|
dec
LIGHT_DEB
; decrement debouncer
|
SKIPLIGHTDEC:
|
cp
LIGHT_DEB,#LIGHT_BREAK
; if not at break then exit
|
jr
nz,DECLIGHTEXIT
; if not break then exit
|
clr
LIGHT_DEB
; reset the debouncer
|
DECLIGHTEXIT:
|
ret
; and exit
|
DECVAC:
|
cp
VAC_DEB,#00H
; test for one min number
|
jr
z,SKIPVACDEC
; if at the min skip dec
|
dec
VAC_DEB
; decrement debouncer
|
SKIPVACDEC:
|
cp
VACFLAG,#00H
; test for vacation mode
|
jr
z,DECVACOUT
; if not vacation use out time
|
DECVACIN:
|
cp
VAC_DEB,#VAC_BREAK_IN
; test for the vacation break point
|
jr
nz,DECVACEXIT
; exit if not
|
jr
CLEARVACDEB
;
|
DECVACOUT:
|
cp
VAC_DEB,#VAC_BREAK_OUT
; test for the vacation break point
|
jr
nz,DECVACEXIT
; exit if not
|
CLEARVACDEB:
|
clr
VAC_DEb
; reset the debouncer
|
DECVACEXIT:
|
ret
; and exit
|
FORCE TABLE
|
force_table:
|
f_0:
.byte 000H, 06BH, 06CH
|
.byte 000H, 06BH, 06CH
|
.byte 000H, 06DH, 073H
|
.byte 000H, 06FH, 08EH
|
.byte 000H, 071H, 0BEH
|
.byte 000H, 074H, 004H
|
.byte 000H, 076H, 062H
|
.byte 000H, 078H, 0DAH
|
.byte 000H, 07BH, 06CH
|
.byte 000H, 07EH, 01BH
|
.byte 000H, 080H, 0E8H
|
.byte 000H, 083H, 0D6H
|
.byte 000H, 086H, 09BH
|
.byte 000H, 089H, 07FH
|
.byte 000H, 08CH, 084H
|
.byte 000H, 08FH, 0ABH
|
.byte 000H, 092H, 0F7H
|
.byte 000H, 096H, 06BH
|
.byte 000H, 09AH, 009H
|
.byte 000H, 09DH, 0D5H
|
.byte 000H,
0A1H, 0D2H
|
.byte 000H, 0A6H, 004H
|
.byte 000H, 0AAH, 076H
|
.byte 000H, 0AFH, 027H
|
.byte 000H, 0B4H, 01CH
|
.byte 000H, 0B9H, 05BH
|
.byte 000H, 0BEH, 0EBH
|
.byte 000H, 0C4H, 0D3H
|
.byte 000H, 0CBH, 01BH
|
.byte 000H, 0D1H, 0CDH
|
.byte 000H, 0D8H, 0F4H
|
.byte 000H, 0E0H, 09CH
|
.byte 001H, 005H, 05DH
|
.byte 001H, 00EH, 035H
|
.byte 001H, 017H, 0ABH
|
.byte 001H, 021H, 0D2H
|
.byte 001H, 320H, 0BBH
|
.byte 001H, 138H, 060H
|
.byte 001H, 045H, 03AH
|
.byte 001H, 053H, 008H
|
.byte 001H, 062H, 010H
|
.byte 001H, 072H, 07DH
|
.byte 001H, 084H, 083H
|
.byte 001H, 098H, 061H
|
.byte 001H, 0AEH, 064H
|
.byte 001H, 0C6H, 0E8H
|
.byte 001H, 0E2H, 062H
|
.byte 002H, 001H, 065H
|
.byte 002H, 024H, 0AAH
|
.byte 002H, 04DH, 024H
|
.byte 002H, 07CH, 010H
|
.byte 002H, 0B3H, 01BH
|
.byte 002H, 0F4H, 094H
|
.byte 003H, 043H, 0C1H
|
.byte 003H, 0A5H, 071H
|
.byte 004H, 020H, 0FCH
|
.byte 004H, 0C2H, 038H
|
.byte 005H, 09DH, 080H
|
.byte 013H, 012H, 0D0H
|
f_63:
.byte 013H, 012H, 0D0H
|
SIM_TABLE:
|
.WORD 00000H
; Numbers set to zero (proprietary table)
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
.WORD 00000H
|
SPEED_TABLE_50:
|
.BYTE 40
|
.BYTE 34
|
.BYTE 30
|
.BYTE 26
|
.BYTE 27
|
.BYTE 25
|
.BYTE 24
|
.BYTE 23
|
.BYTE 21
|
.BYTE 20
|
.BYTE 17
|
.BYTE 16
|
.BYTE 15
|
.BYTE 13
|
.BYTE 12
|
.BYTE 10
|
.BYTE
8
|
.BYTE 6
|
SPEED_TABLE_60:
|
.BYTE 33
|
.BYTE 29
|
.BYTE 27
|
.BYTE 25
|
.BYTE 23
|
.BYTE 22
|
.BYTE 21
|
.BYTE 20
|
.BYTE 19
|
.BYTE 18
|
.BYTE 17
|
.BYTE 16
|
.BYTE 15
|
.BYTE 13
|
.BYTE 12
|
.BYTE 11
|
.BYTE 10
|
.BYTE 8
|
.BYTE 7
|
.BYTE 5
|
.BYTE 0
|
; Fill 49 bytes of unused memory
|
FILL 10
|
FILL 10
|
FILL 10
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
FILL
|
.end
|
|
Claims
- 1. A movable barrier operator operable from alternating current comprising:
an electric motor; a transmission connected to the motor to be driven thereby and to the movable barrier to be moved; an electric circuit for detecting AC line voltage and frequency of the alternating current; a worklight; a first set of operational values for operating the worklight, when a first AC line frequency is detected; a second set of operational values for operating the worklight, when a second AC line frequency is detected; and a controller, responsive to the detected AC line frequency, for activating the corresponding operational set of values for operating the worklight.
- 2. A movable barrier operator operable from alternating current according to claim 1 wherein the first AC line frequency comprises 50 Hz and the first set of values comprises a first shut-off time and the second AC line frequency comprises 60 Hz and the second set of values comprises a second shut-off time.
- 3. A movable barrier operator operable from alternating current according to claim 2 further comprising a routine for controlling motor speed and wherein the first set of values further comprises a scaling factor for scaling the motor speed.
- 4. A movable barrier operator operable from alternating current according to claim 3 wherein the scaling factor is stored in a look-up table stored in a memory.
- 5. A movable barrier operator operable from alternating current according to claim 2 wherein the first shut-off time comprises about two and one half minutes and wherein the second shut-off time comprises about four and one half minutes.
- 6. A movable barrier operator having linearly variable output speed, comprising:
an electric motor having a motor output shaft; a transmission connected to the motor output shaft to be driven thereby and to the movable barrier to be moved; a circuit for providing a pulse signal comprising a series of pulses; a motor control circuit responsive to the pulse signal, for starting the motor and for determining the direction of rotation of the motor output shaft; and a controller for controlling the length of the pulses in the pulse signal in accordance with a predetermined set of values, wherein in accordance with the predetermined set of values, a speed of the motor is linearly varied from zero to a maximum speed and from the maximum speed to zero.
- 7. A movable barrier operator according to claim 6 wherein the predetermined set of values causes incrementing of the motor speed from zero to a maximum motor speed in a plurality of steps, causing the motor to operate at the maximum speed for a predetermined period of time, then decrementing the motor speed from the maximum speed to zero in a plurality of steps.
- 8. A movable barrier operator according to claim 7 wherein each step comprises a value corresponding to about five percent of a maximum speed of the motor.
- 9. A moveable barrier operator according to claim 6 wherein the motor control circuit comprises:
a first electromechanical switch for causing the motor output shaft to rotate in a first direction; a second electromechanical switch for causing the motor output shaft to rotate in a second direction; and a solid state device responsive to the pulse signal, for providing current to the motor to cause it to rotate.
- 10. A movable barrier operator according to claim 9 wherein the first and second electromechanical switches comprise relays and the solid state device comprises an FET.
- 11. A movable barrier operator which automatically detects barrier size, comprising:
an electric motor having a maximum output speed; a transmission connected to the motor to be driven thereby and to the movable barrier to be moved; a position detector for sensing the position of the barrier with respect to a frame of reference; and a controller, responsive to the position detector, for calculating a time of travel between a first barrier travel limit and a second barrier travel limit and responsive to the calculated time of barrier travel, for automatically adjusting a barrier travel speed.
- 12. A movable barrier operator according to claim 11 wherein the barrier comprises a segmented panel door and wherein the controller adjusts the barrier travel speed such that a maximum barrier travel speed is based on one hundred percent of the motor's maximum output speed.
- 13. A movable barrier operator according to claim 11 wherein the barrier comprises a single panel door and wherein the controller adjusts the barrier travel speed such that a maximum barrier travel speed is based on percentage less than one hundred percent of the motor's maximum output speed.
- 14. A movable barrier operator according to claim 12 further comprising a routine for varying the motor speed in accordance with a predetermined set of values, wherein in accordance with the predetermined set of values, a speed of the motor is linearly varied from zero to a maximum speed and from the maximum speed to zero.
- 15. A movable barrier operator according to claim 13 further comprising a routine for varying the motor speed in accordance with a predetermined set of values, wherein in accordance with the predetermined set of values, a speed of the motor speed is linearly varied from zero to the motor's scaled output speed and from the motor's scaled output speed to zero.
- 16. A movable barrier operator having full closure, comprising:
an electric motor; a transmission connected to the motor to be driven thereby and connectable to a movable barrier to be moved; a position detector for sensing a position of the barrier; a learn routine for determining a minimum reversal position of the barrier relative to a close limit, wherein the minimum reversal position of the barrier position is located a short distance above the close limit; a controller responsive to the position detector and to a close command to move the barrier to the close limit, for controlling the motor, wherein when the position detector senses the position of the barrier at the minimum reversal position, the controller causes the motor to continue to operate for a predetermined period of time prior to shutting off the motor, effective for driving the barrier to the close limit.
- 17. A movable barrier operator according to claim 16 wherein the electric motor comprises a DC motor.
- 18. A movable barrier operator according to claim 16 wherein the electric motor comprises an AC motor.
- 19. A movable barrier operator according to claim 16 wherein the minimum reversal position is located approximately one inch above the close limit.
- 20. A movable barrier operator according to claim 16 wherein the close limit corresponds to a location of a floor.
- 21. A movable barrier operator having automatic force settings, comprising:
an electric motor; a transmission connected to the motor to be driven thereby and connectable to the movable barrier to be moved; a circuit for providing a pulse signal comprising a series of pulses; a motor control circuit, responsive to the pulse signal, for starting the motor and for determining the direction of rotation of the motor output shaft; a first force command device for setting a first force limit for use when the motor is rotating in a first direction; a second force command device for setting a second force limit for use when the motor is rotating in a second direction; and a controller responsive to the first force limit and to the second force limit for varying the length of the pulses in the pulse signal, effective for varying the motor speed during travel in the first direction and in the second direction.
- 22. A movable barrier operator according to claim 21 wherein the barrier comprises a door having a pedestrian door and the operator further comprises a sensor for detecting the position of the pedestrian door, wherein the controller, responsive to the pedestrian door sensor detecting the pedestrian door is not closed, disables movement of the barrier.
- 23. A moveable barrier operator according to claim 21 wherein the motor control circuit comprises a first electromechanical switch for causing the motor output shaft to rotate in the first direction, a second electromechanical switch for causing the motor output shaft to rotate in the second direction and a solid state device responsive to the pulse signal, for providing current to the motor to cause it to rotate.
- 24. A movable barrier operator according to claim 21 wherein the first force command device comprises a force potentiometer for generating a first analog force signal and the second force command device comprises a force potentiometer for generating a second analog force signal.
- 25. A movable barrier operator according to claim 24 further comprising a first A/D converter for converting the first analog signal to a first digital signal and a second A/D converter for converting the second analog signal to a second digital signal.
- 26. A movable barrier operator according to claim 25 further comprising a look-up table comprising a plurality of motor speeds stored in a memory in the controller, wherein responsive to the first digital signal and the second digital signal selects a corresponding motor speed stored in the look-up table.
- 27. A movable barrier operator having a flasher module, comprising:
an electric motor; a transmission connected to the motor to be driven thereby and connectable to a movable barrier to be moved; a flasher module light; a flasher routine for enabling and disabling the flasher module light in a predetermined pattern; a controller, responsive to a command to move the barrier, for controlling the motor and for automatically detecting the presence of the flasher module light, wherein responsive only to the presence of the flasher module light, the controller executes the flasher routine and delays starting the motor for a predetermined delay time.
- 28. A movable barrier operator according to claim 27, wherein the flasher routine continues until the controller causes the motor to stop.
- 29. A movable barrier operator according to claim 27 wherein the predetermined delay time comprises about two seconds.
- 30. A movable barrier operator according to claim 27, wherein the flasher routine continues only during the predetermined delay period.
Divisions (1)
|
Number |
Date |
Country |
Parent |
09161840 |
Sep 1998 |
US |
Child |
09536833 |
Mar 2000 |
US |
Continuations (1)
|
Number |
Date |
Country |
Parent |
09536833 |
Mar 2000 |
US |
Child |
09785619 |
Feb 2001 |
US |