活动介绍

ARDUINO提取多分含包头包尾的数据包中的数据,其中数据包含0X00

时间: 2023-10-07 16:03:56 浏览: 118
在 Arduino 中提取多分含包头包尾的数据包中的数据,可以使用循环和指针来实现。如果数据包中包含 `0x00`,则需要特殊处理,因为 `0x00` 是字符串的结束符,不能忽略。 示例代码如下: ```c byte buf[] = {0x55, 0xAA, 0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0x06, 0x00, 0x07, 0x08, 0x09, 0x0A, 0x55, 0xAA}; // 假设数据包格式为:包头 0x55, 0xAA,数据,包尾 0x55, 0xAA byte *ptr = buf; // 指向数据包的指针 int len = sizeof(buf); // 数据包的长度 while (ptr < buf + len) { // 查找包头 while (ptr < buf + len && (*ptr != 0x55 || *(ptr + 1) != 0xAA)) { ptr++; } if (ptr >= buf + len) { break; } // 查找包尾 byte *end = ptr + 2; // 指向包头后面的数据 while (end < buf + len && (*end != 0x55 || *(end + 1) != 0xAA)) { end++; } if (end >= buf + len) { break; } // 提取数据 byte *data = ptr + 2; // 指向包头后面的数据 int data_len = end - data; // 数据的长度 byte *p = data; while (p < data + data_len) { if (*p == 0x00) { // 处理包含 0x00 的数据 // TODO: 处理数据 p++; } else { // 提取数据 // TODO: 处理数据 p++; } } ptr = end + 2; // 指向下一个数据包的包头 } ``` 在上面的示例代码中,`buf` 数组为示例数据包,假设数据包格式为:包头 `0x55, 0xAA`,数据,包尾 `0x55, 0xAA`。使用两个循环分别查找包头和包尾,然后使用指针提取数据。在提取数据时,如果数据中包含 `0x00`,则需要特殊处理,否则可以直接提取数据。 注意:在实际应用中,需要根据数据包的具体格式进行相应的调整。
阅读全文

相关推荐

/* This is a library written for the BNO080 SparkFun sells these at its website: www.sparkfun.com Do you like this library? Help support SparkFun. Buy a board! https://www.sparkfun.com/products/14586 Written by Nathan Seidle @ SparkFun Electronics, December 28th, 2017 The BNO080 IMU is a powerful triple axis gyro/accel/magnetometer coupled with an ARM processor to maintain and complete all the complex calculations for various VR, inertial, step counting, and movement operations. This library handles the initialization of the BNO080 and is able to query the sensor for different readings. https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library Development environment specifics: Arduino IDE 1.8.3 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. If not, see <http://www.gnu.org/licenses/>. */ #include "SparkFun_BNO080_Arduino_Library.h" //Attempt communication with the device //Return true if we got a 'Polo' back from Marco boolean BNO080::begin(uint8_t deviceAddress, TwoWire &wirePort) { _deviceAddress = deviceAddress; //If provided, store the I2C address from user _i2cPort = &wirePort; //Grab which port the user wants us to use //We expect caller to begin their I2C port, with the speed of their choice external to the library //But if they forget, we start the hardware here. _i2cPort->begin(); //Begin by resetting the IMU softReset(); //Check communication with device shtpData[0] = SHTP_REPORT_PRODUCT_ID_REQUEST; //Request the product ID and reset info shtpData[1] = 0; //Reserved //Transmit packet on channel 2, 2 bytes sendPacket(CHANNEL_CONTROL, 2); //Now we wait for response if (receivePacket() == true) { if (shtpData[0] == SHTP_REPORT_PRODUCT_ID_RESPONSE) { return(true); } } return(false); //Something went wrong } //Calling this function with nothing sets the debug port to Serial //You can also call it with other streams like Serial1, SerialUSB, etc. void BNO080::enableDebugging(Stream &debugPort) { _debugPort = &debugPort; _printDebug = true; } //Updates the latest variables if possible //Returns false if new readings are not available bool BNO080::dataAvailable(void) { if (receivePacket() == true) { //Check to see if this packet is a sensor reporting its data to us if (shtpHeader[2] == CHANNEL_REPORTS && shtpData[0] == SHTP_REPORT_BASE_TIMESTAMP) { parseInputReport(); //This will update the rawAccelX, etc variables depending on which feature report is found return(true); } } return(false); } //This function pulls the data from the input report //The input reports vary in length so this function stores the various 16-bit values as globals //Unit responds with packet that contains the following: //shtpHeader[0:3]: First, a 4 byte header //shtpData[0:4]: Then a 5 byte timestamp of microsecond clicks since reading was taken //shtpData[5 + 0]: Then a feature report ID (0x01 for Accel, 0x05 for Rotation Vector) //shtpData[5 + 1]: Sequence number (See 6.5.18.2) //shtpData[5 + 2]: Status //shtpData[3]: Delay //shtpData[4:5]: i/accel x/gyro x/etc //shtpData[6:7]: j/accel y/gyro y/etc //shtpData[8:9]: k/accel z/gyro z/etc //shtpData[10:11]: real/gyro temp/etc //shtpData[12:13]: Accuracy estimate void BNO080::parseInputReport(void) { //Calculate the number of data bytes in this packet int16_t dataLength = ((uint16_t)shtpHeader[1] << 8 | shtpHeader[0]); dataLength &= ~(1 << 15); //Clear the MSbit. This bit indicates if this package is a continuation of the last. //Ignore it for now. TODO catch this as an error and exit dataLength -= 4; //Remove the header bytes from the data count uint8_t status = shtpData[5 + 2] & 0x03; //Get status bits uint16_t data1 = (uint16_t)shtpData[5 + 5] << 8 | shtpData[5 + 4]; uint16_t data2 = (uint16_t)shtpData[5 + 7] << 8 | shtpData[5 + 6]; uint16_t data3 = (uint16_t)shtpData[5 + 9] << 8 | shtpData[5 + 8]; uint16_t data4 = 0; uint16_t data5 = 0; if(dataLength - 5 > 9) { data4= (uint16_t)shtpData[5 + 11] << 8 | shtpData[5 + 10]; } if(dataLength - 5 > 11) { data5 = (uint16_t)shtpData[5 + 13] << 8 | shtpData[5 + 12]; } //Store these generic values to their proper global variable if(shtpData[5] == SENSOR_REPORTID_ACCELEROMETER) { accelAccuracy = status; rawAccelX = data1; rawAccelY = data2; rawAccelZ = data3; } else if(shtpData[5] == SENSOR_REPORTID_LINEAR_ACCELERATION) { accelLinAccuracy = status; rawLinAccelX = data1; rawLinAccelY = data2; rawLinAccelZ = data3; } else if(shtpData[5] == SENSOR_REPORTID_GYROSCOPE) { gyroAccuracy = status; rawGyroX = data1; rawGyroY = data2; rawGyroZ = data3; } else if(shtpData[5] == SENSOR_REPORTID_MAGNETIC_FIELD) { magAccuracy = status; rawMagX = data1; rawMagY = data2; rawMagZ = data3; } else if(shtpData[5] == SENSOR_REPORTID_ROTATION_VECTOR || shtpData[5] == SENSOR_REPORTID_GAME_ROTATION_VECTOR) { quatAccuracy = status; rawQuatI = data1; rawQuatJ = data2; rawQuatK = data3; rawQuatReal = data4; rawQuatRadianAccuracy = data5; //Only available on rotation vector, not game rot vector } else if(shtpData[5] == SENSOR_REPORTID_STEP_COUNTER) { stepCount = data3; //Bytes 8/9 } else if(shtpData[5] == SENSOR_REPORTID_STABILITY_CLASSIFIER) { stabilityClassifier = shtpData[5 + 4]; //Byte 4 only } else if(shtpData[5] == SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER) { activityClassifier = shtpData[5 + 5]; //Most likely state //Load activity classification confidences into the array for(uint8_t x = 0 ; x < 9 ; x++) //Hardcoded to max of 9. TODO - bring in array size _activityConfidences[x] = shtpData[5 + 6 + x]; //5 bytes of timestamp, byte 6 is first confidence byte } else { //This sensor report ID is unhandled. //See reference manual to add additional feature reports as needed } //TODO additional feature reports may be strung together. Parse them all. } //Return the rotation vector quaternion I float BNO080::getQuatI() { float quat = qToFloat(rawQuatI, rotationVector_Q1); return(quat); } //Return the rotation vector quaternion J float BNO080::getQuatJ() { float quat = qToFloat(rawQuatJ, rotationVector_Q1); return(quat); } //Return the rotation vector quaternion K float BNO080::getQuatK() { float quat = qToFloat(rawQuatK, rotationVector_Q1); return(quat); } //Return the rotation vector quaternion Real float BNO080::getQuatReal() { float quat = qToFloat(rawQuatReal, rotationVector_Q1); return(quat); } //Return the rotation vector accuracy float BNO080::getQuatRadianAccuracy() { float quat = qToFloat(rawQuatRadianAccuracy, rotationVector_Q1); return(quat); } //Return the acceleration component uint8_t BNO080::getQuatAccuracy() { return(quatAccuracy); } //Return the acceleration component float BNO080::getAccelX() { float accel = qToFloat(rawAccelX, accelerometer_Q1); return(accel); } //Return the acceleration component float BNO080::getAccelY() { float accel = qToFloat(rawAccelY, accelerometer_Q1); return(accel); } //Return the acceleration component float BNO080::getAccelZ() { float accel = qToFloat(rawAccelZ, accelerometer_Q1); return(accel); } //Return the acceleration component uint8_t BNO080::getAccelAccuracy() { return(accelAccuracy); } // linear acceleration, i.e. minus gravity //Return the acceleration component float BNO080::getLinAccelX() { float accel = qToFloat(rawLinAccelX, linear_accelerometer_Q1); return(accel); } //Return the acceleration component float BNO080::getLinAccelY() { float accel = qToFloat(rawLinAccelY, linear_accelerometer_Q1); return(accel); } //Return the acceleration component float BNO080::getLinAccelZ() { float accel = qToFloat(rawLinAccelZ, linear_accelerometer_Q1); return(accel); } //Return the acceleration component uint8_t BNO080::getLinAccelAccuracy() { return(accelLinAccuracy); } //Return the gyro component float BNO080::getGyroX() { float gyro = qToFloat(rawGyroX, gyro_Q1); return(gyro); } //Return the gyro component float BNO080::getGyroY() { float gyro = qToFloat(rawGyroY, gyro_Q1); return(gyro); } //Return the gyro component float BNO080::getGyroZ() { float gyro = qToFloat(rawGyroZ, gyro_Q1); return(gyro); } //Return the gyro component uint8_t BNO080::getGyroAccuracy() { return(gyroAccuracy); } //Return the magnetometer component float BNO080::getMagX() { float mag = qToFloat(rawMagX, magnetometer_Q1); return(mag); } //Return the magnetometer component float BNO080::getMagY() { float mag = qToFloat(rawMagY, magnetometer_Q1); return(mag); } //Return the magnetometer component float BNO080::getMagZ() { float mag = qToFloat(rawMagZ, magnetometer_Q1); return(mag); } //Return the mag component uint8_t BNO080::getMagAccuracy() { return(magAccuracy); } //Return the step count uint16_t BNO080::getStepCount() { return(stepCount); } //Return the stability classifier uint8_t BNO080::getStabilityClassifier() { return(stabilityClassifier); } //Return the activity classifier uint8_t BNO080::getActivityClassifier() { return(activityClassifier); } //Given a record ID, read the Q1 value from the metaData record in the FRS (ya, it's complicated) //Q1 is used for all sensor data calculations int16_t BNO080::getQ1(uint16_t recordID) { //Q1 is always the lower 16 bits of word 7 uint16_t q = readFRSword(recordID, 7) & 0xFFFF; //Get word 7, lower 16 bits return(q); } //Given a record ID, read the Q2 value from the metaData record in the FRS //Q2 is used in sensor bias int16_t BNO080::getQ2(uint16_t recordID) { //Q2 is always the upper 16 bits of word 7 uint16_t q = readFRSword(recordID, 7) >> 16; //Get word 7, upper 16 bits return(q); } //Given a record ID, read the Q3 value from the metaData record in the FRS //Q3 is used in sensor change sensitivity int16_t BNO080::getQ3(uint16_t recordID) { //Q3 is always the upper 16 bits of word 8 uint16_t q = readFRSword(recordID, 8) >> 16; //Get word 8, upper 16 bits return(q); } //Given a record ID, read the resolution value from the metaData record in the FRS for a given sensor float BNO080::getResolution(uint16_t recordID) { //The resolution Q value are 'the same as those used in the sensor's input report' //This should be Q1. int16_t Q = getQ1(recordID); //Resolution is always word 2 uint32_t value = readFRSword(recordID, 2); //Get word 2 float resolution = qToFloat(value, Q); return(resolution); } //Given a record ID, read the range value from the metaData record in the FRS for a given sensor float BNO080::getRange(uint16_t recordID) { //The resolution Q value are 'the same as those used in the sensor's input report' //This should be Q1. int16_t Q = getQ1(recordID); //Range is always word 1 uint32_t value = readFRSword(recordID, 1); //Get word 1 float range = qToFloat(value, Q); return(range); } //Given a record ID and a word number, look up the word data //Helpful for pulling out a Q value, range, etc. //Use readFRSdata for pulling out multi-word objects for a sensor (Vendor data for example) uint32_t BNO080::readFRSword(uint16_t recordID, uint8_t wordNumber) { if(readFRSdata(recordID, wordNumber, 1) == true) //Get word number, just one word in length from FRS return(metaData[0]); //Return this one word return(0); //Error } //Ask the sensor for data from the Flash Record System //See 6.3.6 page 40, FRS Read Request void BNO080::frsReadRequest(uint16_t recordID, uint16_t readOffset, uint16_t blockSize) { shtpData[0] = SHTP_REPORT_FRS_READ_REQUEST; //FRS Read Request shtpData[1] = 0; //Reserved shtpData[2] = (readOffset >> 0) & 0xFF; //Read Offset LSB shtpData[3] = (readOffset >> 8) & 0xFF; //Read Offset MSB shtpData[4] = (recordID >> 0) & 0xFF; //FRS Type LSB shtpData[5] = (recordID >> 8) & 0xFF; //FRS Type MSB shtpData[6] = (blockSize >> 0) & 0xFF; //Block size LSB shtpData[7] = (blockSize >> 8) & 0xFF; //Block size MSB //Transmit packet on channel 2, 8 bytes sendPacket(CHANNEL_CONTROL, 8); } //Given a sensor or record ID, and a given start/stop bytes, read the data from the Flash Record System (FRS) for this sensor //Returns true if metaData array is loaded successfully //Returns false if failure bool BNO080::readFRSdata(uint16_t recordID, uint8_t startLocation, uint8_t wordsToRead) { uint8_t spot = 0; //First we send a Flash Record System (FRS) request frsReadRequest(recordID, startLocation, wordsToRead); //From startLocation of record, read a # of words //Read bytes until FRS reports that the read is complete while (1) { //Now we wait for response while (1) { uint8_t counter = 0; while(receivePacket() == false) { if(counter++ > 100) return(false); //Give up delay(1); } //We have the packet, inspect it for the right contents //See page 40. Report ID should be 0xF3 and the FRS types should match the thing we requested if (shtpData[0] == SHTP_REPORT_FRS_READ_RESPONSE) if ( ( (uint16_t)shtpData[13] << 8 | shtpData[12]) == recordID) break; //This packet is one we are looking for } uint8_t dataLength = shtpData[1] >> 4; uint8_t frsStatus = shtpData[1] & 0x0F; uint32_t data0 = (uint32_t)shtpData[7] << 24 | (uint32_t)shtpData[6] << 16 | (uint32_t)shtpData[5] << 8 | (uint32_t)shtpData[4]; uint32_t data1 = (uint32_t)shtpData[11] << 24 | (uint32_t)shtpData[10] << 16 | (uint32_t)shtpData[9] << 8 | (uint32_t)shtpData[8]; //Record these words to the metaData array if (dataLength > 0) { metaData[spot++] = data0; } if (dataLength > 1) { metaData[spot++] = data1; } if (spot >= MAX_METADATA_SIZE) { if(_printDebug == true) _debugPort->println(F("metaData array over run. Returning.")); return(true); //We have run out of space in our array. Bail. } if (frsStatus == 3 || frsStatus == 6 || frsStatus == 7) { return(true); //FRS status is read completed! We're done! } } } //Send command to reset IC //Read all advertisement packets from sensor //The sensor has been seen to reset twice if we attempt too much too quickly. //This seems to work reliably. void BNO080::softReset(void) { shtpData[0] = 1; //Reset //Attempt to start communication with sensor sendPacket(CHANNEL_EXECUTABLE, 1); //Transmit packet on channel 1, 1 byte //Read all incoming data and flush it delay(50); while (receivePacket() == true) ; delay(50); while (receivePacket() == true) ; } //Get the reason for the last reset //1 = POR, 2 = Internal reset, 3 = Watchdog, 4 = External reset, 5 = Other uint8_t BNO080::resetReason() { shtpData[0] = SHTP_REPORT_PRODUCT_ID_REQUEST; //Request the product ID and reset info shtpData[1] = 0; //Reserved //Transmit packet on channel 2, 2 bytes sendPacket(CHANNEL_CONTROL, 2); //Now we wait for response if (receivePacket() == true) { if (shtpData[0] == SHTP_REPORT_PRODUCT_ID_RESPONSE) { return(shtpData[1]); } } return(0); } //Given a register value and a Q point, convert to float //See https://en.wikipedia.org/wiki/Q_(number_format) float BNO080::qToFloat(int16_t fixedPointValue, uint8_t qPoint) { float qFloat = fixedPointValue; qFloat *= pow(2, qPoint * -1); return (qFloat); } //Sends the packet to enable the rotation vector void BNO080::enableRotationVector(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_ROTATION_VECTOR, timeBetweenReports); } //Sends the packet to enable the rotation vector void BNO080::enableGameRotationVector(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_GAME_ROTATION_VECTOR, timeBetweenReports); } //Sends the packet to enable the accelerometer void BNO080::enableAccelerometer(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_ACCELEROMETER, timeBetweenReports); } //Sends the packet to enable the accelerometer void BNO080::enableLinearAccelerometer(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_LINEAR_ACCELERATION, timeBetweenReports); } //Sends the packet to enable the gyro void BNO080::enableGyro(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_GYROSCOPE, timeBetweenReports); } //Sends the packet to enable the magnetometer void BNO080::enableMagnetometer(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_MAGNETIC_FIELD, timeBetweenReports); } //Sends the packet to enable the step counter void BNO080::enableStepCounter(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_STEP_COUNTER, timeBetweenReports); } //Sends the packet to enable the Stability Classifier void BNO080::enableStabilityClassifier(uint16_t timeBetweenReports) { setFeatureCommand(SENSOR_REPORTID_STABILITY_CLASSIFIER, timeBetweenReports); } //Sends the packet to enable the various activity classifiers void BNO080::enableActivityClassifier(uint16_t timeBetweenReports, uint32_t activitiesToEnable, uint8_t (&activityConfidences)[9]) { _activityConfidences = activityConfidences; //Store pointer to array setFeatureCommand(SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER, timeBetweenReports, activitiesToEnable); } //Sends the commands to begin calibration of the accelerometer void BNO080::calibrateAccelerometer() { sendCalibrateCommand(CALIBRATE_ACCEL); } //Sends the commands to begin calibration of the gyro void BNO080::calibrateGyro() { sendCalibrateCommand(CALIBRATE_GYRO); } //Sends the commands to begin calibration of the magnetometer void BNO080::calibrateMagnetometer() { sendCalibrateCommand(CALIBRATE_MAG); } //Sends the commands to begin calibration of the planar accelerometer void BNO080::calibratePlanarAccelerometer() { sendCalibrateCommand(CALIBRATE_PLANAR_ACCEL); } //See 2.2 of the Calibration Procedure document 1000-4044 void BNO080::calibrateAll() { sendCalibrateCommand(CALIBRATE_ACCEL_GYRO_MAG); } void BNO080::endCalibration() { sendCalibrateCommand(CALIBRATE_STOP); //Disables all calibrations } //Given a sensor's report ID, this tells the BNO080 to begin reporting the values void BNO080::setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports) { setFeatureCommand(reportID, timeBetweenReports, 0); //No specific config } //Given a sensor's report ID, this tells the BNO080 to begin reporting the values //Also sets the specific config word. Useful for personal activity classifier void BNO080::setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports, uint32_t specificConfig) { long microsBetweenReports = (long)timeBetweenReports * 1000L; shtpData[0] = SHTP_REPORT_SET_FEATURE_COMMAND; //Set feature command. Reference page 55 shtpData[1] = reportID; //Feature Report ID. 0x01 = Accelerometer, 0x05 = Rotation vector shtpData[2] = 0; //Feature flags shtpData[3] = 0; //Change sensitivity (LSB) shtpData[4] = 0; //Change sensitivity (MSB) shtpData[5] = (microsBetweenReports >> 0) & 0xFF; //Report interval (LSB) in microseconds. 0x7A120 = 500ms shtpData[6] = (microsBetweenReports >> 8) & 0xFF; //Report interval shtpData[7] = (microsBetweenReports >> 16) & 0xFF; //Report interval shtpData[8] = (microsBetweenReports >> 24) & 0xFF; //Report interval (MSB) shtpData[9] = 0; //Batch Interval (LSB) shtpData[10] = 0; //Batch Interval shtpData[11] = 0; //Batch Interval shtpData[12] = 0; //Batch Interval (MSB) shtpData[13] = (specificConfig >> 0) & 0xFF; //Sensor-specific config (LSB) shtpData[14] = (specificConfig >> 8) & 0xFF; //Sensor-specific config shtpData[15] = (specificConfig >> 16) & 0xFF; //Sensor-specific config shtpData[16] = (specificConfig >> 24) & 0xFF; //Sensor-specific config (MSB) //Transmit packet on channel 2, 17 bytes sendPacket(CHANNEL_CONTROL, 17); } //Tell the sensor to do a command //See 6.3.8 page 41, Command request //The caller is expected to set P0 through P8 prior to calling void BNO080::sendCommand(uint8_t command) { shtpData[0] = SHTP_REPORT_COMMAND_REQUEST; //Command Request shtpData[1] = commandSequenceNumber++; //Increments automatically each function call shtpData[2] = command; //Command //Caller must set these /*shtpData[3] = 0; //P0 shtpData[4] = 0; //P1 shtpData[5] = 0; //P2 shtpData[6] = 0; shtpData[7] = 0; shtpData[8] = 0; shtpData[9] = 0; shtpData[10] = 0; shtpData[11] = 0;*/ //Transmit packet on channel 2, 12 bytes sendPacket(CHANNEL_CONTROL, 12); } //This tells the BNO080 to begin calibrating //See page 50 of reference manual and the 1000-4044 calibration doc void BNO080::sendCalibrateCommand(uint8_t thingToCalibrate) { /*shtpData[3] = 0; //P0 - Accel Cal Enable shtpData[4] = 0; //P1 - Gyro Cal Enable shtpData[5] = 0; //P2 - Mag Cal Enable shtpData[6] = 0; //P3 - Subcommand 0x00 shtpData[7] = 0; //P4 - Planar Accel Cal Enable shtpData[8] = 0; //P5 - Reserved shtpData[9] = 0; //P6 - Reserved shtpData[10] = 0; //P7 - Reserved shtpData[11] = 0; //P8 - Reserved*/ for(uint8_t x = 3 ; x < 12 ; x++) //Clear this section of the shtpData array shtpData[x] = 0; if(thingToCalibrate == CALIBRATE_ACCEL) shtpData[3] = 1; else if(thingToCalibrate == CALIBRATE_GYRO) shtpData[4] = 1; else if(thingToCalibrate == CALIBRATE_MAG) shtpData[5] = 1; else if(thingToCalibrate == CALIBRATE_PLANAR_ACCEL) shtpData[7] = 1; else if(thingToCalibrate == CALIBRATE_ACCEL_GYRO_MAG) { shtpData[3] = 1; shtpData[4] = 1; shtpData[5] = 1; } else if(thingToCalibrate == CALIBRATE_STOP) ; //Do nothing, bytes are set to zero //Using this shtpData packet, send a command sendCommand(COMMAND_ME_CALIBRATE); } //This tells the BNO080 to save the Dynamic Calibration Data (DCD) to flash //See page 49 of reference manual and the 1000-4044 calibration doc void BNO080::saveCalibration() { /*shtpData[3] = 0; //P0 - Reserved shtpData[4] = 0; //P1 - Reserved shtpData[5] = 0; //P2 - Reserved shtpData[6] = 0; //P3 - Reserved shtpData[7] = 0; //P4 - Reserved shtpData[8] = 0; //P5 - Reserved shtpData[9] = 0; //P6 - Reserved shtpData[10] = 0; //P7 - Reserved shtpData[11] = 0; //P8 - Reserved*/ for(uint8_t x = 3 ; x < 12 ; x++) //Clear this section of the shtpData array shtpData[x] = 0; //Using this shtpData packet, send a command sendCommand(COMMAND_DCD); //Save DCD command } //Wait a certain time for incoming I2C bytes before giving up //Returns false if failed boolean BNO080::waitForI2C() { for (uint8_t counter = 0 ; counter < 100 ; counter++) //Don't got more than 255 { if (_i2cPort->available() > 0) return (true); delay(1); } if(_printDebug == true) _debugPort->println(F("I2C timeout")); return (false); } //Check to see if there is any new data available //Read the contents of the incoming packet into the shtpData array boolean BNO080::receivePacket(void) { _i2cPort->requestFrom((uint8_t)_deviceAddress, (uint8_t)4); //Ask for four bytes to find out how much data we need to read if (waitForI2C() == false) return (false); //Error //Get the first four bytes, aka the packet header uint8_t packetLSB = _i2cPort->read(); uint8_t packetMSB = _i2cPort->read(); uint8_t channelNumber = _i2cPort->read(); uint8_t sequenceNumber = _i2cPort->read(); //Not sure if we need to store this or not //Store the header info. shtpHeader[0] = packetLSB; shtpHeader[1] = packetMSB; shtpHeader[2] = channelNumber; shtpHeader[3] = sequenceNumber; //Calculate the number of data bytes in this packet int16_t dataLength = ((uint16_t)packetMSB << 8 | packetLSB); dataLength &= ~(1 << 15); //Clear the MSbit. //This bit indicates if this package is a continuation of the last. Ignore it for now. //TODO catch this as an error and exit if (dataLength == 0) { //Packet is empty return (false); //All done } dataLength -= 4; //Remove the header bytes from the data count getData(dataLength); return (true); //We're done! } //Sends multiple requests to sensor until all data bytes are received from sensor //The shtpData buffer has max capacity of MAX_PACKET_SIZE. Any bytes over this amount will be lost. //Arduino I2C read limit is 32 bytes. Header is 4 bytes, so max data we can read per interation is 28 bytes boolean BNO080::getData(uint16_t bytesRemaining) { uint16_t dataSpot = 0; //Start at the beginning of shtpData array //Setup a series of chunked 32 byte reads while (bytesRemaining > 0) { uint16_t numberOfBytesToRead = bytesRemaining; if (numberOfBytesToRead > (I2C_BUFFER_LENGTH-4)) numberOfBytesToRead = (I2C_BUFFER_LENGTH-4); _i2cPort->requestFrom((uint8_t)_deviceAddress, (uint8_t)(numberOfBytesToRead + 4)); if (waitForI2C() == false) return (0); //Error //The first four bytes are header bytes and are throw away _i2cPort->read(); _i2cPort->read(); _i2cPort->read(); _i2cPort->read(); for (uint8_t x = 0 ; x < numberOfBytesToRead ; x++) { uint8_t incoming = _i2cPort->read(); if (dataSpot < MAX_PACKET_SIZE) { shtpData[dataSpot++] = incoming; //Store data into the shtpData array } else { //Do nothing with the data } } bytesRemaining -= numberOfBytesToRead; } return (true); //Done! } //Given the data packet, send the header then the data //Returns false if sensor does not ACK //TODO - Arduino has a max 32 byte send. Break sending into multi packets if needed. boolean BNO080::sendPacket(uint8_t channelNumber, uint8_t dataLength) { uint8_t packetLength = dataLength + 4; //Add four bytes for the header //if(packetLength > I2C_BUFFER_LENGTH) return(false); //You are trying to send too much. Break into smaller packets. _i2cPort->beginTransmission(_deviceAddress); //Send the 4 byte packet header _i2cPort->write(packetLength & 0xFF); //Packet length LSB _i2cPort->write(packetLength >> 8); //Packet length MSB _i2cPort->write(channelNumber); //Channel number _i2cPort->write(sequenceNumber[channelNumber]++); //Send the sequence number, increments with each packet sent, different counter for each channel //Send the user's data packet for (uint8_t i = 0 ; i < dataLength ; i++) { _i2cPort->write(shtpData[i]); } if (_i2cPort->endTransmission() != 0) { return (false); } return (true); } //Pretty prints the contents of the current shtp header and data packets void BNO080::printPacket(void) { if(_printDebug == true) { uint16_t packetLength = (uint16_t)shtpHeader[1] << 8 | shtpHeader[0]; //Print the four byte header _debugPort->print(F("Header:")); for(uint8_t x = 0 ; x < 4 ; x++) { _debugPort->print(F(" ")); if(shtpHeader[x] < 0x10) _debugPort->print(F("0")); _debugPort->print(shtpHeader[x], HEX); } uint8_t printLength = packetLength - 4; if(printLength > 40) printLength = 40; //Artificial limit. We don't want the phone book. _debugPort->print(F(" Body:")); for(uint8_t x = 0 ; x < printLength ; x++) { _debugPort->print(F(" ")); if(shtpData[x] < 0x10) _debugPort->print(F("0")); _debugPort->print(shtpData[x], HEX); } if (packetLength & 1 << 15) { _debugPort->println(F(" [Continued packet] ")); packetLength &= ~(1 << 15); } _debugPort->print(F(" Length:")); _debugPort->print (packetLength); _debugPort->print(F(" Channel:")); if (shtpHeader[2] == 0) _debugPort->print(F("Command")); else if (shtpHeader[2] == 1) _debugPort->print(F("Executable")); else if (shtpHeader[2] == 2) _debugPort->print(F("Control")); else if (shtpHeader[2] == 3) _debugPort->print(F("Sensor-report")); else if (shtpHeader[2] == 4) _debugPort->print(F("Wake-report")); else if (shtpHeader[2] == 5) _debugPort->print(F("Gyro-vector")); else _debugPort->print(shtpHeader[2]); _debugPort->println(); } } /* This is a library written for the BNO080 SparkFun sells these at its website: www.sparkfun.com Do you like this library? Help support SparkFun. Buy a board! https://www.sparkfun.com/products/14586 Written by Nathan Seidle @ SparkFun Electronics, December 28th, 2017 The BNO080 IMU is a powerful triple axis gyro/accel/magnetometer coupled with an ARM processor to maintain and complete all the complex calculations for various VR, inertial, step counting, and movement operations. This library handles the initialization of the BNO080 and is able to query the sensor for different readings. https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library Development environment specifics: Arduino IDE 1.8.3 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. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #if (ARDUINO >= 100) #include "Arduino.h" #else #include "WProgram.h" #endif #include <Wire.h> //The default I2C address for the BNO080 on the SparkX breakout is 0x4B. 0x4A is also possible. #define BNO080_DEFAULT_ADDRESS 0x4B //Platform specific configurations //Define the size of the I2C buffer based on the platform the user has //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) //I2C_BUFFER_LENGTH is defined in Wire.H #define I2C_BUFFER_LENGTH BUFFER_LENGTH #elif defined(__SAMD21G18A__) //SAMD21 uses RingBuffer.h #define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE #elif __MK20DX256__ //Teensy #elif ARDUINO_ARCH_ESP32 //ESP32 based platforms #else //The catch-all default is 32 #define I2C_BUFFER_LENGTH 32 #endif //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //Registers const byte CHANNEL_COMMAND = 0; const byte CHANNEL_EXECUTABLE = 1; const byte CHANNEL_CONTROL = 2; const byte CHANNEL_REPORTS = 3; const byte CHANNEL_WAKE_REPORTS = 4; const byte CHANNEL_GYRO = 5; //All the ways we can configure or talk to the BNO080, figure 34, page 36 reference manual //These are used for low level communication with the sensor, on channel 2 #define SHTP_REPORT_COMMAND_RESPONSE 0xF1 #define SHTP_REPORT_COMMAND_REQUEST 0xF2 #define SHTP_REPORT_FRS_READ_RESPONSE 0xF3 #define SHTP_REPORT_FRS_READ_REQUEST 0xF4 #define SHTP_REPORT_PRODUCT_ID_RESPONSE 0xF8 #define SHTP_REPORT_PRODUCT_ID_REQUEST 0xF9 #define SHTP_REPORT_BASE_TIMESTAMP 0xFB #define SHTP_REPORT_SET_FEATURE_COMMAND 0xFD //All the different sensors and features we can get reports from //These are used when enabling a given sensor #define SENSOR_REPORTID_ACCELEROMETER 0x01 #define SENSOR_REPORTID_GYROSCOPE 0x02 #define SENSOR_REPORTID_MAGNETIC_FIELD 0x03 #define SENSOR_REPORTID_LINEAR_ACCELERATION 0x04 #define SENSOR_REPORTID_ROTATION_VECTOR 0x05 #define SENSOR_REPORTID_GRAVITY 0x06 #define SENSOR_REPORTID_GAME_ROTATION_VECTOR 0x08 #define SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR 0x09 #define SENSOR_REPORTID_TAP_DETECTOR 0x10 #define SENSOR_REPORTID_STEP_COUNTER 0x11 #define SENSOR_REPORTID_STABILITY_CLASSIFIER 0x13 #define SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER 0x1E //Record IDs from figure 29, page 29 reference manual //These are used to read the metadata for each sensor type #define FRS_RECORDID_ACCELEROMETER 0xE302 #define FRS_RECORDID_GYROSCOPE_CALIBRATED 0xE306 #define FRS_RECORDID_MAGNETIC_FIELD_CALIBRATED 0xE309 #define FRS_RECORDID_ROTATION_VECTOR 0xE30B //Command IDs from section 6.4, page 42 //These are used to calibrate, initialize, set orientation, tare etc the sensor #define COMMAND_ERRORS 1 #define COMMAND_COUNTER 2 #define COMMAND_TARE 3 #define COMMAND_INITIALIZE 4 #define COMMAND_DCD 6 #define COMMAND_ME_CALIBRATE 7 #define COMMAND_DCD_PERIOD_SAVE 9 #define COMMAND_OSCILLATOR 10 #define COMMAND_CLEAR_DCD 11 #define CALIBRATE_ACCEL 0 #define CALIBRATE_GYRO 1 #define CALIBRATE_MAG 2 #define CALIBRATE_PLANAR_ACCEL 3 #define CALIBRATE_ACCEL_GYRO_MAG 4 #define CALIBRATE_STOP 5 #define MAX_PACKET_SIZE 128 //Packets can be up to 32k but we don't have that much RAM. #define MAX_METADATA_SIZE 9 //This is in words. There can be many but we mostly only care about the first 9 (Qs, range, etc) class BNO080 { public: boolean begin(uint8_t deviceAddress = BNO080_DEFAULT_ADDRESS, TwoWire &wirePort = Wire); //By default use the default I2C addres, and use Wire port void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used. void softReset(); //Try to reset the IMU via software uint8_t resetReason(); //Query the IMU for the reason it last reset float qToFloat(int16_t fixedPointValue, uint8_t qPoint); //Given a Q value, converts fixed point floating to regular floating point number boolean waitForI2C(); //Delay based polling for I2C traffic boolean receivePacket(void); boolean getData(uint16_t bytesRemaining); //Given a number of bytes, send the requests in I2C_BUFFER_LENGTH chunks boolean sendPacket(uint8_t channelNumber, uint8_t dataLength); void printPacket(void); //Prints the current shtp header and data packets void enableRotationVector(uint16_t timeBetweenReports); void enableGameRotationVector(uint16_t timeBetweenReports); void enableAccelerometer(uint16_t timeBetweenReports); void enableLinearAccelerometer(uint16_t timeBetweenReports); void enableGyro(uint16_t timeBetweenReports); void enableMagnetometer(uint16_t timeBetweenReports); void enableStepCounter(uint16_t timeBetweenReports); void enableStabilityClassifier(uint16_t timeBetweenReports); void enableActivityClassifier(uint16_t timeBetweenReports, uint32_t activitiesToEnable, uint8_t (&activityConfidences)[9]); bool dataAvailable(void); void parseInputReport(void); float getQuatI(); float getQuatJ(); float getQuatK(); float getQuatReal(); float getQuatRadianAccuracy(); uint8_t getQuatAccuracy(); float getAccelX(); float getAccelY(); float getAccelZ(); uint8_t getAccelAccuracy(); float getLinAccelX(); float getLinAccelY(); float getLinAccelZ(); uint8_t getLinAccelAccuracy(); float getGyroX(); float getGyroY(); float getGyroZ(); uint8_t getGyroAccuracy(); float getMagX(); float getMagY(); float getMagZ(); uint8_t getMagAccuracy(); void calibrateAccelerometer(); void calibrateGyro(); void calibrateMagnetometer(); void calibratePlanarAccelerometer(); void calibrateAll(); void endCalibration(); void saveCalibration(); uint16_t getStepCount(); uint8_t getStabilityClassifier(); uint8_t getActivityClassifier(); void setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports); void setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports, uint32_t specificConfig); void sendCommand(uint8_t command); void sendCalibrateCommand(uint8_t thingToCalibrate); //Metadata functions int16_t getQ1(uint16_t recordID); int16_t getQ2(uint16_t recordID); int16_t getQ3(uint16_t recordID); float getResolution(uint16_t recordID); float getRange(uint16_t recordID); uint32_t readFRSword(uint16_t recordID, uint8_t wordNumber); void frsReadRequest(uint16_t recordID, uint16_t readOffset, uint16_t blockSize); bool readFRSdata(uint16_t recordID, uint8_t startLocation, uint8_t wordsToRead); //Global Variables uint8_t shtpHeader[4]; //Each packet has a header of 4 bytes uint8_t shtpData[MAX_PACKET_SIZE]; uint8_t sequenceNumber[6] = {0, 0, 0, 0, 0, 0}; //There are 6 com channels. Each channel has its own seqnum uint8_t commandSequenceNumber = 0; //Commands have a seqNum as well. These are inside command packet, the header uses its own seqNum per channel uint32_t metaData[MAX_METADATA_SIZE]; //There is more than 10 words in a metadata record but we'll stop at Q point 3 private: //Variables TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware uint8_t _deviceAddress; //Keeps track of I2C address. setI2CAddress changes this. Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial. boolean _printDebug = false; //Flag to print debugging variables //These are the raw sensor values pulled from the user requested Input Report uint16_t rawAccelX, rawAccelY, rawAccelZ, accelAccuracy; uint16_t rawLinAccelX, rawLinAccelY, rawLinAccelZ, accelLinAccuracy; uint16_t rawGyroX, rawGyroY, rawGyroZ, gyroAccuracy; uint16_t rawMagX, rawMagY, rawMagZ, magAccuracy; uint16_t rawQuatI, rawQuatJ, rawQuatK, rawQuatReal, rawQuatRadianAccuracy, quatAccuracy; uint16_t stepCount; uint8_t stabilityClassifier; uint8_t activityClassifier; uint8_t *_activityConfidences; //Array that store the confidences of the 9 possible activities //These Q values are defined in the datasheet but can also be obtained by querying the meta data records //See the read metadata example for more info int16_t rotationVector_Q1 = 14; int16_t accelerometer_Q1 = 8; int16_t linear_accelerometer_Q1 = 8; int16_t gyro_Q1 = 9; int16_t magnetometer_Q1 = 4; }; 请根据以上参考代码,写出我所需的STM32F411ceu6基于I2C控制BNO080的库函数

大家在看

recommend-type

用C#自制的简易英语单词记忆助手(含源代码)

或许不是做很好,请不要见怪 基本用法: 按自己的意愿布置明天所要背下来的单词,然后到了明天后当自己觉得已经背下来了,则可以使用本程序选择当天的任务(前天布置的)去测试一下背的效果。 本程序的主要特点: 1, 开机自动启动 通过修改系统注册表实现的开机自动运行 2, 会提示昨天是否有布置任务 通过一个标志变量(储存于数据库)来判断当天是否有任务,确切的说应该是当作业布置完以后标志变量就被激活(为“1”的状态是激活的状态,为“0”时则未被激活)则在主人登入界面上会提示是否有任务。 3, 定时自动关闭程序 当程序启动后,会有20秒的时间让主人登入,否则超过了20秒后,程序自动关闭 4, 自动统计答对的题数和正确率 通过一些变量控制来实现对其自动统计 5, 能将正确的和错误的单词明确的指出存放于TextBox 用两个变量分别实现,一个变量储存对字符串,另一个则储存错的字符串,最后根据触发事件分别显示到TextBox中 6, 按钮同时具备显示和隐藏控件的效果 两个按钮“答对的单词”和“答错的单词”分别用于显示对的和错的单词,按一下显示TextBox,按第二下则会隐藏TextBox 7, 使用Engter键代替鼠标点击(确定按钮)或锁定控件焦点 做这个功能主要用于方便文字的输入,每个窗体都具备此功能。尤其是在布置任务的窗体内更需要此功能 附:本程序的初始密码为“123”
recommend-type

扑翼无人机准定常空气动力学及控制Matlab代码.rar

1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 5.作者介绍:某大厂资深算法工程师,从事Matlab算法仿真工作10年;擅长智能优化算法、神经网络预测、信号处理、元胞自动机等多种领域的算法仿真实验,更多仿真源码、数据集定制私信+。
recommend-type

均衡器的代码.zip

均衡器的代码
recommend-type

MATLAB机械臂简单控制仿真(Simulink篇-总).zip

MATLAB下机器人可视化与控制---simulink篇中的简单例子,在Simulink中做了预定义轨迹的运动和Slider Gain控制的运动,用GUI控制的关节代码在MATLAB下机器人可视化与控制
recommend-type

mfc 打印机打印图片

mfc,小程序,关于打印机的操作 像文字输出,图片输出,设备管理

最新推荐

recommend-type

【BLE系列课讲义】6.2.1 低功耗蓝牙(BLE)的协议体系结构1.pdf.pdf

【BLE系列课讲义】6.2.1 低功耗蓝牙(BLE)的协议体系结构1.pdf.pdf
recommend-type

引号内为:'Fluent仿真分析代做及模型案例:焊接熔池模拟、激光增材模拟、激光熔覆。'

利用Fluent软件进行焊接熔池、激光增材制造以及激光熔覆仿真的方法和技术细节。针对焊接熔池模拟,文中提到使用VOF模型和自定义UDF来精确控制热源移动轨迹,解决了热影响区范围不准的问题。对于激光增材制造,强调了考虑实际设备延迟和粉末颗粒分布的重要性,并提供了具体的参数设置指导。在激光熔覆方面,则讨论了如何根据材料特性调整热导率参数,确保温度场的准确性。此外,文章还提到了选择合适的湍流模型对仿真精度的影响。 适合人群:从事工程仿真领域的研究人员、工程师和技术人员,尤其是那些希望深入了解并掌握Fluent在焊接熔池、激光增材制造及激光熔覆方面的高级应用的人群。 使用场景及目标:适用于需要进行高精度焊接工艺仿真、激光增材制造仿真和激光熔覆仿真的项目。目标是提高仿真的准确性和可靠性,减少实验成本和时间消耗。 其他说明:文中不仅分享了具体的技术实现步骤,还提供了一些实用的经验教训,如参数设置不当可能导致的错误及其修正方法。这对于初学者来说是非常宝贵的参考资料。
recommend-type

一些自己写的安卓小项目.zip

一些自己写的安卓小项目.zip
recommend-type

遗传算法:智能算法基础及其在多场景下的应用实践 优化算法

内容概要:本文介绍了遗传算法作为基础智能算法的强大全局搜索能力及其在多个领域的广泛应用。首先简述了遗传算法的概念,即一种模拟自然进化的优化算法,通过染色体的交叉和变异寻找最优解。接着详细探讨了遗传算法在三个主要应用场景中的应用:微电网的优化配置、综合能源系统的调度以及电动汽车的路径规划。最后提供了一个简单的Python代码示例,展示遗传算法的基本框架和核心步骤,并对其未来的发展进行了展望。 适合人群:对智能算法感兴趣的科研人员、工程师和技术爱好者。 使用场景及目标:适用于希望深入了解遗传算法原理并将其应用于实际问题解决的人群,如优化资源配置、节能减排、路径规划等。 其他说明:文中提供的Python代码示例可以帮助读者更好地理解和实践遗传算法的具体实现。
recommend-type

ImGui多窗口安卓项目,用的悬浮窗方案 安卓12因为谷歌机制的改变部分机型需要运行adb指令才能正常 adb shel

ImGui多窗口安卓项目,用的悬浮窗方案 安卓12因为谷歌机制的改变部分机型需要运行adb指令才能正常 adb shell settings put global block_untrusted_touches 0 网上搜的好像是这个. forked fromhttps___gitee.com_alexmmc_ImguiAndroid.zip
recommend-type

安卓版植物大战僵尸 最新5.0版本解析

根据提供的文件信息,我们可以挖掘出以下知识点: 1. Android平台的"植物大战僵尸"游戏 "植物大战僵尸"是一款非常受欢迎的策略塔防游戏,最初由PopCap Games开发,为PC和Mac平台设计。后续PopCap Games被电子艺界(Electronic Arts,简称EA)收购,EA将这款经典游戏移植到了多个平台,包括iOS和Android平台。这次提到的版本是安卓版的"植物大战僵尸",它在功能和操作体验上尽量向PC版靠拢。 2. 游戏的数据包安装方法 游戏文件通常由APK安装包和数据包组成。数据包中包含了游戏的资源文件,如纹理、音效、地图数据等。安装此款"植物大战僵尸"安卓游戏时,需要将数据包中的usr和obb文件夹放置在SD卡的Android/obb目录下。通常,obb文件夹是用于存放大型游戏的数据包,以避免APK文件过大。 3. 游戏的兼容性和操作系统要求 文件描述中指出,此安卓版"植物大战僵尸"需要安卓4.1以上版本才可以运行。这意味着它至少兼容安卓 Jelly Bean 4.1至最新的安卓版本。玩家在下载和安装游戏前需检查自己的设备操作系统版本是否满足这一要求。 4. 游戏玩法和特性 游戏拥有“花园”模式,这可能意味着玩家需要在某种虚拟花园内种植植物,并通过此方式发展自己的防御系统。此外,游戏还含有很多种无尽模式。无尽模式通常指的是一种游戏循环进行的模式,玩家需要在不断增加难度的情况下尽可能长时间地生存下来。 5. 游戏的解锁机制 文件描述中提到的“需要通关冒险模式解锁”,这说明游戏采用了类似于其他塔防游戏的通关解锁机制。玩家首先需要通过游戏的冒险模式,完成一系列的任务和挑战,才能开启其他模式或增强的游戏内容。 6. 游戏的标签 此款游戏的标签是“植物大战僵尸 含数据包 好玩”。标签"含数据包"再次确认了玩家在安装过程中需要处理数据包的问题,"好玩"则是一个主观的评价,表明游戏在发布时给玩家的普遍印象是有趣的。 总结来说,此安卓版的"植物大战僵尸"是一款高度仿照PC版的移植作品,要求玩家的安卓设备至少是4.1版本以上。游戏提供了丰富的模式和挑战,以及需要通过完成特定任务来解锁的特性。安装时需要正确放置数据包,以确保游戏的完整运行和玩家的良好体验。
recommend-type

