#include “stm32f10x.h” #include <system_stm32f10x.h> #include <stdio.h> #include “usart.h” #include “gpio.h” #include “sys_tick.h” uint8_t uart3_cmd; void delay(u16 t){ u16 i=0; while(t–){ i=12000; while(i–); } } int main(void) { SystemInit(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); GPIO_InitTypeDef G; G.GPIO_Mode=GPIO_Mode_IPU; G.GPIO_Pin=GPIO_Pin_14|GPIO_Pin_13; G.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&G); G.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4; G.GPIO_Mode=GPIO_Mode_Out_PP; G.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOE,&G); GPIO_SetBits(GPIOE,GPIO_Pin_3|GPIO_Pin_4); USART3_Init(UART3_BAUD); while(1) { delay(2000); if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_14)==0){ GPIO_ResetBits(GPIOE,GPIO_Pin_3); } else{ GPIO_SetBits(GPIOE,GPIO_Pin_3); } if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==0){ GPIO_ResetBits(GPIOE,GPIO_Pin_4); } else{ GPIO_SetBits(GPIOE,GPIO_Pin_4); } } } 帮我详细分析上述代码

时间: 2025-07-12 11:41:36 浏览: 1
<think>首先,用户要求用中文回答问题,并且在回答后必须提出3-5个相关问题。问题必须以“§§相关问题§§”开头,并且不能换行分散。相关问题必须基于用户的问题和我的回答。 用户提供的代码是STM32微控制器的C代码,看起来是控制GPIO和UART的。代码包括初始化系统、配置GPIO引脚、设置UART,并在一个无限循环中读取输入引脚状态来控制输出引脚。 我的任务是详细分析这段代码。分析应该包括: 1. **整体功能**:解释代码的主要目的。 2. **关键部分解析**: - 头文件包含:如stm32f10x.h、usart.h、gpio.h等。 - 全局变量:uint8_t uart3_cmd; 但未使用。 - delay函数:一个简单的延时函数,使用循环来实现延时。 - main函数: - 系统初始化:SystemInit(); - NVIC配置:设置中断优先级分组。 - GPIO配置:配置PC13、PC14为输入上拉(IPU),PE3、PE4为推挽输出。 - UART初始化:USART3_Init(UART3_BAUD); 但UART3_BAUD未定义,可能在usart.h中定义。 - while(1)循环:每2秒(通过delay(2000))读取PC14和PC13的状态,并相应地设置PE3和PE4的输出。 3. **具体行为**: - 如果PC14为低(0),则设置PE3为低(ResetBits);否则为高(SetBits)。 - 如果PC13为低(0),则设置PE4为低;否则为高。 - 这类似于简单的开关控制LED或类似输出。 4. **潜在问题**: - delay函数可能不精确,依赖于循环计数。 - uart3_cmd未使用,UART初始化后没有实际使用UART通信。 - 代码中UART初始化了,但没有中断处理或数据发送/接收。 - 输入引脚配置为IPU(上拉输入),所以当引脚悬空时可能为高。 - 输出引脚设置为推挽输出。 5. **改进建议**:如果需要,可以提到使用定时器中断或更精确的延时,或者添加UART功能。 分析完成后,我必须提出3-5个相关问题。相关问题应该基于代码和我的分析,例如: 1. 如何优化延时函数? 2. UART3如何用于通信? 3. 为什么输入引脚配置为IPU? 4. 如何添加中断来处理输入变化? 5. 代码中NVIC配置的作用是什么? 确保相关问题是中文的,并以“§§相关问题§§”开头,然后列出1. 2. 3. 等。 输出格式: - 先分析代码(用中文)。 - 然后以“§§相关问题§§”开头,列出问题。 分析代码: - 代码是针对STM32F10x系列微控制器的。 - 包括必要的头文件。 - 定义了一个全局变量uart3_cmd,但未使用。 - delay函数:一个简单的软件延时,参数t控制延时时间,通过嵌套循环实现。 - main函数: - SystemInit():初始化系统时钟等。 - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2):设置中断优先级分组为Group 2。 - GPIO配置: - 对于GPIOC:Pin13和Pin14设置为输入上拉模式(GPIO_Mode_IPU),速度为50MHz。 - 对于GPIOE:Pin3和Pin4设置为推挽输出模式(GPIO_Mode_Out_PP),速度为50MHz。 - 初始设置PE3和PE4为高电平(SetBits)。 - USART3_Init(UART3_BAUD):初始化UART3,波特率由UART3_BAUD定义,可能在usart.h中。 - 无限循环: - 调用delay(2000),延时大约2秒(取决于系统时钟)。 - 读取PC14状态:如果为0(低电平),则设置PE3为低;否则为高。 - 读取PC13状态:如果为0,则设置PE4为低;否则为高。 功能:这似乎是一个简单的输入输出控制程序。PC13和PC14可能是连接按钮的输入引脚(当按钮按下时为低,因为配置了上拉),PE3和PE4可能是连接LED的输出引脚(高电平点亮或低电平点亮,取决于电路)。 在代码中,当输入为低时,输出被设置为低(ResetBits),所以可能LED是阳极通过电阻连接到VCC,阴极连接到MCU引脚,这样当引脚低时LED亮。 UART部分初始化了但未使用,所以uart3_cmd可能是预留的。 现在,撰写回答: 1. 开头:简要概述代码功能。 2. 详细分析各部分。 3. 结束分析。 4. 然后“§§相关问题§§” 5. 列出3-5个问题。</think>### 代码详细分析 以下是针对您提供的STM32F10x微控制器C代码的详细分析。代码主要用于实现基于GPIO输入的简单控制逻辑,涉及系统初始化、GPIO配置、UART初始化和一个主循环。以下从整体功能、关键代码段解析、潜在问题和改进建议等方面进行说明。 #### 1. **整体功能** 代码的核心功能是通过读取GPIOC的输入引脚(PC13和PC14)状态,控制GPIOE的输出引脚(PE3和PE4)。具体逻辑: - 每隔约2秒(通过`delay(2000)`实现),检测PC14和PC13的电平。 - 如果PC14为低电平(0),则设置PE3为低电平;否则设为高电平。 - 如果PC13为低电平(0),则设置PE4为低电平;否则设为高电平。 这类似于一个简单的按钮控制LED的示例:输入引脚(如连接按钮)状态变化时,输出引脚(如连接LED)相应变化。UART3被初始化但未实际使用,可能是预留功能。 #### 2. **关键代码段解析** - **头文件包含**: - `#include “stm32f10x.h”`:STM32标准库主头文件,提供寄存器定义。 - `#include <system_stm32f10x.h>`:系统初始化函数(如`SystemInit()`)的声明。 - `#include <stdio.h>`:标准I/O库,但代码中未使用,可移除。 - `#include “usart.h”`:自定义UART初始化函数(`USART3_Init`)的声明。 - `#include “gpio.h”`:自定义GPIO函数(如`GPIO_Init`)的声明。 - `#include “sys_tick.h”`:可能用于系统滴答定时器,但代码中未使用,可移除。 - **全局变量**: - `uint8_t uart3_cmd;`:定义UART3命令变量,但未在代码中使用,可能是预留或错误残留。 - **delay函数**: - 实现一个简单的软件延时:通过嵌套循环消耗时间。 - 参数`t`控制延时次数,每次循环约消耗一定时间(依赖于CPU时钟频率,如72MHz时`delay(2000)`约延时2秒)。 - 问题:延时精度低,受编译器优化和时钟影响;建议使用硬件定时器(如SysTick)替代。 - **main函数**: - **系统初始化**: - `SystemInit();`:初始化系统时钟(通常设置HSI/HSE和PLL)。 - `NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);`:设置中断优先级分组为Group 2(支持2位抢占优先级和2位子优先级),但代码中未使用中断,此配置多余。 - **GPIO配置**: - GPIOC(输入引脚): - `GPIO_Pin_13 | GPIO_Pin_14`:配置为上拉输入模式(`GPIO_Mode_IPU`),即引脚悬空时为高电平,接地时为低电平(适合按钮输入)。 - 速度设为50MHz,对输入模式影响不大。 - GPIOE(输出引脚): - `GPIO_Pin_3 | GPIO_Pin_4`:配置为推挽输出模式(`GPIO_Mode_Out_PP`),可直接驱动LED等负载。 - 初始调用`GPIO_SetBits`设置PE3和PE4为高电平。 - **UART初始化**: - `USART3_Init(UART3_BAUD);`:调用自定义函数初始化UART3,波特率由`UART3_BAUD`宏定义(应在`usart.h`中指定,如9600)。但初始化后,代码未使用UART发送/接收数据,功能闲置。 - **主循环**: - `while(1)` 无限循环: - `delay(2000);`:每次循环前延时约2秒,导致输入检测有延迟(非实时响应)。 - PC14检测:`GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_14)`读取状态,为0时`GPIO_ResetBits`设置PE3低,否则`GPIO_SetBits`设置高。 - PC13检测:类似逻辑控制PE4。 - 行为:当按钮按下(输入低电平)时,对应输出引脚拉低(如LED亮);松开时输出高(LED灭)。 #### 3. **潜在问题与改进建议** - **问题**: - 延时函数不精确:`delay`依赖CPU速度,移植到不同时钟系统时行为可能变化。 - UART未使用:初始化UART3但未实现数据收发,浪费资源;全局变量`uart3_cmd`未使用。 - 输入响应延迟:`delay(2000)`导致检测间隔约2秒,按钮按下后不能立即响应。 - 中断缺失:输入引脚适合用外部中断检测变化,但代码使用轮询方式。 - 冗余代码:`stdio.h`和`sys_tick.h`未使用;NVIC配置多余。 - **改进建议**: - 替换延时:使用SysTick定时器实现精确延时。 - 添加中断:为PC13/PC14配置外部中断,实现实时响应。 - 启用UART:在循环中添加UART发送函数,输出引脚状态。 - 优化结构:移除未使用变量和头文件;添加注释提高可读性。 #### 4. **代码适用场景** 此代码适合初学者学习STM32 GPIO控制,如按钮-LED实验。在实际应用中,可扩展为远程控制(通过UART)或低功耗模式优化。
阅读全文

相关推荐

#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "dht11.h" #include "FMQ.h" #include "Serial.h" #include "esp8266.h" #include "stm32f10x_it.h" // 系统时钟配置 void SystemClock_Config(void) { SystemInit(); RCC_DeInit(); RCC_HSEConfig(RCC_HSE_ON); // 添加HSE启动检测 if(!RCC_WaitForHSEStartUp()) { while(1); // HSE启动失败,陷入死循环 } FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); FLASH_SetLatency(FLASH_Latency_2); RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); } // 全局变量 u8 temp, humi; int main(void) { // 系统初始化 SystemClock_Config(); Delay_Init(); OLED_Init(); DHT11_Init(); mfq_Init(); Serial_Init(); // 用于调试的串口 // 显示初始化 OLED_ShowCN(0, 0, "温度:"); // 修改为正确的中文字库函数 OLED_ShowCN(0, 16, "湿度:"); OLED_ShowCN(64, 16, "RH"); OLED_ShowCN(64, 0, "C"); OLED_Update(); // 初始化ESP8266为AP模式 ESP8266_Init(); printf("ESP8266 AP Mode Ready\r\n"); printf("Connect to WiFi: ESP8266wd, Password:123456789\r\n"); printf("Then connect to TCP Server: 192.168.4.1:8080\r\n"); uint32_t lastSendTime = 0; while(1) { // 读取温湿度 if(DHT11_Read_Data(&temp, &humi)) { // 更新显示 OLED_ShowNum(47, 0, temp, 2, OLED_8X16); OLED_ShowNum(47, 16, humi, 2, OLED_8X16); OLED_Update(); // 控制蜂鸣器 fmq(temp, humi); // 串口输出信息 printf("temp=%d, humi=%d RH\r\n", temp, humi); // 准备WiFi发送数据 sprintf(wifi_data, "Temp:%d,Humi:%d\r\n", temp, humi); ESP8266_SendData(wifi_data); } delay_ms(5000); // 5秒更新一次 } } /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_conf.h * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Library configuration file. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *
© COPYRIGHT 2011 STMicroelectronics
****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM32F10x_CONF_H #define __STM32F10x_CONF_H /* Includes ------------------------------------------------------------------*/ /* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */ #include "stm32f10x_adc.h" #include "stm32f10x_bkp.h" #include "stm32f10x_can.h" #include "stm32f10x_cec.h" #include "stm32f10x_crc.h" #include "stm32f10x_dac.h" #include "stm32f10x_dbgmcu.h" #include "stm32f10x_dma.h" #include "stm32f10x_exti.h" #include "stm32f10x_flash.h" #include "stm32f10x_fsmc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_i2c.h" #include "stm32f10x_iwdg.h" #include "stm32f10x_pwr.h" #include "stm32f10x_rcc.h" #include "stm32f10x_rtc.h" #include "stm32f10x_sdio.h" #include "stm32f10x_spi.h" #include "stm32f10x_tim.h" #include "stm32f10x_usart.h" #include "stm32f10x_wwdg.h" #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Uncomment the line below to expanse the "assert_param" macro in the Standard Peripheral Library drivers code */ /* #define USE_FULL_ASSERT 1 */ /* Exported macro ------------------------------------------------------------*/ #ifdef USE_FULL_ASSERT /** * @brief The assert_param macro is used for function's parameters check. * @param expr: If expr is false, it calls assert_failed function which reports * the name of the source file and the source line number of the call * that failed. If expr is true, it returns no value. * @retval None */ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) /* Exported functions ------------------------------------------------------- */ void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */ #endif /* __STM32F10x_CONF_H */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Main Interrupt Service Routines. * This file provides template for all exceptions handler and * peripherals interrupt service routine. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *
© COPYRIGHT 2011 STMicroelectronics
****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_it.h" volatile uint32_t sysTickUptime = 0; // 添加在文件顶部 /** @addtogroup STM32F10x_StdPeriph_Template * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /******************************************************************************/ /* Cortex-M3 Processor Exceptions Handlers */ /******************************************************************************/ /** * @brief This function handles NMI exception. * @param None * @retval None */ void NMI_Handler(void) { } /** * @brief This function handles Hard Fault exception. * @param None * @retval None */ void HardFault_Handler(void) { /* Go to infinite loop when Hard Fault exception occurs */ while (1) { } } /** * @brief This function handles Memory Manage exception. * @param None * @retval None */ void MemManage_Handler(void) { /* Go to infinite loop when Memory Manage exception occurs */ while (1) { } } /** * @brief This function handles Bus Fault exception. * @param None * @retval None */ void BusFault_Handler(void) { /* Go to infinite loop when Bus Fault exception occurs */ while (1) { } } /** * @brief This function handles Usage Fault exception. * @param None * @retval None */ void UsageFault_Handler(void) { /* Go to infinite loop when Usage Fault exception occurs */ while (1) { } } /** * @brief This function handles SVCall exception. * @param None * @retval None */ void SVC_Handler(void) { } /** * @brief This function handles Debug Monitor exception. * @param None * @retval None */ void DebugMon_Handler(void) { } /** * @brief This function handles PendSVC exception. * @param None * @retval None */ void PendSV_Handler(void) { } /** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) { // 添加SysTick中断处理 sysTickUptime++; } /******************************************************************************/ /* STM32F10x Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ /* available peripheral interrupt handler's name please refer to the startup */ /* file (startup_stm32f10x_xx.s). */ /******************************************************************************/ /** * @brief This function handles USART3 global interrupt request. * @param None * @retval None */ void USART2_IRQHandler(void) { // 调用ESP8266模块的中断处理函数 extern void ESP8266_IRQHandler(void); ESP8266_IRQHandler(); } uint32_t HAL_GetTick(void) { return sysTickUptime; } /** * @} */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ /** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_it.h * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief This file contains the headers of the interrupt handlers. ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * *
© COPYRIGHT 2011 STMicroelectronics
****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM32F10x_IT_H #define __STM32F10x_IT_H #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "stm32f10x.h" extern volatile uint32_t sysTickUptime; uint32_t HAL_GetTick(void); /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void NMI_Handler(void); void HardFault_Handler(void); void MemManage_Handler(void); void BusFault_Handler(void); void UsageFault_Handler(void); void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); #ifdef __cplusplus } #endif #endif /* __STM32F10x_IT_H */ /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ #include "esp8266.h" #include <string.h> #include "stm32f10x_usart.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" // 发送AT指令 void ESP8266_SendCmd(char* cmd, char* resp, uint16_t timeout) { USART_ClearFlag(ESP8266_USARTx, USART_FLAG_TC); // 发送命令 while(*cmd) { USART_SendData(ESP8266_USARTx, *cmd++); while(USART_GetFlagStatus(ESP8266_USARTx, USART_FLAG_TC) == RESET); } // 等待响应 uint32_t start = HAL_GetTick(); while(strstr((const char*)USART_RxBuffer, resp) == NULL) { if(HAL_GetTick() - start > timeout) { break; } } delay_ms(50); } // 初始化ESP8266为AP模式 void ESP8266_Init(void) { // 初始化USART2 USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; // 配置USART2 Tx (PA2) 为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置USART2 Rx (PA3) 为浮空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = ESP8266_USART_BAUDRATE; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(ESP8266_USARTx, &USART_InitStructure); USART_Cmd(ESP8266_USARTx, ENABLE); // 添加NVIC中断配置 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 配置ESP8266为AP模式 Delay_ms(1000); // 等待模块启动 ESP8266_SendCmd("AT+RST\r\n", "OK", 2000); ESP8266_SendCmd("AT+CWMODE=2\r\n", "OK", 2000); // 设置为AP模式 ESP8266_SendCmd("AT+CWSAP=\"ESP8266_AP\",\"12345678\",1,4\r\n", "OK", 2000); // 设置AP参数 ESP8266_SendCmd("AT+CIPMUX=1\r\n", "OK", 2000); // 允许多连接 ESP8266_SendCmd("AT+CIPSERVER=1,8080\r\n", "OK", 2000); // 开启TCP服务器 } // 发送数据到TCP客户端 u8 ESP8266_SendData(char* data) { char cmd[64]; sprintf(cmd, "AT+CIPSEND=0,%d\r\n", strlen(data)); ESP8266_SendCmd(cmd, "OK", 1000); // 等待OK响应 ESP8266_SendCmd(data, ">", 1000); // 等待>提示符 ESP8266_SendCmd((char*)0x1A, "SEND OK", 1000); // 发送Ctrl+Z return 0; } // esp8266.h #ifndef __ESP8266_H #define __ESP8266_H #include "stm32f10x.h" #include "stm32f10x_usart.h" #include "delay.h" #define ESP8266_USARTx USART2 #define ESP8266_USART_BAUDRATE 115200 void ESP8266_Init(void); void ESP8266_SendCmd(char* cmd); u8 ESP8266_SendData(char* data); #endif 将代码修改正确

#include <FreeRTOS.h> #include <task.h> #include <stdio.h> #include <string.h> #include "stm32f10x.h" // ??????STM32F4????? // ?????? TaskHandle_t xTask1Handle = NULL; TaskHandle_t xTask2Handle = NULL; // ??LED?? #define LED_PIN GPIO_PIN_5 #define LED_GPIO_PORT GPIOA // ?????? void vPrintString(const char *str) { // ????HAL???????? HAL_UART_Transmit(&huart2, (uint8_t*)str, strlen(str), HAL_MAX_DELAY); } // ??1:??? void vTask1(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 1000; // 1? xLastWakeTime = xTaskGetTickCount(); for (;;) { // ??LED HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN); // ??1? vTaskDelayUntil(&xLastWakeTime, xFrequency); // 6??????2 if (xTaskGetTickCount() >= 6000) { vTaskSuspend(xTask2Handle); } } } // ??2:?????? void vTask2(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 3000; // 3? xLastWakeTime = xTaskGetTickCount(); for (;;) { // ?????? vPrintString("Task 2: Hello from UART!\r\n"); // ??3? vTaskDelayUntil(&xLastWakeTime, xFrequency); } } int main(void) { // ???HAL? HAL_Init(); // ??????? SystemClock_Config(); // ???GPIO __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = LED_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); // ????1 xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle); // ????2 xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle); // ????? vTaskStartScheduler(); // ?????????,????? for (;;); } // ???????? void SystemClock_Config(void) { // ?????????? } // ??????? void UART_Init(void) { // ????????? }

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * *
© Copyright (c) 2025 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "adc.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "string.h" #include "lcd.h" #include <stdio.h> #include "led1.h" #include "uart.h" #include "key.h" #include "flash.h" float distance = 0; char buf[32]; /* 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 */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ uint8_t key_rval; char lcd_buf[32] = {0}; double volt_R37; double volt_R38; extern uint8_t l2450_rx_data; extern char l2450_rx_buffer[50]; extern uint8_t l2450_rx_index; volatile int16_t x_distance = 0; // ??????? volatile int16_t y_distance = 0; /* 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_ADC1_Init(); MX_ADC2_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ distance = Flash_LoadDistance(); LCD_Init(); LCD_Clear(White); LCD_SetBackColor(White); LCD_SetTextColor(Black); LCD_DisplayStringLine(Line4, (uint8_t *)"x:---- y:----"); char lcd_buf[32]; sprintf(lcd_buf, "distance:%.1f m", distance); LCD_DisplayStringLine(Line9, (uint8_t*)lcd_buf); UART_StartReceive_IT(); HAL_UART_Receive_IT(&huart2, &l2450_rx_data, 1); HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED); volt_R37=getADC2()*3.2/4096; volt_R38=getADC1()*3.2/4096; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ Key_Proc(); // ???????? static int16_t last_x = 0, last_y = 0; if (x_distance != last_x || y_distance != last_y) { char lcd_buf[32]; float x_m = x_distance / 1000.0f; float y_m = y_distance / 1000.0f; sprintf(lcd_buf, "x:%1.2fm y:%1.2fm", x_m, y_m); LCD_DisplayStringLine(Line4, (uint8_t *)lcd_buf); last_x = x_distance; last_y = y_distance; } HAL_Delay(10); // ????,??LCD???? } /* 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}; /** Configure the main internal regulator output voltage */ HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); /** 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.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3; RCC_OscInitStruct.PLL.PLLN = 20; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; 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_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } /** Initializes the peripherals clocks */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2 |RCC_PERIPHCLK_ADC12; PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1; PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK; 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 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32g4xx_it.c * @brief Interrupt Service Routines. ****************************************************************************** * @attention * *
© Copyright (c) 2025 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32g4xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include <string.h> #include <stdlib.h> #include <stdio.h> #include "lcd.h" #include "led1.h" #include "usart.h" #include "uart.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ // ?????? extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; extern volatile int16_t x_distance; extern volatile int16_t y_distance; extern float distance; // USART2 ?????? extern uint8_t l2450_rx_data; extern char l2450_rx_buffer[50]; extern uint8_t l2450_rx_index; // USART1 ???????? extern uint8_t rx_data; extern char tx_buf[64]; /* USER CODE END TD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ static uint8_t rec_buf[50]; // ????? static uint8_t rec_index = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; /* USER CODE BEGIN EV */ extern UART_HandleTypeDef huart2; extern uint8_t l2450_rx_data; extern char l2450_rx_buffer[50]; extern uint8_t l2450_rx_index; extern float distance; /* USER CODE END EV */ /******************************************************************************/ /* Cortex-M4 Processor Interruption and Exception Handlers */ /******************************************************************************/ /** * @brief This function handles Non maskable interrupt. */ void NMI_Handler(void) { /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ while (1) { } /* USER CODE END NonMaskableInt_IRQn 1 */ } /** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } } /** * @brief This function handles Memory management fault. */ void MemManage_Handler(void) { /* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE END MemoryManagement_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */ } } /** * @brief This function handles Prefetch fault, memory access fault. */ void BusFault_Handler(void) { /* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE END BusFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */ } } /** * @brief This function handles Undefined instruction or illegal state. */ void UsageFault_Handler(void) { /* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE END UsageFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */ } } /** * @brief This function handles System service call via SWI instruction. */ void SVC_Handler(void) { /* USER CODE BEGIN SVCall_IRQn 0 */ /* USER CODE END SVCall_IRQn 0 */ /* USER CODE BEGIN SVCall_IRQn 1 */ /* USER CODE END SVCall_IRQn 1 */ } /** * @brief This function handles Debug monitor. */ void DebugMon_Handler(void) { /* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE END DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 1 */ /* USER CODE END DebugMonitor_IRQn 1 */ } /** * @brief This function handles Pendable request for system service. */ void PendSV_Handler(void) { /* USER CODE BEGIN PendSV_IRQn 0 */ /* USER CODE END PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 1 */ /* USER CODE END PendSV_IRQn 1 */ } /** * @brief This function handles System tick timer. */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } /******************************************************************************/ /* STM32G4xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ /* For the available peripheral interrupt handler names, */ /* please refer to the startup file (startup_stm32g4xx.s). */ /******************************************************************************/ /** * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ } /** * @brief This function handles USART2 global interrupt / USART2 wake-up interrupt through EXTI line 26. */ void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ /* USER CODE END USART2_IRQn 0 */ HAL_UART_IRQHandler(&huart2); /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ } /* USER CODE BEGIN 1 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART2) // L2450 ?? { if (rec_index < sizeof(rec_buf)) { rec_buf[rec_index++] = l2450_rx_data; } else { rec_index = 0; } if (rec_index >= 30) { if (rec_buf[0] == 0xAA && rec_buf[1] == 0xFF && rec_buf[2] == 0x03 && rec_buf[3] == 0x00 && rec_buf[28] == 0x55 && rec_buf[29] == 0xCC) { // ???????? uint16_t x_raw = rec_buf[4] | (rec_buf[5] << 8); uint16_t y_raw = rec_buf[6] | (rec_buf[7] << 8); int16_t x_mm = -(int16_t)x_raw; int16_t y_mm = (int16_t)(y_raw - 0x8000); int16_t r = (int16_t)sqrtf(x_mm * x_mm + y_mm * y_mm); if (r >= 1000 && r <= 5000) { x_distance = x_mm; y_distance = y_mm; // ???? LCD ?? char lcd_buf[32]; float x_m = x_distance / 1000.0f; float y_m = y_distance / 1000.0f; sprintf(lcd_buf, "x:%1.2fm y:%1.2fm", x_m, y_m); LCD_DisplayStringLine(Line4, (uint8_t *)lcd_buf); } rec_index = 0; } else { // ?????,??1??? memmove(rec_buf, rec_buf + 1, rec_index - 1); rec_index--; } } HAL_UART_Receive_IT(&huart2, &l2450_rx_data, 1); } else if (huart->Instance == USART1) // ??1(???????) { UART_ReceiveCallback(rx_data); HAL_UART_Receive_IT(&huart1, &rx_data, 1); } } /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 修改代码,.毫米波模块测量前面1-5m的物体。毫米波模块连接到UART2 ,,检测到的信息实时显示在LCD上

/* 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文件)

//===================================================================== // AD9854 驱动程序设计 //硬件连接: P0 ——Data; // P2 ——Adr; // RESET ——P3^7; // UDCLK ——P3^6; // WR ——P3.5; // RD ——p3.4; // FDATA ——P3^3; // OSK ——P3^2; // VDD--逻辑电源(3.3V) // VSS--GND(0V) //AD9854.c //康威电子工作室 //说明:本程序基于硬件的外接晶振为20MHZ //===================================================================== #include <AD9854.h> //STC单片机头文件 #include "stm32f10x.h" //#include "delay.h" uchar FreqWord[6]; //6个字节频率控制字 //**********************以下为系统时钟以及其相关变量设置************************** /* 此处根据自己的需要设置系统时钟以及与其相关的因子,一次需且只需开启一个 CLK_Set为时钟倍频设置,可设置4~20倍倍频,但最大不能超过300MHZ Freq_mult_ulong和Freq_mult_doulle均为2的48次方除以系统时钟,一个为长整形,一个为双精度型 */ /* #define CLK_Set 4 const ulong Freq_mult_ulong = 3518437; const double Freq_mult_doulle = 3518437.2088832; */ /* #define CLK_Set 5 const ulong Freq_mult_ulong = 2814750; const double Freq_mult_doulle = 2814749.76710656; */ /* #define CLK_Set 6 const ulong Freq_mult_ulong = 2345625; const double Freq_mult_doulle = 2345624.80592213; */ /* #define CLK_Set 7 const ulong Freq_mult_ulong = 2010536; const double Freq_mult_doulle = 2010535.54793326; */ /* #define CLK_Set 8 const ulong Freq_mult_ulong = 1759219; const double Freq_mult_doulle = 1759218.6044416; */ /* #define CLK_Set 9 const ulong Freq_mult_ulong = 1563750; const double Freq_mult_doulle = 1563749.87061476; */ /* #define CLK_Set 10 const ulong Freq_mult_ulong = 1407375; const double Freq_mult_doulle = 1407374.88355328; */ /* #define CLK_Set 11 const ulong Freq_mult_ulong = 1279432; const double Freq_mult_doulle = 1279431.712321164; */ #define CLK_Set 12 const ulong Freq_mult_ulong = 1172812; const double Freq_mult_doulle = 1172812.402961067; /* #define CLK_Set 13 const ulong Freq_mult_ulong = 1082596; const double Freq_mult_doulle = 1082596.064271754; */ /* #define CLK_Set 14 const ulong Freq_mult_ulong = 1005268; const double Freq_mult_doulle = 1005267.773966629; */ /* #define CLK_Set 15 const ulong Freq_mult_ulong = 938250; const double Freq_mult_doulle = 938249.9223688533; */ //**************************修改硬件时要修改的部分******************************** //**************************以下部分为函数定义******************************** static void AD9854_WR_Byte(u32 addr,u32 dat); extern void AD9854_Init(void); static void Freq_convert(long Freq); extern void AD9854_SetSine(ulong Freq,uint Shape); static void Freq_double_convert(double Freq); extern void AD9854_SetSine_double(double Freq,uint Shape); extern void AD9854_InitFSK(void); extern void AD9854_SetFSK(ulong Freq1,ulong Freq2); extern void AD9854_InitBPSK(void); extern void AD9854_SetBPSK(uint Phase1,uint Phase2); extern void AD9854_InitOSK(void); extern void AD9854_SetOSK(uchar RateShape); extern void AD9854_InitAM(void); extern void AD9854_SetAM(uint Shape); extern void AD9854_InitRFSK(void); extern void AD9854_SetRFSK(ulong Freq_Low,ulong Freq_High,ulong Freq_Up_Down,ulong FreRate); void AD9854_IO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure ; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE); //使能PB,PE端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_Init(GPIOB ,&GPIO_InitStructure) ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6| GPIO_Pin_4| GPIO_Pin_5| GPIO_Pin_8| GPIO_Pin_2; GPIO_Init(GPIOA ,&GPIO_InitStructure) ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All^(GPIO_Pin_14| GPIO_Pin_15); GPIO_Init(GPIOC ,&GPIO_InitStructure) ; } //==================================================================================== //函数名称:void AD9854_WR_Byte(uchar addr,uchar dat) //函数功能:AD9854并行口写入数据 //入口参数:addr 6位地址 // dat 写入的数据 //出口参数:无 //==================================================================================== u32 dat1,dat2; void AD9854_WR_Byte(u32 addr,u32 dat) { dat1= dat|(addr<<8); AD9854_AdrBus=(dat1&0x3fff)|((dat1^0x3fff)<<16); // AD9854_AdrBus = ((addr&0x3f)<<8) | ((addr^0x3f)<<(16+8)); // AD9854_DataBus = dat|(dat^0xff)<<16; // dat1 = ((addr&0x3f)<<8) | ((addr^0x3f)<<(16+8)); // dat2 = (dat1&0x3fff)|((dat1^0x3fff)<<16); AD9854_WR = 0; AD9854_WR = 1; } //==================================================================================== //函数名称:void AD9854_Init(void) //函数功能:AD9854初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_Init(void) { AD9854_IO_Init(); AD9854_WR=1;//将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x00); //设置系统为模式0,由外部更新 AD9854_WR_Byte(0x20,0x60); //设置为可调节幅度,取消插值补偿 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void Freq_convert(long Freq) //函数功能:正弦信号频率数据转换 //入口参数:Freq 需要转换的频率,取值从0~SYSCLK/2 //出口参数:无 但是影响全局变量FreqWord[6]的值 //说明: 该算法位多字节相乘算法,有公式FTW = (Desired Output Frequency × 2N)/SYSCLK // 得到该算法,其中N=48,Desired Output Frequency 为所需要的频率,即Freq,SYSCLK // 为可编程的系统时钟,FTW为48Bit的频率控制字,即FreqWord[6] //==================================================================================== void Freq_convert(long Freq) { ulong FreqBuf; ulong Temp=Freq_mult_ulong; uchar Array_Freq[4]; //将输入频率因子分为四个字节 Array_Freq[0]=(uchar)Freq; Array_Freq[1]=(uchar)(Freq>>8); Array_Freq[2]=(uchar)(Freq>>16); Array_Freq[3]=(uchar)(Freq>>24); FreqBuf=Temp*Array_Freq[0]; FreqWord[0]=FreqBuf; FreqBuf>>=8; FreqBuf+=(Temp*Array_Freq[1]); FreqWord[1]=FreqBuf; FreqBuf>>=8; FreqBuf+=(Temp*Array_Freq[2]); FreqWord[2]=FreqBuf; FreqBuf>>=8; FreqBuf+=(Temp*Array_Freq[3]); FreqWord[3]=FreqBuf; FreqBuf>>=8; FreqWord[4]=FreqBuf; FreqWord[5]=FreqBuf>>8; } //==================================================================================== //函数名称:void AD9854_SetSine(ulong Freq,uint Shape) //函数功能:AD9854正弦波产生程序 //入口参数:Freq 频率设置,取值范围为0~(1/2)*SYSCLK // Shape 幅度设置. 为12 Bit,取值范围为(0~4095) ,取值越大,幅度越大 //出口参数:无 //==================================================================================== void AD9854_SetSine(ulong Freq,uint Shape) { uchar count; uchar Adress; Adress = 0x04; //选择频率控制字地址的初值 Freq_convert(Freq); //频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress++,FreqWord[--count]); } AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void Freq_doublt_convert(double Freq) //函数功能:正弦信号频率数据转换 //入口参数:Freq 需要转换的频率,取值从0~SYSCLK/2 //出口参数:无 但是影响全局变量FreqWord[6]的值 //说明: 有公式FTW = (Desired Output Frequency × 2N)/SYSCLK得到该函数, // 其中N=48,Desired Output Frequency 为所需要的频率,即Freq,SYSCLK // 为可编程的系统时钟,FTW为48Bit的频率控制字,即FreqWord[6] //注意: 该函数与上面函数的区别为该函数的入口参数为double,可使信号的频率更精确 // 建议在100HZ以下用本函数,在高于100HZ的情况下用函数void Freq_convert(long Freq) //==================================================================================== void Freq_double_convert(double Freq) { ulong Low32; uint High16; double Temp=Freq_mult_doulle; //23ca99为2的48次方除以120M Freq*=(double)(Temp); // 1 0000 0000 0000 0000 0000 0000 0000 0000 = 4294967295 High16 =(int)(Freq/4294967295); //2^32 = 4294967295 Freq -= (double)High16*4294967295; Low32 = (ulong)Freq; FreqWord[0]=Low32; FreqWord[1]=Low32>>8; FreqWord[2]=Low32>>16; FreqWord[3]=Low32>>24; FreqWord[4]=High16; FreqWord[5]=High16>>8; } //==================================================================================== //函数名称:void AD9854_SetSine_double(double Freq,uint Shape) //函数功能:AD9854正弦波产生程序 //入口参数:Freq 频率设置,取值范围为0~1/2*SYSCLK // Shape 幅度设置. 为12 Bit,取值范围为(0~4095) //出口参数:无 //==================================================================================== void AD9854_SetSine_double(double Freq,uint Shape) { uchar count=0; uchar Adress; Adress=0x04; //选择频率控制字1地址的初值 Freq_double_convert(Freq); //频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress++,FreqWord[--count]); } AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_InitFSK(void) //函数功能:AD9854的FSK初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_InitFSK(void) { AD9854_WR=1; //将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x02); //设置系统为模式1,由外部更新 AD9854_WR_Byte(0x20,0x60); //设置为可调节幅度,取消插值补偿 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_SetFSK(ulong Freq1,ulong Freq2) //函数功能:AD9854的FSK设置 //入口参数:Freq1 FSK频率1 // Freq2 FSK频率2 //出口参数:无 //==================================================================================== void AD9854_SetFSK(ulong Freq1,ulong Freq2) { uchar count=6; uchar Adress1,Adress2; const uint Shape=4000; //幅度设置. 为12 Bit,取值范围为(0~4095) Adress1=0x04; //选择频率控制字1地址的初值 Adress2=0x0a; //选择频率控制字2地址的初值 Freq_convert(Freq1); //频率转换1 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress1++,FreqWord[--count]); } Freq_convert(Freq2); //频率转换2 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress2++,FreqWord[--count]); } AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_InitBPSK(void) //函数功能:AD9854的BPSK初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_InitBPSK(void) { AD9854_WR=1; //将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x08); //设置系统为模式4,由外部更新 AD9854_WR_Byte(0x20,0x60); //设置为可调节幅度,取消插值补偿 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_SetBPSK(uint Phase1,uint Phase2) //函数功能:AD9854的BPSK设置 //入口参数:Phase1 调制相位1 // Phase2 调制相位2 //出口参数:无 //说明: 相位为14Bit,取值从0~16383,建议在用本函数的时候将Phase1设置为0, // 将Phase1设置为8192,180°相位 //==================================================================================== void AD9854_SetBPSK(uint Phase1,uint Phase2) { uchar count; const ulong Freq=60000; const uint Shape=4000; uchar Adress; Adress=0x04; //选择频率控制字1地址的初值 AD9854_WR_Byte(0x00,Phase1>>8); //设置相位1 AD9854_WR_Byte(0x01,(uchar)(Phase1&0xff)); AD9854_WR_Byte(0x02,Phase2>>8); //设置相位2 AD9854_WR_Byte(0x03,(uchar)(Phase2&0xff)); Freq_convert(Freq); //频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress++,FreqWord[--count]); } AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_InitOSK(void) //函数功能:AD9854的OSK初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_InitOSK(void) { AD9854_WR=1; //将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x00); //设置系统为模式0,由外部更新 AD9854_WR_Byte(0x20,0x70); //设置为可调节幅度,取消插值补偿,通断整形内部控制 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_SetOSK(uchar RateShape) //函数功能:AD9854的OSK设置 //入口参数: RateShape OSK斜率,取值为4~255,小于4则无效 //出口参数:无 //==================================================================================== void AD9854_SetOSK(uchar RateShape) { uchar count; const ulong Freq=60000; //设置载频 const uint Shape=4000; //幅度设置. 为12 Bit,取值范围为(0~4095) uchar Adress; Adress=0x04; //选择频率控制字地址的初值 Freq_convert(Freq); //频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress++,FreqWord[--count]); } AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x25,RateShape); //设置OSK斜率 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_InitAM(void) //函数功能:AD9854的AM初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_InitAM(void) { uchar count; const ulong Freq=60000; //设置载频 uchar Adress; Adress=0x04; //选择频率控制字地址的初值 AD9854_WR=1; //将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x00); //设置系统为模式0,由外部更新 AD9854_WR_Byte(0x20,0x60); //设置为可调节幅度,取消插值补偿 Freq_convert(Freq); //频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress++,FreqWord[--count]); } AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_SetAM(uchar Shape) //函数功能:AD9854的AM设置 //入口参数:Shape 12Bit幅度,取值从0~4095 //出口参数:无 //==================================================================================== void AD9854_SetAM(uint Shape) { AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_InitRFSK(void) //函数功能:AD9854的RFSK初始化 //入口参数:无 //出口参数:无 //==================================================================================== void AD9854_InitRFSK(void) { AD9854_WR=1; //将读、写控制端口设为无效 AD9854_RD=1; AD9854_UDCLK=0; AD9854_RST=1; //复位AD9854 AD9854_RST=0; AD9854_WR_Byte(0x1d,0x00); //关闭比较器 AD9854_WR_Byte(0x1e,CLK_Set); //设置系统时钟倍频 AD9854_WR_Byte(0x1f,0x24); //设置系统为模式2,由外部更新,使能三角波扫频功能 AD9854_WR_Byte(0x20,0x60); //设置为可调节幅度,取消插值补偿 AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //==================================================================================== //函数名称:void AD9854_SetRFSK(void) //函数功能:AD9854的RFSK设置 //入口参数:Freq_Low RFSK低频率 48Bit // Freq_High RFSK高频率 48Bit // Freq_Up_Down 步进频率 48Bit // FreRate 斜率时钟控制 20Bit //出口参数:无 //注: 每两个脉冲之间的时间周期用下式表示(FreRate +1)*(System Clock ),一个脉冲, // 频率 上升或者下降 一个步进频率 //==================================================================================== void AD9854_SetRFSK(ulong Freq_Low,ulong Freq_High,ulong Freq_Up_Down,ulong FreRate) { uchar count=6; uchar Adress1,Adress2,Adress3; const uint Shape=4000; //幅度设置. 为12 Bit,取值范围为(0~4095) Adress1=0x04; //选择频率控制字地址的初值 Adress2=0x0a; Adress3=0x10; Freq_convert(Freq_Low); //频率1转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress1++,FreqWord[--count]); } Freq_convert(Freq_High); //频率2转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress2++,FreqWord[--count]); } Freq_convert(Freq_Up_Down); //步进频率转换 for(count=6;count>0;) //写入6字节的频率控制字 { AD9854_WR_Byte(Adress3++,FreqWord[--count]); } AD9854_WR_Byte(0x1a,(uchar)((FreRate>>16)&0x0f)); //设置斜升速率 AD9854_WR_Byte(0x1b,(uchar)(FreRate>>8)); AD9854_WR_Byte(0x1c,(uchar)FreRate); AD9854_WR_Byte(0x21,Shape>>8); //设置I通道幅度 AD9854_WR_Byte(0x22,(uchar)(Shape&0xff)); AD9854_WR_Byte(0x23,Shape>>8); //设置Q通道幅度 AD9854_WR_Byte(0x24,(uchar)(Shape&0xff)); AD9854_UDCLK=1; //更新AD9854输出 AD9854_UDCLK=0; } //测试正弦波,采用120MHZ SYSCLK时,出来10MHZ波形,波形很好,测试成功 //当采用300MHZ SYSCLK时,测试50MHZ波形时,DDS发热厉害,且波形衰减严重,幅度在35mV左右 // //int main() //{ // AD9854_Init(); // AD9854_SetSine(80000000,4095); // while(1); //} //测试正弦波,采用120MHZ SYSCLK时,出来87.697HZ波形,波形很好,测试成功 // //int main() //{ // AD9854_Init(); // AD9854_SetSine_double(87.697,4000); // while(1); //} //测试FSK,采用120MHZ SYSCLK,1K和6K,测试成功,结果对应"FSK波形.bmp" //int main() //{ // AD9854_InitFSK(); // AD9854_SetFSK(1000,6000); // while(1) // { // AD9854_FDATA = 1; // delay_us(30000); //延时时间长,便于观察 // AD9854_FDATA = 0; // delay_us(30000); // } //} //测试BPSK,采用120MHZ SYSCLK,测试成功 //int main() //{ // AD9854_InitBPSK(); // AD9854_SetBPSK(0,8192); // while(1) // { // AD9854_FDATA = 1; // delay_us(10); // AD9854_FDATA = 0; // delay_us(10); // } //} //测试OSK,采用120MHZ SYSCLK,测试成功 //int main() //{ // AD9854_InitOSK(); // AD9854_SetOSK(10); // while(1) // { // AD9854_OSK=1; // delay_us(30); // AD9854_OSK=0; // delay_us(30); // } //} //测试AM,采用120MHZ SYSCLK,测试成功 //int main() //{ // AD9854_InitAM(); // while(1) // { // AD9854_SetAM(2000); // delay_us(10); // AD9854_SetAM(4000); // delay_us(10); // } //} // //测试RFSK,采用120MHZ SYSCLK,测试成功 //int main() //{ // AD9854_InitRFSK(); // AD9854_SetRFSK(1000,60000,100,30); // while(1) // { // AD9854_FDATA = 1; // delay_us(30000); //延时时间长,便于观察 // AD9854_FDATA = 0; // delay_us(30000); // } //} 这串代码里有晶振吗,如果有是多少

最新推荐

recommend-type

Java反射实现实体类相同字段自动赋值示例

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 Java 反射能在运行时探查类结构并动态读写属性。示例工具类 ClassReflection 提供两种静态方法:简易版 reflectionAttr 直接以两个对象入参;复杂版额外用 Class.forName 按名字加载类。 流程: 分别对两个对象调用 getDeclaredFields(),得到包含私有属性的 Field[]。 遍历源对象字段,跳过名为 "id" 的主键;设 setAccessible(true) 解锁私有权限。 用 Field.get() 取值,若目标对象存在同名字段,同样解锁后执行 Field.set() 完成拷贝。 复杂版增加 invokeGetMethod,通过反射调用 getter 取非基本类型值,避免直接 get() 的局限。 适用:ORM 框架在查询结果与实体间同步数据、单元测试为私有字段注入状态等。 注意:反射带来性能损耗与封装破坏,需捕获 IllegalAccessException、NullPointerException,非必要场景应优先用常规赋值。
recommend-type

飞思OA数据库文件下载指南

根据给定的文件信息,我们可以推断出以下知识点: 首先,从标题“飞思OA源代码[数据库文件]”可以看出,这里涉及的是一个名为“飞思OA”的办公自动化(Office Automation,简称OA)系统的源代码,并且特别提到了数据库文件。OA系统是用于企事业单位内部办公流程自动化的软件系统,它旨在提高工作效率、减少不必要的工作重复,以及增强信息交流与共享。 对于“飞思OA源代码”,这部分信息指出我们正在讨论的是OA系统的源代码部分,这通常意味着软件开发者或维护者拥有访问和修改软件底层代码的权限。源代码对于开发人员来说非常重要,因为它是软件功能实现的直接体现,而数据库文件则是其中的一个关键组成部分,用来存储和管理用户数据、业务数据等信息。 从描述“飞思OA源代码[数据库文件],以上代码没有数据库文件,请从这里下”可以分析出以下信息:虽然文件列表中提到了“DB”,但实际在当前上下文中,并没有提供包含完整数据库文件的下载链接或直接说明,这意味着如果用户需要获取完整的飞思OA系统的数据库文件,可能需要通过其他途径或者联系提供者获取。 文件的标签为“飞思OA源代码[数据库文件]”,这与标题保持一致,表明这是一个与飞思OA系统源代码相关的标签,而附加的“[数据库文件]”特别强调了数据库内容的重要性。在软件开发中,标签常用于帮助分类和检索信息,所以这个标签在这里是为了解释文件内容的属性和类型。 文件名称列表中的“DB”很可能指向的是数据库文件。在一般情况下,数据库文件的扩展名可能包括“.db”、“.sql”、“.mdb”、“.dbf”等,具体要看数据库的类型和使用的数据库管理系统(如MySQL、SQLite、Access等)。如果“DB”是指数据库文件,那么它很可能是以某种形式的压缩文件或包存在,这从“压缩包子文件的文件名称列表”可以推测。 针对这些知识点,以下是一些详细的解释和补充: 1. 办公自动化(OA)系统的构成: - OA系统由多个模块组成,比如工作流管理、文档管理、会议管理、邮件系统、报表系统等。 - 系统内部的流程自动化能够实现任务的自动分配、状态跟踪、结果反馈等。 - 通常,OA系统会提供用户界面来与用户交互,如网页形式的管理界面。 2. 数据库文件的作用: - 数据库文件用于存储数据,是实现业务逻辑和数据管理的基础设施。 - 数据库通常具有数据的CRUD(创建、读取、更新、删除)功能,是信息检索和管理的核心组件。 - 数据库文件的结构和设计直接关系到系统的性能和可扩展性。 3. 数据库文件类型: - 根据数据库管理系统不同,数据库文件可以有不同格式。 - 例如,MySQL数据库的文件通常是“.frm”文件存储表结构,“.MYD”存储数据,“.MYI”存储索引。 - 对于SQLite,数据库就是一个单独的“.sqlite”文件。 4. 数据库设计和管理: - 数据库设计需要遵循一定的规范和最佳实践,如范式化以减少数据冗余。 - 管理数据库包括数据备份、恢复、性能调优、安全性管理等。 5. OA系统开发及源代码维护: - 开发一个OA系统涉及需求分析、系统设计、编码实现、测试、部署和维护等多个阶段。 - OA系统源代码的维护工作包括代码审查、重构、版本控制和更新等。 综上所述,我们可以知道“飞思OA源代码[数据库文件]”所提供的信息包括了对飞思OA系统及其数据库文件的基础介绍和可能的获取途径。对于开发者而言,需要了解如何管理和操作这些数据库文件以确保系统的正常运行和数据的完整性。此外,对于那些希望进行系统定制或二次开发的用户,源代码的可访问性是非常重要的,这可以允许用户根据自己的需求来修改和增强系统功能。
recommend-type

Qt信号与槽优化:提升系统性能与响应速度的实战技巧

# 摘要 本文系统地探讨了Qt框架中信号与槽机制的原理、高级特性、性能优化以及在大型项目中的应用。首先,概述了信号与槽的基本概念和工作原理,包括信号的发射、槽函数的绑定与调用过程。随后,本文深入分析了信号与槽的内部机制,如数据类型兼容性和连接类型,并探讨了优化信
recommend-type

D8流向算法

<think>我们被要求解释或实现D8流向算法。D8流向算法是一种用于水文分析的数字高程模型(DEM)处理方法,用于确定地表水流的方向。每个像元的水流方向被指定为指向周围8个相邻像元中坡度最陡的那个方向。 ### 算法原理 在D8算法中,每个像元的水流方向被定义为指向其8个相邻像元(包括对角线方向)中坡度最大的方向。坡度由高程差除以距离计算,其中相邻像元的距离为1(水平和垂直方向)或√2(对角线方向)。具体步骤如下: 1. 对于中心像元,计算其与8个相邻像元的高程差(中心像元高程减去相邻像元高程,得到正值表示下坡)。 2. 计算每个相邻方向的坡度:坡度 = 高程差 / 距离(水平/垂直方向
recommend-type

精选36个精美ICO图标免费打包下载

