📄 motor_control_module.asm
字号:
; $Id: motor_control_module.asm,v 1.5 2003/10/08 02:45:20 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 "motor_control_module.asm - OAP Motor Control Module" processor pic16f876 list r=dec ; set radix to decimal include "p16f876.inc"; ----------------------------------------------------------------------; Digital Inputs:; RB0 - Right quadrature encoder A channel; RB7 - Left quadrature encoder A channel; RC5 - Right quadrature encoder B channel; RC6 - Left quadrature encoder B channel;; Digital Outputs:; RA2 - LMD18200 'pwm' signals; RA3 - LMD18200 'brake' signals; RC1/CCP2 - Left LMD18200 'direction' signal; RC2/CCP1 - Right LMD18200 'direction' signal; ; I2C (initially inputs):; RC3 - SCL; RC4 - SDA;; Not Used:; RA0; RA1; RA4; RA5; RB1; RB2; BR3; RB4; RB5; RB6; RC0; RC7;;; I2C and SMBus:; ; The SMBus protocol commands are handled entirely in the interrupt handling; code. The Motor 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;; - 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, or the; first data byte in a 'Write Word Data'/'Read Word 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.;; - State 6: Transferring fourth data byte in a 'Block Read' sequence.;; - State 7: Transferring fifth data byte in a 'Block Read' sequence.;; - State 8: Transferring second data byte in a 'Write Word Data' or; 'Read Word Data' 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 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:;; - TMR1 is used for driving the 8-bit free-running up counter; - TMR2 is used for PWM output;; ----------------------------------------------------------------------; Constants#define I2C_ADDRESS 89#define ENCODER_MASK_EE_ADDR 0#define RIGHT_ENCODER_A PORTB,0#define RIGHT_B 5 ; Port C bit number only#define LEFT_ENCODER_A PORTB,7#define LEFT_B 6 ; Port C bit number only#define PWM PORTA,2#define BRAKE PORTA,3#define LEFT_DIR PORTC,1#define RIGHT_DIR PORTC,2; SMBus commands from Host:#define GET_ODOMETRY_COMMAND 20 ; SMBus: Block Read #define GET_OUTPUT_STATE_COMMAND 21 ; SMBus: Read Byte Data #define GET_PWM_COMMAND 22 ; SMBus: Read Word Data#define GET_TIMER_COMMAND 23 ; SMBus: Read Byte Data #define GET_ENCODER_MASK_COMMAND 24 ; SMBus: Read Byte Data#define WRITE_PWM_COMMAND 120 ; SMBus: Write Word Data#define ACTIVATE_OUTPUT_COMMAND 121 ; SMBus: Send Byte#define DEACTIVATE_OUTPUT_COMMAND 122 ; SMBus: Send Byte#define ZERO_TIMER_COMMAND 123 ; SMBus: Send Byte#define WRITE_ENCODER_MASK_COMMAND 124 ; SMBus: Write Byte Data; ----------------------------------------------------------------------; Variable Declarations (GPR) starting at data address 0x020 cblock 0x020Timer ; Up counterLeftCounterLSB ; Left wheel odometer count least sig. byteLeftCounterMSB ; Left wheel odometer count most sig. byteRightCounterLSB ; Right wheel odometer count least sig. byteRightCounterMSB ; Right wheel odometer count most sig. byteSMBusCommand ; Most recent SMBus command from hostSMBusState ; Current SMBus state (see comments above)I2CDataBuffer0 ; 1st data byte of current data block transferI2CDataBuffer1 ; 2nd data byte of current data block transferI2CDataBuffer2 ; 3rd data byte of current data block transferI2CDataBuffer3 ; 4th data byte of current data block transferI2CDataBuffer4 ; 5th data byte of current data block transferI2CRxByte ; Most recent I2C byte received from hostSspStatSaved ; Temporary variable to hold SSPSTAT registerOutputState ; Output mode: 0=low power, 1=activePortCTemp ; Temporary variable to hold Port C valueEncoderMask ; Port C mask byte 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: HS (high speed) __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_ON & _PWRTE_ON & _WDT_OFF & _HS_OSC; ----------------------------------------------------------------------; Program entry point at device reset org 0 goto MainStart; ----------------------------------------------------------------------; Interrupt Handler entry point org 4 btfss INTCON,RBIF ; Has Left encoder A state gone Low to High? goto NotPortBChange; Left quadrature encoder A channel went Low to High movf PORTB,w ; Read Port B to clear interrupt condition bcf INTCON,RBIF ; Clear interrupt flag movf PORTC,w xorwf EncoderMask,w movwf PortCTemp ; Save Port C value ASAP btfss PortCTemp,LEFT_B ; B channel high? goto LeftBLow ; No; Left quadrature encoder B channel is High movf LeftCounterLSB,f btfsc STATUS,Z decf LeftCounterMSB,f decf LeftCounterLSB,f ; Decrement 16-bit counter goto FinishISRLeftBLow; Left quadrature encoder B channel is Low incf LeftCounterLSB,f ; Increment 16-bit counter btfsc STATUS,Z incf LeftCounterMSB,f goto FinishISRNotPortBChange btfss INTCON,INTF ; Right A channel gone high? goto NotIntPin; Right quadrature encoder A channel has gone Low to High bcf INTCON,INTF ; Clear interrupt flag movf PORTC,w xorwf EncoderMask,w movwf PortCTemp ; Save Port C value ASAP btfss PortCTemp,RIGHT_B ; B channel high? goto RightBLow ; No; Right quadrature encoder B channel is High movf RightCounterLSB,f btfsc STATUS,Z decf RightCounterMSB,f decf RightCounterLSB,f ; Decrement 16-bit counter goto FinishISRRightBLow; Right quadrature encoder B channel is Low incf RightCounterLSB,f ; Increment 16-bit counter btfsc STATUS,Z incf RightCounterMSB,f goto FinishISRNotIntPin btfss PIR1,TMR1IF ; Timer 1 ? goto NotTimer1; Timer 1 bcf PIR1,TMR1IF ; Clear Timer 1 interrupt flag incf Timer,f ; Increment timer count goto FinishISR NotTimer1 btfss PIR1,SSPIF goto FinishISR; 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 goto I2CState2SMBusState3 goto I2CState2SMBusState4 goto I2CState2SMBusState5 goto I2CState2SMBusState6 goto I2CState2SMBusState7 goto I2CState2SMBusState8 IF ((HIGH($)) != (HIGH($-10))) ERROR("Table crosses page boundary!") ENDIFI2CState2SMBusState0 ; SMBus State 0 (expecting command byte next) movf I2CRxByte,w movwf SMBusCommand ; Save SMBus command code sublw ACTIVATE_OUTPUT_COMMAND btfss STATUS,Z goto NotActivateOutput; Activate Output command (Send Byte) bsf OutputState,0 bsf PWM bcf BRAKE clrf TMR2 movlw b'00001100' ; PWM mode movwf CCP1CON movwf CCP2CON clrf SMBusState goto FinishISRNotActivateOutput movf SMBusCommand,w sublw DEACTIVATE_OUTPUT_COMMAND btfss STATUS,Z goto NotDeActivateOutput; Deactivate output Command (Send Byte) clrf OutputState bcf PWM bsf BRAKE clrf CCP1CON clrf CCP2CON bcf LEFT_DIR bcf RIGHT_DIR clrf SMBusState goto FinishISRNotDeActivateOutput movf SMBusCommand,w sublw ZERO_TIMER_COMMAND btfss STATUS,Z goto NotZeroTimer; Zero Timer clrf Timer clrf SMBusState goto FinishISRNotZeroTimer movf SMBusCommand,w sublw GET_ODOMETRY_COMMAND btfss STATUS,Z goto NotGetOdometryCommand; Get odometry command movlw 2 movwf SMBusState ; Next SMBus state = 2 goto FinishISRNotGetOdometryCommand movlw 1 movwf SMBusState ; Next SMBus state = 1 goto FinishISRI2CState2SMBusState1 ; SMBus state 1 (transferring data byte) movf SMBusCommand,w sublw WRITE_PWM_COMMAND btfss STATUS,Z goto NotWritePWM; First data byte of Write PWM command movf I2CRxByte,w movwf I2CDataBuffer0 ; Cache the Left PWM command movlw 8 movwf SMBusState ; Next SMBus state is 8 (second data byte) goto FinishISRNotWritePWM movf SMBusCommand,w sublw WRITE_ENCODER_MASK_COMMAND btfss STATUS,Z goto NotWriteEncoderMask; Write XOR Encoder Mask movf I2CRxByte,w movwf EncoderMask call WriteEncoderMaskEEPROM clrf SMBusState goto FinishISR NotWriteEncoderMask clrf SMBusState goto FinishISRI2CState2SMBusState2 ; SMBus state 2 (transferring num data bytes) clrf SMBusState goto FinishISRI2CState2SMBusState3 ; SMBus state 3 (1st data byte in block) clrf SMBusState goto FinishISRI2CState2SMBusState4 ; SMBus state 4 (2nd data byte in block) clrf SMBusState
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -