📄 head_control_module.asm
字号:
; $Id: head_control_module.asm,v 1.10 2003/10/15 06:03:35 dwalters Exp $; Copyright (C) 2003 Dafydd Walters <dwalters@users.sourceforge.net>;; This program is free software; you can redistribute it and/or modify; it under the terms of the GNU General Public License as published by; the Free Software Foundation; either version 2 of the License, or; (at your option) any later version.;; This program is distributed in the hope that it will be useful,; but WITHOUT ANY WARRANTY; without even the implied warranty of; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License; along with this program (COPYING.SOFTWARE); if not, write to the ; Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, ; MA 02111-1307 USA; ---------------------------------------------------------------------- title "head_control_module.asm - OAP Head Control Module" processor pic16f819 list r=dec ; set radix to decimal include "p16f819.inc"; ----------------------------------------------------------------------; Analog Inputs; AN0 - Eltec 442-3 infrared body-heat detector;; Digital Outputs:; RA2 - Pan RC Servo PWM signal; RB2 - Tilt RC Servo PWM signal; ; I2C (initially inputs):; RB4 - SCL; RB1 - SDA;; Not Used:; RA1; RA3; RA4; RA5; RA6; RA7; RB0; RB3; RB5; RB6; RB7; RC PWM:;; The PWM drive for RC servos has on on-time of between 500us and 2500us, ; repeated at 20ms intervals.;;; Timers:;; TMR1 is used in conjuncton with the CCP Compare mode for timing the 500us ; "always on" period at the start of the PWM cycle, and TMR1 overflow is used; for timing the end of the 20ms repeat period.;; TMR0 is used for timing the remaining on-time of the Pan RC Servo output.;; TMR2 is used for timing the remaining on-time of the Tilt RC Servo output.; I2C and SMBus:; ; The SMBus protocol commands are handled entirely in the interrupt handling; code. The Head Control Module appears as a slave device on the I2C bus.; Each time an I2C interrupt is detected, the interrupt handler code; determines which of the following 5 states the I2C interface is in:; ; - State1: Host wants to write (send) a byte to us, and has just sent us ; our device address. In this state, we must read (and discard) the; address from the receive buffer. The device does not need to take; any further action in response to this state. We should be seeing; State2 next.;; - State2: Host has just finished sending a byte to us. We must read the data; byte from the receive buffer, and act on it (what we do at this; point depends on whether we were expecting a command byte from the; host, or whether we had already recevied that, and are now waiting; for data from the host).;; - State3: Host wants to read a byte from us, and has just sent us our device; address. We must first read the address, and then write a byte to; the buffer (this would typically be a response to host's request; for data).;; - State4: Host has just read a byte from us, and is now expecting us to send; another byte. This state is for transfers of more than one byte; This state should never occur in this application. However, if we; ever find ourselves in this state, we're obliged to send dummy ; data to the host to satisfy protocol requirements.;; - State5: Host has just read a byte from us, and does NOT expect us to send; any more. The device does not need to do anything in response to; this state.;; The interrupt handler also keeps track of which of three states the SMBus; transfers are in as follows:;; - State 0: Waiting for a command byte from the host.;; - State 1: Transferring a data byte (either reading or writing) to/from host.;; - State 2: Transferring a second data byte (either reading or writing) ; to/from host.;; We can sometimes set the SMBus state according to which state the I2C ; interface is in. For example, in response to I2C State1 or State5, we know; that the next byte we receive from the host should be a SMBus command, so we; set the SMBus state to 0.;; See the README document for more information on the SMBus commands that; are implemented by this device.; ; ----------------------------------------------------------------------; Constants#define SERVO_CONTROL_PERIOD_MICROSECOND (20000-11) ; Adjusted for latency#define SERVO_ALWAYS_ON_TIME_MICROSECOND (500-35) ; Adjusted for latency#define MAX_CHANGE_PER_PERIOD_EE_ADDR 0#define IR_SENSOR_NEUTRAL_EE_ADDR 1#define IR_TRIGGER_THRESHOLD_EE_ADDR 2#define IR_TRIGGERED_EVENT_MODE_EE_ADDR 3#define CHECK_VALUE_EE_ADDR 4#define I2C_ADDRESS 88#define PAN_SERVO PORTA,2#define TILT_SERVO PORTB,2; SMBus commands from Host:#define READ_PAN_SERVO_SETPOINT_COMMAND 1 ; SMBus Read Byte#define READ_PAN_SERVO_ACTUAL_COMMAND 2 ; SMBus Read Word#define READ_TILT_SERVO_SETPOINT_COMMAND 3 ; SMBus Read Byte#define READ_TILT_SERVO_ACTUAL_COMMAND 4 ; SMBus Read Word#define READ_MAX_CHANGE_PER_PERIOD 5 ; SMBus Read Byte#define READ_RAW_ANALOG_IR_SENSOR 6 ; SMBus Read Byte#define READ_IR_SENSOR_NEUTRAL_VALUE 7 ; SMBus Read Byte#define READ_IR_SENSOR_TRIGGER_THRESHOLD 8 ; SMBus Read Byte#define READ_IR_EVENT_PAN_ACTUAL 9 ; SMBus Read Byte#define READ_IR_EVENT_STATUS 10 ; SMBus Read Byte#define READ_IR_EVENT_MODE 11 ; SMBus Read Byte#define READ_IR_EVENT_ANALOG 12 ; SMBus Read Byte#define READ_IR_EVENT_TIMER_COUNT 13 ; SMBus Read Byte#define READ_CURRENT_TIMER_COUNT_COMMAND 14 ; SMBus Read Byte#define READ_PWM_OUTPUT_STATUS_COMMAND 15 ; SMBus Read Byte#define WRITE_PAN_SERVO_SETPOINT_COMMAND 100 ; SMBus Write Byte#define WRITE_TILT_SETPOINT_COMMAND 101 ; SMBus Write Byte#define WRITE_MAX_CHANGE_PER_PERIOD 102 ; SMBus Write Byte#define WRITE_IR_SENSOR_NEUTRAL_VALUE 103 ; SMBus Write Byte#define WRITE_IR_TRIGGER_THRESHOLD 104 ; SMBus Write Byte#define RESET_IR_TRIGGERED_EVENT_COMMAND 105 ; SMBus Send Byte#define WRITE_IR_EVENT_MODE_COMMAND 106 ; SMBus Write Byte#define RESET_TIMER_COUNT_COMMAND 107 ; SMBus Send Byte#define ENABLE_PWM_OUTPUT_COMMAND 108 ; SMBus Send Byte#define DISABLE_PWM_OUTPUT_COMMAND 109 ; SMBus Send Byte; ----------------------------------------------------------------------; Variable Declarations (GPR) starting at data address 0x020 cblock 0x020MaxChangePerPeriod ; Maximum PWM drive change per 20ms periodIRSensorNeutral ; Expected nominal ADC value of IR sensorIRSensorTriggerThreshold ; Trigger deviation from IRSensorNeutralIRTriggeredEventMode ; The capture mode for IR eventsRawAnalogIR ; ADC bitcount read from IR sensorTimer ; Free running 8-bit up timer counter (20ms)IRTriggeredEventStatus ; 0 = no IR event stored, 1 = IR event storedIRTriggeredEventLocked ; 0 = not locked, 1 = lockedIRTriggeredEventADC ; Analog bitcount of stored IR eventIRTriggeredEventTimer ; Timer count of stored IR eventIRTriggeredEventPan ; Pan actual driven position of stored IR eventIRTriggeredEventMaxThreshold ; Maximum threshold of stored eventIRDeviationFromNeutral ; temp value of ir-threshold diffPanSetpoint ; Current Pan servo setpoint (target position)TiltSetpoint ; Current Tilt servo setpoint (target position)PanActual ; Current Pan servo actual driven positionTiltActual ; Current Tilt servo actual driven positionSMBusCommand ; Most recent SMBus command from hostSMBusState ; Current SMBus state (see comments above)SecondDataByte ; Value of 2nd data byte for Read Word (SMBus)I2CRxByte ; Most recent I2C byte received from hostSspStatSaved ; Temporary variable to hold SSPSTAT registerSavedW ; Variable to hold saved register during ISRSavedStatus ; Variable to hold saved register during ISRSavedFSR ; Variable to hold saved register during ISRSavedPCLATH ; Variable to hold saved register during ISR endc; ----------------------------------------------------------------------; Configuration bits: ;; - Flash Code Protection off; - CCP1 on RB3; - In-circuit Debugger disabled; - Flash program memory write enable off; - EE Code Protection off; - Low Voltage Programming Enable off, RB3 is I/O; - Brown-out Reset Enable on; - RA5/MCLR pin function is digital I/O; - Power-Up Timer on; - Watchdog Timer off; - Oscillator: INTRC, port I/O function of RA6 and RA7 __CONFIG _CP_OFF & _CCP1_RB3 & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _MCLR_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_IO; ----------------------------------------------------------------------; Program entry point at device reset org 0 goto MainStart; ----------------------------------------------------------------------; Interrupt Handler entry point org 4 btfss INTCON,TMR0IF goto NotTimer0 btfss INTCON,TMR0IE goto NotTimer0; Timer 0 bcf INTCON,TMR0IE ; Disable Timer 0 interrupt bcf PAN_SERVO ; Pan servo signal LOW goto FinishISRNotTimer0 btfss PIR1,TMR2IF ; Timer 2 ? goto NotTimer2 bsf STATUS,RP0 btfss PIE1^0x080,TMR2IE goto NotTimer2; Timer 2 bcf PIE1^0x080,TMR2IE ; Disable Timer 2 interrupt bcf STATUS,RP0 bcf TILT_SERVO ; Turn Tilt servo signal LOW goto FinishISRNotTimer2 bcf STATUS,RP0 btfss PIR1,TMR1IF goto NotTimer1 bsf STATUS,RP0 btfss PIE1^0x080,TMR1IE goto NotTimer1; Timer 1 bcf STATUS,RP0 bcf PIR1,TMR1IF ; TMR1 interrupt call StartPWMCycle call UpdateActuals call SenseIR incf Timer,f ; Increment free running timer goto FinishISRNotTimer1 bcf STATUS,RP0 btfss PIR1,CCP1IF ; Compare interrupt? goto NotCCP bsf STATUS,RP0 btfss PIE1^0x080,CCP1IE goto NotCCP; CCP interrupt bcf PIE1^0x080,CCP1IE ; Disable CCP interrupt bcf STATUS,RP0 movf PanActual,w btfsc STATUS,Z movlw 1 ; 1 is lower limit sublw 0 movwf TMR0 bcf INTCON,TMR0IF ; Clear interrupt flag movf TiltActual,w btfsc STATUS,Z movlw 1 ; 1 is lower limit bsf STATUS,RP0 movwf PR2^0x080 bsf PIE1^0x080,TMR2IE ; Enable TMR2 interrupt bcf STATUS,RP0 clrf TMR2 bcf PIR1,TMR2IF ; Make sure flag is clear bsf INTCON,TMR0IE ; Enable TMR0 interrupt goto FinishISRNotCCP bcf STATUS,RP0 btfss PIR1,SSPIF goto FinishISR ; Not I2C; I2C bcf PIR1,SSPIF ; Clear interrupt flag btfsc SSPCON,SSPOV ; Check overflow bit bcf SSPCON,SSPOV ; Make sure overflow bit is clear bsf STATUS,RP0 ; Select Page 1 movf SSPSTAT^0x080,w ; Get I2C status (SSPSTAT register) bcf STATUS,RP0 ; Back to page 0 andlw b'00101101' ; Mask for interesting bits in SSPSTAT movwf SspStatSaved ; Save the result in a variable movlw b'00001001' subwf SspStatSaved,w btfss STATUS,Z ; Is it I2C State 1 (Write, last byte address)? goto I2CNotState1; Write, last byte is address (I2C State 1) movf SSPBUF,w ; Read receive buffer byte (clear BF) movwf I2CRxByte ; Save received byte clrf SMBusState ; Expecting SMBus command code next goto FinishISR ; Nothing more to do in this stateI2CNotState1 movlw b'00101001' ; Is it I2C State 2 (Write, last byte data)? subwf SspStatSaved,w btfss STATUS,Z goto I2CNotState2 ; No; Write, last byte data (I2C State 2) movf SSPBUF,w ; Read receive buffer byte (clear BF) movwf I2CRxByte ; Save received byte movlw HIGH($+4) movwf PCLATH movf SMBusState,w addwf PCL,f ; Jump table for SMBus state goto I2CState2SMBusState0 goto I2CState2SMBusState1 goto I2CState2SMBusState2 IF ((HIGH($)) != (HIGH($-3))) ERROR("Table crosses page boundary!") ENDIFI2CState2SMBusState0 ; SMBus State 0 (expecting command byte next) movf I2CRxByte,w movwf SMBusCommand ; Save SMBus command code sublw RESET_IR_TRIGGERED_EVENT_COMMAND btfss STATUS,Z goto NotResetEvent; Reset IR event call ResetEvent clrf SMBusState goto FinishISRNotResetEvent movf SMBusCommand,w sublw RESET_TIMER_COUNT_COMMAND btfss STATUS,Z goto NotZeroTimer; Zero Timer clrf Timer clrf SMBusState goto FinishISRNotZeroTimer movf SMBusCommand,w sublw ENABLE_PWM_OUTPUT_COMMAND btfss STATUS,Z goto NotEnablePWM; Enable PWM Output bsf STATUS,RP0 bsf PIE1^0x080,TMR1IE ; Enable timer 1 overflow interrupt bcf STATUS,RP0 bcf PIR1,TMR1IF clrf SMBusState goto FinishISRNotEnablePWM movf SMBusCommand,w sublw DISABLE_PWM_OUTPUT_COMMAND btfss STATUS,Z goto NotDisablePWM; Disable PWM Output bsf STATUS,RP0 bcf PIE1^0x080,TMR1IE ; Disable timer 1 overflow interrupt bcf STATUS,RP0 clrf SMBusState goto FinishISRNotDisablePWM movlw 1 movwf SMBusState ; Next SMBus state = 1 goto FinishISRI2CState2SMBusState1 movf SMBusCommand,w sublw WRITE_PAN_SERVO_SETPOINT_COMMAND btfss STATUS,Z ; Is this command 100? goto NotWritePanSetpoint ; No; Write Pan setpoint movf I2CRxByte,w movwf PanSetpoint clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWritePanSetpoint movf SMBusCommand,w sublw WRITE_TILT_SETPOINT_COMMAND btfss STATUS,Z goto NotWriteTiltSetpoint; Write Tilt setpoint movf I2CRxByte,w movwf TiltSetpoint clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWriteTiltSetpoint movf SMBusCommand,w sublw WRITE_MAX_CHANGE_PER_PERIOD btfss STATUS,Z goto NotWriteMaxChangePerPeriod; Write Max Change per Period setting movf I2CRxByte,w movwf MaxChangePerPeriod call WriteMaxChangePerPeriodEeprom clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWriteMaxChangePerPeriod movf SMBusCommand,w sublw WRITE_IR_SENSOR_NEUTRAL_VALUE btfss STATUS,Z goto NotWriteIRSensorNeutral; Write IR Sensor Neutral setting movf I2CRxByte,w movwf IRSensorNeutral call WriteIRSensorNeutralEeprom clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWriteIRSensorNeutral movf SMBusCommand,w sublw WRITE_IR_TRIGGER_THRESHOLD btfss STATUS,Z goto NotWriteIRSensorTriggerThreshold; Write IR Sensor Trigger Threshold setting movf I2CRxByte,w movwf IRSensorTriggerThreshold call WriteIRTriggerThresholdEeprom clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWriteIRSensorTriggerThreshold movf SMBusCommand,w sublw WRITE_IR_EVENT_MODE_COMMAND btfss STATUS,Z goto NotWriteIRTriggeredEventMode; Write IR Triggered Event Mode setting movf I2CRxByte,w movwf IRTriggeredEventMode call WriteIRTriggeredEventModeEeprom clrf SMBusState ; Expecting SMBus command code byte next goto FinishISRNotWriteIRTriggeredEventMode goto FinishISRI2CState2SMBusState2 ; Second data byte goto FinishISR ; Shouldn't be hereI2CNotState2 movlw b'00001100' ; I2C state 3 (Read, last byte address)? subwf SspStatSaved,w btfss STATUS,Z goto I2CNotState3 ; No; Read, last byte address (I2C State 3) movlw HIGH($+4) movwf PCLATH movf SMBusState,w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -