📄 sonar_array_module.asm
字号:
; $Id: sonar_array_module.asm,v 1.11 2003/10/05 05:56:54 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 "sonar_array_module.asm - OAP Sonar Array Module" processor pic16f876 list r=dec ; set radix to decimal include "p16f876.inc"; ----------------------------------------------------------------------; Digital Inputs:; RC1/CCP2 - Sonar echo pulse (capture mode) odd numbered channels; RC2/CCP1 - Sonar echo pulse (capture mode) even numbered channels;; Digital Outputs:; RA0 - channel 1 trigger; RA1 - channel 3 trigger; RA2 - channel 5 trigger; RA3 - channel 7 trigger; RA4 - channel 9 trigger; RA5 - channel 11 trigger; RC5 - channel 13 trigger; RC6 - channel 15 trigger; RB7 - channel 2 trigger; RB6 - channel 4 trigger; RB5 - channel 6 trigger; RB4 - channel 8 trigger; RB3 - channel 10 trigger; RB2 - channel 12 trigger; RB1 - channel 14 trigger; RB0 - channel 16 trigger; ; I2C (initially inputs):; RC3 - SCL; RC4 - SDA;; Not Used:; RC0; RC7;;; I2C and SMBus:; ; The SMBus protocol commands are handled entirely in the interrupt handling; code. The Sonar Array 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;; - 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 the following 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; for a 'Read Byte Data' or 'Write Byte Data' sequence.;; - State 2: Transferring 'number of data bytes' for a 'Block Read' sequence.;; - State 3: Transferring first data byte in a 'Block Read' sequence.;; - State 4: Transferring second data byte in a 'Block Read' sequence.;; - State 5: Transferring third data byte in a 'Block Read' sequence.;; 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 data 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.; ;; Timers:;; - TMR0 is used for the master timer-tick; - TMR1 is used for timing sonar ping returns;; ----------------------------------------------------------------------; Constants#define I2C_ADDRESS 87#define NUM_ENABLED_CHANS_EE_ADDR 0#define CHANNEL_1_TRIGGER PORTA,0#define CHANNEL_3_TRIGGER PORTA,1#define CHANNEL_5_TRIGGER PORTA,2#define CHANNEL_7_TRIGGER PORTA,3#define CHANNEL_9_TRIGGER PORTA,4#define CHANNEL_11_TRIGGER PORTA,5#define CHANNEL_13_TRIGGER PORTC,5#define CHANNEL_15_TRIGGER PORTC,6#define CHANNEL_2_TRIGGER PORTB,7#define CHANNEL_4_TRIGGER PORTB,6#define CHANNEL_6_TRIGGER PORTB,5#define CHANNEL_8_TRIGGER PORTB,4#define CHANNEL_10_TRIGGER PORTB,3#define CHANNEL_12_TRIGGER PORTB,2#define CHANNEL_14_TRIGGER PORTB,1#define CHANNEL_16_TRIGGER PORTB,0; SMBus commands from Host:#define GET_SONAR_READING_COMMAND_MIN 1 ; SMBus: Block Read #define GET_SONAR_READING_COMMAND_MAX 16 #define GET_NUM_SONARS_COMMAND 17 ; SMBus: Read Byte Data #define GET_SONAR_POWER_STATE_COMMAND 18 ; SMBus: Read Byte Data#define SET_NUM_SONARS_COMMAND 100 ; SMBus: Write Byte Data#define SET_TIMER_ZERO_COMMAND 101 ; SMBus: Send Byte#define SET_SONAR_POWER_ON_COMMAND 102 ; SMBus: Send Byte#define SET_SONAR_POWER_OFF_COMMAND 103 ; SMBus: Send Byte; ----------------------------------------------------------------------; Variable Declarations (GPR) starting at data address 0x020 cblock 0x020Counter ; General counter variable used in main threadTimer0 ; Interrupt driven up counter, 25ms periodTimer0tmp ; Temporary variable used with Timer0SMBusCommand ; Most recent SMBus command from hostSMBusState ; Current SMBus state (see comments above)SonarBuffer0 ; 1st data byte of current data block transferSonarBuffer1 ; 2nd data byte of current data block transferSonarBuffer2 ; 3rd data byte of current data block transferI2CRxByte ; 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 ISRCurrentChanM1 ; The current sonar channel in the range 0-15PrevChanM1 ; The previous sonar channel in the range 0-15NumEnabledChans ; Number of sonar sensorsSonarPowerState ; Sonar power 0=low power, 1=active (scanning)SonarDataTable ; The start of a 64-byte block containing ; 16 4-byte structures, one for each sonar ; reading, arranged as follows: ; ; byte 0 - sonar reading low byte ; byte 1 - sonar reading high byte ; byte 2 - timer count ; byte 3 - padding ; No variables after SonarDataTable endc; ----------------------------------------------------------------------; Configuration bits: ;; - Flash program memory code protection: Off; - In-circuit debugger mode: disabled (RB6 and RB7 are I/O); - Flash program memory write enable: Off; - Data EE memory code protection: Off; - Low voltage programming: Off (RB3 is I/O); - Brown-out reset enable bit: Enabled; - Power-up timer enabled: On; - Watchdog timer: Off; - Oscillator: XT (crystal) __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _PWRTE_ON & _WDT_OFF & _XT_OSC; ----------------------------------------------------------------------; Program entry point at device reset org 0 goto MainStart; ----------------------------------------------------------------------; Interrupt Handler entry point org 4 movwf SavedW ; Save W movf STATUS,w bcf STATUS,RP0 ; Make sure we're on Page 0 bcf STATUS,RP1 movwf SavedStatus ; Save STATUS movf FSR,w movwf SavedFSR ; Save FSR movf PCLATH,w movwf SavedPCLATH ; Save PCLATH clrf PCLATH ; Execution page 0 btfss INTCON,T0IF goto NotTimer0; Timer0 bcf INTCON,T0IF ; TMR0 interrupt movlw 256 - 125 movwf TMR0 decf Timer0tmp,f btfss STATUS,Z goto FinishISR movlw 25 movwf Timer0tmp incf Timer0,f ; Increment Timer0 call ProcessTimer goto FinishISRNotTimer0 btfss PIR1,CCP1IF ; CCP1 interrupt? goto NotCCP1; CCP1 Interrupt bcf PIR1,CCP1IF call ProcessCCP1 goto FinishISRNotCCP1 btfss PIR2,CCP2IF ; CCP2 interrupt? goto NotCCP2; CCP2 Interrupt bcf PIR2,CCP2IF call ProcessCCP2 goto FinishISRNotCCP2 btfss PIR1,SSPIF goto FinishISR; I2C bcf PIR1,SSPIF ; Clear interrupt flag call ProcessI2C goto FinishISR goto $ ; Illegal interruptFinishISR movf SavedPCLATH,w movwf PCLATH ; Restore PCLATH movf SavedFSR,w movwf FSR ; Restore FSR movf SavedStatus,w movwf STATUS ; Restore STATUS swapf SavedW,f swapf SavedW,w ; Restore W (without affecting Z,C flags,etc) retfie; ----------------------------------------------------------------------; Main Program start pointMainStart call InitIO ; Initialize IO ports call InitTimer ; Initialize Timer call InitI2C ; Initialize the I2C interface call InitCapture ; Initialize CCP1 and CCP2 call GetNumEnabledChansEEPROM movwf NumEnabledChans call ClearSonarDataTable clrf CurrentChanM1 clrf PrevChanM1 clrf SonarPowerState call InitInterrupts ; Enable interrupts goto $ ; All work done in ISR; ----------------------------------------------------------------------; Subroutines; ----------------------------------------------------------------------ProcessTimer ; Called every 25ms btfss SonarPowerState,0 goto FinishTimer ; Low power mode movf CurrentChanM1,w movwf PrevChanM1 ; Save previous channel incf CurrentChanM1,f ; Next channel movlw b'00001111' ; Make sure value is in range 0-15 andwf CurrentChanM1,f movf NumEnabledChans,w subwf CurrentChanM1,w btfsc STATUS,Z clrf CurrentChanM1 ; Roll channel over to 0 call CheckPingPrevChan ; Check if previous channel echo received movlw HIGH($+4) movwf PCLATH movf CurrentChanM1,w addwf PCL,f ; Jump table goto Sonar1 goto Sonar2 goto Sonar3 goto Sonar4 goto Sonar5 goto Sonar6 goto Sonar7 goto Sonar8 goto Sonar9 goto Sonar10 goto Sonar11 goto Sonar12 goto Sonar13 goto Sonar14 goto Sonar15 goto Sonar16 IF ((HIGH($)) != (HIGH($-16))) ERROR("Table crosses page boundary!") ENDIFSonar1 bsf CHANNEL_1_TRIGGER call Delay10us bcf CHANNEL_1_TRIGGER goto FinishTimerSonar2 bsf CHANNEL_2_TRIGGER call Delay10us bcf CHANNEL_2_TRIGGER goto FinishTimerSonar3 bsf CHANNEL_3_TRIGGER call Delay10us bcf CHANNEL_3_TRIGGER goto FinishTimerSonar4 bsf CHANNEL_4_TRIGGER call Delay10us bcf CHANNEL_4_TRIGGER goto FinishTimerSonar5 bsf CHANNEL_5_TRIGGER call Delay10us bcf CHANNEL_5_TRIGGER goto FinishTimerSonar6 bsf CHANNEL_6_TRIGGER call Delay10us bcf CHANNEL_6_TRIGGER goto FinishTimerSonar7 bsf CHANNEL_7_TRIGGER call Delay10us bcf CHANNEL_7_TRIGGER goto FinishTimerSonar8 bsf CHANNEL_8_TRIGGER call Delay10us bcf CHANNEL_8_TRIGGER goto FinishTimerSonar9 bsf CHANNEL_9_TRIGGER call Delay10us bcf CHANNEL_9_TRIGGER goto FinishTimerSonar10 bsf CHANNEL_10_TRIGGER call Delay10us bcf CHANNEL_10_TRIGGER goto FinishTimerSonar11 bsf CHANNEL_11_TRIGGER call Delay10us bcf CHANNEL_11_TRIGGER goto FinishTimerSonar12 bsf CHANNEL_12_TRIGGER call Delay10us bcf CHANNEL_12_TRIGGER goto FinishTimerSonar13 bsf CHANNEL_13_TRIGGER call Delay10us bcf CHANNEL_13_TRIGGER goto FinishTimerSonar14 bsf CHANNEL_14_TRIGGER call Delay10us bcf CHANNEL_14_TRIGGER goto FinishTimerSonar15 bsf CHANNEL_15_TRIGGER call Delay10us bcf CHANNEL_15_TRIGGER goto FinishTimerSonar16 bsf CHANNEL_16_TRIGGER call Delay10us bcf CHANNEL_16_TRIGGER goto FinishTimerFinishTimer bcf T1CON,TMR1ON ; Stop timer 1 clrf TMR1H clrf TMR1L ; Zero timer 1 bcf PIR1,CCP1IF ; Clear any possible false interrupt. bcf PIR2,CCP2IF ; Clear any possible false interrupt. bsf T1CON,TMR1ON ; Restart timer 1 return; ----------------------------------------------------------------------CheckPingPrevChan movf PrevChanM1,w ; Previous sonar number in range 0 to 15 movwf FSR rlf FSR,f rlf FSR,f ; Multiply by 4 movlw b'11111100' andwf FSR,f ; Make sure 2 LSbits clear movlw (SonarDataTable+2) addwf FSR,f ; Add offset to get Timer value movf INDF,w ; Get timer value of previous channel addlw 1 subwf Timer0,w btfsc STATUS,Z goto EndCheckPing ; We DID receive an echo for prev chan; We've not yet received echo for previous channel! movf Timer0,w movwf INDF decf INDF,f ; Store Timer0-1 for previous channel decf FSR,f clrf INDF ; Store zero reading for previous channel decf FSR,f clrf INDFEndCheckPing return; ----------------------------------------------------------------------ProcessCCP1 btfss SonarPowerState,0 goto FinishCCP1 ; Low power mode btfss CurrentChanM1,0 goto FinishCCP1 ; Out of synch - ignore; Sonars 2,4,6,8,10,12,14,16 movf CurrentChanM1,w ; Sonar number in range 0 to 15 movwf FSR rlf FSR,f rlf FSR,f ; Multiply by 4 movlw b'11111100' andwf FSR,f ; Make sure 2 LSbits clear movlw SonarDataTable addwf FSR,f ; Add to table start address movf CCPR1L,w movwf INDF incf FSR,f movf CCPR1H,w movwf INDF incf FSR,f movf Timer0,w movwf INDFFinishCCP1 return; ----------------------------------------------------------------------ProcessCCP2 btfss SonarPowerState,0 goto FinishCCP2 ; Low power mode btfsc CurrentChanM1,0 goto FinishCCP2 ; Out of sync
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -