活动介绍

void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, uint16_t duration, uint8_t maxExtAdvEvents, MultiAdvCb timeout_cb) override { VLOG(1) << __func__ << " inst_id: " << +inst_id; if (inst_id >= inst_count) { LOG(ERROR) << "bad instance id " << +inst_id; return; } AdvertisingInstance* p_inst = &adv_inst[inst_id]; VLOG(1) << __func__ << " enable: " << enable << ", duration: " << +duration; if (!p_inst->in_use) { LOG(ERROR) << "Invalid or no active instance"; cb.Run(BTM_BLE_MULTI_ADV_FAILURE); return; } if (enable && (duration || maxExtAdvEvents)) { p_inst->timeout_cb = std::move(timeout_cb); } p_inst->duration = duration; p_inst->maxExtAdvEvents = maxExtAdvEvents; if (enable && p_inst->address_update_required) { p_inst->address_update_required = false; ConfigureRpa(p_inst, base::Bind(&BleAdvertisingManagerImpl::EnableFinish, weak_factory_.GetWeakPtr(), p_inst, enable, std::move(cb))); return; } EnableFinish(p_inst, enable, std::move(cb), 0); }

时间: 2024-03-29 18:40:33 浏览: 131
这段代码是一个 BLE 广播管理器的 Enable 函数。该函数用于启用或禁用指定实例的广播,并支持设置广播的持续时间、最大事件数和超时回调函数。 具体解释如下: - 首先,函数接受四个参数:实例 ID、启用/禁用标志、广播持续时间、最大事件数和超时回调函数。 - 接下来,通过 inst_id 获取 AdvertisingInstance 对象指针 p_inst,用于存储广播实例的相关信息。 - 然后,检查 p_inst 是否已经被使用。如果没有被使用,直接返回错误信息,并调用回调函数 cb。 - 如果启用广播并且设置了持续时间或最大事件数,则将超时回调函数 timeout_cb 移动到 p_inst->timeout_cb 中。 - 接着,设置广播持续时间和最大事件数,并检查是否需要更新随机地址。如果需要,则调用 ConfigureRpa 函数更新随机地址,并在更新完成后调用 EnableFinish 函数完成启用广播的操作。 - 如果不需要更新随机地址,则直接调用 EnableFinish 函数完成启用广播的操作。其中,该函数将根据 enable 参数决定是启用广播还是停止广播,并调用回调函数 cb 通知结果。如果启用广播时设置了持续时间或最大事件数,则在广播结束后调用超时回调函数。
相关问题

void AT24C02_WriteByte(uint8_t addr, uint8_t dat) { uint8_t temp[2]; temp[0] = addr; temp[1] = dat; DL_I2C_fillControllerTXFIFO(I2C_1_INST, temp, 2); while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE)); DL_I2C_startControllerTransfer(I2C_1_INST, I2C_ADDRESS_AT24C02, DL_I2C_CONTROLLER_DIRECTION_TX, 2); while (DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS); while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE)); DL_I2C_flushControllerTXFIFO(I2C_1_INST); } uint8_t AT24C02_ReadByte(uint8_t addr) { uint8_t data; DL_I2C_fillControllerTXFIFO(I2C_1_INST, &addr, 1); while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE)); DL_I2C_startControllerTransfer(I2C_1_INST, I2C_ADDRESS_AT24C02, DL_I2C_CONTROLLER_DIRECTION_TX, 1); while (DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS); while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE)); DL_I2C_flushControllerTXFIFO(I2C_1_INST); DL_I2C_startControllerTransfer(I2C_1_INST, I2C_ADDRESS_AT24C02, DL_I2C_CONTROLLER_DIRECTION_RX, 1); while (DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS); while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE)); data = DL_I2C_receiveControllerData(I2C_1_INST); return data; }根据以上代码写一个与灰度传感器IIC通信(单个灰度模拟值)参照方法3 单片机为MSPM0G3507

<think>我们已知方法3的步骤: 1. 启动I2C 2. 发送设备地址(写) 3. 发送要读取的寄存器地址 4. 重新启动I2C 5. 发送设备地址(读) 6. 读取数据(一个字节) 7. 停止I2C 根据用户需求,我们需要读取灰度传感器的单个模拟值。假设灰度传感器的I2C设备地址为0x70(具体地址需根据传感器手册确定,这里假设),并且假设传感器返回的模拟值是一个8位的数据(即一个字节)。 我们基于提供的I2C读写函数来编写。假设提供的I2C函数如下(根据之前的信息): - I2C_Write:用于向I2C总线写入数据,参数为从机地址、写入数据数组、数据长度。 - I2C_Read:用于从I2C总线读取数据,参数为从机地址、读取数据数组、读取长度。 但是注意,方法3的步骤中需要先写入寄存器地址,然后重新启动并读取。因此,我们可以使用两次I2C操作:第一次写(发送寄存器地址),第二次读(读取数据)。 然而,在I2C协议中,这种操作通常称为“复合格式”,即先写后读。在MSPM0的I2C驱动中,我们可以使用以下步骤: 步骤: 1. 启动I2C,发送起始条件。 2. 发送设备地址(写模式)和ACK检查。 3. 发送寄存器地址(假设我们要读取的模拟值存储在某个寄存器,例如0x00,具体看传感器手册)和ACK检查。 4. 重新启动(Restart)。 5. 发送设备地址(读模式)和ACK检查。 6. 读取一个字节的数据(主机产生非应答然后停止条件,或者读取后停止)。 注意:在MSPM0的驱动库中,可能有专门的函数来处理复合读写。但这里我们假设用户已经提供了基本的I2C读写函数,我们需要组合使用。 由于提供的函数可能是简单的读写,我们需要自己实现复合操作。我们可以这样设计: 函数原型: uint8_t I2C_ReadGraySensorValue(uint8_t devAddr, uint8_t regAddr) 步骤: - 启动I2C(在每次传输前,通常需要初始化传输结构体,并设置从机地址和传输方向) - 先写:发送寄存器地址(regAddr) - 然后读:从设备读取一个字节 但是,在MSPM0的驱动库中,我们可以使用I2C_transfer函数来执行复合传输。然而,用户要求基于提供的I2C读写函数,因此我们假设提供的函数是底层操作。 假设我们有以下底层函数(这些函数需要用户实现或已经提供): - I2C_init(): 初始化I2C - I2C_write(uint8_t devAddr, uint8_t *data, uint32_t len): 向设备写入数据,返回是否成功(0表示成功) - I2C_read(uint8_t devAddr, uint8_t *data, uint32_t len): 从设备读取数据,返回是否成功 但是,如果直接使用I2C_read和I2C_write,无法实现复合传输(中间有重启信号)。因此,我们需要一个更底层的函数来支持复合传输,或者使用I2C_transfer函数(如果驱动库支持)。 考虑到MSPM0的SDK提供了I2C_transfer函数,我们可以使用它。但是用户要求基于提供的I2C读写函数,那么如果提供的函数不支持复合传输,我们就需要自己实现复合传输。 这里,我们假设用户提供的I2C读写函数是简单的单次传输(即一次写或一次读),那么我们需要自己构建复合传输。 然而,在MSPM0的驱动库中,我们可以这样操作(参考SDK): 使用`I2C_Transfer`结构体来设置传输序列。 但是,由于用户要求参考方法3,并且使用提供的I2C读写函数,我们这里假设没有提供复合传输函数,因此需要自己实现。 我们可以这样: 1. 调用I2C_start()函数(如果提供)来产生起始条件。 2. 发送设备地址(写)和寄存器地址(使用I2C_writeByte等底层函数,并检查ACK)。 3. 重新启动(调用I2C_start()或I2C_restart())。 4. 发送设备地址(读),然后读取一个字节(并发送NACK表示结束读取)。 5. 停止条件。 但是,如果用户提供的函数是封装好的I2C_write和I2C_read,那么可能无法在中间插入重启。因此,我们需要更底层的操作。 鉴于用户没有提供具体的函数,这里我们假设有更底层的函数可以使用,例如: - I2C_sendStart() - I2C_sendStop() - I2C_sendByte(uint8_t byte) - uint8_t I2C_receiveByte(bool ack) 那么,我们可以按照以下步骤实现: 伪代码: I2C_sendStart(); // 发送写地址 I2C_sendByte(devAddr << 1 | 0); // 0表示写 if (I2C_checkAck() != ACK) { ... 错误处理 } // 发送寄存器地址 I2C_sendByte(regAddr); if (I2C_checkAck() != ACK) { ... 错误处理 } // 重新启动 I2C_sendStart(); // 重启 // 发送读地址 I2C_sendByte(devAddr << 1 | 1); // 1表示读 if (I2C_checkAck() != ACK) { ... 错误处理 } // 读取数据 uint8_t data = I2C_receiveByte(NACK); // 读取一个字节,然后发送NACK(表示最后一个字节) I2C_sendStop(); 但是,在MSPM0的驱动库中,通常使用更高层的API。因此,我们也可以使用SDK提供的复合传输函数。 参考MSPM0 SDK的I2C驱动,我们可以使用`I2C_transfer`函数。该函数需要一个`I2C_Transaction`结构体,其中可以设置写数据和读数据的缓冲区。 示例代码: I2C_Transaction i2cTransaction = {0}; uint8_t writeBuffer[1] = {regAddr}; uint8_t readBuffer[1] = {0}; i2cTransaction.slaveAddress = devAddr; i2cTransaction.writeBuf = writeBuffer; i2cTransaction.writeCount = 1; i2cTransaction.readBuf = readBuffer; i2cTransaction.readCount = 1; if (I2C_transfer(i2cHandle, &i2cTransaction) == I2C_STATUS_SUCCESS) { return readBuffer[0]; } else { // 错误处理 return 0xFF; // 错误值 } 但是,用户要求基于提供的I2C读写函数,并且参考方法3。如果用户已经提供了类似`I2C_Write`和`I2C_Read`的函数,那么我们需要组合它们,但注意中间需要重启。 然而,简单的组合`I2C_Write`和`I2C_Read`并不能实现重启,因为两次调用之间可能会产生停止条件。因此,我们需要确保在两次调用之间不产生停止条件,而是产生重启条件。 在MSPM0的I2C模块中,我们可以通过控制寄存器来实现重启。但是,这需要直接操作寄存器,或者使用驱动库中支持重启传输的函数。 因此,我们建议使用驱动库的复合传输函数。如果用户没有提供,我们可以自己实现一个复合传输函数,使用底层寄存器操作。 但是,由于问题要求基于提供的I2C读写函数,我们假设用户提供了支持复合传输的底层操作函数。如果用户没有提供,那么我们需要自己实现。 鉴于问题的复杂性,我们假设用户已经提供了`I2C_Transfer`函数,或者我们可以使用两次传输(但中间没有停止条件)来实现。 实际上,在MSPM0的SDK中,`I2C_transfer`函数可以处理复合传输。因此,我们推荐使用`I2C_transfer`函数。 但是,用户要求基于提供的I2C读写函数,所以我们先确认用户提供的函数是什么。根据之前的信息,用户可能提供了: - I2C_Master_write - I2C_Master_read 这些函数可能每次传输都会产生起始和停止条件。因此,我们需要一个专门的复合传输函数。 由于用户没有提供复合传输函数,我们这里假设使用MSPM0 SDK的标准方式,即使用`I2C_transfer`。 因此,我们编写如下: 步骤: 1. 初始化I2C事务结构体 2. 设置从机地址 3. 设置要写入的数据(寄存器地址) 4. 设置读取数据的缓冲区 5. 调用I2C_transfer 代码示例: ```c #include <ti/devices/msp/msp.h> #include <ti/driverlib/driverlib.h> // 假设已经初始化了I2C,并且有i2cHandle(I2C_Handle) uint8_t I2C_ReadGraySensorValue(I2C_Handle i2cHandle, uint8_t devAddr, uint8_t regAddr) { I2C_Transaction i2cTransaction; uint8_t writeBuffer[1]; uint8_t readBuffer[1]; // 设置写入的寄存器地址 writeBuffer[0] = regAddr; i2cTransaction.slaveAddress = devAddr; i2cTransaction.writeBuf = writeBuffer; i2cTransaction.writeCount = 1; i2cTransaction.readBuf = readBuffer; i2cTransaction.readCount = 1; // 执行传输 if (I2C_transfer(i2cHandle, &i2cTransaction) == I2C_STATUS_SUCCESS) { return readBuffer[0]; } else { // 传输失败 return 0xFF; // 或者根据错误处理返回 } } ``` 注意:这里假设了I2C_transfer函数内部实现了复合传输(即写后重启再读)。 如果用户没有提供I2C_transfer函数,而是提供了更底层的函数,那么我们需要自己实现复合传输。但根据MSPM0的SDK,I2C_transfer是标准函数。 因此,我们推荐使用上述代码。 但是,用户要求使用提供的I2C读写函数,并且参考方法3。如果用户提供的函数只有I2C_Master_write和I2C_Master_read,那么我们需要检查这些函数是否支持在中间不产生停止条件。如果不支持,那么我们需要修改这些函数或使用其他方式。 在MSPM0的驱动库中,I2C_Master_write和I2C_Master_read每次传输都是独立的(即开始+传输+停止)。因此,无法直接实现复合传输。 所以,我们需要使用I2C_transfer函数。如果用户没有初始化I2C_transfer所需的句柄,那么需要先初始化I2C。 初始化I2C的代码示例(参考): ```c I2C_Params i2cParams; I2C_Params_init(&i2cParams); i2cParams.bitRate = I2C_400kHz; // 根据传感器要求设置 I2C_Handle i2cHandle = I2C_open(Board_I2C0, &i2cParams); if (i2cHandle == NULL) { // 错误处理 } ``` 总结:使用I2C_transfer函数来实现复合传输。 因此,我们编写一个函数,通过I2C_transfer来读取灰度传感器的值。 注意:需要根据实际传感器手册确定设备地址和寄存器地址。假设寄存器地址为0x00,设备地址为0x70(7位地址,所以写入时左移1位,但I2C_transfer内部会处理,我们只需要提供7位地址)。 所以,调用方式: uint8_t grayValue = I2C_ReadGraySensorValue(i2cHandle, 0x70, 0x00); 最后,我们提供完整的函数实现。 如果用户没有使用TI的驱动库,而是使用寄存器操作,那么需要自己实现复合传输。但为了通用性,我们按照驱动库的方式。 因此,我们假设用户使用的是MSPM0的驱动库,并按照上述代码实现。 如果用户使用的是其他方式,请根据实际情况调整。 相关问题: 1. 如何初始化MSPM0G3507的I2C模块? 2. 如何确定灰度传感器的I2C设备地址和寄存器地址? 3. 如果I2C_transfer返回失败,可能的原因是什么?</think>基于您的要求,我将使用MSPM0G3507单片机的I2C模块,按照方法3的时序实现灰度传感器模拟值读取功能。以下是完整的实现方案: ### 1. I2C通信时序分析(方法3) 灰度传感器读取流程: ```mermaid sequenceDiagram participant MCU as MSPM0G3507 participant Sensor as 灰度传感器 MCU->>Sensor: 启动信号(S) MCU->>Sensor: 设备地址+写(0x52) Sensor-->>MCU: ACK MCU->>Sensor: 寄存器地址(0x00) Sensor-->>MCU: ACK MCU->>Sensor: 重启信号(Sr) MCU->>Sensor: 设备地址+读(0x53) Sensor-->>MCU: ACK Sensor->>MCU: 高8位数据 MCU-->>Sensor: ACK Sensor->>MCU: 低8位数据 MCU-->>Sensor: NACK MCU->>Sensor: 停止信号(P) ``` ### 2. 代码实现(基于MSPM0 SDK) ```c #include <ti/devices/msp/msp.h> #include "ti_msp_dl_config.h" #define GRAY_SENSOR_ADDR 0x52 // 7位设备地址 #define DATA_REGISTER 0x00 // 数据寄存器地址 // I2C初始化(已在sysconfig配置) void init_i2c(void) { DL_I2C_initController(I2C_0_INST); DL_I2C_setControllerMode(I2C_0_INST, DL_I2C_CONTROLLER_MODE_CONTROLLER); DL_I2C_enable(I2C_0_INST); } // 读取灰度值(16位模拟值) uint16_t read_gray_value(void) { uint8_t tx_data[1] = {DATA_REGISTER}; uint8_t rx_data[2] = {0}; // 步骤1: 发送寄存器地址(写模式) DL_I2C_setSlaveAddress(I2C_0_INST, GRAY_SENSOR_ADDR); DL_I2C_setTransmitMode(I2C_0_INST, DL_I2C_CONTROLLER_DIRECTION_TX); DL_I2C_generateStartCondition(I2C_0_INST); // 发送寄存器地址 DL_I2C_transmitData(I2C_0_INST, tx_data[0]); while (DL_I2C_isActiveControllerBusy(I2C_0_INST)); // 步骤2: 重启并切换到读模式 DL_I2C_setSlaveAddress(I2C_0_INST, GRAY_SENSOR_ADDR | 0x01); // 读模式 DL_I2C_setTransmitMode(I2C_0_INST, DL_I2C_CONTROLLER_DIRECTION_RX); DL_I2C_generateRepeatedStartCondition(I2C_0_INST); // 步骤3: 读取两个字节数据 // 读取高字节(带ACK) rx_data[0] = DL_I2C_receiveData(I2C_0_INST); DL_I2C_sendControllerAck(I2C_0_INST, DL_I2C_CONTROLLER_ACK_ENABLE); while (DL_I2C_isActiveControllerBusy(I2C_0_INST)); // 读取低字节(带NACK) rx_data[1] = DL_I2C_receiveData(I2C_0_INST); DL_I2C_sendControllerAck(I2C_0_INST, DL_I2C_CONTROLLER_ACK_DISABLE); // 步骤4: 生成停止条件 DL_I2C_generateStopCondition(I2C_0_INST); while (DL_I2C_isActiveControllerBusy(I2C_0_INST)); return (uint16_t)((rx_data[0] << 8) | rx_data[1]); } // 主函数示例 int main(void) { SYSCFG_DL_init(); init_i2c(); while(1) { uint16_t gray_value = read_gray_value(); // 在此处添加数据处理代码(例如通过ADC转换或串口输出) __delay_cycles(1000000); // 1秒延迟 } } ``` ### 3. 关键配置说明 1. **I2C参数配置**(通过SysConfig): - 时钟频率:100 kHz(标准模式) - 引脚分配: - SDA:`PA10`(I2C0_SDA) - SCL:`PA11`(I2C0_SCL) - 中断:禁用(轮询模式) 2. **传感器注意事项**: - 设备地址需根据传感器手册调整(常见0x52-0x55) - 电压匹配:确保传感器与MCU均为3.3V电平 - 上拉电阻:SCL/SDA线需接4.7kΩ上拉电阻 ### 4. 错误处理增强 ```c // 增强版读取函数(带超时和错误检测) uint16_t read_gray_value_safe(void) { // ... [同上] ... uint32_t timeout = 100000; // 超时计数器 // 增加关键步骤超时检测 while (!DL_I2C_getControllerInterruptStatus(I2C_0_INST, DL_I2C_CONTROLLER_INT_TX_COMPLETE)) { if (timeout-- == 0) { DL_I2C_generateStopCondition(I2C_0_INST); return 0xFFFF; // 返回错误值 } } // ... [其他步骤添加类似检测] ... } ``` ### 5. 实测建议 1. 使用逻辑分析仪验证时序: - 检查START/STOP信号位置 - 验证设备地址字节:写模式`0xA4`(0x52<<1),读模式`0xA5` 2. 调试输出: ```c printf("Gray Value: %d\n", gray_value); // 通过UART输出 ``` 3. 典型问题排查: - 无ACK响应:检查设备地址/接线 - 数据错误:确认电源稳定性 - 通信中断:检查是否超过传感器最大采样率

#include "encoder.h" #include "ti_msp_dl_config.h" #include "main.h" #include "motor.h" #include "function.h" #include "xunji.h" uint8_t oled_buffer[32]; uint8_t encoder[32]; uint8_t oled_update=1; volatile uint32_t gEchoData=1000; void oled_show(void) { OLED_Clear(); OLED_ShowString(0,7,(uint8_t *)"LSM6DSV16X Demo",8); OLED_ShowString(0,0,(uint8_t *)"Pitch",8); OLED_ShowString(0,2,(uint8_t *)" Roll",8); OLED_ShowString(0,4,(uint8_t *)" Yaw",8); OLED_ShowString(16*6,3,(uint8_t *)"Accel",8); OLED_ShowString(17*6,4,(uint8_t *)"Gyro",8); sprintf((char *)encoder, "%d",gEchoData); OLED_ShowString(5*8,0,encoder,16);//测试 //sprintf((char *)oled_buffer, "%-6.1f", pitch); // OLED_ShowString(5*8,0,oled_buffer,16); sprintf((char *)oled_buffer, "%-6.1f", roll); OLED_ShowString(5*8,2,oled_buffer,16); sprintf((char *)oled_buffer, "%-6.1f", yaw); OLED_ShowString(5*8,4,oled_buffer,16); sprintf((char *)oled_buffer, "%6d", accel[0]); OLED_ShowString(15*6,0,oled_buffer,8); sprintf((char *)oled_buffer, "%6d", accel[1]); OLED_ShowString(15*6,1,oled_buffer,8); sprintf((char *)oled_buffer, "%6d", accel[2]); OLED_ShowString(15*6,2,oled_buffer,8); sprintf((char *)oled_buffer, "%6d", gyro[0]); OLED_ShowString(15*6,5,oled_buffer,8); sprintf((char *)oled_buffer, "%6d", gyro[1]); OLED_ShowString(15*6,6,oled_buffer,8); sprintf((char *)oled_buffer, "%6d", gyro[2]); OLED_ShowString(15*6,7,oled_buffer,8); } int main(void) { SYSCFG_DL_init(); SysTick_Init(); // MPU6050_Init(); OLED_Init(); // Ultrasonic_Init(); // BNO08X_Init(); // WIT_Init(); // VL53L0X_Init(); // LSM6DSV16X_Init(); /* Don't remove this! */ Interrupt_Init(); NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN ); DL_Timer_startCounter(TIMER_0_INST); // NVIC_EnableIRQ(CAPTURE_0_INST_INT_IRQN ); //DL_Timer_startCounter(CAPTURE_0_INST); NVIC_ClearPendingIRQ( UART_0_INST_INT_IRQN ); NVIC_EnableIRQ( UART_0_INST_INT_IRQN ); while (1) { if(oled_update==1) { oled_show(); oled_update=0; } } } void TIMER_0_INST_IRQHandler() { switch( DL_TimerA_getPendingInterrupt(TIMER_0_INST) ) { case DL_TIMER_IIDX_ZERO: break; default: break; } } void UART_0_INST_IRQHandler(void) { switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) { case DL_UART_MAIN_IIDX_RX: gEchoData = DL_UART_Main_receiveData(UART_0_INST); DL_UART_Main_transmitData(UART_0_INST, gEchoData); oled_update=1; break; default: break; } } 为什么从串口中接受的数据在OLED上每次显示为10

