ok, based on kevin's response i'm clearly missing something with the interrupts
being called. here's the code
i'm using htis accelerometer
http://www.analog.com/UploadedFiles/...DXL202EB_a.pdf
Code:
/*
*Alpha 1 for accelerometer
* //accelerometer has pwm frequencies of 263.158 Hz (3.8 ms) (we thought)
*
*/
#include "myaccelerometer.h"
#include "ifi_aliases.h"
#include "ifi_default.h"
#include "ifi_picdefs.h"
volatile int xacceleration;
volatile int yacceleration;
unsigned int Clock = 0; // upper 16 bits of the 32 bit system clock
// timer 1 contains the lower 16 bits
// each clock tick is worth 26.21 milliseconds
void Initialize_Accelerometer(void)
{
// initialize and start timer 1
Initialize_Timer_1();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// initialize external interrupts 3-6 (KBI0 - KBI3 on user 18F8520)
TRISBbits.TRISB4 = 1; // make sure RB4/KBI0 is setup as an input [108]
TRISBbits.TRISB5 = 1; // make sure RB5/KBI1 is setup as an input [108]
INTCON2bits.RBIP = 0; // interrupts 3 through 6 will use the low priority interrupt [90]
INTCONbits.RBIE = 1; // enable interrupts 3 through 6 [89]
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
int Get_xAcceleration(void)//called from user level to get current calculated x acceleration value
{
int temp_xacceleration;
//disable timer 1 interrupt
PIE1bits.TMR1IE = 0;
temp_xacceleration = xacceleration;
//timer 1 interrupt back on
PIE1bits.TMR1IE = 1;
// Return the x acceleration to the caller.
return(temp_xacceleration);
}
int Get_yAcceleration(void)//called from user level to get current calculated y acceleration value
{
int temp_yacceleration;
//disable timer 1 interrupt
PIE1bits.TMR1IE = 0;
temp_yacceleration = yacceleration;
//timer 1 interrupt back on
PIE1bits.TMR1IE = 1;
// Return the y acceleration to the caller.
return(temp_yacceleration);
}
void Initialize_Timer_1(void)
{
/////////////////////////////////////////////////////////////////////////////////////////////////////
// initialize and start timer 1
IPR1bits.TMR1IP = 0; // timer 1 will use the low priority interrupt [98]
PIE1bits.TMR1IE = 1; // enable timer1 roll-over interrupt [95]
T1CONbits.RD16 = 1; // use 16-bit read/write operations with timer 1 [135]
T1CONbits.T1CKPS0 = 0; // timer 1 clock will use a 4:1 prescale value [135]
T1CONbits.T1CKPS1 = 1;
T1CONbits.T1OSCEN = 0; // turn-off the timer 1 oscillator to save power [135]
T1CONbits.TMR1CS = 0; // timer 1 will use the internal 10MHz clock [135]
T1CONbits.TMR1ON = 1; // start timer 1 [135]
////////////////////////////////////////////////////////////////////////////////////////////////////
}
void Timer_1_Int_Handler(void)
{
Clock++; // increment the upper 16-bits of the system clock
}
void Int_3_Handler(unsigned char RB4_State) //parts of this provided by K. Watson from JPL who helps out FIRST teams with code
//it appeared as help for pwm input for an infrared tracking device
{
unsigned char tempbuf; // temporary data buffer
unsigned int Int_3_Period; // pulse-width period
unsigned int Int_3_Up_Edge_Count_Low; // lower 16-bits of the rising-edge time snapshot
unsigned int Int_3_Up_Edge_Count_High; // upper 16-bits of the rising-edge time snapshot
static unsigned int Int_3_Down_Edge_Count_Low; // lower 16-bits of the falling-edge time snapshot
static unsigned int Int_3_Down_Edge_Count_High; // upper 16-bits of the falling-edge time snapshot
switch(RB4_State) // current state determines how the function behaves
{
case 0: // falling-edge detected (beginning of the pulse)
Int_3_Down_Edge_Count_High = Clock; // get a snapshot of the time
tempbuf = TMR1L; // TMR1L must be read before TMR1H
Int_3_Down_Edge_Count_Low = TMR1H;
Int_3_Down_Edge_Count_Low <<= 8;
Int_3_Down_Edge_Count_Low += tempbuf;
break; // now wait for the rising-edge interrupt to happen...
case 1: // rising-edge detected (end of the pulse)
Int_3_Up_Edge_Count_High = Clock; // get a snapshot of the time
tempbuf = TMR1L;
Int_3_Up_Edge_Count_Low = TMR1H;
Int_3_Up_Edge_Count_Low <<= 8;
Int_3_Up_Edge_Count_Low += tempbuf;
// determine the pulse-width period by determining the time
// difference between the falling-edge and rising-edge interrupts
if (Int_3_Up_Edge_Count_High == Int_3_Down_Edge_Count_High)
{
// this is quicker because the 16-bit system clock hasn't changed and therefore has no effect on the outcome
Int_3_Period = Int_3_Up_Edge_Count_Low - Int_3_Down_Edge_Count_Low;
}
else
{
//this works because the pulse-width will always be less than one clock tick(= 65536 timer ticks)
//(=0.0000001 seconds) 1 * 10^-7 sec (0.1 micro seconds)
Int_3_Period = 65536 - Int_3_Down_Edge_Count_Low + Int_3_Up_Edge_Count_Low;
}
break; // now wait for another falling-edge interrupt to happen...
}
/*
A(g)=(T1/T2 - 0.5)/0.0125
T2 is set by resistor (1.2 M Ohm resistor yields 9.6 ms T2)
at rest 0g=50% Duty cycle
(Int_3_Period/65536)/26.21 ----> yields Int_3_Period in ms
{[(Int_3_Period in ms)/(9.6 ms T2)]-0.5}/0.0125 -------> yields acceleration in g's
but from what i understand this thing doesn't like floating point numbers
so, plug it into a TI-89 with Int_3 as x, go to approx mode and hit expand
you get this:
(x/206124) - 40
so we will use this instead as its both simpler and only deals with integers
for x's smaller than 500,000 there is essentially no error in using this approx (0.0002 percent)
*/
// xacceleration=(Int_3_Period/206124) - 40; THIS IS THE ONE WE WANT WHEN IT WORKS
// xacceleration=(Int_3_Period); ---------> this doesn't even give me anything (seems that Int_3_Period always remains at 0)
//xacceleration=Int_3_Down_Edge_Count_High; ------>never gets here or at least it says its always 0
//xacceleration=Int_3_Up_Edge_Count_High; ---------> never gets here either
}
//parts of this provided by K. Watson from JPL who helps out FIRST teams with code
//it appeared as help for pwm input for an infrared tracking device
void Int_4_Handler(unsigned char RB5_State)
{
unsigned char tbuf; // temporary data buffer
unsigned int Int_4_Period; // pulse-width period
unsigned int Int_4_Up_Edge_Count_Low; // lower 16-bits of the rising-edge time snapshot
unsigned int Int_4_Up_Edge_Count_High; // upper 16-bits of the rising-edge time snapshot
static unsigned int Int_4_Down_Edge_Count_Low; // lower 16-bits of the falling-edge time snapshot
static unsigned int Int_4_Down_Edge_Count_High; // upper 16-bits of the falling-edge time snapshot
switch(RB5_State) // current state determines how the function behaves
{
case 0: // falling-edge detected (beginning of the pulse)
Int_4_Down_Edge_Count_High = Clock; // get a snapshot of the time
tbuf = TMR1L; // TMR1L must be read before TMR1H
Int_4_Down_Edge_Count_Low = TMR1H;
Int_4_Down_Edge_Count_Low <<= 8;
Int_4_Down_Edge_Count_Low += tbuf;
break; // now wait for the rising-edge interrupt to happen...
case 1: // rising-edge detected (end of the pulse)
Int_4_Up_Edge_Count_High = Clock; // get a snapshot of the time
tbuf = TMR1L;
Int_4_Up_Edge_Count_Low = TMR1H;
Int_4_Up_Edge_Count_Low <<= 8;
Int_4_Up_Edge_Count_Low += tbuf;
// determine the pulse-width period by determining the time
// difference between the falling-edge and rising-edge interrupts
if (Int_4_Up_Edge_Count_High == Int_4_Down_Edge_Count_High)
{
// this is quicker because the 16-bit system clock hasn't changed and therefore has no effect on the outcome
Int_4_Period = Int_4_Up_Edge_Count_Low - Int_4_Down_Edge_Count_Low;
}
else
{
//this works because the pulse-width will always be less than one clock tick(= 65536 timer ticks)
//(=0.0000001 seconds) 1 * 10^-7 sec (0.1 micro seconds)
Int_4_Period = 65536 - Int_4_Down_Edge_Count_Low + Int_4_Up_Edge_Count_Low;
}
break; // now wait for another falling-edge interrupt to happen...
}
/*
A(g)=(T1/T2 - 0.5)/0.0125
T2 is set by resistor (1.2 M Ohm resistor yields 9.6 ms T2)
at rest 0g=50% Duty cycle
(Int_4_Period/65536)*10000 ----> yields Int_4_Period in ms
{[(Int_4_Period in ms)/(9.6 ms T2)]-0.5}/0.0125 -------> yields acceleration in g's
but from what i understand this thing doesn't like floating point numbers
so, plug it into a TI-89 with Int_3 as x, go to approx mode and hit expand
you get this:
(x/206124) - 40
so we will use this instead as its both simpler and only deals with integers
for x's smaller than 500,000 there is essentially no error in using this approx (0.0002 percent)
*/
yacceleration=(Int_4_Period/206124) - 40;
}
Code:
/*
*Alpha 1 for accelerometer
*goal: get any sort of reading off the signal pins
*and print it to the screen so we can see what we are dealing with
*
*/
#ifndef _accelerometer_h
#define _accelerometer_h
void Initialize_Accelerometer(void); // initializes and starts the accelerometer code
int Get_xAcceleration(void); // returns the current measured x acceleration
int Get_yAcceleration(void); // returns the current measured y acceleration
void Initialize_Timer_1(void); // initializes and starts timer 1
void Int_3_Handler(unsigned char); // interrupt 3 routine (x axis) power yellow
void Int_4_Handler(unsigned char); // interrupt 4 routine (y axis) red white
void Timer_1_Int_Handler(void); //timer routine
// some handy macros
#define HIBYTE(value) ((unsigned char)(((unsigned int)(value)>>8)&0xFF))
#define LOBYTE(value) ((unsigned char)(value))
// state machine defines
#define WAITING_FOR_UP_EDGE 0
#define WAITING_FOR_DOWN_EDGE 1
extern unsigned int Clock; //in myaccel.c
#endif
Code:
/*******************************************************************************
* FILE NAME: user_routines.c <FRC VERSION>
*
* DESCRIPTION:
* This file contains the default mappings of inputs
* (like switches, joysticks, and buttons) to outputs on the RC.
*
* USAGE:
* You can either modify this file to fit your needs, or remove it from your
* project and replace it with a modified copy.
*
*******************************************************************************/
#include <stdio.h>
#include "ifi_aliases.h"
#include "ifi_default.h"
#include "ifi_utilities.h"
#include "user_routines.h"
#include "user_Serialdrv.h"
#include "myaccelerometer.h"
/*** DEFINE USER VARIABLES AND INITIALIZE THEM HERE ***/
extern unsigned char aBreakerWasTripped;
/*******************************************************************************
* FUNCTION NAME: Limit_Switch_Max
* PURPOSE: Sets a PWM value to neutral (127) if it exceeds 127 and the
* limit switch is on.
* CALLED FROM: this file
* ARGUMENTS:
* Argument Type IO Description
* -------- ------------- -- -----------
* switch_state unsigned char I limit switch state
* *input_value pointer O points to PWM byte value to be limited
* RETURNS: void
*******************************************************************************/
void Limit_Switch_Max(unsigned char switch_state, unsigned char *input_value)
{
if (switch_state == CLOSED)
{
if(*input_value > 127)
*input_value = 127;
}
}
/*******************************************************************************
* FUNCTION NAME: Limit_Switch_Min
* PURPOSE: Sets a PWM value to neutral (127) if it's less than 127 and the
* limit switch is on.
* CALLED FROM: this file
* ARGUMENTS:
* Argument Type IO Description
* -------- ------------- -- -----------
* switch_state unsigned char I limit switch state
* *input_value pointer O points to PWM byte value to be limited
* RETURNS: void
*******************************************************************************/
void Limit_Switch_Min(unsigned char switch_state, unsigned char *input_value)
{
if (switch_state == CLOSED)
{
if(*input_value < 127)
*input_value = 127;
}
}
/*******************************************************************************
* FUNCTION NAME: Limit_Mix
* PURPOSE: Limits the mixed value for one joystick drive.
* CALLED FROM: Default_Routine, this file
* ARGUMENTS:
* Argument Type IO Description
* -------- ---- -- -----------
* intermediate_value int I
* RETURNS: unsigned char
*******************************************************************************/
unsigned char Limit_Mix (int intermediate_value)
{
static int limited_value;
if (intermediate_value < 2000)
{
limited_value = 2000;
}
else if (intermediate_value > 2254)
{
limited_value = 2254;
}
else
{
limited_value = intermediate_value;
}
return (unsigned char) (limited_value - 2000);
}
/*******************************************************************************
* FUNCTION NAME: User_Initialization
* PURPOSE: This routine is called first (and only once) in the Main function.
* You may modify and add to this function.
* CALLED FROM: main.c
* ARGUMENTS: none
* RETURNS: void
*******************************************************************************/
void User_Initialization (void)
{
Set_Number_of_Analog_Channels(SIXTEEN_ANALOG); /* DO NOT CHANGE! */
/* FIRST: Set up the I/O pins you want to use as digital INPUTS. */
digital_io_01 = digital_io_02 = digital_io_03 = digital_io_04 = INPUT;
digital_io_05 = digital_io_06 = digital_io_07 = digital_io_08 = INPUT;
digital_io_09 = digital_io_10 = digital_io_11 = digital_io_12 = INPUT;
digital_io_13 = digital_io_14 = digital_io_15 = digital_io_16 = INPUT;
digital_io_18 = INPUT; /* Used for pneumatic pressure switch. */
/*
Note: digital_io_01 = digital_io_02 = ... digital_io_04 = INPUT;
is the same as the following:
digital_io_01 = INPUT;
digital_io_02 = INPUT;
...
digital_io_04 = INPUT;
*/
/* SECOND: Set up the I/O pins you want to use as digital OUTPUTS. */
digital_io_17 = OUTPUT; /* Example - Not used in Default Code. */
/* THIRD: Initialize the values on the digital outputs. */
rc_dig_out17 = 0;
/* FOURTH: Set your initial PWM values. Neutral is 127. */
pwm01 = pwm02 = pwm03 = pwm04 = pwm05 = pwm06 = pwm07 = pwm08 = 127;
pwm09 = pwm10 = pwm11 = pwm12 = pwm13 = pwm14 = pwm15 = pwm16 = 127;
/* FIFTH: Set your PWM output types for PWM OUTPUTS 13-16.
/* Choose from these parameters for PWM 13-16 respectively: */
/* IFI_PWM - Standard IFI PWM output generated with Generate_Pwms(...) */
/* USER_CCP - User can use PWM pin as digital I/O or CCP pin. */
Setup_PWM_Output_Type(IFI_PWM,IFI_PWM,IFI_PWM,IFI_PWM);
/*
Example: The following would generate a 40KHz PWM with a 50% duty cycle on the CCP2 pin:
CCP2CON = 0x3C;
PR2 = 0xF9;
CCPR2L = 0x7F;
T2CON = 0;
T2CONbits.TMR2ON = 1;
Setup_PWM_Output_Type(USER_CCP,IFI_PWM,IFI_PWM,IFI_PWM);
*/
/* Add any other initialization code here. */
Putdata(&txdata); /* DO NOT CHANGE! */
Serial_Driver_Initialize();
Initialize_Serial_Comms();
//printf("IFI 2005 User Processor Initialized ...\r"); /* Optional - Print initialization message. */
/* Note: use a '\r' rather than a '\n' with the new compiler (v2.4) */
User_Proc_Is_Ready(); /* DO NOT CHANGE! - last line of User_Initialization */
}
/*******************************************************************************
* FUNCTION NAME: Process_Data_From_Master_uP
* PURPOSE: Executes every 26.2ms when it gets new data from the master
* microprocessor.
* CALLED FROM: main.c
* ARGUMENTS: none
* RETURNS: void
*******************************************************************************/
void Process_Data_From_Master_uP(void)
{
static unsigned char i;
static unsigned char delay;
int xaccel;
int yaccel;
Getdata(&rxdata); /* Get fresh data from the master microprocessor. */
Default_Routine(); /* Optional. See below. */
Generate_Pwms(pwm13,pwm14,pwm15,pwm16);
/* Eample code to check if a breaker was ever tripped. */
if (aBreakerWasTripped)
{
for (i=1;i<29;i++)
{
if (Breaker_Tripped(i))
User_Byte1 = i; /* Update the last breaker tripped on User_Byte1 (to demonstrate the use of a user byte)
// Normally, you do something else if a breaker got tripped (ex: limit a PWM output) */
}
}
///////////////////////////////////////////////////////////////////
//get x and y accel and print them to the serial port
xaccel=Get_xAcceleration();
printf("The x accel: %d", xaccel);
//////////////////////////////////////////////////////////////
yaccel=Get_yAcceleration();
printf("The y accel: %d", yaccel);
//////////////////////////////////////////////////////////////////
Putdata(&txdata); /* DO NOT CHANGE! */
}
/*******************************************************************************
* FUNCTION NAME: Default_Routine
* PURPOSE: Performs the default mappings of inputs to outputs for the
* Robot Controller.
* CALLED FROM: this file, Process_Data_From_Master_uP routine
* ARGUMENTS: none
* RETURNS: void
*******************************************************************************/
void Default_Routine(void)
{
/*---------- Analog Inputs (Joysticks) to PWM Outputs-----------------------
*--------------------------------------------------------------------------
* This maps the joystick axes to specific PWM outputs.
*/
pwm01 = p1_y;
pwm02 = p2_y;
pwm03 = p3_y;
pwm04 = p4_y;
pwm05 = p1_x;
pwm06 = p2_x;
pwm07 = p3_x;
pwm08 = p4_x;
pwm09 = p1_wheel;
pwm10 = p2_wheel;
pwm11 = p3_wheel;
pwm12 = p4_wheel;
/*---------- 1 Joystick Drive ----------------------------------------------
*--------------------------------------------------------------------------
* This code mixes the Y and X axis on Port 1 to allow one joystick drive.
* Joystick forward = Robot forward
* Joystick backward = Robot backward
* Joystick right = Robot rotates right
* Joystick left = Robot rotates left
* Connect the right drive motors to PWM13 and/or PWM14 on the RC.
* Connect the left drive motors to PWM15 and/or PWM16 on the RC.
*/
/*---------- Buttons to Relays----------------------------------------------
*--------------------------------------------------------------------------
* This default code maps the joystick buttons to specific relay outputs.
* Relays 1 and 2 use limit switches to stop the movement in one direction.
* The & used below is the C symbol for AND
*/
relay1_fwd = p1_sw_trig & rc_dig_in01; /* FWD only if switch1 is not closed. */
relay1_rev = p1_sw_top & rc_dig_in02; /* REV only if switch2 is not closed. */
relay2_fwd = p2_sw_trig & rc_dig_in03; /* FWD only if switch3 is not closed. */
relay2_rev = p2_sw_top & rc_dig_in04; /* REV only if switch4 is not closed. */
relay3_fwd = p3_sw_trig;
relay3_rev = p3_sw_top;
relay4_fwd = p4_sw_trig;
relay4_rev = p4_sw_top;
relay5_fwd = p1_sw_aux1;
relay5_rev = p1_sw_aux2;
relay6_fwd = p3_sw_aux1;
relay6_rev = p3_sw_aux2;
relay7_fwd = p4_sw_aux1;
relay7_rev = p4_sw_aux2;
relay8_fwd = !rc_dig_in18; /* Power pump only if pressure switch is off. */
relay8_rev = 0;
/*---------- PWM outputs Limited by Limit Switches ------------------------*/
Limit_Switch_Max(rc_dig_in05, &pwm03);
Limit_Switch_Min(rc_dig_in06, &pwm03);
Limit_Switch_Max(rc_dig_in07, &pwm04);
Limit_Switch_Min(rc_dig_in08, &pwm04);
Limit_Switch_Max(rc_dig_in09, &pwm09);
Limit_Switch_Min(rc_dig_in10, &pwm09);
Limit_Switch_Max(rc_dig_in11, &pwm10);
Limit_Switch_Min(rc_dig_in12, &pwm10);
Limit_Switch_Max(rc_dig_in13, &pwm11);
Limit_Switch_Min(rc_dig_in14, &pwm11);
Limit_Switch_Max(rc_dig_in15, &pwm12);
Limit_Switch_Min(rc_dig_in16, &pwm12);
/*---------- ROBOT FEEDBACK LEDs------------------------------------------------
*------------------------------------------------------------------------------
* This section drives the "ROBOT FEEDBACK" lights on the Operator Interface.
* The lights are green for joystick forward and red for joystick reverse.
* Both red and green are on when the joystick is centered. Use the
* trim tabs on the joystick to adjust the center.
* These may be changed for any use that the user desires.
*/
if (user_display_mode == 0) /* User Mode is Off */
{ /* Check position of Port 1 Joystick */
if (p1_y >= 0 && p1_y <= 56)
{ /* Joystick is in full reverse position */
Pwm1_green = 0; /* Turn PWM1 green LED - OFF */
Pwm1_red = 1; /* Turn PWM1 red LED - ON */
}
else if (p1_y >= 125 && p1_y <= 129)
{ /* Joystick is in neutral position */
Pwm1_green = 1; /* Turn PWM1 green LED - ON */
Pwm1_red = 1; /* Turn PWM1 red LED - ON */
}
else if (p1_y >= 216 && p1_y <= 255)
{ /* Joystick is in full forward position*/
Pwm1_green = 1; /* Turn PWM1 green LED - ON */
Pwm1_red = 0; /* Turn PWM1 red LED - OFF */
}
else
{ /* In either forward or reverse position */
Pwm1_green = 0; /* Turn PWM1 green LED - OFF */
Pwm1_red = 0; /* Turn PWM1 red LED - OFF */
} /*END Check position of Port 1 Joystick
/* Check position of Port 2 Y Joystick
(or Port 1 X in Single Joystick Drive Mode) */
if (p2_y >= 0 && p2_y <= 56)
{ /* Joystick is in full reverse position */
Pwm2_green = 0; /* Turn pwm2 green LED - OFF */
Pwm2_red = 1; /* Turn pwm2 red LED - ON */
}
else if (p2_y >= 125 && p2_y <= 129)
{ /* Joystick is in neutral position */
Pwm2_green = 1; /* Turn PWM2 green LED - ON */
Pwm2_red = 1; /* Turn PWM2 red LED - ON */
}
else if (p2_y >= 216 && p2_y <= 255)
{ /* Joystick is in full forward position */
Pwm2_green = 1; /* Turn PWM2 green LED - ON */
Pwm2_red = 0; /* Turn PWM2 red LED - OFF */
}
else
{ /* In either forward or reverse position */
Pwm2_green = 0; /* Turn PWM2 green LED - OFF */
Pwm2_red = 0; /* Turn PWM2 red LED - OFF */
} /* END Check position of Port 2 Joystick */
/* This drives the Relay 1 and Relay 2 "Robot Feedback" lights on the OI. */
Relay1_green = relay1_fwd; /* LED is ON when Relay 1 is FWD */
Relay1_red = relay1_rev; /* LED is ON when Relay 1 is REV */
Relay2_green = relay2_fwd; /* LED is ON when Relay 2 is FWD */
Relay2_red = relay2_rev; /* LED is ON when Relay 2 is REV */
Switch1_LED = !(int)rc_dig_in01;
Switch2_LED = !(int)rc_dig_in02;
Switch3_LED = !(int)rc_dig_in03;
} /* (user_display_mode = 0) (User Mode is Off) */
else /* User Mode is On - displays data in OI 4-digit display*/
{
User_Mode_byte = backup_voltage*10; /* so that decimal doesn't get truncated. */
}
} /* END Default_Routine(); */
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/