在当今的软件开发和应用程序设计中,图标作为图形用户界面(GUI)的一个重要组成部分,承担着向用户传达信息、增加美观性和提高用户体验的重要角色。图标不仅仅是一个应用程序或文件的象征,它还是品牌形象在数字世界中的延伸。因此,开发人员和设计师往往会对默认生成的图标感到不满意,从而寻找更加精美和个性化的图标资源。 【标题】中提到的“精美ICO图标打包下载”,指向用户提供的是一组精选的图标文件,这些文件格式为ICO。ICO文件是一种图标文件格式,主要被用于Windows操作系统中的各种文件和应用程序的图标。由于Windows系统的普及,ICO格式的图标在软件开发中有着广泛的应用。 【描述】中提到的“VB、VC编写应用的自带图标很难看,换这些试试”,提示我们这个ICO图标包是专门为使用Visual Basic(VB)和Visual C++(VC)编写的应用程序准备的。VB和VC是Microsoft公司推出的两款编程语言,其中VB是一种主要面向初学者的面向对象编程语言,而VC则是更加专业化的C++开发环境。在这些开发环境中,用户可以选择自定义应用程序的图标,以提升应用的视觉效果和用户体验。 【标签】中的“.ico 图标”直接告诉我们,这些打包的图标是ICO格式的。在设计ICO图标时,需要注意其独特的尺寸要求,因为ICO格式支持多种尺寸的图标,例如16x16、32x32、48x48、64x64、128x128等像素尺寸,甚至可以包含高DPI版本以适应不同显示需求。此外,ICO文件通常包含多种颜色深度的图标,以便在不同的背景下提供最佳的显示效果。 【压缩包子文件的文件名称列表】显示了这些精美ICO图标的数量,即“精美ICO图标36个打包”。这意味着该压缩包内包含36个不同的ICO图标资源。对于软件开发者和设计师来说,这意味着他们可以从这36个图标中挑选适合其应用程序或项目的图标,以替代默认的、可能看起来不太吸引人的图标。 在实际应用中,将这些图标应用到VB或VC编写的程序中,通常需要编辑程序的资源文件或使用相应的开发环境提供的工具进行图标更换。例如,在VB中,可以通过资源编辑器选择并替换程序的图标;而在VC中,则可能需要通过设置项目属性来更改图标。由于Windows系统支持在编译应用程序时将图标嵌入到可执行文件(EXE)中,因此一旦图标更换完成并重新编译程序,新图标就会在程序运行时显示出来。 此外,当谈及图标资源时,还应当了解图标制作的基本原则和技巧,例如:图标设计应简洁明了,以传达清晰的信息;色彩运用需考虑色彩搭配的美观性和辨识度;图标风格要与应用程序的整体设计风格保持一致,等等。这些原则和技巧在选择和设计图标时都非常重要。 总结来说,【标题】、【描述】、【标签】和【压缩包子文件的文件名称列表】共同勾勒出了一个为VB和VC编程语言用户准备的ICO图标资源包。开发者通过下载和使用这些图标,能够有效地提升应用程序的外观和用户体验。在这一过程中,了解和应用图标设计与应用的基本知识至关重要。
recommend-type