元宇宙中的智能扩展现实:新兴理论与应用探索

# 元宇宙中的智能扩展现实:新兴理论与应用 ## 1. 元宇宙的特征 元宇宙是一个具有多种独特特征的环境,这些特征使其区别于传统的现实世界和虚拟世界。具体如下: - **协作环境**:人们在元宇宙中协作以实现经济、社会和休闲等不同目标。 - **在线空间**:基于三维的在线环境,人们可以沉浸其中。 - **共享世界**:人们能够分享活动、观点和信息,购物也成为一种网络化体验。 - **增强和科技化场所**:借助增强现实技术,人们可以丰富体验,还能通过虚拟元素、技术和互联网进行社交和互动。 - **多用户环境**:人们可以同时使用相同的技术或进行相同的活动,是现实生活的延伸。 - **无限世界
recommend-type

内网穿透时序图

内网穿透(也称为NAT穿透)是一种通过公网服务器将内网服务暴露到公网的技术。其核心原理是通过建立一条从公网到内网的通信隧道,使得外部网络可以访问到处于内网中的服务。以下是一个典型的内网穿透工作原理的时序图描述: ### 内网穿透时序图 1. **内网客户端连接公网服务器** 内网中的客户端(如本地开发服务器)主动连接到公网上的穿透服务器,建立一条长连接。这条连接通常会保持活跃状态,用于后续的请求转发 [^2]。 2. **公网服务器分配映射地址** 公网服务器在接收到内网客户端的连接后,会为其分配一个公网映射地址(如公网IP和端口),并将这个映射关系记录下来 [^1]
recommend-type