<think>根据您提供的代码,我注意到在串口中断服务程序(UART_0_INST_IRQHandler)中,每次接收到一个字节的数据,就设置`oled_update=1`,然后主循环中检测到`oled_update`为1时就会调用`oled_show()`函数更新显示。 但是您提到显示的数据总是10,这可能是由于以下原因: 1. **串口接收的数据问题**:您从串口发送的数据可能确实是10(十进制)或0x0A(十六进制,即换行符)。请检查您发送的数据内容。 2. **变量类型问题**:在您的代码中,`gEchoData`被定义为`volatile uint32_t`,但在串口中断中,`DL_UART_Main_receiveData`返回的是8位数据(一个字节),而您将其赋值给一个32位变量。这不会导致数据错误,但请注意高位字节是未定义的(实际上,由于`gEchoData`是局部变量,高位字节可能是0)。但是,在显示时,您使用`%d`格式化,所以会显示这个32位整数的十进制值。如果发送的是0x0A(换行符),那么显示为10是正常的。 3. **显示函数问题**:在`oled_show`函数中,您使用以下代码显示`gEchoData`: ```c sprintf((char *)encoder, "%d",gEchoData); OLED_ShowString(5*8,0,encoder,16);//测试 ``` 这里将`gEchoData`以十进制整数形式输出到字符串`encoder`中,然后在OLED的指定位置显示。如果每次发送的都是0x0A(即10),那么显示10是正常的。 4. **串口助手设置问题**:检查串口助手是否以十六进制发送,或者您发送的数据是否是字符(比如发送字符'1',其ASCII码为49,则显示49)。 ### 解决方案: 1. **确认发送的数据**:在串口助手中,尝试发送不同的数据(比如发送数字0、1、2等)并观察显示。 2. **在串口中断中回显数据**:您已经在中断中回显了接收到的数据(`DL_UART_Main_transmitData(UART_0_INST, gEchoData);`),所以您可以在串口助手中查看回显的数据是否正确。如果回显的数据和发送的数据一致,说明接收正确。 3. **修改显示格式**:为了更清楚地看到数据,您可以同时显示十六进制和十进制: ```c sprintf((char *)encoder, "DEC:%d HEX:0x%02X", gEchoData, (unsigned int)gEchoData); OLED_ShowString(0,0,encoder,16); ``` 这样,您就可以同时看到十进制和十六进制表示。 4. **检查变量覆盖**:在您的代码中,`gEchoData`是全局变量,但在中断和主循环中都被访问,由于是32位变量,而MSPM0是32位处理器,所以单次读写是原子的(对于32位对齐的地址)。但为了确保安全,可以在主循环中读取时暂时关闭中断,但这里因为只是显示,而且数据变化不会太频繁,所以可以不用。 5. **注意OLED显示位置**:在您的`oled_show`函数中,显示`gEchoData`的位置是`(5*8,0)`,而在这个位置之前,您还显示了“Pitch”等字符串。请确保这个显示位置不会被其他内容覆盖,或者因为清屏而消失。 ### 修改后的代码建议: 在`oled_show`函数中,修改显示`gEchoData`的部分,以便同时显示十进制和十六进制: ```c void oled_show(void) { OLED_Clear(); // ... 其他显示内容 ... // 显示串口接收的数据,同时显示十进制和十六进制 sprintf((char *)encoder, "UART:%d(0x%02X)", gEchoData, (unsigned int)gEchoData); OLED_ShowString(0, 0, encoder, 16); // 显示在屏幕顶部,位置(0,0) // ... 其他显示内容 ... } ``` ### 调试步骤: 1. 发送单个字节数据,比如0x41(即字母'A'的ASCII),观察显示: - 十进制应为65,十六进制为0x41。 2. 如果显示正确,说明之前发送的是0x0A(即10)是正常的。 3. 如果显示仍然不正确,请检查串口配置(波特率、数据位、停止位等)是否匹配。 4. 检查硬件连接是否正确(RX/TX是否交叉连接)。 如果问题仍然存在,请提供更多信息,例如您发送的数据和实际显示的数据。 §§相关问题§§: 1. 如何确保在嵌入式系统中串口接收数据的稳定性? 2. 在中断服务程序中更新全局变量时需要注意什么? 3. 如何实现OLED的多行显示和自动换行? 4. 在MSPM0G系列微控制器上,如何配置串口以接收不定长数据?</think>您的代码中串口接收数据显示始终为10的问题,可能是由以下几个原因造成的: ### 问题分析: 1. **串口配置问题**: - UART配置可能未正确设置波特率、数据位、停止位等 - 时钟源配置不正确导致通信错误 2. **数据接收处理问题**: - `gEchoData` 定义为 `uint32_t` 但接收的是单字节数据 - 未处理串口接收缓冲区状态 3. **显示刷新机制问题**: - OLED刷新频率过高导致显示异常 - 变量更新与显示刷新同步问题 ### 解决方案: ```c #include "ti_msp_dl_config.h" // 增加串口状态标志 volatile bool uartDataReady = false; volatile uint8_t gEchoData = 0; // 改为 uint8_t 类型 // 修改串口中断处理 void UART_0_INST_IRQHandler(void) { switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) { case DL_UART_MAIN_IIDX_RX: // 检查接收状态 if(DL_UART_Main_isReceiveDataReady(UART_0_INST)) { gEchoData = DL_UART_Main_receiveData(UART_0_INST); DL_UART_Main_transmitData(UART_0_INST, gEchoData); // 回显 uartDataReady = true; // 设置数据就绪标志 } break; default: break; } } // 修改主循环 int main(void) { // 初始化代码... // 配置UART参数(关键!) DL_UART_Main_Config config; config.baudrate = 115200; // 设置波特率 config.dataLength = DL_UART_MAIN_DATALENGTH_8_BITS; config.stopBits = DL_UART_MAIN_STOPBITS_ONE; config.parity = DL_UART_MAIN_PARITY_NONE; DL_UART_Main_init(UART_0_INST, &config); // 启用UART接收中断 DL_UART_Main_enableInterrupt(UART_0_INST, DL_UART_MAIN_IIDX_RX); while (1) { if(uartDataReady) { oled_update = 1; uartDataReady = false; } if(oled_update == 1) { oled_show(); oled_update = 0; // 增加延时防止刷新过快 for(volatile int i = 0; i < 10000; i++); } } } // 修改显示函数中的显示部分 void oled_show(void) { // ... 其他显示代码 ... // 修改为十六进制显示,便于调试 sprintf((char *)encoder, "0x%02X", gEchoData); OLED_ShowString(5*8, 0, encoder, 16); // ... 其他显示代码 ... } ``` ### 关键修改点解释: 1. **串口配置**: - 明确设置了波特率(115200)、数据位(8位)、停止位(1位)和无校验 - 确保与PC端串口助手的设置完全一致 2. **数据类型修正**: - 将 `gEchoData` 从 `uint32_t` 改为 `uint8_t`,避免高位数据污染 3. **接收状态检查**: - 添加 `DL_UART_Main_isReceiveDataReady()` 确保数据有效 - 避免在接收缓冲区为空时读取数据 4. **刷新控制优化**: - 使用双重标志机制(`uartDataReady` 和 `oled_update`) - 添加简单延时防止OLED刷新过快 5. **显示格式优化**: - 使用十六进制显示(`0x%02X`)便于识别特殊字符 - 0x10 的十进制正好是16,不是10(0x0A的十进制是10) ### 调试建议: 1. **测试特殊字符**: ```c // 在main函数中添加测试代码 gEchoData = 0x55; // ASCII 'U' oled_update = 1; while(1); // 暂停观察 ``` 如果显示0x55,则OLED显示功能正常 2. **串口回环测试**: ```c // 在串口中断中只做回环测试 void UART_0_INST_IRQHandler(void) { uint8_t data = DL_UART_Main_receiveData(UART_0_INST); DL_UART_Main_transmitData(UART_0_INST, data); } ``` 验证串口硬件是否正常工作 3. **波特率校准**: ```c // 检查系统时钟配置 SysCtl_setClockFreq(SYSCTL_CPUCLK_FREQ_48M); DL_UART_Main_setBaudrate(UART_0_INST, 48000000, 115200); ``` ### 常见问题原因: 1. 波特率不匹配(最常见) 2. 串口线接触不良 3. 地线未连接 4. 串口助手发送了不可见字符(如0x0A换行符) 5. OLED驱动不兼容当前显示格式
阅读全文

相关推荐

#include "ti_msp_dl_config.h" #include "tjc_usart_hmi.h" #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <ti/driverlib/dl_uart.h> #include <ti/devices/msp/msp.h> #include <ti/driverlib/driverlib.h> #include <ti/driverlib/dl_common.h> // 红外协议时序宏 (单位:微秒) #define LEADER_HIGH 9000 // 引导码高电平9ms #define LEADER_LOW 4500 // 引导码低电平4.5ms #define BIT_HIGH 560 // 数据位高电平560μs #define BIT_ONE_LOW 1690 // 逻辑"1"低电平1690μs #define BIT_ZERO_LOW 560 // 逻辑"0"低电平560μs #define TOLERANCE 150 // 时序容差±150μs #define SYSTEM_CLOCK 32000000 //// 32MHz // 安全参数 #define MAX_RETRY 3 // 最大重试次数 #define LOCK_TIME 15000 // 锁定时间(ms) #define TIME_WINDOW 3000 // 时间容错窗口(±3000ms) // 淘晶驰屏定义 #define TJC_PAGE_MAIN 0 #define TJC_TEXT_STATUS "t0" #define TJC_TEXT_TIME "t1" #define TJC_BUTTON_RESET "b0" // 全局变量 volatile uint32_t delay_value __attribute__((section(".bss"))); volatile uint8_t retry_count __attribute__((section(".bss"))); volatile uint32_t last_fail_time __attribute__((section(".bss"))); volatile uint32_t rtc_counter __attribute__((section(".bss"))); volatile uint32_t now_time __attribute__((section(".bss"))); #define GLOBAL_VARS_BASE 0x20000000 typedef struct { volatile uint32_t delay_value; volatile uint8_t retry_count; volatile uint32_t last_fail_time; volatile uint32_t rtc_counter; volatile uint32_t now_time; volatile uint32_t last_time; volatile uint32_t counter; char str[50]; } GlobalVars; volatile GlobalVars* const globals = (GlobalVars*)GLOBAL_VARS_BASE; /******************** 淘晶驰串口屏驱动 ********************/ void tjc_send_cmd(const char *cmd) { // 发送命令主体 const char *p = cmd; while(*p) { while(!DL_UART_isTXFIFOEmpty(UART_0_INST)); // 等待发送完成 DL_UART_transmitData(UART_0_INST, *p++); } // 发送TJC协议结束符(0xFF 0xFF 0xFF) for(uint8_t i = 0; i < 3; i++) { while(!DL_UART_isTXFIFOEmpty(UART_0_INST)); DL_UART_transmitData(UART_0_INST, 0xFF); } } void tjc_set_text(const char *obj_name, const char *text) { char cmd[128]; snprintf(cmd, sizeof(cmd), "%s.txt=\"%s\"", obj_name, text); tjc_send_cmd(cmd); } void tjc_change_page(uint8_t page_id) { char cmd[16]; snprintf(cmd, sizeof(cmd), "page %d", page_id); tjc_send_cmd(cmd); } void tjc_beep(uint16_t duration_ms) { char cmd[16]; snprintf(cmd, sizeof(cmd), "beep %u", duration_ms); tjc_send_cmd(cmd); } /******************** 系统基础功能 ********************/ void delay_us(uint32_t us) { delay_value = us; while(delay_value != 0); } void SysTick_Handler(void) { if(delay_value > 0) delay_value--; rtc_counter++; // 简单的RTC计数器(每毫秒增加1) now_time = rtc_counter; // 更新全局时间 } uint32_t get_timestamp(void) { return rtc_counter; } /******************** 红外解码功能(8位) ********************/ bool validate_dynamic_code(uint8_t rx_code) { uint32_t current_seed = get_timestamp(); for(int offset = -TIME_WINDOW; offset <= TIME_WINDOW; offset++) { uint32_t seed = current_seed + offset; uint32_t calc_code = (seed * 0x5DEECE66D) & 0xFFFFFFFF; // 比较低8位 if(rx_code == (calc_code & 0xFF)) return true; } return false; } uint8_t ir_receive_packet(void) { uint8_t data = 0; uint32_t start_time = 0; uint32_t duration = 0; // 1. 检测引导码 while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); // 等待高电平结束 start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); // 等待低电平结束 duration = get_timestamp() - start_time; // 检查引导码低电平部分是否符合要求(转换为毫秒) if(duration < (LEADER_HIGH/1000 - TOLERANCE/1000) || duration > (LEADER_HIGH/1000 + TOLERANCE/1000)) return 0xFF; // 2. 检测引导码高电平部分 start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; if(duration < (LEADER_LOW/1000 - TOLERANCE/1000) || duration > (LEADER_LOW/1000 + TOLERANCE/1000)) return 0xFF; // 3. 接收8位数据 for(int i = 0; i < 8; i++) { start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); duration = get_timestamp() - start_time; // 检查数据位高电平部分 if(duration < (BIT_HIGH/1000 - TOLERANCE/1000) || duration > (BIT_HIGH/1000 + TOLERANCE/1000)) return 0xFF; start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; // 判断逻辑位 if(duration >= (BIT_ONE_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ONE_LOW/1000 + TOLERANCE/1000)) { data |= (1 << (7 - i)); // 设置逻辑"1" } else if(duration >= (BIT_ZERO_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ZERO_LOW/1000 + TOLERANCE/1000)) { // 逻辑"0"不需要设置,默认为0 } else { return 0xFF; // 无效时序 } } return data; } /******************** 系统初始化 ********************/ void init_system(void) { // 添加SysTick初始化(1ms中断) DL_SYSTICK_config(32000); // 设置SysTick中断优先级 NVIC_SetPriority(SysTick_IRQn, 3); DL_GPIO_initDigitalInput(DL_GPIO_PIN_9); // 设置 NVIC_SetPriority(SysTick_IRQn, 3); // 启用全局中断 __enable_irq(); // 初始化串口屏 delay_us(2000000); // 等待串口屏启动(2秒) tjc_change_page(TJC_PAGE_MAIN); tjc_set_text(TJC_TEXT_STATUS, "等待红外信号"); tjc_set_text(TJC_TEXT_TIME, "系统启动完成"); tjc_send_cmd("vis b0,1"); // 显示复位按钮 } /******************** 主业务逻辑 ********************/ void security_fsm(void) { // 1. 检测锁定状态 if(retry_count >= MAX_RETRY) { if(get_timestamp() - last_fail_time < LOCK_TIME) { tjc_set_text(TJC_TEXT_STATUS, "锁定中,请稍候"); return; } retry_count = 0; } // 2. 尝试接收数据包 uint8_t rx_code = ir_receive_packet(); if(rx_code == 0xFF) { tjc_set_text(TJC_TEXT_STATUS, "信号接收失败"); tjc_beep(200); return; } // 3. 动态解码验证 if(validate_dynamic_code(rx_code)) { tjc_set_text(TJC_TEXT_STATUS, "认证成功"); tjc_beep(100); delay_us(50000); // 50ms延迟 tjc_beep(100); retry_count = 0; } else { char msg[30]; snprintf(msg, sizeof(msg), "失败(剩余%d次)", MAX_RETRY - retry_count - 1); tjc_set_text(TJC_TEXT_STATUS, msg); tjc_beep(500); retry_count++; last_fail_time = get_timestamp(); } } /******************** 主函数 ********************/ int main(void) { // 系统初始化 - 必须先调用 SYSCFG_DL_init(); // 初始化系统 init_system(); //rx_code =ir_receive_packet(); // 清除中断标志 NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); NVIC_EnableIRQ(UART_0_INST_INT_IRQN); char str[50]; uint32_t last_time = 0; uint32_t counter = 0; uint8_t rx_code ; // 添加调试信息 #ifdef DEBUG printf("SystemCoreClock: %lu Hz\n", SystemCoreClock); printf("SysTick LOAD: 0x%08lX\n", SysTick->LOAD); printf("SysTick CTRL: 0x%08lX\n", SysTick->CTRL); #endif while(1) { // 每秒更新显示 if(now_time - last_time >= 1000) { last_time = now_time; counter++; // 更新显示内容 snprintf(str, sizeof(str), "t1.txt=\"运行: %d秒\"", counter); tjc_send_cmd(str); } // 红外信号检测 security_fsm(); // 低功耗等待 __WFI(); } } 修改一下

#include "ti_msp_dl_config.h" #include "tjc_usart_hmi.h" #include "stdio.h" #include <stdint.h> #include <stdbool.h> #include <ti/driverlib/dl_uart.h> #include <ti/devices/msp/msp.h> #include <ti/driverlib/driverlib.h> #include <ti/driverlib/dl_common.h> #define FRAME_LENGTH 7 volatile uint32_t delay_times = 0; volatile uint8_t uart_data = 0; volatile uint32_t now_time = 0; // 红外协议时序宏 (单位:微秒) #define LEADER_HIGH 9000 // 引导码高电平9ms #define LEADER_LOW 4500 // 引导码低电平4.5ms #define BIT_HIGH 560 // 数据位高电平560μs #define BIT_ONE_LOW 1690 // 逻辑"1"低电平1690μs #define BIT_ZERO_LOW 560 // 逻辑"0"低电平560μs #define TOLERANCE 150 // 时序容差±150μs // 安全参数 #define MAX_RETRY 3 // 最大重试次数 #define LOCK_TIME 15000 // 锁定时间(ms) #define TIME_WINDOW 3000 // 时间容错窗口(±3000ms) // 淘晶驰屏定义 #define TJC_PAGE_MAIN 0 #define TJC_TEXT_STATUS "t0" #define TJC_TEXT_TIME "t1" #define TJC_BUTTON_RESET "b0" // 全局变量 volatile uint32_t delay_value = 0; // 延时函数 volatile uint8_t retry_count = 0; volatile uint32_t last_fail_time = 0; volatile uint32_t rtc_counter = 0; /******************** 淘晶驰串口屏驱动 ********************/ void tjc_send_cmd(const char *cmd) { // 发送命令主体 const char *p = cmd; while(*p) { while(!DL_UART_isTXFIFOFull(UART_0_INST)); DL_UART_transmitData(UART_0_INST, *p++); } // 发送TJC协议结束符(0xFF 0xFF 0xFF) for(uint8_t i = 0; i < 3; i++) { while(!DL_UART_isTXFIFOFull(UART_0_INST)); DL_UART_transmitData(UART_0_INST, 0xFF); } } void tjc_set_text(const char *obj_name, const char *text) { char cmd[128]; snprintf(cmd, sizeof(cmd), "%s.txt=\"%s\"", obj_name, text); tjc_send_cmd(cmd); } void tjc_change_page(uint8_t page_id) { char cmd[16]; snprintf(cmd, sizeof(cmd), "page %d", page_id); tjc_send_cmd(cmd); } void tjc_beep(uint16_t duration_ms) { char cmd[16]; snprintf(cmd, sizeof(cmd), "beep %u", duration_ms); tjc_send_cmd(cmd); } /******************** 系统基础功能 ********************/ void delay_us(uint32_t us) { delay_value = us; while(delay_value != 0); } void SysTick_Handler(void) { if(delay_value > 0) delay_value--; rtc_counter++; // 简单的RTC计数器(每毫秒增加1) } uint32_t get_timestamp(void) { return rtc_counter; } /******************** 红外解码功能 ********************/ bool validate_dynamic_code(uint32_t rx_code) { uint32_t current_seed = get_timestamp(); for(int offset = -TIME_WINDOW; offset <= TIME_WINDOW; offset++) { uint32_t seed = current_seed + offset; uint32_t calc_code = (seed * 0x5DEECE66D) & 0xFFFFFFFF; if(rx_code == calc_code) return true; } return false; } uint8_t ir_receive_packet(void) { uint8_t data = 0; uint32_t start_time = 0; uint32_t duration = 0; // 1. 检测引导码 while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); duration = get_timestamp() - start_time; if(duration < (LEADER_HIGH/1000 - TOLERANCE/1000) || duration > (LEADER_HIGH/1000 + TOLERANCE/1000)) return 0xFF; // 2. 检测引导码高电平部分 start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; if(duration < (LEADER_LOW/1000 - TOLERANCE/1000) || duration > (LEADER_LOW/1000 + TOLERANCE/1000)) return 0xFF; // 3. 接收8位数据 for(int i = 0; i < 8; i++) { start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 0); duration = get_timestamp() - start_time; if(duration < (BIT_HIGH/1000 - TOLERANCE/1000) || duration > (BIT_HIGH/1000 + TOLERANCE/1000)) return 0xFF; start_time = get_timestamp(); while(DL_GPIO_readPins(GPIOA, DL_GPIO_PIN_9) == 1); duration = get_timestamp() - start_time; if(duration >= (BIT_ONE_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ONE_LOW/1000 + TOLERANCE/1000)) { data |= (1UL << (7 - i)); } else if(!(duration >= (BIT_ZERO_LOW/1000 - TOLERANCE/1000) && duration <= (BIT_ZERO_LOW/1000 + TOLERANCE/1000))) { return 0xFF; } } return data; } /******************** 系统初始化 ********************/ void init_system(void) { char *obj_name; char *text; // 串口屏初始化 int init_hmi_uart(); tjc_change_page(TJC_PAGE_MAIN); tjc_set_text(TJC_TEXT_STATUS, "等待红外信号"); tjc_set_text(TJC_TEXT_TIME, "系统启动中..."); } /******************** 主业务逻辑 ********************/ void security_fsm(void) { // 1. 检测锁定状态 if(retry_count >= MAX_RETRY) { if(get_timestamp() - last_fail_time < LOCK_TIME) { tjc_set_text(TJC_TEXT_STATUS, "锁定中,请稍候"); return; } retry_count = 0; } // 2. 尝试接收数据包 uint32_t rx_code = ir_receive_packet(); if(rx_code == 0xFFFFFFFF) { tjc_set_text(TJC_TEXT_STATUS, "信号接收失败"); tjc_beep(200); return; } // 3. 动态解码验证 if(validate_dynamic_code(rx_code)) { tjc_set_text(TJC_TEXT_STATUS, "认证成功"); tjc_beep(100); delay_us(50000); tjc_beep(100); retry_count = 0; } else { char msg[30]; snprintf(msg, sizeof(msg), "失败(剩余%d次)", MAX_RETRY-retry_count-1); tjc_set_text(TJC_TEXT_STATUS, msg); tjc_beep(500); retry_count++; last_fail_time = get_timestamp(); } } int main(void) { uint8_t recv; char time_str[20]; SYSCFG_DL_init(); init_system(); while(1) { recv=ir_receive_packet(); // 红外信号检测 NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN); // 使能串口中断 NVIC_EnableIRQ(UART_0_INST_INT_IRQN); int a= 100; char str[100]; uint32_t last_time = 0; while (1) { if (now_time - last_time >= 1000) { last_time = now_time; sprintf(str, "t0.txt=\"%d\"\xff\xff\xff", a); tjc_send_string(str); sprintf(str, "t0.txt=\"认证成功" ); tjc_send_string(str); } } } }用的CCS,把他改成8位接收的

#include "Dri_BT.h" // 定义蓝牙状态 static bool bt_initialized = false; /* 定义esp32收到手机数据时的回调弱函数 */ void __attribute__((weak)) App_Communication_DealBtData(uint8_t *data, uint16_t dataLen) { } // 设置蓝牙名称 static char example_device_name[ESP_BLE_ADV_NAME_LEN_MAX] = "Zkevin_SmartHumidifier"; static uint8_t adv_config_done = 0; static uint16_t heart_rate_handle_table[HRS_IDX_NB]; static uint8_t test_manufacturer[3] = {'E', 'S', 'P'}; static uint8_t sec_service_uuid[16] = { /* LSB <--------------------------------------------------------------------------------> MSB */ // first uuid, 16bit, [12],[13] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x18, 0x0D, 0x00, 0x00, }; // config adv data static esp_ble_adv_data_t heart_rate_adv_config = { .set_scan_rsp = false, .include_txpower = true, .min_interval = 0x0006, // slave connection min interval, Time = min_interval * 1.25 msec .max_interval = 0x0010, // slave connection max interval, Time = max_interval * 1.25 msec .appearance = 0x00, .manufacturer_len = 0, // TEST_MANUFACTURER_DATA_LEN, .p_manufacturer_data = NULL, //&test_manufacturer[0], .service_data_len = 0, .p_service_data = NULL, .service_uuid_len = sizeof(sec_service_uuid), .p_service_uuid = sec_service_uuid, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), }; // config scan response data static esp_ble_adv_data_t heart_rate_scan_rsp_config = { .set_scan_rsp = true, .include_name = true, .manufacturer_len = sizeof(test_manufacturer), .p_manufacturer_data = test_manufacturer, }; static esp_ble_adv_params_t heart_rate_adv_params = { .adv_int_min = 0x100, .adv_int_max = 0x100, .adv_type = ADV_TYPE_IND, .own_addr_type = BLE_ADDR_TYPE_RPA_PUBLIC, .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; struct gatts_profile_inst { esp_gatts_cb_t gatts_cb; uint16_t gatts_if; uint16_t app_id; uint16_t conn_id; uint16_t service_handle; esp_gatt_srvc_id_t service_id; uint16_t char_handle; esp_bt_uuid_t char_uuid; esp_gatt_perm_t perm; esp_gatt_char_prop_t property; uint16_t descr_handle; esp_bt_uuid_t descr_uuid; }; static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ static struct gatts_profile_inst heart_rate_profile_tab[HEART_PROFILE_NUM] = { [HEART_PROFILE_APP_IDX] = { .gatts_cb = gatts_profile_event_handler, .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ }, }; /* * Heart Rate PROFILE ATTRIBUTES **************************************************************************************** */ /// Heart Rate Sensor Service static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEART_RATE_SVC; #define CHAR_DECLARATION_SIZE (sizeof(uint8_t)) static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE; static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY; static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ; /// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS; static const uint8_t heart_measurement_ccc[2] = {0x00, 0x00}; /// Heart Rate Sensor Service -Body Sensor Location characteristic, read static const uint16_t body_sensor_location_uuid = ESP_GATT_BODY_SENSOR_LOCATION; static const uint8_t body_sensor_loc_val[1] = {0x00}; /// Heart Rate Sensor Service - Heart Rate Control Point characteristic, write&read static const uint16_t heart_rate_ctrl_point = ESP_GATT_HEART_RATE_CNTL_POINT; static const uint8_t heart_ctrl_point[1] = {0x00}; /// Full HRS Database Description - Used to add attributes into the database static const esp_gatts_attr_db_t heart_rate_gatt_db[HRS_IDX_NB] = { // Heart Rate Service Declaration [HRS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(heart_rate_svc), (uint8_t *)&heart_rate_svc}}, // Heart Rate Measurement Characteristic Declaration [HRS_IDX_HR_MEAS_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}}, // Heart Rate Measurement Characteristic Value [HRS_IDX_HR_MEAS_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_meas_uuid, ESP_GATT_PERM_READ, HRPS_HT_MEAS_MAX_LEN, 0, NULL}}, // Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor [HRS_IDX_HR_MEAS_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}}, // Body Sensor Location Characteristic Declaration [HRS_IDX_BOBY_SENSOR_LOC_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}}, // Body Sensor Location Characteristic Value [HRS_IDX_BOBY_SENSOR_LOC_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&body_sensor_location_uuid, ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint8_t), sizeof(body_sensor_loc_val), (uint8_t *)body_sensor_loc_val}}, // Heart Rate Control Point Characteristic Declaration [HRS_IDX_HR_CTNL_PT_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}}, // Heart Rate Control Point Characteristic Value [HRS_IDX_HR_CTNL_PT_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&heart_rate_ctrl_point, ESP_GATT_PERM_WRITE_ENCRYPTED | ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint8_t), sizeof(heart_ctrl_point), (uint8_t *)heart_ctrl_point}}, }; static char *esp_key_type_to_str(esp_ble_key_type_t key_type) { char *key_str = NULL; switch (key_type) { case ESP_LE_KEY_NONE: key_str = "ESP_LE_KEY_NONE"; break; case ESP_LE_KEY_PENC: key_str = "ESP_LE_KEY_PENC"; break; case ESP_LE_KEY_PID: key_str = "ESP_LE_KEY_PID"; break; case ESP_LE_KEY_PCSRK: key_str = "ESP_LE_KEY_PCSRK"; break; case ESP_LE_KEY_PLK: key_str = "ESP_LE_KEY_PLK"; break; case ESP_LE_KEY_LLK: key_str = "ESP_LE_KEY_LLK"; break; case ESP_LE_KEY_LENC: key_str = "ESP_LE_KEY_LENC"; break; case ESP_LE_KEY_LID: key_str = "ESP_LE_KEY_LID"; break; case ESP_LE_KEY_LCSRK: key_str = "ESP_LE_KEY_LCSRK"; break; default: key_str = "INVALID BLE KEY TYPE"; break; } return key_str; } static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req) { char *auth_str = NULL; switch (auth_req) { case ESP_LE_AUTH_NO_BOND: auth_str = "ESP_LE_AUTH_NO_BOND"; break; case ESP_LE_AUTH_BOND: auth_str = "ESP_LE_AUTH_BOND"; break; case ESP_LE_AUTH_REQ_MITM: auth_str = "ESP_LE_AUTH_REQ_MITM"; break; case ESP_LE_AUTH_REQ_BOND_MITM: auth_str = "ESP_LE_AUTH_REQ_BOND_MITM"; break; case ESP_LE_AUTH_REQ_SC_ONLY: auth_str = "ESP_LE_AUTH_REQ_SC_ONLY"; break; case ESP_LE_AUTH_REQ_SC_BOND: auth_str = "ESP_LE_AUTH_REQ_SC_BOND"; break; case ESP_LE_AUTH_REQ_SC_MITM: auth_str = "ESP_LE_AUTH_REQ_SC_MITM"; break; case ESP_LE_AUTH_REQ_SC_MITM_BOND: auth_str = "ESP_LE_AUTH_REQ_SC_MITM_BOND"; break; default: auth_str = "INVALID BLE AUTH REQ"; break; } return auth_str; } static void show_bonded_devices(void) { int dev_num = esp_ble_get_bond_device_num(); if (dev_num == 0) { ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number zero\n"); return; } esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); if (!dev_list) { ESP_LOGI(GATTS_TABLE_TAG, "malloc failed, return\n"); return; } esp_ble_get_bond_device_list(&dev_num, dev_list); ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number %d", dev_num); for (int i = 0; i < dev_num; i++) { ESP_LOGI(GATTS_TABLE_TAG, "[%u] addr_type %u, addr " ESP_BD_ADDR_STR "", i, dev_list[i].bd_addr_type, ESP_BD_ADDR_HEX(dev_list[i].bd_addr)); } free(dev_list); } static void __attribute__((unused)) remove_all_bonded_devices(void) { int dev_num = esp_ble_get_bond_device_num(); if (dev_num == 0) { ESP_LOGI(GATTS_TABLE_TAG, "Bonded devices number zero\n"); return; } esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); if (!dev_list) { ESP_LOGI(GATTS_TABLE_TAG, "malloc failed, return\n"); return; } esp_ble_get_bond_device_list(&dev_num, dev_list); for (int i = 0; i < dev_num; i++) { esp_ble_remove_bond_device(dev_list[i].bd_addr); } free(dev_list); } static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { ESP_LOGV(GATTS_TABLE_TAG, "GAP_EVT, event %d", event); switch (event) { case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: adv_config_done &= (~SCAN_RSP_CONFIG_FLAG); if (adv_config_done == 0) { esp_ble_gap_start_advertising(&heart_rate_adv_params); } break; case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: adv_config_done &= (~ADV_CONFIG_FLAG); if (adv_config_done == 0) { esp_ble_gap_start_advertising(&heart_rate_adv_params); } break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: // advertising start complete event to indicate advertising start successfully or failed if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "Advertising start failed, status %x", param->adv_start_cmpl.status); break; } ESP_LOGI(GATTS_TABLE_TAG, "Advertising start successfully"); break; case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ ESP_LOGI(GATTS_TABLE_TAG, "Passkey request"); /* Call the following function to input the passkey which is displayed on the remote device */ // esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00); break; case ESP_GAP_BLE_OOB_REQ_EVT: { ESP_LOGI(GATTS_TABLE_TAG, "OOB request"); uint8_t tk[16] = {1}; // If you paired with OOB, both devices need to use the same tk esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); break; } case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ ESP_LOGI(GATTS_TABLE_TAG, "Local identity root"); break; case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ ESP_LOGI(GATTS_TABLE_TAG, "Local encryption root"); break; case ESP_GAP_BLE_NC_REQ_EVT: /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. show the passkey number to the user to confirm it with the number displayed by peer device. */ esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); ESP_LOGI(GATTS_TABLE_TAG, "Numeric Comparison request, passkey %" PRIu32, param->ble_security.key_notif.passkey); break; case ESP_GAP_BLE_SEC_REQ_EVT: /* send the positive(true) security response to the peer device to accept the security request. If not accept the security request, should send the security response with negative(false) accept value*/ esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); break; case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /// the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. /// show the passkey number to the user to input it in the peer device. ESP_LOGI(GATTS_TABLE_TAG, "Passkey notify, passkey %06" PRIu32, param->ble_security.key_notif.passkey); break; case ESP_GAP_BLE_KEY_EVT: // shows the ble key info share with peer device to the user. ESP_LOGI(GATTS_TABLE_TAG, "Key exchanged, key_type %s", esp_key_type_to_str(param->ble_security.ble_key.key_type)); break; case ESP_GAP_BLE_AUTH_CMPL_EVT: { esp_bd_addr_t bd_addr; memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t)); ESP_LOGI(GATTS_TABLE_TAG, "Authentication complete, addr_type %u, addr " ESP_BD_ADDR_STR "", param->ble_security.auth_cmpl.addr_type, ESP_BD_ADDR_HEX(bd_addr)); if (!param->ble_security.auth_cmpl.success) { ESP_LOGI(GATTS_TABLE_TAG, "Pairing failed, reason 0x%x", param->ble_security.auth_cmpl.fail_reason); } else { ESP_LOGI(GATTS_TABLE_TAG, "Pairing successfully, auth_mode %s", esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode)); } show_bonded_devices(); break; } case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: { ESP_LOGD(GATTS_TABLE_TAG, "Bond device remove, status %d, device " ESP_BD_ADDR_STR "", param->remove_bond_dev_cmpl.status, ESP_BD_ADDR_HEX(param->remove_bond_dev_cmpl.bd_addr)); break; } case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TABLE_TAG, "Local privacy config failed, status %x", param->local_privacy_cmpl.status); break; } ESP_LOGI(GATTS_TABLE_TAG, "Local privacy config successfully"); esp_err_t ret = esp_ble_gap_config_adv_data(&heart_rate_adv_config); if (ret) { ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret); } else { adv_config_done |= ADV_CONFIG_FLAG; } ret = esp_ble_gap_config_adv_data(&heart_rate_scan_rsp_config); if (ret) { ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret); } else { adv_config_done |= SCAN_RSP_CONFIG_FLAG; } break; default: break; } } static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { ESP_LOGV(GATTS_TABLE_TAG, "event = %x", event); switch (event) { case ESP_GATTS_REG_EVT: ESP_LOGI(GATTS_TABLE_TAG, "GATT server register, status %d, app_id %d, gatts_if %d", param->reg.status, param->reg.app_id, gatts_if); esp_ble_gap_set_device_name(example_device_name); // generate a resolvable random address esp_ble_gap_config_local_privacy(true); esp_ble_gatts_create_attr_tab(heart_rate_gatt_db, gatts_if, HRS_IDX_NB, HEART_RATE_SVC_INST_ID); break; case ESP_GATTS_READ_EVT: break; case ESP_GATTS_WRITE_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Characteristic write, value "); ESP_LOG_BUFFER_HEX(GATTS_TABLE_TAG, param->write.value, param->write.len); App_Communication_DealBtData(param->write.value, param->write.len); break; case ESP_GATTS_EXEC_WRITE_EVT: break; case ESP_GATTS_MTU_EVT: break; case ESP_GATTS_CONF_EVT: break; case ESP_GATTS_UNREG_EVT: break; case ESP_GATTS_DELETE_EVT: break; case ESP_GATTS_START_EVT: break; case ESP_GATTS_STOP_EVT: break; case ESP_GATTS_CONNECT_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Connected, conn_id %u, remote " ESP_BD_ADDR_STR "", param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda)); /* start security connect with peer device when receive the connect event sent by the master */ esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); break; case ESP_GATTS_DISCONNECT_EVT: ESP_LOGI(GATTS_TABLE_TAG, "Disconnected, remote " ESP_BD_ADDR_STR ", reason 0x%x", ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason); /* start advertising again when missing the connect */ esp_ble_gap_start_advertising(&heart_rate_adv_params); break; case ESP_GATTS_OPEN_EVT: break; case ESP_GATTS_CANCEL_OPEN_EVT: break; case ESP_GATTS_CLOSE_EVT: break; case ESP_GATTS_LISTEN_EVT: break; case ESP_GATTS_CONGEST_EVT: break; case ESP_GATTS_CREAT_ATTR_TAB_EVT: { if (param->create.status == ESP_GATT_OK) { if (param->add_attr_tab.num_handle == HRS_IDX_NB) { ESP_LOGI(GATTS_TABLE_TAG, "Attribute table create successfully, num_handle %x", param->add_attr_tab.num_handle); memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table)); esp_ble_gatts_start_service(heart_rate_handle_table[HRS_IDX_SVC]); } else { ESP_LOGE(GATTS_TABLE_TAG, "Attribute table create abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB); } } else { ESP_LOGE(GATTS_TABLE_TAG, "Attribute table create failed, error code = %x", param->create.status); } break; } default: break; } } static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { /* If event is register event, store the gatts_if for each profile */ if (event == ESP_GATTS_REG_EVT) { if (param->reg.status == ESP_GATT_OK) { heart_rate_profile_tab[HEART_PROFILE_APP_IDX].gatts_if = gatts_if; } else { ESP_LOGI(GATTS_TABLE_TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status); return; } } do { int idx; for (idx = 0; idx < HEART_PROFILE_NUM; idx++) { if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ gatts_if == heart_rate_profile_tab[idx].gatts_if) { if (heart_rate_profile_tab[idx].gatts_cb) { heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param); } } } } while (0); } /** * @brief 初始化蓝牙模块 * */ void Dri_BT_Init(void) { // 避免重复初始化 if (bt_initialized) { ESP_LOGI(GATTS_TABLE_TAG, "Bluetooth already initialized"); return; } esp_err_t ret; // 获取当前蓝牙状态 esp_bt_controller_status_t bt_status = esp_bt_controller_get_status(); // 蓝牙未被初始化 if (bt_status == ESP_BT_CONTROLLER_STATUS_IDLE) { // 初始化NVS.为了存入蓝牙连接信息; ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // 释放经典蓝牙部署 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); // 初始化蓝牙硬件配置 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); esp_bt_controller_init(&bt_cfg); esp_bt_controller_enable(ESP_BT_MODE_BLE); // 初始化蓝牙应用层软件配置 esp_bluedroid_init(); esp_bluedroid_enable(); } // 蓝牙未初始化 if (!bt_initialized) { // 注册回调函数 esp_ble_gatts_register_callback(gatts_event_handler); esp_ble_gap_register_callback(gap_event_handler); esp_ble_gatts_app_register(ESP_HEART_RATE_APP_ID); // 设置安全参数,未来传输数据需要加密,采用非对称加密方式(公钥和私钥) esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; // bonding with peer device after authentication esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; // set the IO capability to No output No input uint8_t key_size = 16; // the key size should be 7~16 bytes uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; // 安全密钥 uint32_t passkey = 123456; uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE; uint8_t oob_support = ESP_BLE_OOB_DISABLE; esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); } bt_initialized = true; } #include "Dri_Wifi.h" // 蓝牙的两种情况 // 二维码扫描前需要配网低功耗蓝牙和自定义GATT低功耗蓝牙 // WIFI配网成功后,只需要自定义GATT低功耗蓝牙 typedef enum { BT_MODE_GATT, // GATT服务模式 BT_MODE_DUAL // 双模式(同时支持配网和GATT) } bt_mode_t; // 默认双模式 static bt_mode_t current_bt_mode = BT_MODE_DUAL; static wifi_conn wifi_success_cb; static const char *TAG = "WIFI"; const int WIFI_CONNECTED_EVENT = BIT0; static EventGroupHandle_t wifi_event_group; #define PROV_QR_VERSION "v1" #define PROV_TRANSPORT_BLE "ble" #define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html" // WIFI各种事件的回调函数 static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { // 记录失败次数 static int retries; // 记录WIFI连接失败次数 static uint8_t wifi_conn_retries = 0; if (event_base == WIFI_PROV_EVENT) // WIFI配置事件 { switch (event_id) { case WIFI_PROV_START: ESP_LOGI(TAG, "Provisioning started"); break; case WIFI_PROV_CRED_RECV: { wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; ESP_LOGI(TAG, "Received Wi-Fi credentials" "\n\tSSID : %s\n\tPassword : %s", (const char *)wifi_sta_cfg->ssid, (const char *)wifi_sta_cfg->password); break; } case WIFI_PROV_CRED_FAIL: { wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" "\n\tPlease reset to factory and retry provisioning", (*reason == WIFI_PROV_STA_AUTH_ERROR) ? "Wi-Fi station authentication failed" : "Wi-Fi access-point not found"); retries++; if (retries >= 5) { ESP_LOGI(TAG, "Failed to connect with provisioned AP, resetting provisioned credentials"); wifi_prov_mgr_reset_sm_state_on_failure(); retries = 0; } break; } case WIFI_PROV_CRED_SUCCESS: ESP_LOGI(TAG, "Provisioning successful"); retries = 0; break; case WIFI_PROV_END: // 配置完成后,取消初始化管理器 wifi_prov_mgr_deinit(); break; default: break; } } else if (event_base == WIFI_EVENT) // WIFI事件 { switch (event_id) { case WIFI_EVENT_STA_START: esp_wifi_connect(); break; case WIFI_EVENT_STA_DISCONNECTED: ESP_LOGI(TAG, "Disconnected. Connecting to the AP again..."); wifi_conn_retries++; if (wifi_conn_retries >= 10) { // 重置WIFI配置 wifi_prov_mgr_reset_provisioning(); // 重启芯片 esp_restart(); } esp_wifi_connect(); break; default: break; } } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) // 连接成功 { // 重置记录WIFI连接失败次数 wifi_conn_retries = 0; // 引用运行回调函数代码 wifi_success_cb(); ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; ESP_LOGI(TAG, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip)); xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); } else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT) // 蓝牙事件 { switch (event_id) { case PROTOCOMM_TRANSPORT_BLE_CONNECTED: ESP_LOGI(TAG, "BLE transport: Connected!"); break; case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED: ESP_LOGI(TAG, "BLE transport: Disconnected!"); break; default: break; } } } static void wifi_init_sta(void) { /* Start Wi-Fi in station mode */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); } static void get_device_service_name(char *service_name, size_t max) { uint8_t eth_mac[6]; const char *ssid_prefix = "PROV_"; esp_wifi_get_mac(WIFI_IF_STA, eth_mac); snprintf(service_name, max, "%s%02X%02X%02X", ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]); } esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data) { if (inbuf) { ESP_LOGI(TAG, "Received data: %.*s", inlen, (char *)inbuf); } char response[] = "SUCCESS"; *outbuf = (uint8_t *)strdup(response); if (*outbuf == NULL) { ESP_LOGE(TAG, "System out of memory"); return ESP_ERR_NO_MEM; } *outlen = strlen(response) + 1; /* +1 for NULL terminating byte */ return ESP_OK; } static void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport) { if (!name || !transport) { ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing."); return; } char payload[150] = {0}; snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" ",\"transport\":\"%s\"}", PROV_QR_VERSION, name, transport); ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning."); esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT(); esp_qrcode_generate(&cfg, payload); ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload); } /** * @brief 初始化WIFI模块 * */ void Dri_Wifi_Init(wifi_conn wifi_conn_success) { // 赋值回调函数 wifi_success_cb = wifi_conn_success; // 初始化NVS,用于保存WIFI名称于Flash esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_init()); } // 初始化TCP/IP ESP_ERROR_CHECK(esp_netif_init()); // 创建事件循环组 ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_event_group = xEventGroupCreate(); // 注册各种事件回调函数 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); // 根据TCP/IP网络协议,初始化WIFI esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // 初始化自定义GATT蓝牙 Dri_BT_Init(); // 配网配置信息 wifi_prov_mgr_config_t config = { .scheme = wifi_prov_scheme_ble, .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM, }; // 配网初始化 ESP_ERROR_CHECK(wifi_prov_mgr_init(config)); bool provisioned = false; // wifi_prov_mgr_reset_provisioning(); // 检查是否配网 ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned)); // 根据是否配网,做对应操作 // 没有配网 if (!provisioned) { ESP_LOGI(TAG, "Starting provisioning"); // 配网模式:同时支持配网和GATT current_bt_mode = BT_MODE_DUAL; // WIFI设备名称 char service_name[12]; get_device_service_name(service_name, sizeof(service_name)); // 无安全设置 const char *service_key = NULL; // WIFI设备唯一标识 uint8_t custom_service_uuid[] = { /* LSB <--------------------------------------- * ---------------------------------------> MSB */ 0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf, 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02, }; wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid); // 创建WIFI设备节点信息 wifi_prov_mgr_endpoint_create("custom-data"); // 启动配网设备 wifi_prov_security_t security = WIFI_PROV_SECURITY_0; ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, (const void *)NULL, service_name, service_key)); // 在网络中进行设备注册 wifi_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL); // 打印二维码 wifi_prov_print_qr(service_name, NULL, NULL, PROV_TRANSPORT_BLE); // 启动双服务广播 start_dual_service_advertising(); } else { ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA"); // 已配网:仅GATT模式 current_bt_mode = BT_MODE_GATT; // 配网初始化 wifi_prov_mgr_deinit(); // 启动WIFI wifi_init_sta(); // 启动GATT服务广播 esp_ble_gap_start_advertising(&heart_rate_adv_params); } // 等待WIFI连接成功 xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY); } 蓝牙的两种情况怎么实现

include "ti_msp_dl_config.h" volatile uint32_t gCaptureCnt; volatile bool gSynced; volatile bool gCheckCaptures; uint32_t gLoadValue; int main(void) { volatile static uint32_t pwmPeriod; __attribute__((unused)) volatile static uint32_t pwmDuty; SYSCFG_DL_init(); /* * This value is used to reload timer manually. Due to timer capture * limitation */ gLoadValue = DL_TimerG_getLoadValue(CAPTURE_0_INST); /* Initialize capture global states */ gSynced = false; gCheckCaptures = false; /* * Forcing timers to halt immediately to prevent timers getting out of sync * when code is halted */ DL_TimerG_setCoreHaltBehavior( CAPTURE_0_INST, DL_TIMER_CORE_HALT_IMMEDIATE); DL_TimerG_setCoreHaltBehavior(PWM_0_INST, DL_TIMER_CORE_HALT_IMMEDIATE); NVIC_EnableIRQ(CAPTURE_0_INST_INT_IRQN); DL_TimerG_startCounter(CAPTURE_0_INST); DL_TimerG_startCounter(PWM_0_INST); while (1) { while (false == gCheckCaptures) { __WFE(); } gCheckCaptures = false; /* * Calculate PWM period and PWM duty cycle. IMPORTANT: These calculation * assume timer is running in DOWN counting mode */ pwmPeriod = gLoadValue - gCaptureCnt; pwmDuty = ((gLoadValue - DL_TimerG_getCaptureCompareValue( CAPTURE_0_INST, DL_TIMER_CC_0_INDEX)) * 100) / pwmPeriod; __BKPT(0); } } void CAPTURE_0_INST_IRQHandler(void) { switch (DL_TimerG_getPendingInterrupt(CAPTURE_0_INST)) { case DL_TIMERG_IIDX_CC1_DN: if (gSynced == true) { gCaptureCnt = DL_TimerG_getCaptureCompareValue( CAPTURE_0_INST, DL_TIMER_CC_1_INDEX); gCheckCaptures = true; } else { gSynced = true; } /* Manual reload is needed to workaround timer capture limitation */ DL_TimerG_setTimerCount(CAPTURE_0_INST, gLoadValue); break; case DL_TIMERG_IIDX_ZERO: /* If Timer reaches zero then no PWM signal is detected and it * requires re-synchronization */ gSynced = false; break; default: break; } } 帮我分析一下

/*------------------------ 系统配置 ------------------------*/ #include "ti_msp_dl_config.h" // TI官方驱动库 #define ALARM_THRESHOLD 1500 // ADC报警阈值(根据实际标定调整) #define FILTER_WINDOW 7 // 中值滤波窗口大小 /*------------------------ 硬件接口定义 ------------------------*/ // FSR406连接配置 #define FSR_ADC_CHANNEL DL_ADC_INPUT_CH0 // 使用ADC通道0 #define BUZZER_PIN DL_GPIO_PIN_13 // 蜂鸣器控制引脚(PB13) /*------------------------ 全局变量 ------------------------*/ volatile uint16_t g_adc_raw_value = 0; // ADC原始值 volatile bool g_adc_conversion_done = false;// ADC转换完成标志 /*------------------------ ADC初始化 ------------------------*/ void ADC_Init_FSR406(void) { // ADC时钟配置 DL_ADC_setClockConfig(ADC_0_INST, DL_ADC_CLOCK_SYSCLK, DL_ADC_CLOCK_DIVIDER_1, DL_ADC_CLOCK_DIVIDER_1); // ADC参数配置(单次转换模式) DL_ADC_init(ADC_0_INST); DL_ADC_enableConversions(ADC_0_INST); DL_ADC_setResolution(ADC_0_INST, DL_ADC_RESOLUTION_12BIT); DL_ADC_setReferenceVoltage(ADC_0_INST, DL_ADC_REFERENCE_VOLTAGE_VREF); DL_ADC_enableChannel(ADC_0_INST, FSR_ADC_CHANNEL); // 配置ADC中断 DL_ADC_enableConversionCompleteInterrupt(ADC_0_INST); NVIC_EnableIRQ(ADC_0_INST_INT_IRQn); } /*------------------------ 中值滤波函数 ------------------------*/ uint16_t Median_Filter(uint16_t *buffer) { uint16_t temp[FILTER_WINDOW]; memcpy(temp, buffer, sizeof(uint16_t)*FILTER_WINDOW); // 冒泡排序 for(int i=0; i<FILTER_WINDOW-1; i++) { for(int j=0; j<FILTER_WINDOW-i-1; j++) { if(temp[j] > temp[j+1]) { uint16_t swap = temp[j]; temp[j] = temp[j+1]; temp[j+1] = swap; } } } return temp[FILTER_WINDOW/2]; // 返回中值 } /*------------------------ ADC中断处理 ------------------------*/ void ADC_0_INST_IRQHandler(void) { if(DL_ADC_getStatus(ADC_0_INST) & DL_ADC_STATUS_CONVERSION_COMPLETE) { g_adc_raw_value = DL_ADC_getData(ADC_0_INST); g_adc_conversion_done = true; DL_ADC_clearStatus(ADC_0_INST, DL_ADC_STATUS_CONVERSION_COMPLETE); } } /*------------------------ 报警控制 ------------------------*/ void Trigger_Alarm(bool enable) { static uint8_t alarm_counter = 0; const uint8_t DEBOUNCE_COUNT = 3; if(enable) { if(++alarm_counter >= DEBOUNCE_COUNT) { DL_GPIO_setPins(GPIOB_PORT, BUZZER_PIN); // 开启蜂鸣器 } } else { alarm_counter = 0; DL_GPIO_clearPins(GPIOB_PORT, BUZZER_PIN); // 关闭蜂鸣器 } } /*------------------------ 主函数 ------------------------*/ int main(void) { // 系统时钟初始化(32MHz) DL_SystemInit_SYSCTL_32MHZ_INTERNAL(); // GPIO初始化 DL_GPIO_initDigitalOutput(GPIOB_PORT, BUZZER_PIN); // ADC初始化 ADC_Init_FSR406(); // 主循环 while(1) { if(g_adc_conversion_done) { static uint16_t adc_buffer[FILTER_WINDOW]; static uint8_t buf_index = 0; // 更新滤波缓冲区 adc_buffer[buf_index++] = g_adc_raw_value; if(buf_index >= FILTER_WINDOW) buf_index = 0; // 获取滤波后数值 uint16_t filtered_val = Median_Filter(adc_buffer); // 压力异常判断 Trigger_Alarm(filtered_val > ALARM_THRESHOLD); // 触发下一次转换 DL_ADC_startConversion(ADC_0_INST); g_adc_conversion_done = false; } __WFI(); // 进入低功耗模式 } }为什么其中的DL_ADC_会报错

#include "ti_msp_dl_config.h" #include "arm_math.h" #include <ti/iqmath/include/IQmathLib.h> #include <stdio.h> #include "string.h" #include <sys/cdefs.h> #include "arm_const_structs.h" #include "ili9341_driver.h" #include "KBD/ps2_driver_mspm0.h" #include "Delay/lethe_delay.h" #include "font.h" #include "DAC8563/dac8563.h" #include "ADS8688/ads8688.h" #include "AD9959/ad9959.h" #include "printf.h" #define FFT_SIZE 1024 typedef struct { float32_t amplitude; uint32_t index; float phase; } Harmonic; Harmonic harmonics[5]; void CFFT(void); float hanningWindow(int n); void PreparefftInput(void); void ComputeHarmonics(void); void ConfigureSampling(void); void SynthesizeWaveform(void); void CalculateTHD(void); #define ADC0_Memory0Address (0x40556280) #define ADC0_SAMPLE_SIZE (1024) uint16_t gADC0Samples[FFT_SIZE]; float32_t fftInput[FFT_SIZE * 2]; float32_t fftOutput[FFT_SIZE / 2 + 1]; volatile bool ADC0Ready = false; volatile float32_t SamplingFreqency = 1000000; float U0,U1,U2,U3,U4; int synthesizedWave[200]; void send_int_data(int data) { uint8_t checksum = 0; DL_UART_Main_transmitDataBlocking(UART_0_INST, 0xA5); uint8_t *bytes = (uint8_t *)&data; for (int i = 0; i < sizeof(int); i++) { DL_UART_Main_transmitDataBlocking(UART_0_INST, bytes[i]); checksum += bytes[i]; } DL_UART_Main_transmitDataBlocking(UART_0_INST, checksum); DL_UART_Main_transmitDataBlocking(UART_0_INST, 0x5A); } int main(void) { SYSCFG_DL_init(); ILI9341_init(BLACK); ILI9341_clear(BLACK); dac8563_init(); ADS8688_Init(); AD9959_Init(); DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID,(uint32_t) ADC0_Memory0Address); DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gADC0Samples[0]); DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, FFT_SIZE); DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID); NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN); DL_TimerA_startCounter(TIMER_1_INST); while(1) { if(ADC0Ready == true){ DL_TimerA_stopCounter(TIMER_1_INST); ADC0Ready = false; // 閲嶇疆鐘舵€? PreparefftInput(); CFFT(); ComputeHarmonics(); ConfigureSampling(); CalculateTHD(); SynthesizeWaveform(); DL_TimerA_startCounter(TIMER_1_INST); } } } void ADC12_0_INST_IRQHandler(void) { switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST)) { case DL_ADC12_IIDX_DMA_DONE: ADC0Ready = true; break; default: break; } } void CFFT(void) { arm_cfft_f32(&arm_cfft_sR_f32_len1024, fftInput, 0, 1); arm_cmplx_mag_f32(fftInput, fftOutput, FFT_SIZE / 2 + 1); } float hanningWindow(int n) { float hanningWindow = 0.5f - 0.5f * arm_cos_f32(2 * PI * n / (FFT_SIZE - 1)); return hanningWindow; } void PreparefftInput(void) { for(int i = 0; i < FFT_SIZE; i++) { fftInput[2*i] = (float32_t)(gADC0Samples[i] - 2048)*hanningWindow(i); fftInput[2*i + 1] = 0; } } void ConfigureSampling(void) { if(harmonics[0].index * SamplingFreqency / FFT_SIZE > 1000) { DL_TimerA_setLoadValue(TIMER_1_INST,79); SamplingFreqency = 1000000; } else { DL_TimerA_setLoadValue(TIMER_1_INST,780); SamplingFreqency = 102400; } } void ComputeHarmonics(void) { arm_max_f32(fftOutput, FFT_SIZE / 2 + 1, &harmonics[0].amplitude, &harmonics[0].index); harmonics[0].phase = atan2f(fftInput[2*harmonics[0].index+1], fftInput[2*harmonics[0].index]); for (int h = 2; h <= 5; h++) { uint32_t harmonicIndex = h - 1; uint32_t expectedIdx = h * harmonics[0].index; uint32_t startIdx = (expectedIdx > 3) ? expectedIdx - 3 : 0; uint32_t endIdx = expectedIdx + 3; if (endIdx > FFT_SIZE / 2) endIdx = FFT_SIZE / 2; harmonics[harmonicIndex].amplitude = 0; harmonics[harmonicIndex].index = 0; for (uint32_t i = startIdx; i <= endIdx; i++) { if (fftOutput[i] > harmonics[harmonicIndex].amplitude && fftOutput[i] > harmonics[0].amplitude * 0.15) { harmonics[harmonicIndex].amplitude = fftOutput[i]; harmonics[harmonicIndex].index = i; } } } for(int i=1;i<5;i++) { if(harmonics[i].amplitude!=0 && harmonics[i].index!=0) { harmonics[i].phase = atan2f(fftInput[2*harmonics[i].index+1], fftInput[2*harmonics[i].index]); } } } void CalculateTHD(void) { U0=harmonics[0].amplitude/harmonics[0].amplitude; U1=harmonics[1].amplitude/harmonics[0].amplitude; U2=harmonics[2].amplitude/harmonics[0].amplitude; U3=harmonics[3].amplitude/harmonics[0].amplitude; U4=harmonics[4].amplitude/harmonics[0].amplitude; double thd = sqrt(U1*U1+U2*U2+U3*U3+U4*U4) / U0; } void SynthesizeWaveform(void) { const float32_t baseFreq = harmonics[0].index * SamplingFreqency / FFT_SIZE; for (int i = 0; i < 200; i++) { synthesizedWave[i] = (int)((U0 * arm_sin_f32(2 * PI * i / 200) + U1 * arm_sin_f32(2 * PI * 2 * i / 200) + U2 * arm_sin_f32(2 * PI * 3 * i / 200) + U3 * arm_sin_f32(2 * PI * 4 * i / 200) + U4 * arm_sin_f32(2 * PI * 5 * i / 200)+2)*20); //printf("add s0.id,0,%d\xff\xff\xff",synthesizedWave[i]); while(!DL_UART_Main_isBusy(UART_0_INST)) { send_int_data(synthesizedWave[i]); } } } 你优化一下我的代码

