活动介绍

解释这个函数的运行流程 const char* parse_string(CJSON *node, const char *buf) { //找出第一个双引号 和 最后一个双引号 const char *src = buf + 1;//第一个双引号之后 char *dest; char *out; int len = 0; while (*src != '\"' && *src)//求真正内容的长度 { len++; src++; } out = (char *)malloc(len + 1);//分配字符串的堆内存 if (!out) return NULL; src = buf + 1; dest = out; while (*src != '\"' && *src)//拷贝,没考虑里面有转义字符 { *dest++ = *src; src++; } *dest = '\0'; node->vString = out; node->type = cJSON_String; if (*src == '\"') { src++; }//总字符串需要跳过最后的 return src; }

时间: 2024-04-06 10:31:36 浏览: 97
这个函数的作用是从一个 JSON 字符串中解析出一个字符串类型的节点,并将其存储在对应的 CJSON 结构体中。函数的输入参数是一个指向 CJSON 结构体的指针和一个指向 JSON 字符串的指针,函数返回值是指向解析完该字符串节点后剩余未解析的 JSON 字符串的指针。 函数首先找到第一个双引号和最后一个双引号,这两个双引号之间的内容就是该字符串节点的真正内容。函数先遍历一遍这个内容,计算出该字符串节点的长度。接着函数分配一块堆内存,将该字符串节点的内容拷贝到这个新分配的内存中。最后函数将这个新分配内存中的指针赋值给 CJSON 结构体中的 vString 字段,将节点类型设置为 cJSON_String,然后返回指向未解析部分的指针。 需要注意的是,这个函数没有考虑字符串中可能含有转义字符的情况。
相关问题

解释这个函数的运行流程 const char* parse_string(CJSON *node, const char *buf) { //找出第一个双引号 和 最后一个双引号 const char *src = buf + 1;//第一个双引号之后 char *dest; char *out; int len = 0; while (*src != '"' && *src)//求真正内容的长度 { len++; src++; } out = (char *)malloc(len + 1);//分配字符串的堆内存 if (!out) return NULL; src = buf + 1; dest = out; while (*src != '"' && *src)//拷贝,没考虑里面有转义字符 { *dest++ = *src; src++; } *dest = '\0'; node->vString = out; node->type = cJSON_String; if (*src == '"') { src++; }//总字符串需要跳过最后的 return src; }

这个函数的作用是从一个 JSON 字符串中解析出一个字符串类型的节点,并将其存储在对应的 CJSON 结构体中。函数的输入参数是一个指向 CJSON 结构体的指针和一个指向 JSON 字符串的指针,函数返回值是指向解析完该字符串节点后剩余未解析的 JSON 字符串的指针。 函数首先找到第一个双引号和最后一个双引号,这两个双引号之间的内容就是该字符串节点的真正内容。函数先遍历一遍这个内容,计算出该字符串节点的长度。接着函数分配一块堆内存,将该字符串节点的内容拷贝到这个新分配的内存中。最后函数将这个新分配内存中的指针赋值给 CJSON 结构体中的 vString 字段,将节点类型设置为 cJSON_String,然后返回指向未解析部分的指针。 需要注意的是,这个函数没有考虑字符串中可能含有转义字符的情况。

解析这个函数的运行流程 const char* parse_array(CJSON *node, const char *buf) { CJSON *child; node->type = cJSON_Array; buf = filter(buf + 1); if (*buf == ']') return buf + 1; node->child = child = JSON_New_Node();//设置孩子指针 if (!node->child) return NULL; buf = filter(parse_buf(child, filter(buf)));//嵌套调用parse_buff if (!buf) return NULL; while (*buf == ‘,’)//数组中存在下一个元素 { CJSON *new_node = JSON_New_Node();//以下设置前后驱指针 if (!new_node) return NULL; child->next = new_node; new_node->prev = child; child = new_node; buf = filter(parse_buf(child, filter(buf + 1)));//解析下一个元素 if (!buf) return NULL; } if (*buf == ‘]’) return buf + 1; //遇到“]”解析结束 return NULL; }

这个函数的作用是解析一个JSON数组,并返回指向解析完该数组后的下一个字符的指针。 函数的参数node是一个CJSON结构体指针,表示当前要解析的JSON数组节点。buf是一个指向待解析的JSON字符串的指针,该字符串以数组的左括号"["开始。 函数的运行流程如下: 1. 设置当前节点类型为数组类型。 2. 调用filter函数过滤掉buf指针当前位置之前的空白字符。 3. 如果当前位置为右括号"]",表示该数组为空,函数直接返回下一个字符的指针(即"]"之后的第一个字符)。 4. 创建一个新的CJSON结构体节点,并将它设置为当前节点的孩子节点。如果无法创建新节点,函数返回NULL。 5. 调用parse_buf函数解析该节点,并将解析后的结果赋值给孩子节点。如果解析失败,函数返回NULL。 6. 如果当前位置为逗号",",表示该数组还有下一个元素,继续解析下一个元素。 7. 创建一个新的CJSON结构体节点,并将它设置为当前节点孩子节点的下一个兄弟节点。如果无法创建新节点,函数返回NULL。 8. 将新节点的前驱指针指向当前节点孩子节点,当前节点孩子节点的后继指针指向新节点。 9. 将当前节点设置为新节点,继续解析下一个元素。 10. 如果当前位置为右括号"]",表示该数组解析完毕,函数返回下一个字符的指针(即"]"之后的第一个字符)。 11. 如果以上步骤中出现了错误,函数返回NULL。
阅读全文

相关推荐

#include "esp8266.h" #include "cJSON.h" #include <string.h> #include <stdio.h> #define BUFF_SIZE 1024 uint8_t ESP_Buff[BUFF_SIZE]={0}; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart6; extern UART_HandleTypeDef huart1; extern uint8_t temperature; extern uint8_t humidity; extern uint8_t temperature_xs1; extern uint8_t temperature_xs2; int TCP_DataLength=0; char TCPData[1024]={0}; /* * recvdata:接收到的数据包 * data_length:接收到的数据长度 * data:得到的实际数据 * data_size:指定每次可以复制的数据大小 */ static int parse_ipd(char* recvdata,int* data_length,char* data,int data_size) { //找到头部 const char* prefix="+IPD"; const char* start=strstr(recvdata,prefix); if(!start) { return -1; } start+=strlen(prefix); //找到‘,’,解析出数据的长度 const char* colon1=strchr(start,','); if(!colon1) { return -2; } *data_length=atoi(colon1+1); //找到‘:’,解析出数据的内容 const char* colon2=strchr(start,':'); if(!colon2) { return -2; } int length=*data_length; if(length>data_size) { return -3; } strncpy(data,colon2+1,length); data[length]='\0'; return 0; } void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart,uint16_t Size) { if(huart->Instance==USART2) { if(parse_ipd((char*)ESP_Buff,&TCP_DataLength,TCPData,1024)==0) { printf("TCP recv:%s",TCPData); } if(strstr(TCPData, "thing/property/set")) { // 示例 JSON 数据格式: // {"id":"123","version":"1.0","params":{"LED":1}} // 提取 params 字段中的命令 cJSON* root = cJSON_Parse(TCPData); cJSON* params = cJSON_GetObjectItem(root, "params"); if(params) { cJSON* led_cmd = cJSON_GetObjectItem(params, "LED"); if(led_cmd) { uint8_t led_state = led_cmd->valueint; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, led_state); // 控制 LED } } cJSON_Delete(root); } memset(ESP_Buff,0,1024); HAL_UARTEx_ReceiveToIdle_DMA(&huart2,ESP_Buff,BUFF_SIZE); } } void Start_Recv(void) { memset(ESP_Buff,0,BUFF_SIZE); HAL_UARTEx_ReceiveToIdle_DMA(&huart2,ESP_Buff,BUFF_SIZE); } int ESP_SendC

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2022 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /** ****************************************************************************** * 作者:好家伙VCC * 联系方式:[email protected] * 软件版本:V3.3.0 * 使用硬件版本:V3.3.0 * ****************************************************************************** * 更新日志: * * * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "adc.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "oled.h" #include "stdio.h" #include "motor.h" #include "niming.h" #include "pid.h" #include "cJSON.h" #include <string.h> #include "HC_SR04.h" #include "mpu6050.h" #include "inv_mpu.h" #include "inv_mpu_dmp_motion_driver.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ extern float Motor1Speed ;//声明电机1速度 extern float Motor2Speed ;//声明电机2速度 extern tPid pidMotor1Speed;//声明电机1PID速度控制结构体类型变量 extern tPid pidMotor2Speed; extern tPid pidFollow; //定距离跟随PID extern tPid pidMPU6050YawMovement; //利用6050偏航角 进行姿态控制的PID extern uint8_t Usart1_ReadBuf[255]; //串口1 缓冲数组 float p,i,d,a,b;//使用JSON时候使用的变量 uint8_t OledString[50];//OLED显示使用的字符串数组 extern float Mileage;//里程数 extern tPid pidHW_Tracking;//红外循迹的PID uint8_t g_ucaHW_Read[4] = {0};//保存红外对管电平的数组 int8_t g_cThisState = 0;//这次状态 int8_t g_cLastState = 0; //上次状态 float g_fHW_PID_Out;//红外对管PID计算输出速度 float g_fHW_PID_Out1;//电机1的最后循迹PID控制速度 float g_fHW_PID_Out2;//电机2的最后循迹PID控制速度 uint8_t g_ucUsart3ReceiveData; //保存串口三接收的数据 uint8_t Usart3String[50];//串口三输出字符串使用的字符串数组 float g_fHC_SR04_Read;//超声波传感器读取障碍物数据 float g_fFollow_PID_Out;//定距离跟随PID计算输出速度 float pitch,roll,yaw; //俯仰角 横滚角 航向角 float g_fMPU6050YawMovePidOut = 0.00f; //姿态PID运算输出 float g_fMPU6050YawMovePidOut1 = 0.00f; //第一个电机控制输出 float g_fMPU6050YawMovePidOut2 = 0.00f; //第一个电机控制输出 uint8_t g_ucMode = 0; //小车运动模式标志位 0:显示功能、1:PID循迹模式、2:手机遥控普通运动模式、3.超声波避障模式、4:PID跟随模式、5:遥控角度闭环 /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_TIM1_Init(); MX_TIM2_Init(); MX_TIM4_Init(); MX_ADC2_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ OLED_Init(); //初始化OLED OLED_Clear() ; HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//开启定时器1 通道1 PWM输出 HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);//开启定时器1 通道4 PWM输出 HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);//开启定时器2 HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);//开启定时器4 HAL_TIM_Base_Start_IT(&htim2); //开启定时器2 中断 HAL_TIM_Base_Start_IT(&htim4); //开启定时器4 中断 HAL_TIM_Base_Start_IT(&htim1); //开启定时器1 中断 __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); //开启串口1接收中断 PID_init();//PID参数初始化 HAL_UART_Receive_IT(&huart3,&g_ucUsart3ReceiveData,1); //串口三接收数据 HAL_Delay(500);//延时0.5秒 6050上电稳定后初始化 MPU_Init(); //初始化MPU6050 while(MPU_Init()!=0);//初始化MPU6050模块的MPU 注意初始化阶段不要移动小车 while(mpu_dmp_init()!=0);//mpu6050,dmp初始化 // cJSON *cJsonData ,*cJsonVlaue; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ sprintf((char *)OledString," g_ucMode:%d",g_ucMode);//显示g_ucMode 当前模式 OLED_ShowString(0,6,OledString,12); //显示在OLED上 sprintf((char *)Usart3String," g_ucMode:%d",g_ucMode);//蓝牙APP显示 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 if(g_ucMode == 0) { //0LED显示功能 sprintf((char*)OledString, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//显示速度 OLED_ShowString(0,0,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, sprintf((char*)OledString, "Mileage:%.2f", Mileage);//显示里程 OLED_ShowString(0,1,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, sprintf((char*)OledString, "U:%.2fV", adcGetBatteryVoltage());//显示电池电压 OLED_ShowString(0,2,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, sprintf((char *)OledString,"HC_SR04:%.2fcm\r\n",HC_SR04_Read());//显示超声波数据 OLED_ShowString(0,3,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, sprintf((char *)OledString,"p:%.2f r:%.2f \r\n",pitch,roll);//显示6050数据 俯仰角 横滚角 OLED_ShowString(0,4,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, sprintf((char *)OledString,"y:%.2f \r\n",yaw);//显示6050数据 航向角 OLED_ShowString(0,5,OledString,12);//这个是oled驱动里面的,是显示位置的一个函数, //蓝牙APP显示 sprintf((char*)Usart3String, "V1:%.2fV2:%.2f", Motor1Speed,Motor2Speed);//显示速度 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 //阻塞方式发送可以保证数据发送完毕,中断发送不一定可以保证数据已经发送完毕才启动下一次发送 sprintf((char*)Usart3String, "Mileage:%.2f", Mileage);//显示里程 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 sprintf((char*)Usart3String, "U:%.2fV", adcGetBatteryVoltage());//显示电池电压 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 sprintf((char *)Usart3String,"HC_SR04:%.2fcm\r\n",HC_SR04_Read());//显示超声波数据 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 sprintf((char *)Usart3String,"p:%.2f r:%.2f \r\n",pitch,roll);//显示6050数据 俯仰角 横滚角 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 sprintf((char *)Usart3String,"y:%.2f \r\n",yaw);//显示6050数据 航向角 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 //获得6050数据 while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //这个可以解决经常读不出数据的问题 //在显示模式电机停转 设置小车速度为0 motorPidSetSpeed(0,0); } if(g_ucMode == 1) { ///**** 红外PID循迹功能******************/ g_ucaHW_Read[0] = READ_HW_OUT_1;//读取红外对管状态、这样相比于写在if里面更高效 g_ucaHW_Read[1] = READ_HW_OUT_2; g_ucaHW_Read[2] = READ_HW_OUT_3; g_ucaHW_Read[3] = READ_HW_OUT_4; if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 ) { // printf("应该前进\r\n");//注释掉更加高效,减少无必要程序执行 g_cThisState = 0;//前进 } else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )//使用else if更加合理高效 { // printf("应该右转\r\n"); g_cThisState = -1;//应该右转 } else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 ) { // printf("快速右转\r\n"); g_cThisState = -2;//快速右转 } else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0) { // printf("快速右转\r\n"); g_cThisState = -3;//快速右转 } else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 0 ) { // printf("应该左转\r\n"); g_cThisState = 1;//应该左转 } else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 1 ) { // printf("快速左转\r\n"); g_cThisState = 2;//快速左转 } else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 1) { // printf("快速左转\r\n"); g_cThisState = 3;//快速左转 } g_fHW_PID_Out = PID_realize(&pidHW_Tracking,g_cThisState);//PID计算输出目标速度 这个速度,会和基础速度加减 g_fHW_PID_Out1 = 3 + g_fHW_PID_Out;//电机1速度=基础速度+循迹PID输出速度 g_fHW_PID_Out2 = 3 - g_fHW_PID_Out;//电机1速度=基础速度-循迹PID输出速度 if(g_fHW_PID_Out1 >5) g_fHW_PID_Out1 =5;//进行限幅 限幅速度在0-5之间 if(g_fHW_PID_Out1 <0) g_fHW_PID_Out1 =0; if(g_fHW_PID_Out2 >5) g_fHW_PID_Out2 =5;//进行限幅 限幅速度在0-5之间 if(g_fHW_PID_Out2 <0) g_fHW_PID_Out2 =0; if(g_cThisState != g_cLastState)//如何这次状态不等于上次状态、就进行改变目标速度和控制电机、在定时器中依旧定时控制电机 { motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通过计算的速度控制电机 } g_cLastState = g_cThisState;//保存上次红外对管状态 } if(g_ucMode == 2) { //***************遥控模式***********************// //遥控模式的控制在串口三的中断里面 } if(g_ucMode == 3) { //******超声波避障模式*********************// ////避障逻辑 if(HC_SR04_Read() > 25)//前方无障碍物 { motorPidSetSpeed(1,1);//前运动 HAL_Delay(100); } else{ //前方有障碍物 motorPidSetSpeed(-1,1);//右边运动 原地 HAL_Delay(500); if(HC_SR04_Read() > 25)//右边无障碍物 { motorPidSetSpeed(1,1);//前运动 HAL_Delay(100); } else{//右边有障碍物 motorPidSetSpeed(1,-1);//左边运动 原地 HAL_Delay(1000); if(HC_SR04_Read() >25)//左边无障碍物 { motorPidSetSpeed(1,1);//前运动 HAL_Delay(100); } else{ motorPidSetSpeed(-1,-1);//后运动 HAL_Delay(1000); motorPidSetSpeed(-1,1);//右边运动 HAL_Delay(50); } } } } if(g_ucMode == 4) { //**********PID跟随功能***********// g_fHC_SR04_Read=HC_SR04_Read();//读取前方障碍物距离 if(g_fHC_SR04_Read < 60){ //如果前60cm 有东西就启动跟随 g_fFollow_PID_Out = PID_realize(&pidFollow,g_fHC_SR04_Read);//PID计算输出目标速度 这个速度,会和基础速度加减 if(g_fFollow_PID_Out > 6) g_fFollow_PID_Out = 6;//对输出速度限幅 if(g_fFollow_PID_Out < -6) g_fFollow_PID_Out = -6; motorPidSetSpeed(g_fFollow_PID_Out,g_fFollow_PID_Out);//速度作用与电机上 } else motorPidSetSpeed(0,0);//如果前面60cm 没有东西就停止 HAL_Delay(10);//读取超声波传感器不能过快 } if(g_ucMode == 5) { //*************MPU6050航向角 PID转向控制*****************// sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2f\r\n",pitch,roll,yaw);//显示6050数据 俯仰角 横滚角 航向角 HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小 //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出欧拉角 while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //这个可以解决经常读不出数据的问题 g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID计算输出目标速度 这个速度,会和基础速度加减 g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基础速度加减PID输出速度 g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut; if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//进行限幅 if(g_fMPU6050YawMovePidOut1 <0) g_fMPU6050YawMovePidOut1 =0; if(g_fMPU6050YawMovePidOut2 >3.5) g_fMPU6050YawMovePidOut2 =3.5;//进行限幅 if(g_fMPU6050YawMovePidOut2 <0) g_fMPU6050YawMovePidOut2 =0; motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2);//将最后计算的目标速度 通过motorPidSetSpeed控制电机 } ///**** 红外PID循迹功能******************/ // g_ucaHW_Read[0] = READ_HW_OUT_1;//读取红外对管状态、这样相比于写在if里面更高效 // g_ucaHW_Read[1] = READ_HW_OUT_2; // g_ucaHW_Read[2] = READ_HW_OUT_3; // g_ucaHW_Read[3] = READ_HW_OUT_4; // if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 ) // { //// printf("应该前进\r\n");//注释掉更加高效,减少无必要程序执行 // g_cThisState = 0;//前进 // } // else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 )//使用else if更加合理高效 // { //// printf("应该右转\r\n"); // g_cThisState = -1;//应该右转 // } // else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0 ) // { //// printf("快速右转\r\n"); // g_cThisState = -2;//快速右转 // } // else if(g_ucaHW_Read[0] == 1&&g_ucaHW_Read[1] == 1&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 0) // { //// printf("快速右转\r\n"); // g_cThisState = -3;//快速右转 // } // else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 0 ) // { //// printf("应该左转\r\n"); // g_cThisState = 1;//应该左转 // } // else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 0&&g_ucaHW_Read[3] == 1 ) // { //// printf("快速左转\r\n"); // g_cThisState = 2;//快速左转 // } // else if(g_ucaHW_Read[0] == 0&&g_ucaHW_Read[1] == 0&&g_ucaHW_Read[2] == 1&&g_ucaHW_Read[3] == 1) // { //// printf("快速左转\r\n"); // g_cThisState = 3;//快速左转 // } // g_fHW_PID_Out = PID_realize(&pidHW_Tracking,g_cThisState);//PID计算输出目标速度 这个速度,会和基础速度加减 // g_fHW_PID_Out1 = 3 + g_fHW_PID_Out;//电机1速度=基础速度+循迹PID输出速度 // g_fHW_PID_Out2 = 3 - g_fHW_PID_Out;//电机1速度=基础速度-循迹PID输出速度 // if(g_fHW_PID_Out1 >5) g_fHW_PID_Out1 =5;//进行限幅 限幅速度在0-5之间 // if(g_fHW_PID_Out1 <0) g_fHW_PID_Out1 =0; // if(g_fHW_PID_Out2 >5) g_fHW_PID_Out2 =5; // if(g_fHW_PID_Out2 <0) g_fHW_PID_Out2 =0; // if(g_cThisState != g_cLastState)//如何这次状态不等于上次状态、就进行改变目标速度和控制电机、在定时器中依旧定时控制电机 // { // motorPidSetSpeed(g_fHW_PID_Out1,g_fHW_PID_Out2);//通过计算的速度控制电机 // } // // g_cLastState = g_cThisState;//保存上次红外对管状态 ////通过串口三(蓝牙)输出信息 ////***************串口三输出****************************// // sprintf((char *)Usart3String,"V1:%.2fV2:%.2f\r\n",Motor1Speed,Motor2Speed);//显示两个电机转速 单位:转/秒 // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 // // sprintf((char *)Usart3String,"Mileage%.2f\r\n",Mileage);//计算小车里程 单位cm // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 // // sprintf((char *)Usart3String,"U:%.2fV\r\n",adcGetBatteryVoltage());//显示电池电压 // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),50);//阻塞式发送通过串口三输出字符 strlen:计算字符串大小 // // sprintf((char *)Usart3String,"HC_SR04:%.2fcm\r\n",HC_SR04_Read());//显示超声波数据 // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小 // // sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2f\r\n",pitch,roll,yaw);//显示6050数据 俯仰角 横滚角 航向角 // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小 // // //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出欧拉角 // while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //这个可以解决经常读不出数据的问题 // // // HAL_Delay(5);//注意调用不可以过于频繁HC_SR04_Read() ////*************MPU6050航向角 PID转向控制*****************// // sprintf((char *)Usart3String,"pitch:%.2f roll:%.2f yaw:%.2f\r\n",pitch,roll,yaw);//显示6050数据 俯仰角 横滚角 航向角 // HAL_UART_Transmit(&huart3,( uint8_t *)Usart3String,strlen(( const char *)Usart3String),0xFFFF);//通过串口三输出字符 strlen:计算字符串大小 // // //mpu_dmp_get_data(&pitch,&roll,&yaw);//返回值:0,DMP成功解出欧拉角 // while(mpu_dmp_get_data(&pitch,&roll,&yaw)!=0){} //这个可以解决经常读不出数据的问题 // // // g_fMPU6050YawMovePidOut = PID_realize(&pidMPU6050YawMovement,yaw);//PID计算输出目标速度 这个速度,会和基础速度加减 // g_fMPU6050YawMovePidOut1 = 1.5 + g_fMPU6050YawMovePidOut;//基础速度加减PID输出速度 // g_fMPU6050YawMovePidOut2 = 1.5 - g_fMPU6050YawMovePidOut; // if(g_fMPU6050YawMovePidOut1 >3.5) g_fMPU6050YawMovePidOut1 =3.5;//进行限幅 // if(g_fMPU6050YawMovePidOut1 <0) g_fMPU6050YawMovePidOut1 =0; // if(g_fMPU6050YawMovePidOut2 >3.5) g_fMPU6050YawMovePidOut2 =3.5; // if(g_fMPU6050YawMovePidOut2 <0) g_fMPU6050YawMovePidOut2 =0; // motorPidSetSpeed(g_fMPU6050YawMovePidOut1,g_fMPU6050YawMovePidOut2); ////**************避障功能********************// ////避障逻辑 // if(HC_SR04_Read() > 25)//前方无障碍物 // { // motorPidSetSpeed(1,1);//前运动 // HAL_Delay(100); // } // else{ //前方有障碍物 // motorPidSetSpeed(-1,1);//右边运动 原地 // HAL_Delay(500); // if(HC_SR04_Read() > 25)//右边无障碍物 // { // motorPidSetSpeed(1,1);//前运动 // HAL_Delay(100); // } // else{//右边有障碍物 // motorPidSetSpeed(1,-1);//左边运动 原地 // HAL_Delay(1000); // if(HC_SR04_Read() >25)//左边无障碍物 // { // motorPidSetSpeed(1,1);//前运动 // HAL_Delay(100); // } // else{ // motorPidSetSpeed(-1,-1);//后运动 // HAL_Delay(1000); // motorPidSetSpeed(-1,1);//右边运动 // HAL_Delay(50); // } // } // } ////*************无PID跟随功能************// // if(HC_SR04_Read() > 25) // { // motorPidSetSpeed(1,1);//前运动 // HAL_Delay(100); // } // if(HC_SR04_Read() < 20) // { // motorPidSetSpeed(-1,-1);//后运动 // HAL_Delay(100); // } ////**********PID跟随功能***********// // g_fHC_SR04_Read=HC_SR04_Read();//读取前方障碍物距离 // if(g_fHC_SR04_Read < 60){ //如果前60cm 有东西就启动跟随 // g_fFollow_PID_Out = PID_realize(&pidFollow,g_fHC_SR04_Read);//PID计算输出目标速度 这个速度,会和基础速度加减 // if(g_fFollow_PID_Out > 6) g_fFollow_PID_Out = 6;//对输出速度限幅 // if(g_fFollow_PID_Out < -6) g_fFollow_PID_Out = -6; // motorPidSetSpeed(g_fFollow_PID_Out,g_fFollow_PID_Out);//速度作用与电机上 // } // else motorPidSetSpeed(0,0);//如果前面60cm 没有东西就停止 // HAL_Delay(10);//读取超声波传感器不能过快 // ANO_DT_Send_F2(Motor1Speed*100, 3.0*100,Motor2Speed*100,3.0*100);//向匿名上位机通过F2帧发送4个int16类型的数据 曲线显示 // if(Usart_WaitReasFinish() == 0)//是否接收完毕 // { // cJsonData = cJSON_Parse((const char *)Usart1_ReadBuf); // if(cJSON_GetObjectItem(cJsonData,"p") !=NULL) // { // cJsonVlaue = cJSON_GetObjectItem(cJsonData,"p"); // p = cJsonVlaue->valuedouble; // pidMotor1Speed.Kp = p; // } // if(cJSON_GetObjectItem(cJsonData,"i") !=NULL) // { // cJsonVlaue = cJSON_GetObjectItem(cJsonData,"i"); // i = cJsonVlaue->valuedouble; // pidMotor1Speed.Ki = i; // } // if(cJSON_GetObjectItem(cJsonData,"d") !=NULL) // { // cJsonVlaue = cJSON_GetObjectItem(cJsonData,"d"); // d = cJsonVlaue->valuedouble; // pidMotor1Speed.Kd = d; // } // if(cJSON_GetObjectItem(cJsonData,"a") !=NULL) // { // // cJsonVlaue = cJSON_GetObjectItem(cJsonData,"a"); // a = cJsonVlaue->valuedouble; // pidMotor1Speed.target_val =a; // } // if(cJSON_GetObjectItem(cJsonData,"b") !=NULL) // { // // cJsonVlaue = cJSON_GetObjectItem(cJsonData,"b"); // b = cJsonVlaue->valuedouble; // pidMotor2Speed.target_val =b; // } // if(cJsonData != NULL){ // cJSON_Delete(cJsonData);//释放空间、但是不能删除cJsonVlaue不然会 出现异常错误 // } // memset(Usart1_ReadBuf,0,255);//清空接收buf,注意这里不能使用strlen // } // printf("P:%.3f I:%.3f D:%.3f A:%.3f\r\n",p,i,d,a); // __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 10); // __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, 10); // HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_SET); // HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_SET); // uint8_t c_Data[] = "串口输出测试:好家伙VCC\r\n"; // HAL_UART_Transmit(&huart1,c_Data,sizeof(c_Data),0xFFFF); // HAL_Delay(1000); // printf("printf:好家伙VCC测试\r\n"); // HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin); // HAL_Delay(500); } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ #include "motor.h" #include "tim.h" #include "pid.h" #define MAX_SPEED_UP 3 extern float Motor1Speed ; extern float Motor2Speed ; extern tPid pidMotor1Speed; extern tPid pidMotor2Speed; float motorSpeedUpCut = 0.5;//加减速速度变量 void Motor_Set(int Motor1,int Motor2) { //取反更适合控制习惯,大于0小车向前运动 Motor1 =-Motor1; Motor2 =-Motor2; //1.先根据正负设置方向GPIO 高低电平 if(Motor1 <0) BIN1_SET; else BIN1_RESET; if(Motor2 <0) AIN1_SET; else AIN1_RESET; //2.然后设置占空比 if(Motor1 <0) { if(Motor1 <-99) Motor1 =-99; __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (100+Motor1)); } else { if(Motor1 >99) Motor1 = 99; __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,Motor1); } if(Motor2<0) { if(Motor2 <-99) Motor2=-99; __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, (100+Motor2)); } else { if(Motor2 >99) Motor2 =99; __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, Motor2); } } /******************* * @brief 通过赋值PID目标速度控制小车运动 * @param Motor1SetSpeed:电机1目标速度 Motor2SetSpeed:电机2目标速度 * @return 无 * motorPidSetSpeed(1,2);//右边运动 motorPidSetSpeed(2,1);//左边运动 motorPidSetSpeed(1,1);//前运动 motorPidSetSpeed(-1,-1);//后运动 motorPidSetSpeed(-1,1); //向右原地旋转 motorPidSetSpeed(1,-1); //向左原地旋转 *******************/ void motorPidSetSpeed(float Motor1SetSpeed,float Motor2SetSpeed) { //设置Pid目标转速 pidMotor1Speed.target_val=Motor1SetSpeed; pidMotor2Speed.target_val=Motor2SetSpeed; //PID计算控制电机 Motor_Set(PID_realize(&pidMotor1Speed,Motor1Speed),PID_realize(&pidMotor2Speed,Motor2Speed)); } //向前加速函数 void motorPidSpeedUp(void) { if(motorSpeedUpCut <= MAX_SPEED_UP) motorSpeedUpCut +=0.5;//如果没有超过最大值就增加0.5 motorPidSetSpeed(motorSpeedUpCut,motorSpeedUpCut);//设置到电机 } //向前减速函数 void motorPidSpeedCut(void) { if(motorSpeedUpCut >=0.5)motorSpeedUpCut-=0.5;//判断是否速度太小 motorPidSetSpeed(motorSpeedUpCut,motorSpeedUpCut);//设置到电机 } #include "pid.h" //定义一个结构体类型变量 tPid pidMotor1Speed;//电机1速度PID闭环参数 tPid pidMotor2Speed;//电机2速度PID闭环参数 tPid pidHW_Tracking;//红外循迹的PID结构体类型变量 tPid pidFollow; //定距离跟随PID结构体类型变量 tPid pidMPU6050YawMovement; //利用6050偏航角 进行姿态控制的PID //给结构体类型变量赋初值 void PID_init() { pidMotor1Speed.actual_val=0.0; pidMotor1Speed.target_val=0.00; pidMotor1Speed.err=0.0; pidMotor1Speed.err_last=0.0; pidMotor1Speed.err_sum=0.0; pidMotor1Speed.Kp=15; pidMotor1Speed.Ki=5; pidMotor1Speed.Kd=0; pidMotor2Speed.actual_val=0.0; pidMotor2Speed.target_val=0.00; pidMotor2Speed.err=0.0; pidMotor2Speed.err_last=0.0; pidMotor2Speed.err_sum=0.0; pidMotor2Speed.Kp=15; pidMotor2Speed.Ki=5; pidMotor2Speed.Kd=0; pidHW_Tracking.actual_val=0.0; pidHW_Tracking.target_val=0.00;//红外循迹PID 的目标值为0 pidHW_Tracking.err=0.0; pidHW_Tracking.err_last=0.0; pidHW_Tracking.err_sum=0.0; pidHW_Tracking.Kp=-1.50; pidHW_Tracking.Ki=0; pidHW_Tracking.Kd=0.80; pidFollow.actual_val=0.0; pidFollow.target_val=22.50;//定距离跟随 目标距离22.5cm pidFollow.err=0.0; pidFollow.err_last=0.0; pidFollow.err_sum=0.0; pidFollow.Kp=-0.5;//定距离跟随的Kp大小通过估算PID输入输出数据,确定大概大小,然后在调试 pidFollow.Ki=-0.001;//Ki小一些 pidFollow.Kd=0; pidMPU6050YawMovement.actual_val=0.0; pidMPU6050YawMovement.target_val=0.00;//设定姿态目标值 pidMPU6050YawMovement.err=0.0; pidMPU6050YawMovement.err_last=0.0; pidMPU6050YawMovement.err_sum=0.0; pidMPU6050YawMovement.Kp=0.02;//6050航向角PID运动控制 pidMPU6050YawMovement.Ki=0; pidMPU6050YawMovement.Kd=0.1; } //比例p调节控制函数 float P_realize(tPid * pid,float actual_val) { pid->actual_val = actual_val;//传递真实值 pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值 //比例控制调节 输出=Kp*当前误差 pid->actual_val = pid->Kp*pid->err; return pid->actual_val; } //比例P 积分I 控制函数 float PI_realize(tPid * pid,float actual_val) { pid->actual_val = actual_val;//传递真实值 pid->err = pid->target_val - pid->actual_val;//当前误差=目标值-真实值 pid->err_sum += pid->err;//误差累计值 = 当前误差累计和 //使用PI控制 输出=Kp*当前误差+Ki*误差累计值 pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum; return pid->actual_val; } // PID控制函数 float PID_realize(tPid * pid,float actual_val) { pid->actual_val = actual_val;//传递真实值 pid->err = pid->target_val - pid->actual_val;////当前误差=目标值-真实值 pid->err_sum += pid->err;//误差累计值 = 当前误差累计和 //使用PID控制 输出 = Kp*当前误差 + Ki*误差累计值 + Kd*(当前误差-上次误差) pid->actual_val = pid->Kp*pid->err + pid->Ki*pid->err_sum + pid->Kd*(pid->err - pid->err_last); //保存上次误差: 这次误差赋值给上次误差 pid->err_last = pid->err; return pid->actual_val; } 提取所有有关于红外循迹的代码部分,并将代码分别分装在pid,sensor,motor(c文件和h文件)

//---------------------- 数据接收处理循环 ----------------------// while (1) { /* 接收服务器数据 */ mqtt_debug(MQTT_RxBUFF, MQTT_RxCounter, "\r\n\r\n* 接收到服务器数据:%x *\r\n"); /* 解析MQTT控制报文类型 */ switch (USART3_RxBuff[0] >> 4) // 首字节高4位表示报文类型 { case 2: // CONNACK - 连接确认 if (1 == MQTT_ConnAck()) // 验证连接确认 { mqtt_debug(MQTT_RxBUFF, MQTT_RxCounter, "\r\n* 连接成功 *\r\n"); IOT_state = Connect_OK; // 更新连接状态 } break; case 3: // PUBLISH - 发布消息 printf("\r\n* 接收到服务器下发 3X 报文 * \r\n"); /* 解析发布报文 */ MQTT_ReceivelPublish(&dup, &qos, &retain, &id, MQTT_RxBUFF); // 解析报文中的重发标志、QoS等级、保留标志、报文ID // 提取报文中的数据,并且实现硬件控制 /* 根据QoS等级响应 */ if (qos == 1) { MQTT_PubAck(id); // QoS1:发送发布确认 } if (qos == 2) { MQTT_PubRec(id); // QoS2第一步:发送接收确认 } break; case 4: // PUBACK - 发布确认(QoS1最终确认) if (MQTT_PubAck(MQTT_PUBLISH_ID)) { printf("\r\n* QoS1等级 报文发布成功 * \r\n"); } break; case 5: // PUBREC - 发布已接收(QoS2第二步) if (MQTT_PubRec(MQTT_PUBLISH_ID)) { MQTT_PubRel(MQTT_PUBLISH_ID); // 发送发布释放 } break; case 6: // PUBREL - 发布释放(QoS2第三步) if (MQTT_PubRel(MQTT_PUBLISH_ID)) { MQTT_PubComp(MQTT_PUBLISH_ID); // 发送发布完成 } break; case 7: // PUBCOMP - 发布完成(QoS2最终确认) printf("\r\n* QoS2消息传输完成 *\r\n"); break; case 9: // SUBACK - 订阅确认 if (1 == MQTT_SubAck(MQTT_SUBSCRIBE_ID)) { mqtt_debug(MQTT_RxBUFF, MQTT_RxCounter, "\r\n* 订阅成功 *\r\n"); IOT_state = Subscribe_OK; // 更新订阅状态 } break; case 11: // UNSUBACK - 取消订阅确认 printf("\r\n* 取消订阅成功 *\r\n"); break; case 13: // PINGRESP - 心跳响应 printf("\r\n* 心跳响应正常 *\r\n"); break; default: printf("\r\n* 未知报文类型:%d *\r\n", USART3_RxBuff[0] >> 4); break; } WIFI_Clean(); // 每次处理完清理缓冲区 } } 完善这个代码

最新推荐

recommend-type

2022年网站美工个人年度工作总结(1).doc

2022年网站美工个人年度工作总结(1).doc
recommend-type

财务软件销售实习报告格式范文-实习报告格式(1).doc

财务软件销售实习报告格式范文-实习报告格式(1).doc
recommend-type

【航迹关联】基于标准 Hough 变换、修正 Hough 变换和序列 Hough 变换实现航迹起始算法研究Matlab代码.rar

【航迹关联】基于标准 Hough 变换、修正 Hough 变换和序列 Hough 变换实现航迹起始算法研究Matlab代码
recommend-type

Windows系统修复工具

Windows 系统修复工具主要用于解决 Windows 11/10 系统中的各种常见问题,具有操作简单、功能全面等特点: 文件资源管理器修复:可解决文件资源管理器卡死、崩溃、无响应等问题,能终止崩溃循环。还可修复右键菜单无响应或选项缺失问题,以及重建缩略图缓存,让图片、视频等文件的缩略图正常显示,此外,还能处理桌面缺少回收站图标、回收站损坏等问题。 互联网和连接修复:能够刷新 DNS 缓存,加速网页加载速度,减少访问延迟。可重置 TCP/IP 协议栈,增强网络连接稳定性,减少网络掉线情况,还能还原 Hosts 文件,清除恶意程序对网络设置的篡改,保障网络安全,解决电脑重装系统后网络无法连接、浏览器主页被篡改等问题。 系统修复:集成系统文件检查器(SFC),可自动扫描并修复受损的系统文件。能解决 Windows 激活状态异常的问题,还可重建 DLL 注册库,恢复应用程序兼容性,解决部分软件无法正常运行的问题,同时也能处理如 Windows 沙箱无法启动、Windows 将 JPG 或 JPEG 保存为 JFIF 等系统问题。 系统工具维护:提供启动管理器、服务管理器和进程管理器等工具,用户可控制和管理启动程序、系统服务和当前运行的进程,提高系统的启动和运行速度,防止不必要的程序和服务占用系统资源。还能查看系统规格,如处理器线程数、最大显示分辨率等。 故障排除:集成超过 20 个微软官方诊断工具,可对系统问题进行专业排查,还能生成硬件健康状态报告。能解决搜索和索引故障、邮件和日历应用程序崩溃、设置应用程序无法启动等问题,也可处理打印机、网络适配器、Windows 更新等相关故障。 其他修复功能:可以重置组策略设置、catroot2 文件夹、记事本等多种系统设置和组件,如重置 Windows 应用商店缓存、Windows 防火墙设置等。还能添加重建图标缓存支持,恢复粘滞便笺删除
recommend-type

高中信息技术《算法与程序设计》练习(1).doc

高中信息技术《算法与程序设计》练习(1).doc
recommend-type

获取本机IP地址的程序源码分析

从给定文件信息中我们可以提取出的关键知识点是“取本机IP”的实现方法以及与之相关的编程技术和源代码。在当今的信息技术领域中,获取本机IP地址是一项基本技能,广泛应用于网络通信类的软件开发中,下面将详细介绍这一知识点。 首先,获取本机IP地址通常需要依赖于编程语言和操作系统的API。不同的操作系统提供了不同的方法来获取IP地址。在Windows操作系统中,可以通过调用Windows API中的GetAdaptersInfo()或GetAdaptersAddresses()函数来获取网络适配器信息,进而得到IP地址。在类Unix操作系统中,可以通过读取/proc/net或是使用系统命令ifconfig、ip等来获取网络接口信息。 在程序设计过程中,获取本机IP地址的源程序通常会用到网络编程的知识,比如套接字编程(Socket Programming)。网络编程允许程序之间进行通信,套接字则是在网络通信过程中用于发送和接收数据的接口。在许多高级语言中,如Python、Java、C#等,都提供了内置的网络库和类来简化网络编程的工作。 在网络通信类中,IP地址是区分不同网络节点的重要标识,它是由IP协议规定的,用于在网络中唯一标识一个网络接口。IP地址可以是IPv4,也可以是较新的IPv6。IPv4地址由32位二进制数表示,通常分为四部分,每部分由8位构成,并以点分隔,如192.168.1.1。IPv6地址则由128位二进制数表示,其表示方法与IPv4有所不同,以冒号分隔的8组16进制数表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。 当编写源代码以获取本机IP地址时,通常涉及到以下几个步骤: 1. 选择合适的编程语言和相关库。 2. 根据目标操作系统的API或系统命令获取网络接口信息。 3. 分析网络接口信息,提取出IP地址。 4. 将提取的IP地址转换成适合程序内部使用的格式。 5. 在程序中提供相应功能,如显示IP地址或用于网络通信。 例如,在Python中,可以使用内置的socket库来获取本机IP地址。一个简单的示例代码如下: ```python import socket # 获取主机名 hostname = socket.gethostname() # 获取本机IP local_ip = socket.gethostbyname(hostname) print("本机IP地址是:", local_ip) ``` 在实际应用中,获取本机IP地址通常是为了实现网络通信功能,例如建立客户端与服务器的连接,或者是在开发涉及到IP地址的其他功能时使用。 关于文件名称“getIP”,这是一个自解释的文件名,明显表示该文件或程序的作用是获取本机的IP地址。从标签“控件 源码 网络通信类 资源”中我们可以看出,这个文件很可能是一个可以嵌入其他软件中的代码片段,用以实现网络通信功能的一部分,具有较高的灵活性和重用性。 综上所述,获取本机IP地址是一个涉及到操作系统API、网络编程以及特定编程语言知识的技能。它不仅需要对编程语言提供的库函数有深入的理解,还要对操作系统的网络配置和IP协议有足够的认识。通过阅读和分析相关的源代码,如“getIP”,可以加深对网络编程实现细节的理解,并能够在实际开发中快速地应用这一技术。
recommend-type

【权威指南】:Win11笔记本上RTX4080驱动的安装与调试秘籍

# 1. Win11笔记本与RTX4080显卡介绍 随着技术的不断发展,笔记本电脑已不再是仅仅满足办公需求的移动设备,而是逐渐成为可以胜任复杂图形处理和游戏任务的强大工具。微软推出的Windows 11操作系统,以其全新的用户界面和改进的系统性能,为用户提供了更为流畅的操作体验。而在硬件方面,NVIDIA的RTX 4080显卡以其卓越的图形处理能力和AI支持,为笔记本电脑带来了前所未有的性能提升。本章节将带您初步了解Windows 11笔记本与NVIDIA RTX 4080显卡的基础信息,为进一步深入探讨它们的优化和调试技巧奠定基础。 ## 1.1 Win11笔记本的优势 Windows
recommend-type

windows环境举例

<think>好的,用户现在想在Windows环境下创建C函数库,需要具体的方法和示例代码。我需要结合之前的回答和用户提供的引用内容来给出合适的指导。 首先回顾之前的回答,用户已经了解了在Linux下创建静态库和动态库的方法,现在需要切换到Windows环境。根据引用[2],Windows下的C标准库和动态链接库的处理与Linux不同,比如使用dlfcn.h在Linux,而Windows可能需要其他方式。另外,引用[1]提到了在Windows下配置gcc环境(MinGW-w64),这可能是一个关键点,因为用户可能需要使用MinGW来编译库。 用户提供的引用[3]提到了使用MSVC编译器,这
recommend-type

QQ自动发送/回复系统源代码开放

根据提供的文件信息,我们可以了解到以下几点关键的知识点: ### 标题:“qqhelp” 1. **项目类型**: 标题“qqhelp”暗示这是一个与QQ相关的帮助工具或项目。QQ是中国流行的即时通讯软件,因此这个标题表明项目可能提供了对QQ客户端功能的辅助或扩展。 2. **用途**: “help”表明此项目的主要目的是提供帮助或解决问题。由于它提到了QQ,并且涉及“autosend/reply”功能,我们可以推测该项目可能用于自动化发送消息回复,或提供某种形式的自动回复机制。 ### 描述:“I put it to my web, but nobody sendmessage to got the source, now I public it. it supply qq,ticq autosend/reply ,full sourcecode use it as you like” 1. **发布情况**: 描述提到该项目原先被放置在某人的网站上,并且没有收到请求源代码的消息。这可能意味着项目不够知名或者需求不高。现在作者决定公开发布,这可能是因为希望项目能够被更多人了解和使用,或是出于开源共享的精神。 2. **功能特性**: 提到的“autosend/reply”表明该项目能够实现自动发送和回复消息。这种功能对于需要进行批量或定时消息沟通的应用场景非常有用,例如客户服务、自动化的营销通知等。 3. **代码可用性**: 作者指出提供了“full sourcecode”,意味着源代码完全开放,用户可以自由使用,无论是查看、学习还是修改,用户都有很大的灵活性。这对于希望学习编程或者有特定需求的开发者来说是一个很大的优势。 ### 标签:“综合系统类” 1. **项目分类**: 标签“综合系统类”表明这个项目可能是一个多功能的集成系统,它可能不仅限于QQ相关的功能,还可能包含了其他类型的综合服务或特性。 2. **技术范畴**: 这个标签可能表明该项目的技术实现比较全面,可能涉及到了多个技术栈或者系统集成的知识点,例如消息处理、网络编程、自动化处理等。 ### 压缩包子文件的文件名称列表: 1. **Unit1.dfm**: 这是一个Delphi或Object Pascal语言的窗体定义文件,用于定义应用程序中的用户界面布局。DFM文件通常用于存储组件的属性和位置信息,使得开发者可以快速地进行用户界面的设计和调整。 2. **qqhelp.dpr**: DPR是Delphi项目文件的扩展名,包含了Delphi项目的核心设置,如程序入口、使用的单元(Units)等。这个文件是编译和构建Delphi项目的起点,它能够帮助开发者了解项目的组织结构和编译指令。 3. **Unit1.pas**: PAS是Delphi或Object Pascal语言的源代码文件。这个文件可能包含了与QQ帮助工具相关的核心逻辑代码,例如处理自动发送和回复消息的算法等。 4. **readme.txt**: 这是一个常见的文本文件,包含项目的基本说明和使用指导,帮助用户了解如何获取、安装、运行和定制该项目。README文件通常是用户与项目首次交互时首先阅读的文件,因此它对于一个开源项目的用户友好度有着重要影响。 通过以上分析,我们可以看出“qqhelp”项目是一个针对QQ通讯工具的自动化消息发送与回复的辅助工具。项目包含完整的源代码,用户可以根据自己的需要进行查看、修改和使用。它可能包含Delphi语言编写的窗体界面和后端逻辑代码,具有一定的综合系统特性。项目作者出于某种原因将其开源,希望能够得到更广泛的使用和反馈。
recommend-type

【7步打造Win11深度学习利器】:Tensorflow-GPU与RTX4080终极优化指南

# 1. 深度学习与Windows 11的融合 在人工智能时代,深度学习已渗透到生活的方方面面,而Windows 11作为最新一代的操作系统,为深度学习提供了一个高效的工作平台。本章节将探讨深度学习技术如何与Windows 11系统融合,以及这一