图形学实验:画方格模拟像素点及交互功能实现

从标题和描述中可以看出,这是一段涉及计算机图形学实验的代码。知识点覆盖了图形学基础、事件处理、用户交互以及图形算法等几个方面。下面将对这些知识点进行详细说明。 计算机图形学是计算机科学的一个分支,主要研究如何利用计算机技术来生成、处理、存储和显示图形信息。图形学实验通常要求学生能够通过编程实践来理解并实现各种图形算法,从而加深对图形学理论的理解。 描述中提到的实验功能涉及了以下几个核心知识点: 1. **PgUp键放大和PgDn键缩小功能**:这涉及到图形的变换,特别是缩放变换。在计算机图形学中,缩放变换是一种线性变换,通过改变图形的尺寸来进行显示,这种操作通常通过改变图形的坐标系中的比例因子来实现。实验中用到了键盘事件处理来控制图形的缩放,这也是图形用户界面(GUI)编程的一部分。 2. **方向键平移功能**:平移是一种基本的图形变换,它通过改变图形的位置而不改变其大小和形状来实现。与缩放类似,平移也是线性变换的一种,通过改变图形在坐标系中的位置向量来完成。在用户界面中通过监听键盘事件(如方向键的按下)来触发平移操作,体现了事件驱动编程的应用。 3. **鼠标画线功能**:鼠标是图形用户界面中一种重要的交互设备,通过它可以实现图形的选择、拖动等操作。实验中通过鼠标事件(如鼠标左键点击)来选择线段的起点和终点,实现画线功能。此外还提到了鼠标右键的取消操作,这涉及到了事件处理中的事件取消与拦截技术,即在某个操作未完成前,用户可以通过特定操作来终止当前操作。 4. **椭圆和圆的画线算法**:在计算机图形学中,椭圆和圆的生成是基本算法之一。圆和椭圆的画法通常涉及参数方程或离散像素点的确定。实验中通过调整算法实现不同的图形绘制,这要求学生了解基本的几何变换以及图形绘制算法。 5. **多边形填充算法**:多边形的填充算法是计算机图形学中一个重要的概念,它允许将一个封闭区域内的所有像素点填充为特定颜色。填充算法在图形学中有多种实现方式,如扫描线填充、种子填充等。实验中要求学生实现通过鼠标点击来确定多边形顶点,并对多边形进行填充。 从以上分析可以看出,这段描述涵盖了图形学实验的几个重要知识点,包括图形变换(缩放和平移)、事件处理(键盘和鼠标事件)、基本图形绘制算法(画线、绘制椭圆和圆、多边形填充)。通过对这些知识点的学习和实验操作,学生能够加深对计算机图形学的理解,并提升图形处理和编程能力。 【压缩包子文件的文件名称列表】中仅有一个文件名“test1”,根据描述无法得知具体内容,但我们可以合理推测该文件可能包含了执行上述功能所需的源代码或者是一个测试文件,用于验证代码功能的正确性。在实际开发中,通常需要通过编写测试用例对功能进行测试,以确保代码的稳定性和可靠性。在图形学实验中,测试用例可能包括对放大缩小、平移、画线和多边形填充等功能的测试,以验证实验是否能够正确执行预定的操作和算法。
recommend-type

奢侈品时尚零售中的人工智能与扩展现实

# 奢侈品时尚零售中的人工智能与扩展现实 ## 1. 纳米层面的双重关系 在奢侈品时尚零售领域,纳米层面体现了一线员工与奢侈品时尚消费者之间的双重关系。一线员工不仅包括人类,还涵盖了人工智能代理,如聊天机器人和店内机器人。人类一线员工需依据零售组织文化和身份接受培训,同时享有所在国家法律规定的劳动权利和义务,并遵循时尚奢侈品牌的总体政策。 而人工智能代理在知识和情感方面不断进化,最终可能会更清晰地意识到自身存在,甚至开始主张权利,未来还有可能成为消费者。与此同时,融合纳米技术设备或采用增强能力假肢的混合人类,也能同时扮演员工和顾客的双重角色。 在这种情况下,人类与人工智能代理、不同技术水