最新推荐

recommend-type

员工工资管理系统VBSQL样本 (1)(1).doc

员工工资管理系统VBSQL样本 (1)(1).doc
recommend-type

门户网站建设方案(1).doc

门户网站建设方案(1).doc
recommend-type

计算机逻辑结构与基础课件4_2ALU的组织new(1).ppt

计算机逻辑结构与基础课件4_2ALU的组织new(1).ppt
recommend-type

化工自动化控制仪表作业试题..(1).doc

化工自动化控制仪表作业试题..(1).doc
recommend-type

模拟微信支付金额输入交互界面设计方案

资源下载链接为: https://pan.quark.cn/s/6e651c43a101 在 PayUI 的预览功能中,这个弹出层是基于 DialogFragment 实现的。所有相关逻辑都已封装在这个 DialogFragment 内部,因此使用起来十分便捷。 使用时,通过 InputCallBack 接口可以获取到用户输入的支付密码。你可以在该接口的回调方法中,发起请求来验证支付密码的正确性;当然,也可以选择在 PayFragment 内部直接修改密码验证的逻辑。 整个实现过程没有运用复杂高深的技术,代码结构清晰易懂,大家通过阅读代码就能轻松理解其实现原理和使用方法。
recommend-type

精选Java案例开发技巧集锦

从提供的文件信息中,我们可以看出,这是一份关于Java案例开发的集合。虽然没有具体的文件名称列表内容,但根据标题和描述,我们可以推断出这是一份包含了多个Java编程案例的开发集锦。下面我将详细说明与Java案例开发相关的一些知识点。 首先,Java案例开发涉及的知识点相当广泛,它不仅包括了Java语言的基础知识,还包括了面向对象编程思想、数据结构、算法、软件工程原理、设计模式以及特定的开发工具和环境等。 ### Java基础知识 - **Java语言特性**:Java是一种面向对象、解释执行、健壮性、安全性、平台无关性的高级编程语言。 - **数据类型**:Java中的数据类型包括基本数据类型(int、short、long、byte、float、double、boolean、char)和引用数据类型(类、接口、数组)。 - **控制结构**:包括if、else、switch、for、while、do-while等条件和循环控制结构。 - **数组和字符串**:Java数组的定义、初始化和多维数组的使用;字符串的创建、处理和String类的常用方法。 - **异常处理**:try、catch、finally以及throw和throws的使用,用以处理程序中的异常情况。 - **类和对象**:类的定义、对象的创建和使用,以及对象之间的交互。 - **继承和多态**:通过extends关键字实现类的继承,以及通过抽象类和接口实现多态。 ### 面向对象编程 - **封装、继承、多态**:是面向对象编程(OOP)的三大特征,也是Java编程中实现代码复用和模块化的主要手段。 - **抽象类和接口**:抽象类和接口的定义和使用,以及它们在实现多态中的不同应用场景。 ### Java高级特性 - **集合框架**:List、Set、Map等集合类的使用,以及迭代器和比较器的使用。 - **泛型编程**:泛型类、接口和方法的定义和使用,以及类型擦除和通配符的应用。 - **多线程和并发**:创建和管理线程的方法,synchronized和volatile关键字的使用,以及并发包中的类如Executor和ConcurrentMap的应用。 - **I/O流**:文件I/O、字节流、字符流、缓冲流、对象序列化的使用和原理。 - **网络编程**:基于Socket编程,使用java.net包下的类进行网络通信。 - **Java内存模型**:理解堆、栈、方法区等内存区域的作用以及垃圾回收机制。 ### Java开发工具和环境 - **集成开发环境(IDE)**:如Eclipse、IntelliJ IDEA等,它们提供了代码编辑、编译、调试等功能。 - **构建工具**:如Maven和Gradle,它们用于项目构建、依赖管理以及自动化构建过程。 - **版本控制工具**:如Git和SVN,用于代码的版本控制和团队协作。 ### 设计模式和软件工程原理 - **设计模式**:如单例、工厂、策略、观察者、装饰者等设计模式,在Java开发中如何应用这些模式来提高代码的可维护性和可扩展性。 - **软件工程原理**:包括软件开发流程、项目管理、代码审查、单元测试等。 ### 实际案例开发 - **项目结构和构建**:了解如何组织Java项目文件,合理使用包和模块化结构。 - **需求分析和设计**:明确项目需求,进行系统设计,如数据库设计、系统架构设计等。 - **代码编写和实现**:根据设计编写符合要求的代码,实现系统的各个模块功能。 - **测试和维护**:进行单元测试、集成测试,确保代码质量,对项目进行维护和升级。 ### 其他相关知识点 - **Java虚拟机(JVM)**:了解JVM的基本工作原理,包括类加载机制、内存管理、垃圾回收算法等。 - **常用Java框架**:比如Spring、Hibernate、MyBatis等,在实际开发中常常与Java基础结合使用,提高开发效率。 以上知识点可以作为学习Java案例开发的基础框架。在实际的开发实践中,开发者需要结合具体的项目需求,对这些知识点进行灵活运用。通过反复的案例实践,可以加深对Java编程的理解,并逐步提升开发技能。这份集锦可能包含的案例可能涉及上述知识点的具体应用,能够帮助学习者更好地理解理论与实践的结合,从而快速提升个人的Java开发能力。
recommend-type

【VASP报错深度解析】:5大技巧识别并永久解决离子距离太近警告

# 1. VASP软件简介及离子距离太近问题概述 ## 1.1 VASP软件简介 **VASP(Vienna Ab initio Simulation Package)** 是一款广泛应用于计算材料科学的软件,它基于密度泛函理论(DFT)计算固体、表面和分子的电子结构和性质。
recommend-type

npm error A complete log of this run can be found in: D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log

<think>好的,我需要帮助用户找到npm的错误调试日志位置,并解决他们遇到的npm错误。首先,用户已经提供了一个具体的日志路径:'D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log',但看起来这个路径可能有问题,因为日期是2025年,这可能是一个示例或输入错误。我需要确认正确的日志路径生成方式。 根据npm的默认配置,日志文件通常位于npm的缓存目录下的_logs文件夹中。默认情况下,Windows系统中npm的缓存路径是%AppData%\npm-cache,而日志文件会以当前日期和
recommend-type

深入理解内存技术文档详解

由于文件内容无法查看,仅能根据文件的标题、描述、标签以及文件名称列表来构建相关知识点。以下是对“内存详解”这一主题的详细知识点梳理。 内存,作为计算机硬件的重要组成部分,负责临时存放CPU处理的数据和指令。理解内存的工作原理、类型、性能参数等对优化计算机系统性能至关重要。本知识点将从以下几个方面来详细介绍内存: 1. 内存基础概念 内存(Random Access Memory,RAM)是易失性存储器,这意味着一旦断电,存储在其中的数据将会丢失。内存允许计算机临时存储正在执行的程序和数据,以便CPU可以快速访问这些信息。 2. 内存类型 - 动态随机存取存储器(DRAM):目前最常见的RAM类型,用于大多数个人电脑和服务器。 - 静态随机存取存储器(SRAM):速度较快,通常用作CPU缓存。 - 同步动态随机存取存储器(SDRAM):在时钟信号的同步下工作的DRAM。 - 双倍数据速率同步动态随机存取存储器(DDR SDRAM):在时钟周期的上升沿和下降沿传输数据,大幅提升了内存的传输速率。 3. 内存组成结构 - 存储单元:由存储位构成的最小数据存储单位。 - 地址总线:用于选择内存中的存储单元。 - 数据总线:用于传输数据。 - 控制总线:用于传输控制信号。 4. 内存性能参数 - 存储容量:通常用MB(兆字节)或GB(吉字节)表示,指的是内存能够存储多少数据。 - 内存时序:指的是内存从接受到请求到开始读取数据之间的时间间隔。 - 内存频率:通常以MHz或GHz为单位,是内存传输数据的速度。 - 内存带宽:数据传输速率,通常以字节/秒为单位,直接关联到内存频率和数据位宽。 5. 内存工作原理 内存基于电容器和晶体管的工作原理,电容器存储电荷来表示1或0的状态,晶体管则用于读取或写入数据。为了保持数据不丢失,动态内存需要定期刷新。 6. 内存插槽与安装 - 计算机主板上有专用的内存插槽,常见的有DDR2、DDR3、DDR4和DDR5等不同类型。 - 安装内存时需确保兼容性,并按照正确的方向插入内存条,避免物理损坏。 7. 内存测试与优化 - 测试:可以使用如MemTest86等工具测试内存的稳定性和故障。 - 优化:通过超频来提高内存频率,但必须确保稳定性,否则会导致数据损坏或系统崩溃。 8. 内存兼容性问题 不同内存条可能由于制造商、工作频率、时序、电压等参数的不匹配而产生兼容性问题。在升级或更换内存时,必须检查其与主板和现有系统的兼容性。 9. 内存条的常见品牌与型号 诸如金士顿(Kingston)、海盗船(Corsair)、三星(Samsung)和芝奇(G.Skill)等知名品牌提供多种型号的内存条,针对不同需求的用户。 由于“内存详解.doc”是文件标题指定的文件内容,我们可以预期在该文档中将详细涵盖以上知识点,并有可能包含更多的实践案例、故障排查方法以及内存技术的最新发展等高级内容。在实际工作中,理解并应用这些内存相关的知识点对于提高计算机性能、解决计算机故障有着不可估量的价值。
recommend-type

【机械特性分析进阶秘籍】:频域与时域对比的全面研究

# 1. 机械特性分析的频域与时域概述 ## 1.1 频域与时域分析的基本概念 机械特性分析是通