您好!
我正在使用基于 BMI160的传感器 Booster Pack 和 MSP430FR6889 Launchpad。 我正在尝试使用 MSPDSP 库对 BMI160加速计数据执行 FFT。 我正在使用一个在3.3至3.5 Hz 之间振动的平台。 不过、FFT 算法只会生成整数。 是否可以使用浮点数据类型来获得更精确的值? 在这种情况下、如何更改库或代码以获得更准确的结果?
谢谢你。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我正在使用基于 BMI160的传感器 Booster Pack 和 MSP430FR6889 Launchpad。 我正在尝试使用 MSPDSP 库对 BMI160加速计数据执行 FFT。 我正在使用一个在3.3至3.5 Hz 之间振动的平台。 不过、FFT 算法只会生成整数。 是否可以使用浮点数据类型来获得更精确的值? 在这种情况下、如何更改库或代码以获得更准确的结果?
谢谢你。
您好 Johson、
感谢你的答复。 我正在使用"MSP_FFT_FIXED_Q15"函数来执行 FFT、但我仍会获取整数值作为输出。 我正在使用 CCS 的控制台串行打印数据。
代码如下:
#include <msp430.h> #include "driverlib.h" #include "DSPLib.h" #include <gpio.h> #include <intrinsics.h> #include <msp430fr5xx_6xxgeneric.h> #include <stdint.h> #include <stdio.h> //new //#include "myClocks.h" //new //****************************************************************************** // Defines ********************************************************************* //****************************************************************************** //Address if the BMI160 #define SLAVE_ADDR 0x69 //Maximum I2C buffer size #define MAX_BUFFER_SIZE 20 //Number of FFT samples #define SAMPLES 1024 #define TimeStampSample 10 /* Declare as persistent to move variable from RAM to FRAM */ #pragma PERSISTENT(input) int16_t input[SAMPLES] = {0}; //Store samples #pragma PERSISTENT(max) int16_t max[SAMPLES] = {0}; //Store frequencies with maximum amplitudes #pragma PERSISTENT(amp) int16_t amp[SAMPLES] = {0}; //Store the maximum amplitudes /* Temporary data array for processing */ DSPLIB_DATA(temp,4) /* Declare as persistent to move variable to FRAM */ #pragma PERSISTENT(temp) int16_t temp[3*SAMPLES/2] = {0}; //Global flags for sensor interrupts to avoid interrupt nesting volatile int motion_trigger = 0; /* Benchmark cycle counts */ volatile uint32_t cycleCount; //#pragma PERSISTENT(SENSORTIME) //volatile int32_t SENSORTIME[SAMPLES] = {0}; //Store samples //new #define UP 0x0010 // Timer_A Up mode #define CONTINUOUS 0x0020 // Timer_A Continuous mode #define ACLK 0x0100 // Timer_A SMCLK source #define DEVELOPMENT 0x5A80 // Stop the watchdog timer #define BOUNCE_DELAY 0xA000 // Delay for Button Bounce #define MS_10 400 // Approximate value to count for 10ms #define SMCLK 0x0200 // Timer_A SMCLK source //new //****************************************************************************** // Frequency Functions ********************************************************* //****************************************************************************** void bubbleSort(int amp[], int max[], int n) { int i, j, temp; for (i = 0; i < n-1; i++) { // Last i elements are already in place for (j = 0; j < n-i-1; j++) { if (amp[j] < amp[j+1]) { temp = max[j]; max[j] = max[j+1]; max[j+1] = temp; temp = amp[j]; amp[j] = amp[j+1]; amp[j+1] = temp; } } } } void getMaximums(int16_t input[], int samples, int16_t max[], int16_t amp[]) { int i,j = 0; for(i=1; i<samples-1; i++) { if((input[i-1] < input[i]) && (input[i] > input[i+1])) { amp[j] = input[i]; max[j++] = i; } } bubbleSort(amp, max, samples); } //****************************************************************************** // Timer Functions ************************************************************* //****************************************************************************** int delay(int count) { if(TA1CTL & TAIFG) // If Timer_1 is done counting { count = count-1; // Decrement count TA1CTL = TA1CTL & (~TAIFG); // Reset Timer_1 } return count; // Return the value of count } // end delay //****************************************************************************** // UART Functions ************************************************************** //****************************************************************************** void UART_transmitString( char *pStr ) //Transmits a string over UART0 { while( *pStr ) { while(!(UCA0IFG&UCTXIFG)); UCA0TXBUF = *pStr; pStr++; } } //****************************************************************************** // I2C Functions *************************************************************** //****************************************************************************** typedef enum I2C_ModeEnum{ IDLE_MODE, NACK_MODE, TX_REG_ADDRESS_MODE, RX_REG_ADDRESS_MODE, TX_DATA_MODE, RX_DATA_MODE, SWITCH_TO_RX_MODE, SWITHC_TO_TX_MODE, TIMEOUT_MODE } I2C_Mode; /* Used to track the state of the software state machine*/ I2C_Mode MasterMode = IDLE_MODE; uint8_t TransmitRegAddr = 0; //Register address for transmission uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for received values uint8_t RXByteCtr = 0; //Count received bytes uint8_t ReceiveIndex = 0; //Index of received data uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for transmitted values uint8_t TXByteCtr = 0; //Count transmitted bytes uint8_t TransmitIndex = 0; //Index of transmitted data void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0; copyIndex < count; copyIndex++) { dest[copyIndex] = source[copyIndex]; } } I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count) { //printf("R\n"); /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; RXByteCtr = count; TXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB1I2CSA = dev_addr; UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB1IE &= ~UCRXIE; // Disable RX interrupt UCB1IE |= UCTXIE; // Enable TX interrupt UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts // UCB1IE &= ~UCRXIE; // Disable RX interrupt return MasterMode; } I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count) { /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; //Copy register data to TransmitBuffer CopyArray(reg_data, TransmitBuffer, count); TXByteCtr = count; RXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB1I2CSA = dev_addr; UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB1IE &= ~UCRXIE; // Disable RX interrupt UCB1IE |= UCTXIE; // Enable TX interrupt UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts //printf("W\n"); return MasterMode; } //****************************************************************************** // BMI160 Functions ************************************************************ //****************************************************************************** void bmi160_init(char FOC_axis) { uint8_t writeData[1]; //Read Chip ID, which is D1 I2C_Master_ReadReg(SLAVE_ADDR, 0x00, 1); if(ReceiveBuffer[0] != 0xD1) { UART_transmitString(" Incorrect sensor chip ID "); printf("Incorrect sensor chip ID\n"); } //Configure the accelerometer writeData[0]=0b00101100; //Set acc_us to 0 for off, and acc_bwp must then be 010. Set acc_odr to 1011(800Hz),1100(1600Hz),1000(100Hz),0001(25/32Hz) I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1); //Check if configuration worked I2C_Master_ReadReg(SLAVE_ADDR, 0x40, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Accelerometer config failed "); printf("Accelerometer config failed\n"); } //Set the range of the accelerometer writeData[0]=0b1000; //0b0011 for 2g, 0b0101 for 4g, 0b1000 for 8g I2C_Master_WriteReg(SLAVE_ADDR, 0x41, writeData, 1); //Check if range is set I2C_Master_ReadReg(SLAVE_ADDR, 0x41, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Accelerometer range set failed "); printf("Accelerometer range set failed\n"); } //Any motion setup //Set the successive slope threshold writeData[0]=0b00000001; //0b00000001 + 1 so two successive slopes I2C_Master_WriteReg(SLAVE_ADDR, 0x5F, writeData, 1); //Check if slope threshold is set I2C_Master_ReadReg(SLAVE_ADDR, 0x5F, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Slope threshold not set "); printf("Slope threshold not set\n"); } //Set trigger level writeData[0]=0b01001101; //15.63mg*value for 8g range, 0b00000000 gives 7.81mg I2C_Master_WriteReg(SLAVE_ADDR, 0x60, writeData, 1); //Check trigger is set I2C_Master_ReadReg(SLAVE_ADDR, 0x60, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Trigger not set "); printf("Trigger not set\n"); } //Double tap setup //Set single and double tap timings writeData[0] = 0b00000110; //Quiet of 30ms, shock of 50ms, double tap within 500ms I2C_Master_WriteReg(SLAVE_ADDR, 0x63, writeData, 1); //Read the timings I2C_Master_ReadReg(SLAVE_ADDR, 0x63, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Tap timings not set "); printf("Tap timings not set\n"); } //Set tap threshold writeData[0] = 0b0000; //125mg threshold I2C_Master_WriteReg(SLAVE_ADDR, 0x64, writeData, 1); //Read the threshold I2C_Master_ReadReg(SLAVE_ADDR, 0x64, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Tap timings not set "); printf("Tap timings not set\n"); } //Interrupt setup //Enable any-motion and double tap interrupts writeData[0] = 0b00010100; //Enables double tap and any-motion z interrupt I2C_Master_WriteReg(SLAVE_ADDR, 0x50, writeData, 1); //Read interrupt enable status I2C_Master_ReadReg(SLAVE_ADDR, 0x50, 1); if(ReceiveBuffer[0] != 0b00010100) { UART_transmitString("Interrupts not enabled"); printf("Interrupts not enabled\n"); } //Set pins writeData[0] = 0b10001000; //Output, push-pull, active low for int1 and int2 I2C_Master_WriteReg(SLAVE_ADDR, 0x53, writeData, 1); //Read pin status I2C_Master_ReadReg(SLAVE_ADDR, 0x53, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Pins not set "); printf("Pins not set\n"); } //Set interrupts to temporary instead of latched (permanent till cleared) writeData[0] = 0b1101; //Temp for 1.28s I2C_Master_WriteReg(SLAVE_ADDR, 0x54, writeData, 1); //Check interrupts I2C_Master_ReadReg(SLAVE_ADDR, 0x54, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Interrupts not temp "); printf("Interrupts not temp"); } //Map any motion detection to Int1 writeData[0] = 0b00000100; //Mapped any motion to int1 I2C_Master_WriteReg(SLAVE_ADDR, 0x55, writeData, 1); //Check interrupt I2C_Master_ReadReg(SLAVE_ADDR, 0x55, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Any motion not mapped "); printf("Any motion not mapped\n"); } //Map double tap to Int2 writeData[0] = 0b00010000; //Mapped double tap to int2 I2C_Master_WriteReg(SLAVE_ADDR, 0x57, writeData, 1); //Check interrupt I2C_Master_ReadReg(SLAVE_ADDR, 0x57, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Double tap not mapped "); printf("Double tap not mapped\n"); } //Set tap data filtering writeData[0] = 0b1000; //Filtered data instead of pre-filtered I2C_Master_WriteReg(SLAVE_ADDR, 0x58, writeData, 1); //Check filtering I2C_Master_ReadReg(SLAVE_ADDR, 0x58, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Filter not set "); printf("Filter not set\n"); } //Set the Accelerometer to normal power mode writeData[0] = 0x11; I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1); //Read power mode status of sensors I2C_Master_ReadReg(SLAVE_ADDR, 0x03, 1); if(ReceiveBuffer[0] != 0x10) { UART_transmitString(" Accelerometer not on "); printf("Accelerometer not on\n"); } //Fast Offset Compensation (FOC) setup //0 for reserved, 0 for gyroscope, 00 for x, 00 for y, 0 for z (10 = -1g, 00 = 0g, 01 = 1g) switch(FOC_axis) { case 'X': writeData[0] = 0b00100000; break; case 'Y': writeData[0] = 0b00001000; break; case 'Z': writeData[0] = 0b00000010; break; default: writeData[0] = 0b00000000; //Default of all 0g break; } I2C_Master_WriteReg(SLAVE_ADDR, 0x69, writeData, 1); //Check FOC I2C_Master_ReadReg(SLAVE_ADDR, 0x69, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" FOC not set "); printf("Incorrect sensor chip ID\n"); } //Start FOC writeData[0] = 0x03; I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1); //Wait until FOC is finished int finish = 0; while(finish==0) { I2C_Master_ReadReg(SLAVE_ADDR, 0x1B, 1); if((ReceiveBuffer[0] & 0b00001000) == 0b00001000) { finish = 1; } } //Enable offset compensation writeData[0] = 0b01000000; //Enable accelerometer offset compensation I2C_Master_WriteReg(SLAVE_ADDR, 0x77, writeData, 1); //Check offset compensation I2C_Master_ReadReg(SLAVE_ADDR, 0x77, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Offset not enabled "); printf("Incorrect sensor chip ID\n"); } //UART_transmitString(" BMI160 Initialized \n"); } //****************************************************************************** // Device Initialization ******************************************************* //****************************************************************************** void initGPIO() { /* Terminate all GPIO pins to Output LOW to minimize power consumption */ GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16); // I2C pins (P4.0 is SDA, P4.1 is SCL) P4SEL1 |= BIT0 | BIT1; P4SEL0 &= ~(BIT0 | BIT1); // Configure P3.4 and P3.5 to UART (Primary, TX and RX respectively) for NeoCortec P3SEL0 |= BIT4 | BIT5; // USCI_A1 UART operation P3SEL1 &= ~(BIT4 | BIT5); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary // Configure P2.0 and P2.1 to UART (Primary, TX and RX respectively) for PC P2SEL0 |= BIT0 | BIT1; // USCI_A0 UART operation P2SEL1 &= ~(BIT0 | BIT1); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary // Configure button S1 (P1.1) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1); // Configure button S2 (P1.2) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN2); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN2); // Configure CTS active (P1.3) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN3, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN3); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN3); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN3); // Configure Nwu (P1.4) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN4); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4); // Configure INT1 (P3.2) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P3, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2); GPIO_clearInterrupt(GPIO_PORT_P3, GPIO_PIN2); GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN2); // Configure INT2 (P2.5) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN5, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN5); GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN5); GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN5); // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; __bis_SR_register(GIE); } void initClockTo16MHz() { // Configure one FRAM waitstate as required by the device datasheet for MCLK // operation beyond 8MHz _before_ configuring the clock system. FRCTL0 = FRCTLPW | NWAITS_1; // Clock System Setup CSCTL0_H = CSKEY_H; // Unlock CS registers CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz // Set SMCLK = MCLK = DCO, ACLK = VLOCLK (9.4kHz) CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Per Device Errata set divider to 4 before changing frequency to // prevent out of spec operation from overshoot transient CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz)) __delay_cycles(60); CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1; // Set ACLK to 239.75Hz, SMCLK to 16MHz, and MCLK to 16MHz CSCTL0_H = 0; // Lock CS registers } void initI2C() { UCB1CTLW0 = UCSWRST; // Enable SW reset UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK UCB1BRW = 160; // fSCL = ACLK/160 = ~100kHz UCB1I2CSA = SLAVE_ADDR; // Slave Address UCB1CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation UCB1IE |= UCNACKIE; } void UART_init(void) { // Configure USCI_A1 for UART mode UCA1CTLW0 = UCSWRST; // Put eUSCI in reset UCA1CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK UCA1BR0 = 8; // Clock prescaler set to 8 UCA1BR1 = 0x00; // High byte empty, low byte is 8 UCA1MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte UCA1CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt // Configure USCI_A0 for UART mode UCA0CTLW0 = UCSWRST; // Put eUSCI in reset UCA0CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK UCA0BR0 = 8; // Clock prescaler set to 8 UCA0BR1 = 0x00; // High byte empty, low byte is 8 UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte UCA0CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt } //****************************************************************************** // Main ************************************************************************ //****************************************************************************** int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer //Initialize all peripherals initClockTo16MHz(); initGPIO(); UART_init(); initI2C(); bmi160_init('Z'); // Initialize the FFT parameters msp_status status; msp_fft_q15_params fftParams; /* Initialize the fft parameter structure. */ fftParams.length = SAMPLES; fftParams.bitReverse = true; fftParams.twiddleTable = msp_cmplx_twiddle_table_4096_q15; //Twiddle table for 4096 values int i = 0; //new TA0CTL = TA0CTL | (SMCLK + CONTINUOUS); // SMCLK: Counts faster than ACLK // CONTINUOUS: Count 0 to 0xFFFF TA0CCTL0 = CCIE; // Timer_0 interrupt TA1CTL = TA1CTL | (ACLK + UP ); // Count up from 0 with ACLK TA1CCR0 = MS_10; // Duration approximatley 10ms _BIS_SR(GIE); // Activate all interrupts //new while(1) { printf("Reading samples\n"); //Read SAMPLES amount of data from the BMI160 for(i=0;i<SAMPLES;i++) { I2C_Master_ReadReg(SLAVE_ADDR, 0x16, 2); //Read the acceleration value from the BMI160 registers input[i]= ReceiveBuffer[0] | (ReceiveBuffer[1] << 8); //Store the value in an array } printf("Samples read\n"); msp_benchmarkStart(MSP_BENCHMARK_BASE, 16); status = msp_fft_fixed_q15(&fftParams, input); //Perform FFT cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE); msp_checkStatus(status); printf("FFT completed\n"); //Transmit all output values to PC //Calculate and transmit frequencies with maximum amplitudes getMaximums(input, SAMPLES, max, amp); printf("Max amp frequencies found\n"); // Transmit all frequencies via NeoCortec printf("Sent freq: \n"); for(i=0; i<SAMPLES/2; i++) { printf("%f\n", (float)max[i]); } GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0); // Transmit matching amplitudes printf("Sent amp: \n"); for(i=0; i<SAMPLES/2; i++) { printf("%f\n", (float)amp[i]); } } } //****************************************************************************** // Interrupts ****************************************************************** //****************************************************************************** //I2C Interrupt #pragma vector = USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) { //Must read from UCB1RXBUF uint8_t rx_val = 0; switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG)) { case USCI_NONE: break; // Vector 0: No interrupts case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG UCB1CTLW0 |= UCTXSTT; // Re-send start if NACK break; case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3 case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3 case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2 case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2 case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1 case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1 case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0 rx_val = UCB1RXBUF; if (RXByteCtr) { ReceiveBuffer[ReceiveIndex++] = rx_val; RXByteCtr--; } if (RXByteCtr == 1) { UCB1CTLW0 |= UCTXSTP; } else if (RXByteCtr == 0) { UCB1IE &= ~UCRXIE; MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0 switch (MasterMode) { case TX_REG_ADDRESS_MODE: UCB1TXBUF = TransmitRegAddr; if (RXByteCtr) MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now else MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer break; case SWITCH_TO_RX_MODE: UCB1IE |= UCRXIE; // Enable RX interrupt UCB1IE &= ~UCTXIE; // Disable TX interrupt UCB1CTLW0 &= ~UCTR; // Switch to receiver MasterMode = RX_DATA_MODE; // State state is to receive data UCB1CTLW0 |= UCTXSTT; // Send repeated start if (RXByteCtr == 1) { //Must send stop since this is the N-1 byte while((UCB1CTLW0 & UCTXSTT)); UCB1CTLW0 |= UCTXSTP; // Send stop condition } break; case TX_DATA_MODE: if (TXByteCtr) { UCB1TXBUF = TransmitBuffer[TransmitIndex++]; TXByteCtr--; } else { //Done with transmission UCB1CTLW0 |= UCTXSTP; // Send stop condition MasterMode = IDLE_MODE; UCB1IE &= ~UCTXIE; // disable TX interrupt __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; default: __no_operation(); break; } break; default: break; } } #pragma vector = PORT2_VECTOR __interrupt void PORT2_ISR(void) { switch(__even_in_range(P2IV, P2IV_P2IFG7)) { case P2IV_NONE : break; case P2IV_P2IFG0 : break; case P2IV_P2IFG1 : break; case P2IV_P2IFG2 : break; case P2IV_P2IFG3 : break; case P2IV_P2IFG4 : break; case P2IV_P2IFG5 : //Int2 sensor interrupt P2IFG = P2IFG & ~(BIT2); break; case P2IV_P2IFG6 : break; case P2IV_P2IFG7 : break; default : _never_executed(); } } // Timer_0 Interrupt Service Routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A0 (void) { TA0CTL = TA0CTL & (~TAIFG); // Reset Timer_0 so it keeps counting }
IQmathLibry:Q15和 IQ31的范围为-1至+1。 我不确定如何使用"int16_t"中的这两种数据类型。
参考:
DSP 库 FFT 函数为低电平、不会以赫兹为单位输出频率。 由于函数不知道采样率、因此它将输出一个与采样率相关的值。 因此、要以赫兹为单位获取频率、您需要从函数中获取的值应为小于0.5的值、并乘以采样数据的速率。
我建议阅读 IQmathLib 用户指南、尤其是第2节"使用 Qmath 和 IQmath 库"、其中介绍了如何在 int16_t 中表示浮点值 如果需要更高的分辨率、可以使用 int32_t/iq31。
谢谢你。 我已更改代码、但即使包含"QmathLib.h"库、它也会显示此错误:
Description Resource Path Location Type unresolved symbol _Q15toF, first referenced in ./main.obj One hour delay4_IQLibrary C/C++ Problem
我仍然没有乘以采样率。 现在、我只是尝试将从"MSP_FFT_FIXED_Q15"函数接收的日期转换为 Q 值、并通过控制台打印这些值。 有什么建议吗?
以下是我的代码:
#define GLOBAL_Q 15 #include "QmathLib.h" #include <msp430.h> #include "driverlib.h" #include "DSPLib.h" #include <gpio.h> #include <intrinsics.h> #include <msp430fr5xx_6xxgeneric.h> #include <stdint.h> #include <stdio.h> //#define GLOBAL_Q 15 //#include "QmathLib.h" _q15 q15FFT; _q15 q15Amp; // Q variables using Q15 type volatile float qFFT_out; volatile float qAmp_out; //new //#include "myClocks.h" //new //****************************************************************************** // Defines ********************************************************************* //****************************************************************************** //Address if the BMI160 #define SLAVE_ADDR 0x69 //Maximum I2C buffer size #define MAX_BUFFER_SIZE 20 //Number of FFT samples #define SAMPLES 1024 #define TimeStampSample 10 /* Declare as persistent to move variable from RAM to FRAM */ #pragma PERSISTENT(input) int16_t input[SAMPLES] = {0}; //Store samples #pragma PERSISTENT(max) int16_t max[SAMPLES] = {0}; //Store frequencies with maximum amplitudes #pragma PERSISTENT(amp) int16_t amp[SAMPLES] = {0}; //Store the maximum amplitudes /* Temporary data array for processing */ DSPLIB_DATA(temp,4) /* Declare as persistent to move variable to FRAM */ #pragma PERSISTENT(temp) int16_t temp[3*SAMPLES/2] = {0}; //Global flags for sensor interrupts to avoid interrupt nesting volatile int motion_trigger = 0; /* Benchmark cycle counts */ volatile uint32_t cycleCount; //#pragma PERSISTENT(SENSORTIME) //volatile int32_t SENSORTIME[SAMPLES] = {0}; //Store samples //new #define UP 0x0010 // Timer_A Up mode #define CONTINUOUS 0x0020 // Timer_A Continuous mode #define ACLK 0x0100 // Timer_A SMCLK source #define DEVELOPMENT 0x5A80 // Stop the watchdog timer #define BOUNCE_DELAY 0xA000 // Delay for Button Bounce #define MS_10 400 // Approximate value to count for 10ms #define SMCLK 0x0200 // Timer_A SMCLK source //new //****************************************************************************** // Frequency Functions ********************************************************* //****************************************************************************** void bubbleSort(int amp[], int max[], int n) { int i, j, temp; for (i = 0; i < n-1; i++) { // Last i elements are already in place for (j = 0; j < n-i-1; j++) { if (amp[j] < amp[j+1]) { temp = max[j]; max[j] = max[j+1]; max[j+1] = temp; temp = amp[j]; amp[j] = amp[j+1]; amp[j+1] = temp; } } } } void getMaximums(int16_t input[], int samples, int16_t max[], int16_t amp[]) { int i,j = 0; for(i=1; i<samples-1; i++) { if((input[i-1] < input[i]) && (input[i] > input[i+1])) { amp[j] = input[i]; max[j++] = i; } } bubbleSort(amp, max, samples); } //****************************************************************************** // Timer Functions ************************************************************* //****************************************************************************** int delay(int count) { if(TA1CTL & TAIFG) // If Timer_1 is done counting { count = count-1; // Decrement count TA1CTL = TA1CTL & (~TAIFG); // Reset Timer_1 } return count; // Return the value of count } // end delay //****************************************************************************** // UART Functions ************************************************************** //****************************************************************************** void UART_transmitString( char *pStr ) //Transmits a string over UART0 { while( *pStr ) { while(!(UCA0IFG&UCTXIFG)); UCA0TXBUF = *pStr; pStr++; } } //****************************************************************************** // I2C Functions *************************************************************** //****************************************************************************** typedef enum I2C_ModeEnum{ IDLE_MODE, NACK_MODE, TX_REG_ADDRESS_MODE, RX_REG_ADDRESS_MODE, TX_DATA_MODE, RX_DATA_MODE, SWITCH_TO_RX_MODE, SWITHC_TO_TX_MODE, TIMEOUT_MODE } I2C_Mode; /* Used to track the state of the software state machine*/ I2C_Mode MasterMode = IDLE_MODE; uint8_t TransmitRegAddr = 0; //Register address for transmission uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for received values uint8_t RXByteCtr = 0; //Count received bytes uint8_t ReceiveIndex = 0; //Index of received data uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; //Buffer for transmitted values uint8_t TXByteCtr = 0; //Count transmitted bytes uint8_t TransmitIndex = 0; //Index of transmitted data void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0; copyIndex < count; copyIndex++) { dest[copyIndex] = source[copyIndex]; } } I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count) { //printf("R\n"); /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; RXByteCtr = count; TXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB1I2CSA = dev_addr; UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB1IE &= ~UCRXIE; // Disable RX interrupt UCB1IE |= UCTXIE; // Enable TX interrupt UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts // UCB1IE &= ~UCRXIE; // Disable RX interrupt return MasterMode; } I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count) { /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; //Copy register data to TransmitBuffer CopyArray(reg_data, TransmitBuffer, count); TXByteCtr = count; RXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB1I2CSA = dev_addr; UCB1IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB1IE &= ~UCRXIE; // Disable RX interrupt UCB1IE |= UCTXIE; // Enable TX interrupt UCB1CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts //printf("W\n"); return MasterMode; } //****************************************************************************** // BMI160 Functions ************************************************************ //****************************************************************************** void bmi160_init(char FOC_axis) { uint8_t writeData[1]; //Read Chip ID, which is D1 I2C_Master_ReadReg(SLAVE_ADDR, 0x00, 1); if(ReceiveBuffer[0] != 0xD1) { UART_transmitString(" Incorrect sensor chip ID "); printf("Incorrect sensor chip ID\n"); } //Configure the accelerometer writeData[0]=0b00101100; //Set acc_us to 0 for off, and acc_bwp must then be 010. Set acc_odr to 1011(800Hz),1100(1600Hz),1000(100Hz),0001(25/32Hz) I2C_Master_WriteReg(SLAVE_ADDR, 0x40, writeData, 1); //Check if configuration worked I2C_Master_ReadReg(SLAVE_ADDR, 0x40, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Accelerometer config failed "); printf("Accelerometer config failed\n"); } //Set the range of the accelerometer writeData[0]=0b1000; //0b0011 for 2g, 0b0101 for 4g, 0b1000 for 8g I2C_Master_WriteReg(SLAVE_ADDR, 0x41, writeData, 1); //Check if range is set I2C_Master_ReadReg(SLAVE_ADDR, 0x41, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Accelerometer range set failed "); printf("Accelerometer range set failed\n"); } //Any motion setup //Set the successive slope threshold writeData[0]=0b00000001; //0b00000001 + 1 so two successive slopes I2C_Master_WriteReg(SLAVE_ADDR, 0x5F, writeData, 1); //Check if slope threshold is set I2C_Master_ReadReg(SLAVE_ADDR, 0x5F, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Slope threshold not set "); printf("Slope threshold not set\n"); } //Set trigger level writeData[0]=0b01001101; //15.63mg*value for 8g range, 0b00000000 gives 7.81mg I2C_Master_WriteReg(SLAVE_ADDR, 0x60, writeData, 1); //Check trigger is set I2C_Master_ReadReg(SLAVE_ADDR, 0x60, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Trigger not set "); printf("Trigger not set\n"); } //Double tap setup //Set single and double tap timings writeData[0] = 0b00000110; //Quiet of 30ms, shock of 50ms, double tap within 500ms I2C_Master_WriteReg(SLAVE_ADDR, 0x63, writeData, 1); //Read the timings I2C_Master_ReadReg(SLAVE_ADDR, 0x63, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Tap timings not set "); printf("Tap timings not set\n"); } //Set tap threshold writeData[0] = 0b0000; //125mg threshold I2C_Master_WriteReg(SLAVE_ADDR, 0x64, writeData, 1); //Read the threshold I2C_Master_ReadReg(SLAVE_ADDR, 0x64, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Tap timings not set "); printf("Tap timings not set\n"); } //Interrupt setup //Enable any-motion and double tap interrupts writeData[0] = 0b00010100; //Enables double tap and any-motion z interrupt I2C_Master_WriteReg(SLAVE_ADDR, 0x50, writeData, 1); //Read interrupt enable status I2C_Master_ReadReg(SLAVE_ADDR, 0x50, 1); if(ReceiveBuffer[0] != 0b00010100) { UART_transmitString("Interrupts not enabled"); printf("Interrupts not enabled\n"); } //Set pins writeData[0] = 0b10001000; //Output, push-pull, active low for int1 and int2 I2C_Master_WriteReg(SLAVE_ADDR, 0x53, writeData, 1); //Read pin status I2C_Master_ReadReg(SLAVE_ADDR, 0x53, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Pins not set "); printf("Pins not set\n"); } //Set interrupts to temporary instead of latched (permanent till cleared) writeData[0] = 0b1101; //Temp for 1.28s I2C_Master_WriteReg(SLAVE_ADDR, 0x54, writeData, 1); //Check interrupts I2C_Master_ReadReg(SLAVE_ADDR, 0x54, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Interrupts not temp "); printf("Interrupts not temp"); } //Map any motion detection to Int1 writeData[0] = 0b00000100; //Mapped any motion to int1 I2C_Master_WriteReg(SLAVE_ADDR, 0x55, writeData, 1); //Check interrupt I2C_Master_ReadReg(SLAVE_ADDR, 0x55, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Any motion not mapped "); printf("Any motion not mapped\n"); } //Map double tap to Int2 writeData[0] = 0b00010000; //Mapped double tap to int2 I2C_Master_WriteReg(SLAVE_ADDR, 0x57, writeData, 1); //Check interrupt I2C_Master_ReadReg(SLAVE_ADDR, 0x57, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Double tap not mapped "); printf("Double tap not mapped\n"); } //Set tap data filtering writeData[0] = 0b1000; //Filtered data instead of pre-filtered I2C_Master_WriteReg(SLAVE_ADDR, 0x58, writeData, 1); //Check filtering I2C_Master_ReadReg(SLAVE_ADDR, 0x58, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Filter not set "); printf("Filter not set\n"); } //Set the Accelerometer to normal power mode writeData[0] = 0x11; I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1); //Read power mode status of sensors I2C_Master_ReadReg(SLAVE_ADDR, 0x03, 1); if(ReceiveBuffer[0] != 0x10) { UART_transmitString(" Accelerometer not on "); printf("Accelerometer not on\n"); } //Fast Offset Compensation (FOC) setup //0 for reserved, 0 for gyroscope, 00 for x, 00 for y, 0 for z (10 = -1g, 00 = 0g, 01 = 1g) switch(FOC_axis) { case 'X': writeData[0] = 0b00100000; break; case 'Y': writeData[0] = 0b00001000; break; case 'Z': writeData[0] = 0b00000010; break; default: writeData[0] = 0b00000000; //Default of all 0g break; } I2C_Master_WriteReg(SLAVE_ADDR, 0x69, writeData, 1); //Check FOC I2C_Master_ReadReg(SLAVE_ADDR, 0x69, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" FOC not set "); printf("Incorrect sensor chip ID\n"); } //Start FOC writeData[0] = 0x03; I2C_Master_WriteReg(SLAVE_ADDR, 0x7E, writeData, 1); //Wait until FOC is finished int finish = 0; while(finish==0) { I2C_Master_ReadReg(SLAVE_ADDR, 0x1B, 1); if((ReceiveBuffer[0] & 0b00001000) == 0b00001000) { finish = 1; } } //Enable offset compensation writeData[0] = 0b01000000; //Enable accelerometer offset compensation I2C_Master_WriteReg(SLAVE_ADDR, 0x77, writeData, 1); //Check offset compensation I2C_Master_ReadReg(SLAVE_ADDR, 0x77, 1); if(ReceiveBuffer[0] != writeData[0]) { UART_transmitString(" Offset not enabled "); printf("Incorrect sensor chip ID\n"); } //UART_transmitString(" BMI160 Initialized \n"); } //****************************************************************************** // Device Initialization ******************************************************* //****************************************************************************** void initGPIO() { /* Terminate all GPIO pins to Output LOW to minimize power consumption */ GPIO_setAsOutputPin(GPIO_PORT_PA, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PB, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PC, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PD, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PE, GPIO_PIN_ALL16); GPIO_setAsOutputPin(GPIO_PORT_PF, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PA, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PB, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PC, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PD, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PE, GPIO_PIN_ALL16); GPIO_setOutputLowOnPin(GPIO_PORT_PF, GPIO_PIN_ALL16); // I2C pins (P4.0 is SDA, P4.1 is SCL) P4SEL1 |= BIT0 | BIT1; P4SEL0 &= ~(BIT0 | BIT1); // Configure P3.4 and P3.5 to UART (Primary, TX and RX respectively) for NeoCortec P3SEL0 |= BIT4 | BIT5; // USCI_A1 UART operation P3SEL1 &= ~(BIT4 | BIT5); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary // Configure P2.0 and P2.1 to UART (Primary, TX and RX respectively) for PC P2SEL0 |= BIT0 | BIT1; // USCI_A0 UART operation P2SEL1 &= ~(BIT0 | BIT1); // SEL1 is 0 and SEL0 is 1 for primary operation, inverse for secondary // Configure button S1 (P1.1) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN1, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN1); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN1); // Configure button S2 (P1.2) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN2); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN2); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN2); // Configure CTS active (P1.3) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN3, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN3); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN3); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN3); // Configure Nwu (P1.4) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P1, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4); GPIO_clearInterrupt(GPIO_PORT_P1, GPIO_PIN4); GPIO_enableInterrupt(GPIO_PORT_P1, GPIO_PIN4); // Configure INT1 (P3.2) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P3, GPIO_PIN2, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P3, GPIO_PIN2); GPIO_clearInterrupt(GPIO_PORT_P3, GPIO_PIN2); GPIO_enableInterrupt(GPIO_PORT_P3, GPIO_PIN2); // Configure INT2 (P2.5) interrupt GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN5, GPIO_HIGH_TO_LOW_TRANSITION); GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN5); GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN5); GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN5); // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; __bis_SR_register(GIE); } void initClockTo16MHz() { // Configure one FRAM waitstate as required by the device datasheet for MCLK // operation beyond 8MHz _before_ configuring the clock system. FRCTL0 = FRCTLPW | NWAITS_1; // Clock System Setup CSCTL0_H = CSKEY_H; // Unlock CS registers CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz // Set SMCLK = MCLK = DCO, ACLK = VLOCLK (9.4kHz) CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Per Device Errata set divider to 4 before changing frequency to // prevent out of spec operation from overshoot transient CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz)) __delay_cycles(60); CSCTL3 = DIVA__32 | DIVS__1 | DIVM__1; // Set ACLK to 239.75Hz, SMCLK to 16MHz, and MCLK to 16MHz CSCTL0_H = 0; // Lock CS registers } void initI2C() { UCB1CTLW0 = UCSWRST; // Enable SW reset UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC; // I2C master mode, SMCLK UCB1BRW = 160; // fSCL = ACLK/160 = ~100kHz UCB1I2CSA = SLAVE_ADDR; // Slave Address UCB1CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation UCB1IE |= UCNACKIE; } void UART_init(void) { // Configure USCI_A1 for UART mode UCA1CTLW0 = UCSWRST; // Put eUSCI in reset UCA1CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK UCA1BR0 = 8; // Clock prescaler set to 8 UCA1BR1 = 0x00; // High byte empty, low byte is 8 UCA1MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte UCA1CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt // Configure USCI_A0 for UART mode UCA0CTLW0 = UCSWRST; // Put eUSCI in reset UCA0CTLW0 |= UCSSEL__SMCLK; // CLK = SMCLK UCA0BR0 = 8; // Clock prescaler set to 8 UCA0BR1 = 0x00; // High byte empty, low byte is 8 UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700; // Over-sampling on, first modulation register set to 10, second modulation register set to 0xF7 (247) for high byte, 0 for low byte UCA0CTLW0 &= ~UCSWRST; // Initialize eUSCI UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt } //****************************************************************************** // Main ************************************************************************ //****************************************************************************** int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer //Initialize all peripherals initClockTo16MHz(); initGPIO(); UART_init(); initI2C(); bmi160_init('Z'); // Initialize the FFT parameters msp_status status; msp_fft_q15_params fftParams; /* Initialize the fft parameter structure. */ fftParams.length = SAMPLES; fftParams.bitReverse = true; fftParams.twiddleTable = msp_cmplx_twiddle_table_4096_q15; //Twiddle table for 4096 values int i = 0; //new TA0CTL = TA0CTL | (SMCLK + CONTINUOUS); // SMCLK: Counts faster than ACLK // CONTINUOUS: Count 0 to 0xFFFF TA0CCTL0 = CCIE; // Timer_0 interrupt TA1CTL = TA1CTL | (ACLK + UP ); // Count up from 0 with ACLK TA1CCR0 = MS_10; // Duration approximatley 10ms _BIS_SR(GIE); // Activate all interrupts //new while(1) { printf("Reading samples\n"); //Read SAMPLES amount of data from the BMI160 for(i=0;i<SAMPLES;i++) { I2C_Master_ReadReg(SLAVE_ADDR, 0x16, 2); //Read the acceleration value from the BMI160 registers input[i]= ReceiveBuffer[0] | (ReceiveBuffer[1] << 8); //Store the value in an array //I2C_Master_ReadReg(SLAVE_ADDR, 0x18, 3); //Read the acceleration value from the BMI160 registers //SENSORTIME[i] = ((uint32_t)ReceiveBuffer[2] << 16) | ((uint32_t)ReceiveBuffer[1] << 8) | ((uint32_t)ReceiveBuffer[0] << 0); //delay_ms(1); //Determines sampling frequency, up to 10kHz //__delay_cycles(4500); //printf("Sent acc: %u\n",input[i]); } printf("Samples read\n"); msp_benchmarkStart(MSP_BENCHMARK_BASE, 16); status = msp_fft_fixed_q15(&fftParams, input); //Perform FFT cycleCount = msp_benchmarkStop(MSP_BENCHMARK_BASE); msp_checkStatus(status); printf("FFT completed\n"); //Transmit all output values to PC //Calculate and transmit frequencies with maximum amplitudes getMaximums(input, SAMPLES, max, amp); printf("Max amp frequencies found\n"); ////Print timestamp to calculate the accurate sampling frequency //printf("Sent SENSORTIME: \n"); //for(i=0; i<SAMPLES/2; i++) //{ // printf("%u\n", (unsigned int)SENSORTIME[i]); //} // Transmit all frequencies via NeoCortec printf("Sent freq: \n"); for(i=0; i<6; i++) { q15FFT = _Q(max[i]); qFFT_out =_Q15toF(q15FFT); printf("%f\n", qFFT_out); } GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0); // Transmit matching amplitudes printf("Sent amp: \n"); for(i=0; i<6; i++) { q15Amp = _Q(amp[i]); qAmp_out =_Q15toF(q15Amp); printf("%f\n", qAmp_out); } } } //****************************************************************************** // Interrupts ****************************************************************** //****************************************************************************** //I2C Interrupt #pragma vector = USCI_B1_VECTOR __interrupt void USCI_B1_ISR(void) { //Must read from UCB1RXBUF uint8_t rx_val = 0; switch(__even_in_range(UCB1IV, USCI_I2C_UCBIT9IFG)) { case USCI_NONE: break; // Vector 0: No interrupts case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG UCB1CTLW0 |= UCTXSTT; // Re-send start if NACK break; case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3 case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3 case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2 case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2 case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1 case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1 case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0 rx_val = UCB1RXBUF; if (RXByteCtr) { ReceiveBuffer[ReceiveIndex++] = rx_val; RXByteCtr--; } if (RXByteCtr == 1) { UCB1CTLW0 |= UCTXSTP; } else if (RXByteCtr == 0) { UCB1IE &= ~UCRXIE; MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0 switch (MasterMode) { case TX_REG_ADDRESS_MODE: UCB1TXBUF = TransmitRegAddr; if (RXByteCtr) MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now else MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer break; case SWITCH_TO_RX_MODE: UCB1IE |= UCRXIE; // Enable RX interrupt UCB1IE &= ~UCTXIE; // Disable TX interrupt UCB1CTLW0 &= ~UCTR; // Switch to receiver MasterMode = RX_DATA_MODE; // State state is to receive data UCB1CTLW0 |= UCTXSTT; // Send repeated start if (RXByteCtr == 1) { //Must send stop since this is the N-1 byte while((UCB1CTLW0 & UCTXSTT)); UCB1CTLW0 |= UCTXSTP; // Send stop condition } break; case TX_DATA_MODE: if (TXByteCtr) { UCB1TXBUF = TransmitBuffer[TransmitIndex++]; TXByteCtr--; } else { //Done with transmission UCB1CTLW0 |= UCTXSTP; // Send stop condition MasterMode = IDLE_MODE; UCB1IE &= ~UCTXIE; // disable TX interrupt __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; default: __no_operation(); break; } break; default: break; } } #pragma vector = PORT2_VECTOR __interrupt void PORT2_ISR(void) { switch(__even_in_range(P2IV, P2IV_P2IFG7)) { case P2IV_NONE : break; case P2IV_P2IFG0 : break; case P2IV_P2IFG1 : break; case P2IV_P2IFG2 : break; case P2IV_P2IFG3 : break; case P2IV_P2IFG4 : break; case P2IV_P2IFG5 : //Int2 sensor interrupt P2IFG = P2IFG & ~(BIT2); break; case P2IV_P2IFG6 : break; case P2IV_P2IFG7 : break; default : _never_executed(); } } // Timer_0 Interrupt Service Routine #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A0 (void) { TA0CTL = TA0CTL & (~TAIFG); // Reset Timer_0 so it keeps counting }
您 需要在链接器文件搜索路径中包含 QMath 库。
Project Properties -> CCS Build -> MSP430 Linker -> File Search Path
在"Include library file or command file as input"部分中、添加 QmathLib.a 文件的位置。 在我的机器上、它位于屏幕截图中的位置。 请注意、IQmathLib.a 和 QmathLib.a. 由于您使用的是 Qmath、请添加"QmathLib.a"文件。