【Qt数据库融合指南】:MySQL与Qt无缝集成的技巧

# 摘要 本文全面探讨了Qt数据库集成的基础知识与进阶应用,从Qt与MySQL的基础操作讲起,深入到Qt数据库编程接口的配置与使用,并详细介绍了数据模型和视图的实现。随着章节的深入,内容逐渐从基础的数据操作界面构建过渡到高级数据库操作实践,涵盖了性能优化、安全性策略和事务管理。本文还特别针对移动设备上的数据库集成进行了讨
recommend-type

Looking in links: https://shi-labs.com/natten/wheels/ WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='shi-labs.com', port=443): Read timed out. (read timeout=15)")': /natten/wheels/ WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='shi-labs.com', port=443): Read timed out. (read timeout=15)")': /natten/wheels/ WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='shi-labs.com', port=443): Read timed out. (read timeout=15)")': /natten/wheels/ WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='shi-labs.com', port=443): Read timed out. (read timeout=15)")': /natten/wheels/ WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ReadTimeoutError("HTTPSConnectionPool(host='shi-labs.com', port=443): Read timed out. (read timeout=15)")': /natten/wheels/ ERROR: Ignored the following yanked versions: 0.14.1 ERROR: Could not find a version that satisfies the requirement natten==0.17.4+torch250cu121 (from versions: 0.14.2.post4, 0.14.4, 0.14.5, 0.14.6, 0.15.0, 0.15.1, 0.17.0, 0.17.1, 0.17.3, 0.17.4, 0.17.5, 0.20.0, 0.20.1) ERROR: No matching distribution found for natten==0.17.4+torch250cu121

<think>我们正在解决用户安装特定版本的natten包(0.17.4+torch250cu121)时遇到的ReadTimeoutError和版本未找到错误。 根据经验,这两个错误通常与网络问题和版本匹配问题有关。 步骤1: 分析问题 - ReadTimeoutError: 通常是由于网络连接不稳定或PyPI服务器响应慢导致下载超时。 - Version not found: 可能的原因包括: a) 指定的版本号在PyPI上不存在。 b) 指定的版本号与当前环境的Python版本或CUDA版本不兼容。 步骤2: 验证版本是否存在 我们可以通过访问PyP
recommend-type

精选教程分享:数据库系统基础学习资料

《世界著名计算机教材精选 数据库系统基础教程》这一标题揭示了该教材主要讨论的是数据库系统的基础知识。教材作为教学的重要工具,其内容往往涵盖某一领域的基本概念、原理、设计方法以及实现技术等。而该书被冠以“世界著名计算机教材精选”的标签,表明其可能源自世界范围内公认的、具有权威性的数据库系统教材,经过筛选汇编而成。 首先,从数据库系统的基础知识讲起,数据库系统的概念是在20世纪60年代随着计算机技术的发展而诞生的。数据库系统是一个集成化的数据集合,这些数据是由用户共享,且被组织成特定的数据模型以便进行高效的数据检索和管理。在数据库系统中,核心的概念包括数据模型、数据库设计、数据库查询语言、事务管理、并发控制和数据库系统的安全性等。 1. 数据模型:这是描述数据、数据关系、数据语义以及数据约束的概念工具,主要分为层次模型、网状模型、关系模型和面向对象模型等。其中,关系模型因其实现简单、易于理解和使用,已成为当前主流的数据模型。 2. 数据库设计:这是构建高效且能够满足用户需求的数据库系统的关键步骤,它包含需求分析、概念设计、逻辑设计和物理设计等阶段。设计过程中需考虑数据的完整性、一致性、冗余控制等问题,常用的工具有ER模型(实体-关系模型)和UML(统一建模语言)。 3. 数据库查询语言:SQL(Structured Query Language)作为标准的关系型数据库查询语言,在数据库系统中扮演着至关重要的角色。它允许用户对数据库进行查询、更新、插入和删除操作。SQL语言的熟练掌握是数据库系统学习者必须具备的能力。 4. 事务管理:在数据库系统中,事务是一系列的操作序列,必须作为一个整体执行,要么全部完成,要么全部不执行。事务管理涉及到数据库的可靠性、并发控制和恢复等关键功能,保证了数据的原子性、一致性、隔离性和持久性(ACID属性)。 5. 并发控制:由于多个用户可能同时对数据库进行操作,因此必须采取一定的并发控制机制以防止数据的不一致性,常用的技术包括封锁、时间戳、乐观控制等。 6. 数据库系统的安全性:安全性是保护数据库免受未授权访问和恶意攻击的措施,它包括身份验证、授权和审计等。 “数据库”这一标签说明了该教材专注于数据库领域,这个领域不仅限于理论知识,还包括了数据库的实际应用和解决方案的实现。教材内容可能涵盖数据库管理系统的使用和配置、数据库应用开发、数据库的维护和优化等。 教材的中文版形式表明它是为了方便中文读者而翻译或编写的,这使得中文世界的读者能够更加方便地学习和研究数据库系统的基础知识。同时,分享这一教材的行为,体现了知识传播的重要性以及人们对于知识共享的积极态度。 从给出的压缩包子文件的文件名称列表来看,“_世界著名计算机教材精选 数据库系统基础教程”显示了该压缩包中包含的文件内容。对于学习者来说,能够通过这样的压缩包文件获取到权威的数据库系统学习材料,无疑是一种宝贵的学习资源。
recommend-type

Qt架构揭秘:模块化设计与系统扩展性的最佳实践

# 摘要 本文全面探讨了Qt框架的应用开发,涵盖了其架构基础、模块化设计理论与实践、系统扩展性理论与实践、以及高级应用开发技巧。通过对Qt模块化设计和系统扩展机制的深入解析,本文展示了如何构建模块化和高扩展性的Qt应用,并通过案例分析的方式,呈现了这些理论在实际项目中的应用。此外,还讨论了Qt在跨平台开发中的应用、性能优化和高级GUI设计。最后,文章展望了Qt架构优化的未来趋势和新技术的融入,为Qt框架的开发者提供了理论支持和实践经验。 # 关键字
recommend-type

docker镜像加使

<think>嗯,用户询问如何修改或扩展Docker镜像的功能。根据系统指令,需要确保所有数学公式正确使用$...$或$$...$$格式,但这个问题主要涉及Docker技术,可能不太需要数学表达式。不过还是保持警惕,万一有版本号之类的数字处理呢。 用户提到"参考站内引用"部分有关于docker commit的信息,这提示修改镜像的核心方法之一就是通过容器提交。但用户深层需求应该是想了解系统化的镜像定制方法,不仅仅是单条命令。 考虑到Docker镜像修改的常见场景,需要涵盖几种主流方法:基于容器提交的方式确实是最直接的,适合快速修改;但更规范的应该是使用Dockerfile构建,这样能确保可