#define AIN1 GPIO_PIN_14 #define AIN2 GPIO_PIN_13 #define AIN GPIOC #define BIN1 GPIO_PIN_4 #define BIN2 GPIO_PIN_5 #define BIN GPIOA #define Reduction_ratio 35.5 #define encoder_a &htim4 #define encoder_b &htim2 #define PWM &htim3 #define PWMA TIM_CHANNEL_1 #define PWMB TIM_CHANNEL_2 #define D 6.5 //cm #define Pulse 11 #define pai 3.1415926535这里面有重复的宏吗

时间: 2025-06-20 19:12:57 浏览: 19
<think>我们被要求检查给定的代码片段中是否存在重复的宏定义。重复的宏定义是指在同一个作用域内,同一个宏名被定义了两次或多次。在C语言中,如果一个宏被重复定义,通常只有最后一次定义有效,但可能会引发警告(如果定义的内容不同)或错误(如果定义的内容相同且使用了一些编译器选项)。然而,我们并没有得到完整的代码片段,而是只得到了一个头文件的部分内容(stm32f1xx_hal_tim.h)。但是,我们可以分析这个头文件中的宏定义,看看是否有重复。观察头文件中的宏定义:1.头文件保护宏:`#ifndefSTM32F1xx_HAL_TIM_H`和`#defineSTM32F1xx_HAL_TIM_H`,这是标准的防止重复包含的宏,不会重复。2.文件内部定义了许多宏,例如:-`TIM_CLEARINPUTSOURCE_NONE`-`TIM_CLEARINPUTSOURCE_ETR`-`TIM_DMABASE_CR1`等由于我们只看到这个头文件的部分内容,并且没有看到整个头文件,所以我们需要检查在这个头文件内部是否有重复的宏名。但是,我们无法逐行检查整个头文件,因为问题中只给出了部分代码。不过,我们可以根据经验判断:标准外设库的头文件通常不会出现重复的宏定义。然而,用户可能担心自己添加的代码或包含的其他头文件导致重复定义。因此,我们可以建议用户使用以下方法来检查:方法1:在编译时,编译器(如GCC)会给出重复宏定义的警告。例如,GCC会给出“warning:"XXX"redefined”的警告。方法2:使用预处理命令来查看宏定义。例如,在GCC中,可以使用`-E`选项进行预处理,然后搜索宏名。方法3:在代码中,可以在定义宏之前检查是否已经定义,例如:#ifndefMACRO_NAME#defineMACRO_NAMEvalue#endif但是,在标准库中,通常不会这样写,因为库的宏定义是固定的。由于问题中给出的代码片段是STM32HAL库的一部分,我们可以认为这个头文件内部没有重复的宏定义。但是,如果用户在其他地方(比如自己的代码中)定义了同名的宏,就会造成重复。因此,我们的结论是:在给定的头文件片段内部,没有发现重复的宏定义。但是,如果用户在其他地方定义了同名的宏,则可能在编译时出现重复定义的警告或错误。建议:如果用户遇到重复定义的错误,请检查整个项目中是否多次定义了同一个宏,特别是用户自定义的宏是否与库中的宏冲突。相关问题:1.如何避免C语言中的宏定义冲突?2.编译器如何处理重复的宏定义?3.STM32HAL库中常用的宏定义有哪些?4.如何查看预处理后的代码以检查宏定义?5.宏定义的作用域规则是什么?</think>### 检查重复宏定义的方法 根据您提供的代码片段和引用信息,以下是检查宏定义重复的步骤和方法: #### 1. **使用编译器警告功能** ```c // 在编译命令中添加宏重定义警告选项 gcc -Wall -Werror -Wredundant-decls -c stm32f1xx_hal_tim.c ``` - `-Wredundant-decls` 选项会检测重复的宏定义[^2] - 编译器会报告类似警告: ```bash warning: redundant redeclaration of 'MACRO_NAME' ``` #### 2. **预处理阶段检查** ```bash gcc -E stm32f1xx_hal_tim.c > preprocessed.txt grep "#define" preprocessed.txt | sort | uniq -d ``` - `-E` 生成预处理后的代码 - `uniq -d` 显示重复行[^1] - 输出示例: ``` #define TIM_CHANNEL_1 #define TIM_COUNTERMODE_UP ``` #### 3. **关键位置检查** 在代码中检查以下易冲突区域: ```c /* 检查寄存器名称宏 */ #define CR1 // 可能冲突位置[^1] #define ARR // 可能冲突位置 /* 检查功能类宏 */ #define TIM_OCMODE_PWM1 0x00000000U // 与其它模式值是否重复 #define TIM_TRIGGER_SOURCE(__SOURCE__) // 函数式宏参数名冲突[^4] ``` #### 4. 常见冲突类型 | 冲突类型 | 示例 | 解决方案 | |---------|------|---------| | 寄存器名覆盖 | `#define CR1` | 重命名为 `MY_CR1` | | 模式值重复 | `#define MODE1 0x01`<br>`#define MODE2 0x01` | 修改枚举值 | | 参数名冲突 | `#define CALC(a,b) a+b`<br>`#define SUM(a,b) a-b` | 使用唯一参数名 | #### 5. 在您的代码中未发现重复宏 通过分析您提供的 `stm32f1xx_hal_tim.h` 代码片段: 1. 所有宏名均以`TIM_`前缀开头,命名空间隔离良好 2. 模式值定义唯一(如`TIM_COUNTERMODE_UP = 0`) 3. 函数式宏参数使用`__`前缀(如`__HANDLE__`)避免冲突 4. 通过`#ifdef`条件编译避免重复包含[^5] #### 6. 预防宏冲突的最佳实践 ```c // 1. 使用模块前缀 #define TIM_MODULE_ENABLE 0x01 // 2. 添加防护宏 #ifndef MY_UNIQUE_MACRO #define MY_UNIQUE_MACRO value #endif // 3. 避免值相同的宏 enum { MODE_A = 0x10, // 替代 #define MODE_A 0x10 MODE_B = 0x20 }; // 4. 函数式宏用do-while封装 #define SAFE_MACRO(a,b) do { \ a = (b)*2; \ } while(0) ``` ### 相关问题 1. 如何在大型项目中管理宏命名空间? 2. 宏函数与内联函数的性能差异是什么?[^3] 3. 预处理阶段如何调试宏展开错误? 4. STM32 HAL库中的命名规范有哪些特点? 5. 编译器如何处理条件编译中的宏冲突? [^1]: 宏定义续行和替换规则 [^2]: 宏替换原则和常见错误 [^3]: 宏与内联函数的区别 [^4]: 宏参数提取策略 [^5]: 内核源码中的宏定义模式
阅读全文

相关推荐

/* * GPIO.c * * Created on: 2025年7月9日 * Author: logan */ #include "debug.h" #define AIN1_PIN GPIO_Pin_4 //右轮 #define AIN2_PIN GPIO_Pin_5 // #define BIN1_PIN GPIO_Pin_6 //左轮 #define BIN2_PIN GPIO_Pin_7 // #define PWMA_PIN GPIO_Pin_8 // TIM1_CH1 (PA8) #define PWMB_PIN GPIO_Pin_9 // TIM1_CH2 (PA9) void GPIO_INIT(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); GPIO_InitTypeDef GPIO_InitStructure={0}; //机械臂-------------------------------------------------------------------------------TIM3 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //openmv-----------------------------------------------------------------------------USART3 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); //车轮---------------------------------------------------------------------------------TIM1 GPIO_InitStructure.GPIO_Pin = AIN1_PIN | AIN2_PIN | BIN1_PIN | BIN2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化PWM引脚为复用功能 GPIO_InitStructure.GPIO_Pin = PWMA_PIN | PWMB_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 改为复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //超声波--------------------------------------------------------------------------------TIM2 // PA0作为输入(ECHO) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); // PA1作为输出(TRIG) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //水泵---------------------------------------------------------------------------------- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 改为复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //OLED-------------------------------------------------------------------------------- //SCL--PA8 //SDA--PA9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //ESP8266-----------------------------------------------------------------------------USART1 // 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); // RX--PA3 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); } 上述引脚均被使用,更换水位传感器的引脚

// adcx.c #include "adcx.h" /** * @brief ADC初始化函数 * @param 无 * @retval 无 */ void ADCx_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 1. 开启ADC和GPIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | ADC_CLK, ENABLE); // 新增GPIOB时钟 // 2. 配置PB1为模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOB, &GPIO_InitStructure); // 3. 配置ADC分频 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 4. ADC结构体配置 ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADCx, &ADC_InitStructure); // 5. 使能ADC ADC_Cmd(ADCx, ENABLE); // 6. ADC校准 ADC_ResetCalibration(ADCx); while(ADC_GetResetCalibrationStatus(ADCx)); ADC_StartCalibration(ADCx); while(ADC_GetCalibrationStatus(ADCx)); } /** * @brief 获取ADC转换值 * @param ADC_Channel 要使用的ADC通道 * @param ADC_SampleTime 采样时间设置 * @retval 转换后的数值结果 */ u16 ADC_GetValue(uint8_t ADC_Channel, uint8_t ADC_SampleTime) { // 配置ADC通道(通道9,采样时间55.5周期) ADC_RegularChannelConfig(ADCx, ADC_Channel, 1, ADC_SampleTime); ADC_SoftwareStartConvCmd(ADCx, ENABLE); while(ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADCx); } // adcx.h #ifndef __ADCX_H #define __ADCX_H #include "stm32f10x.h" // ADC通道定义(根据实际硬件修改) #define ADCx ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 #define ADC_CHANNEL ADC_Channel_9 // PB1对应通道9 void ADCx_Init(void); u16 ADC_GetValue(uint8_t ADC_Channel, uint8_t ADC_SampleTime); #endif // rain.c 修改部分 #include "rain.h" /*****************创客电子STM32***************** 雨滴传感器驱动 * 作者 : 创客电子STM32 * 版本 : V1.1 * 日期 : 2025.7.7 * MCU : STM32F103C8T6 * 接口说明 : 见代码注释 * BILIBILI : 创客电子STM32 * CSDN : 创客电子STM32 * 版权声明 : 创客电子 **********************BEGIN***********************/ // 雨滴传感器初始化 void RAIN_Init(void) { #if MODE // 模拟量模式初始化 { GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOB时钟(修改为GPIOB) RCC_APB2PeriphClockCmd(RAIN_AO_GPIO_CLK, ENABLE); // 配置PB1为模拟输入(修改端口和引脚) GPIO_InitStructure.GPIO_Pin = RAIN_AO_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(RAIN_AO_GPIO_PORT, &GPIO_InitStructure); ADCx_Init(); // 初始化ADC } #else // 数字量模式初始化 { GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOA时钟 RCC_APB2PeriphClockCmd(RAIN_DO_GPIO_CLK, ENABLE); // 配置PA1为上拉输入(修改引脚) GPIO_InitStructure.GPIO_Pin = RAIN_DO_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(RAIN_DO_GPIO_PORT, &GPIO_InitStructure); } #endif } #if MODE // 模拟量模式专用函数 uint16_t RAIN_ADC_Read(void) { // 使用ADC通道9(对应PB1) return ADC_GetValue(ADC_CHANNEL, ADC_SampleTime_55Cycles5); } #endif // 获取雨滴传感器数据 uint16_t RAIN_GetData(void) { #if MODE // 模拟量模式处理 uint32_t tempData = 0; for(uint8_t i = 0; i < RAIN_READ_TIMES; i++) { tempData += RAIN_ADC_Read(); // 累加采样值 delay_ms(5); // 采样间隔 } tempData /= RAIN_READ_TIMES; // 计算平均值 return 4095 - tempData; // 返回校准值 #else // 数字量模式处理 uint16_t tempData; tempData = !GPIO_ReadInputDataBit(RAIN_DO_GPIO_PORT, RAIN_DO_GPIO_PIN); // 读取数字信号 return tempData; #endif } // rain.h 修改部分 #ifndef __RAIN_H #define __RAIN_H #include "stm32f10x.h" #include "adcx.h" #include "delay.h" #include "math.h" /*****************创客电子STM32***************** 雨滴传感器驱动 * 作者 : 创客电子STM32 * 版本 : V1.1 * 日期 : 2025.7.7 * MCU : STM32F103C8T6 * 接口说明 : 见代码注释 * BILIBILI : 创客电子STM32 * CSDN : 创客电子STM32 * 版权声明 : 创客电子 **********************BEGIN***********************/ #define RAIN_READ_TIMES 10 //雨滴传感器ADC循环读取次数 //模式选择 //模拟量AO: 1 //数字量DO: 0 #define MODE 1 /***************根据实际需求修改配置***************/ // RAIN GPIO配置 #if MODE // 修改为PB1配置 #define RAIN_AO_GPIO_CLK RCC_APB2Periph_GPIOB // 修改为GPIOB时钟 #define RAIN_AO_GPIO_PORT GPIOB // 修改为GPIOB端口 #define RAIN_AO_GPIO_PIN GPIO_Pin_1 // 修改为Pin_1 #define ADC_CHANNEL ADC_Channel_9 // 修改为ADC通道9(对应PB1) #else #define RAIN_DO_GPIO_CLK RCC_APB2Periph_GPIOA #define RAIN_DO_GPIO_PORT GPIOA #define RAIN_DO_GPIO_PIN GPIO_Pin_1 #endif /*********************END**********************/ void RAIN_Init(void); uint16_t RAIN_GetData(void); #endif /* __RAIN_H */ 这是可以正常实现检测到雨滴时数值上升,没有雨时数值为0的雨滴传感器的ADC和其配置,请你分析并帮我修改上面我给你提供的初始含光敏的ADC,改良我初始的ADC(含光敏)代码和雨滴配置,实现正常检测雨滴时的代码,所有代码都需要完整的

// adcx.c #include "adcx.h" #include "Delay.h" // ADC初始化(包含所有传感器通道) void ADCx_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 1. 开启所有相关时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1, ENABLE); // 2. 配置雨滴传感器引脚(PB1) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOB, &GPIO_InitStructure); // 3. 配置光敏传感器引脚(PC4) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_Init(GPIOC, &GPIO_InitStructure); // 4. 配置ADC分频 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 5. ADC通用配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 禁用扫描模式 ADC_InitStructure.ADC_NbrOfChannel = 1; // 每次转换1个通道 ADC_Init(ADC1, &ADC_InitStructure); // 6. 使能ADC并校准 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } // 通用ADC读取函数(带错误处理) uint16_t ADC_ReadChannel(uint8_t channel) { // 配置ADC通道 ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5); // 启动转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 等待转换完成(带超时机制) uint32_t timeout = 10000; while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) && --timeout); return (timeout) ? ADC_GetConversionValue(ADC1) : 0; } // 雨滴传感器专用接口(带反向校准) /** * @brief 获取ADC转换值 * @param ADC_Channel 要使用的ADC通道 * @param ADC_SampleTime 采样时间设置 * @retval 转换后的数值结果 */ u16 ADC_GetValue(uint8_t ADC_Channel, uint8_t ADC_SampleTime) { // 配置ADC通道(通道9,采样时间55.5周期) ADC_RegularChannelConfig(ADCx, RAIN_CHANNEL, 1, ADC_SampleTime); ADC_SoftwareStartConvCmd(ADCx, ENABLE); while(ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADCx); } // 光敏传感器专用接口 uint16_t GetLightValue(void) { uint32_t sum = 0; for(uint8_t i=0; i<8; i++) { // 8次采样平均 sum += ADC_ReadChannel(LIGHT_CHANNEL); Delay_ms(2); // 采样间隔 } return sum / 8; // 直接返回平均值 } .c文件 // adcx.h #ifndef __ADCX_H #define __ADCX_H #include "stm32f10x.h" // 传感器通道定义 #define RAIN_CHANNEL ADC_Channel_9 // PB1 #define LIGHT_CHANNEL ADC_Channel_14 // PC4 #define ADCx ADC1 //#define ADC_CLK RCC_APB2Periph_ADC1 //#define ADC_CHANNEL ADC_Channel_9 // PB1对应通道9 // 函数声明 void ADCx_Init(void); uint16_t ADC_ReadChannel(uint8_t channel); u16 ADC_GetValue(uint8_t ADC_Channel, uint8_t ADC_SampleTime); uint16_t GetLightValue(void); #endif .h文件 // rain.c #include "rain.h" #include "Delay.h" /*****************创客电子STM32***************** 雨滴传感器驱动 * 作者 : 创客电子STM32 * 版本 : V1.2 * 日期 : 2025.7.8 * MCU : STM32F103C8T6 * 接口说明 : 见代码注释 * BILIBILI : 创客电子STM32 * CSDN : 创客电子STM32 * 版权声明 : 创客电子 **********************BEGIN***********************/ // 雨滴传感器初始化 void RAIN_Init(void) { #if MODE // 模拟量模式初始化 { GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOB时钟 RCC_APB2PeriphClockCmd(RAIN_AO_GPIO_CLK, ENABLE); // 配置PB1为模拟输入 GPIO_InitStructure.GPIO_Pin = RAIN_AO_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(RAIN_AO_GPIO_PORT, &GPIO_InitStructure); ADCx_Init(); // 初始化ADC } #else // 数字量模式初始化 { GPIO_InitTypeDef GPIO_InitStructure; // 开启GPIOA时钟 RCC_APB2PeriphClockCmd(RAIN_DO_GPIO_CLK, ENABLE); // 配置PA1为上拉输入 GPIO_InitStructure.GPIO_Pin = RAIN_DO_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(RAIN_DO_GPIO_PORT, &GPIO_InitStructure); } #endif } #if MODE // 模拟量模式专用函数 uint16_t RAIN_ADC_Read(void) { // 使用ADC通道9(对应PB1) return ADC_GetValue(RAIN_CHANNEL, ADC_SampleTime_55Cycles5); } #endif // 获取雨滴传感器数据 uint16_t RAIN_GetData(void) { #if MODE // 模拟量模式处理 uint32_t tempData = 0; for(uint8_t i = 0; i < RAIN_READ_TIMES; i++) { tempData += RAIN_ADC_Read(); // 累加采样值 Delay_ms(5); // 采样间隔 } tempData /= RAIN_READ_TIMES; // 计算平均值 return 4095 - tempData; // 返回校准值 #else // 数字量模式处理 uint16_t tempData; tempData = !GPIO_ReadInputDataBit(RAIN_DO_GPIO_PORT, RAIN_DO_GPIO_PIN); // 读取数字信号 return tempData; #endif } .c文件 // rain.h #ifndef __RAIN_H #define __RAIN_H #include "stm32f10x.h" #include "adcx.h" #include "delay.h" /*****************创客电子STM32***************** 雨滴传感器驱动 * 作者 : 创客电子STM32 * 版本 : V1.2 * 日期 : 2025.7.8 * MCU : STM32F103C8T6 * 接口说明 : 见代码注释 * BILIBILI : 创客电子STM32 * CSDN : 创客电子STM32 * 版权声明 : 创客电子 **********************BEGIN***********************/ #define RAIN_READ_TIMES 10 // 雨滴传感器ADC循环读取次数 // 模式选择 // 模拟量AO: 1 // 数字量DO: 0 #define MODE 1 /***************根据实际需求修改配置***************/ // RAIN GPIO配置 #if MODE #define RAIN_AO_GPIO_CLK RCC_APB2Periph_GPIOB // GPIOB时钟 #define RAIN_AO_GPIO_PORT GPIOB // GPIOB端口 #define RAIN_AO_GPIO_PIN GPIO_Pin_1 // Pin_1 #define RAIN_CHANNEL ADC_Channel_9 // ADC通道9(对应PB1) #else #define RAIN_DO_GPIO_CLK RCC_APB2Periph_GPIOA #define RAIN_DO_GPIO_PORT GPIOA #define RAIN_DO_GPIO_PIN GPIO_Pin_1 #endif /*********************END**********************/ void RAIN_Init(void); uint16_t RAIN_GetData(void); #endif /* __RAIN_H */ .h文件,请你帮我修改一下,保证我的雨滴传感器在模拟输出时可以实现有雨稳定增大,无雨时趋向于0,且保留ADC中光敏模块

根据以下程序,分别概括成几个模块的软件设计:#include "stm32f10x.h" #include "1602.h" #include "math.h" typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; //位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考<<CM3权威指南>>第五章(87页~92页). //IO口操作宏定义 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射 #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 //IO口操作,只对单一的IO口! //确保n的值小于16! #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入 #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入 #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入 //以下为汇编函数 void WFI_SET(void); //执行WFI指令 void INTX_DISABLE(void);//关闭所有中断 void INTX_ENABLE(void); //开启所有中断 void MSR_MSP(u32 addr); //设置堆栈地址 #define EnableINT() INTX_ENABLE() #define DisableINT() INTX_DISABLE() static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数 void delay_init() { #if SYSTEM_SUPPORT_OS //如果需要支持OS. u32 reload; #endif SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8 fac_us=SystemCoreClock/8000000; //为系统时钟的1/8 #if SYSTEM_SUPPORT_OS //如果需要支持OS. reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间 //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右 fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断 SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK #else fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数 #endif } //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } //延时nms //注意nms的范围 //SysTick->LOAD为24位寄存器,所以,最大延时为: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit) SysTick->VAL =0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } void USART1_init(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600; 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_Tx | USART_Mode_Rx; //USART1 USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); USART_ClearITPendingBit(USART1, USART_IT_RXNE); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_PE, ENABLE); USART_ITConfig(USART1, USART_IT_ERR, ENABLE); USART1->DR = (0X55 & (uint16_t)0x01FF); while((USART1->SR&0X40)==0); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void UsartSendData1(unsigned char *send_buff,unsigned long int length) { unsigned long int i = 0; delay_ms(1); for(i = 0;i < length;i ++) { USART1->DR = (send_buff[i] & (uint16_t)0x01FF); while((USART1->SR&0X40)==0); } delay_ms(1); } int GQ=0;//保存光强 int LX=0;//光类型 0白光 1黄光 2混合光 int DW=0;//档位 0~5档 int LPWM=0;//亮度 0~100 int moshi=0;//0手动 1自动 2声控 #define LED_B PBout(8) #define LED_H PBout(7) #define C_YR PBin(6) void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //ENABLEPBCLK GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); //Disable jtag RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //LCD1602 管脚 D0~D7 双向I/O GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15| GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(GPIOA, &GPIO_InitStructure); //ADC GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); //LCD1602 管脚 控制 推挽模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 |GPIO_Pin_13|GPIO_Pin_14; 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_9|GPIO_Pin_10|GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); //LED灯 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); } /* ADC配置 */ void ADC_Set(unsigned char ch) { ADC_InitTypeDef ADC_InitStructure;//ADC结构体变量//注意在一个语句快内变量的声明要放在可执行语句的前面,否则出错,因此要放在ADC1_GPIO_Config();前面 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //使能扫描 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC转换工作在连续模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//由软件控制转换,不使用外部触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//转换数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1;//转换通道为1 ADC_Init(ADC1, &ADC_InitStructure); //初始化ADC if(ch == ADC_Channel_7) { ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5); } if(ch == ADC_Channel_6) { ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_239Cycles5); } ADC_Cmd(ADC1, ENABLE);//使能ADC1 ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); } #define ADC_TIMES 10 #define ADCLOST 2 unsigned int GetADC(unsigned char ch) { unsigned int i, j; unsigned int buf[ADC_TIMES]; unsigned long int sum; long int temp; static long int XQ = 0; ADC_Set(ch); for(i=0; i < ADC_TIMES; i++) { buf[i] = ADC_GetConversionValue(ADC1);; delay_ms(10); } for(i = 0; i < ADC_TIMES - 1; i++) { for(j = i + 1; j < ADC_TIMES; j++) { if(buf[i] > buf[j]) { temp = buf[i]; } } } sum = 0; for(i = ADCLOST; i < ADC_TIMES - ADCLOST; i++) { sum += buf[i]; } temp = sum / (ADC_TIMES - 2 * ADCLOST); if( (XQ>=temp && (XQ-temp)<=1 ) || (XQ<temp && (temp-XQ)<=1)) { temp = XQ; } else { XQ = temp; } return (unsigned int)(temp>>4); } void Display_1(int T1,int T2,int T3,int T4,int T5) { char xx=0,yy=0; //光强 WrByte1602(yy,xx++,'G'); //. WrByte1602(yy,xx++,'Q'); WrByte1602(yy,xx++,'='); WrByte1602(yy,xx++,T1%1000/100+'0'); WrByte1602(yy,xx++,T1%100/10+'0'); WrByte1602(yy,xx++,T1%10+'0'); WrByte1602(yy,xx++,' '); //光类型 WrByte1602(yy,xx++,'T'); //. WrByte1602(yy,xx++,'Y'); WrByte1602(yy,xx++,'P'); WrByte1602(yy,xx++,'E'); WrByte1602(yy,xx++,'-'); if(T2==0)//0混合 1白光 2黄光 { WrByte1602(yy,xx++,'B'); WrByte1602(yy,xx++,'H'); } else if(T2==1)//0混合 1白光 2黄光 { WrByte1602(yy,xx++,'B'); WrByte1602(yy,xx++,' '); } else if(T2==2)//0混合 1白光 2黄光 { WrByte1602(yy,xx++,'H'); WrByte1602(yy,xx++,' '); } WrByte1602(yy,xx++,' '); xx=0,yy=1; //档位 WrByte1602(yy,xx++,'D'); //. WrByte1602(yy,xx++,'W'); WrByte1602(yy,xx++,'='); WrByte1602(yy,xx++,T3%10+'0'); WrByte1602(yy,xx++,' '); //亮度 WrByte1602(yy,xx++,'L'); //. WrByte1602(yy,xx++,'D'); WrByte1602(yy,xx++,'='); WrByte1602(yy,xx++,T4%1000/100+'0'); WrByte1602 if(T5==0)//0手动 1自动 2声控 { WrByte1602(yy,xx++,'S'); WrByte1602(yy,xx++,'D'); } else if(T5==1)//0手动 1自动 2声控 { WrByte1602(yy,xx++,'Z'); WrByte1602(yy,xx++,'D'); } else if(T5==2)//0手动 1自动 2声控 { WrByte1602(yy,xx++,'S'); WrByte1602(yy,xx++,'K'); } WrByte1602(yy,xx++,' '); } //int GQ=0;//保存光强 //int LX=0;//光类型 0白光 1黄光 2混合光 //int DW=0;//档位 0~5档 //int LPWM=0;//亮度 0~100 //int moshi=0;//0手动 1自动 2声控 void anjiansaom(void) { static uchar K1,K2,K3; static uchar K1Flag=0,K2Flag=0,K3Flag=0; K1 = GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_9); K2 = GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_11); K3 = GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_10); //手动/自动 if(K1==0) { K1Flag = 1; } else { if(K1Flag) { K1Flag = 0; if(moshi==1||moshi==2)//0手动 1自动 2声控 { moshi=0; } else { moshi=1; } } } //亮度 if(K2==0) { K2Flag = 1; } else { if(K2Flag) { K2Flag = 0; if(moshi==0)//0手动 1自动 2声控 { DW++; if(DW>5) { DW=0; } LPWM=DW*20; } } } { if(K3Flag) { K3Flag = 0; //光类型 0白光 1黄光 2混合光 LX++; if(LX>2) { LX=0; } } } } void TimerConfig(TIM_TypeDef* TIMx,unsigned long int time) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2,ENABLE); RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3,ENABLE); TIM_DeInit(TIMx); TIM_TimeBaseStructure.TIM_Period = time * 2; /* 自动重装载寄存器周期的值(计数值) */ /* 累计 TIM_Period个频率后产生一个更新或者中断 */ TIM_TimeBaseStructure.TIM_Prescaler= (1000- 1); /* 时钟预分频数 例如:时钟频率=72MHZ/(时钟预分频+1) */ TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; /* 采样分频 */ TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上计数模式 */ TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); TIM_ClearFlag(TIMx, TIM_FLAG_Update); /* 清除溢出中断标志 */ TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStr NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /** * @brief 关闭或者开启指定定时器 * @param TIMx: where x can be 1 to 17 to select the TIM peripheral * @param NewState: new state of the TIMx peripheral. * This parameter can be: ENABLE or DISABLE. * @retval None */ void TimerSW( TIM_TypeDef* TIMx, FunctionalState NewState ) { TIM_SetCounter(TIMx,0); TIM_Cmd(TIMx,NewState); } int main(void) { float temp; SystemInit(); SystemCoreClockUpdate(); delay_init(); //引脚配置 GPIO_Configuration(); //关闭LED灯 LED_B=0; LED_H=0; delay_ms(1000); //初始化LCD1602 Init1602(); TimerConfig(TIM2,1); TimerSW(TIM2, ENABLE); //串口初始化 USART1_init(); while (1) { delay_ms(20); //读取ADC的值,然后计算光强 ADC_Set(0); //光强 //先读取ADC值 GQ =(255-GetADC(0))/2-60; if(GQ<0) { GQ=0; } GQ = GQ*2; if(GQ>100) { GQ = 100; } //按键扫描 anjiansaom(); //光强 光类型 档位 亮度 模式 Display_1(GQ,LX,DW,LPWM,moshi); //自动模式光强控制 //首先得有人才会亮 if(moshi==1) { if(C_YR==1 )//传感器输出高电平代表有人 { //根据亮度计算光亮 //越暗 越亮 LPWM=100-GQ; } else { LPWM=0;//关灯 } } } } /** * @brief 定时器2中断服务函数 * @param TIMx: where x can be 1 to 17 to select the TIM peripheral * @param NewState: new state of the TIMx peripheral. * This parameter can be: ENABLE or DISABLE. * @retval None */ void TIM2_IRQHandler(void) { static int i=0; if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) { TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); // PCout(13)=~PCout(13); //这里实现PWM 波形的产生 i++; if(i<=LPWM) { //开灯 //暖光 还是白光 还是混合 if(LX==0)//0混合 1白光 2黄光 { } } else { //关灯 LED_B=0;LED_H=0; } //不能超过100 if(i>100) { i=0; } } } //串口1接收中断 void USART1_IRQHandler(void) { char shuju=0; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_RXNE); //保存收到的数据 shuju=USART_ReceiveData(USART1); //读取接收到的数据 //收到数据1 //你好小灯 唤醒 if(shuju==1)//进入声控模式 { moshi=2; } if(moshi==2) { //收到数据2 //开灯 if(shuju==2)//开灯 { if(LPWM==0) { DW=3; LPWM=DW*20; } } else if(shuju==3)//关灯 { DW=0; LPWM=DW*20; } else if(shuju==4)//亮一点 { DW++; if(DW>5) } } } if(USART_GetITStatus(USART1, USART_IT_PE) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_PE); } if (USART_GetFlagStatus(USART1, USART_IT_LBD) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_LBD); } if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET) { USART_ReceiveData(USART1); USART_ClearFlag(USART1, USART_FLAG_ORE); } if(USART_GetFlagStatus(USART1, USART_FLAG_NE) != RESET) { USART_ClearFlag(USART1, USART_FLAG_NE); } if(USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET) { USART_ClearFlag(USART1, USART_FLAG_FE); } if(USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET) { USART_ClearFlag(USART1, USART_FLAG_PE); } if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) { USART_ClearITPendingBit(USART1, USART_IT_TC); } } #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 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) */ /* Infinite loop */ while (1) {} } #endif /******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/ #include "stm32f10x.h" #include "1602.h" #define uchar unsigned char #define uint unsigned int uchar ASCII[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//2 /* PA8~PA15为数据口 */ #define LCD1602_RS_0 GPIO_ResetBits(GPIOB , GPIO_Pin_12) #define LCD1602_RS_1 GPIO_SetBits(GPIOB , GPIO_Pin_12) #define LCD1602_RW_0 GPIO_ResetBits(GPIOB , GPIO_Pin_13) #define LCD1602_RW_1 GPIO_SetBits(GPIOB , GPIO_Pin_13) #define LCD1602_EN_0 GPIO_ResetBits(GPIOB , GPIO_Pin_14) #define LCD1602_EN_1 GPIO_SetBits(GPIOB , GPIO_Pin_14) #define LCD1602_D0_0 GPIO_ResetBits(GPIOB , GPIO_Pin_15) #define LCD1602_D0_1 GPIO_SetBits(GPIOB , GPIO_Pin_15) #define LCD1602_D1_0 GPIO_ResetBits(GPIOA , GPIO_Pin_8) #define LCD1602_D1_1 GPIO_SetBits(GPIOA , GPIO_Pin_8) #define LCD1602_D2_0 GPIO_ResetBits(GPIOA , GPIO_Pin_11) #define LCD1602_D2_1 GPIO_SetBits(GPIOA , GPIO_Pin_11) #define LCD1602_D3_0 GPIO_ResetBits(GPIOA , GPIO_Pin_12) #define LCD1602_D3_1 GPIO_SetBits(GPIOA , GPIO_Pin_12) #define LCD1602_D4_0 GPIO_ResetBits(GPIOA , GPIO_Pin_15) #define LCD1602_D4_1 GPIO_SetBits(G #define LCD1602_D6_0 GPIO_ResetBits(GPIOB , GPIO_Pin_4) #define LCD1602_D6_1 GPIO_SetBits(GPIOB , GPIO_Pin_4) #define LCD1602_D7_0 GPIO_ResetBits(GPIOB , GPIO_Pin_5) #define LCD1602_D7_1 GPIO_SetBits(GPIOB , GPIO_Pin_5) #define GET_LCD1602_D0 GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_15) #define GET_LCD1602_D1 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_8) #define GET_LCD1602_D2 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_11) #define GET_LCD1602_D3 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_12) #define GET_LCD1602_D4 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_15) #define GET_LCD1602_ void SetLCD1602DValue(unsigned char value) { if(value&0x01) { LCD1602_D0_1; } else { LCD1602_D0_0; } if(value&0x02) { LCD1602_D1_1; } { LCD1602_D2_1; } else { LCD1602_D2_0; } if(value&0x08) { LCD1602_D3_1; } else { LCD1602_D3_0; } if(value&0x10) { LCD1602_D4_1; } else { LCD1602_D4_0; } if(value&0x20) { LCD1602_D5_1; } else { LCD1602_D5_0; } if(value&0x40) if(value&0x80) { LCD1602_D7_1; } else { LCD1602_D7_0; } } unsigned char GetLCD1602DValue(void) { unsigned char dat; dat = 0x00; if(GET_LCD1602_D0) { dat = dat |0x01; } if(GET_LCD1602_D1) { dat = dat |0x02; } if(GET_LCD1602_D2) { dat = dat |0x04; } if(GET_LCD1602_D3) { dat = dat |0x08; } if(GET_LCD1602_D4) { dat = dat |0x10; } if(GET_LCD1602_D5) { dat = dat |0x20; } if(GET_LCD1602_D6) { dat = dat |0x40; } if(GET_LCD1602_D7) { dat = dat |0x80; } return(dat); } /*******************通用延时子程序**************************/ void mDelay(uint i) { for (;i>0;i--) {uchar j=10;while(--j);} } void LCD1602DTest(void) { LCD1602_RS_1; LCD1602_RW_1; LCD1602_EN_1; SetLCD1602DValue(0x00); mDelay(100); mDelay(100); LCD1602_EN_0; SetLCD1602DValue(0xFF); mDelay(100); mDelay(100); LCD1602_RS_0; LCD1602_RW_0; LCD1602_EN_0; SetLCD1602DValue(0x00); } /************************************************************* 函数名称:读忙状态子函数 全局变量:无 参数说明:无 返回说明:无 版 本:1.0 说 明:读取LCD1602忙状态 **************************************************************/ void Read1602() //读忙状态 { long int i=90000; //建一个循环变量避免器件发生故障停在这里 SetLCD1602DValue(0xff); LCD1602_RS_0; LCD1602_RW_1; //设置LCD为读取数据状态 LCD1602_EN_1; //使能LCD,高电平 while ((i--)&&(GetLCD1602DValue()&0x80)); //检测数据口最高位状态,为0则空闲 LCD1602_EN_0; //关闭使能 } /************************************************************** 函数名称:写操作子函数 全局变量:无 参数说明:Dat为数据,command为指令(1为写数据,0为写指令) 返回说明:无 版 本:1.0 说 明:往LCD1602写入数据、指令 ***************************************************************/ void Write1602(uchar Dat,unsigned char command) { Read1602(); SetLCD1602DValue(Dat); if(command) { LCD1602_RS_1; //RS为1写数据、为0写指令 } else { LCD1602_RS_0; } LCD1602_RW_0; //RW为低,进行写操作 LCD1602_EN_1; LCD1602_EN_0; //E端控制一个高脉冲 } /*************************************************************** 函数名称:LCD1602初始化子函数 全局变量:无 参数说明:无 返回说明:无 版 本:1.0 说 明:设置工作模式、清屏、开显示 ***************************************************************/ void Init1602(void) { LCD1602DTest(); mDelay(10); mDelay(10); Write1602(0x38,0); //8位点阵方式 mDelay(10); Write1602(0x38,0); mDelay(10); Write1602(0x38,0); mDelay(10); Write1602(0x38,0); mDelay(10); Write1602(0x01,0); //清屏 mDelay(10); Write1602(0x0c,0); //开显示,光标不显示 } void WrByte1602_EX(uchar x,uchar y,uchar dat) { Write1602(0x80+(x<<6)+y,0); //合并生成地址 Write1602(dat,1); //写入数据 } void WrByte1602(uchar x,uchar y,uchar dat) { Write1602(0x80+(x<<6)+y,0); //合并生成地址 Write1602(dat,1); //写入数据 } /*************************************************************** 函数名称:LCD1602整行字符串写入子函数 全局变量:无 参数说明:x为写入的行(0或1),*p为写入的字符串数组 返回说明:无 版 本:1.0 说 明:在LCD1602任意行写入字符串 ****************************************************************/ void LCD_Write_String(uchar x1,uchar x,uchar *p) { x1 = 1; Write1602(0x80+(x<<6),0); //合并生成行首地址 while(*p) {Write1602(*p,1);p++;} //逐个字符写入 } #include "stm32f10x.h" #include "1602.h" #define uchar unsigned char #define uint unsigned int uchar ASCII[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//2 /* PA8~PA15为数据口 */ #define LCD1602_RS_0 GPIO_ResetBits(GPIOB , GPIO_Pin_12) #define LCD1602_RS_1 GPIO_SetBits(GPIOB , GPIO_Pin_12) #define LCD1602_RW_0 GPIO_ResetBits(GPIOB , GPIO_Pin_13) #define LCD1602_RW_1 GPIO_SetBits(GPIOB , GPIO_Pin_13) #define LCD1602_EN_0 GPIO_ResetBits(GPIOB , GPIO_Pin_14) #define LCD1602_EN_1 GPIO_SetBits(GPIOB , GPIO_Pin_14) #define LCD1602_D0_0 GPIO_ResetBits(GPIOB , GPIO_Pin_15) #define LCD1602_D0_1 GPIO_SetBits(GPIOB , GPIO_Pin_15) #define LCD1602_D1_0 GPIO_ResetBits(GPIOA , GPIO_Pin_8) #define LCD1602_D1_1 GPIO_SetBits(GPIOA , GPIO_Pin_8) #define LCD1602_D2_0 GPIO_ResetBits(GPIOA , GPIO_Pin_11) #define LCD1602_D2_1 GPIO_SetBits(GPIOA , GPIO_Pin_11) #define LCD1602_D3_0 GPIO_ResetBits(GPIOA , GPIO_Pin_12) #define LCD1602_D3_1 GPIO_SetBits(GPIOA , GPIO_Pin_12) #define LCD1602_D4_0 GPIO_ResetBits(GPIOA , GPIO_Pin_15) #define LCD1602_D4_1 GPIO_SetBits(GPIOA , GPIO_Pin_15) #define LCD1602_D5_0 GPIO_ResetBits(GPIOB , GPIO_Pin_3) #define LCD1602_D5_1 GPIO_SetBits(GPIOB , GPIO_Pin_3) #define LCD1602_D6_0 GPIO_ResetBits(GPIOB , GPIO_Pin_4) #define LCD1602_D6_1 GPIO_SetBits(GPIOB , GPIO_Pin_4) #define LCD1602_D7_0 GPIO_ResetBits(GPIOB , GPIO_Pin_5) #define LCD1602_D7_1 GPIO_SetBits(GPIOB , GPIO_Pin_5) #define GET_LCD1602_D0 GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_15) #define GET_LCD1602_D1 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_8) #define GET_LCD1602_D2 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_11) #define GET_LCD1602_D3 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_12) #define GET_LCD1602_D4 GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_15) #define GET_LCD1602_D5 GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_3) #define GET_LCD1602_D6 GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_4) #define GET_LCD1602_D7 GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_5) void SetLCD1602DValue(unsigned char value) { if(value&0x01) { LCD1602_D0_1; } else { LCD1602_D0_0; } if(value&0x02) { LCD1602_D1_1; } else { LCD1602_D1_0; } if(value&0x04) { LCD1602_D2_1; } else { LCD1602_D2_0; } if(value&0x08) { LCD1602_D3_1; } else { LCD1602_D3_0; } if(value&0x10) { LCD1602_D4_1; } else { LCD1602_D4_0; } if(value&0x20) { LCD1602_D5_1; } else { LCD1602_D5_0; } if(value&0x40) { LCD1602_D6_1; } else { LCD1602_D6_0; } if(value&0x80) { LCD1602_D7_1; } else { LCD1602_D7_0; } } unsigned char GetLCD1602DValue(void) { unsigned char dat; dat = 0x00; if(GET_LCD1602_D0) { dat = dat |0x01; } if(GET_LCD1602_D1) { dat = dat |0x02; } if(GET_LCD1602_D2) { dat = dat |0x04; } if(GET_LCD1602_D3) { dat = dat |0x08; } if(GET_LCD1602_D4) { dat = dat |0x10; } if(GET_LCD1602_D5) { dat = dat |0x20; } if(GET_LCD1602_D6) { dat = dat |0x40; } if(GET_LCD1602_D7) { dat = dat |0x80; } return(dat); } /*******************通用延时子程序**************************/ void mDelay(uint i) { for (;i>0;i--) {uchar j=10;while(--j);} } void LCD1602DTest(void) { LCD1602_RS_1; LCD1602_RW_1; LCD1602_EN_1; SetLCD1602DValue(0x00); mDelay(100); mDelay(100); LCD1602_RS_0; LCD1602_RW_0; LCD1602_EN_0; SetLCD1602DValue(0xFF); mDelay(100); mDelay(100); LCD1602_RS_0; LCD1602_RW_0; LCD1602_EN_0; SetLCD1602DValue(0x00); } /************************************************************* 函数名称:读忙状态子函数 全局变量:无 参数说明:无 返回说明:无 版 本:1.0 说 明:读取LCD1602忙状态 **************************************************************/ void Read1602() //读忙状态 { long int i=90000; //建一个循环变量避免器件发生故障停在这里 SetLCD1602DValue(0xff); LCD1602_RS_0; LCD1602_RW_1; //设置LCD为读取数据状态 LCD1602_EN_1; //使能LCD,高电平 while ((i--)&&(GetLCD1602DValue()&0x80)); //检测数据口最高位状态,为0则空闲 LCD1602_EN_0; //关闭使能 } /************************************************************** 函数名称:写操作子函数 全局变量:无 参数说明:Dat为数据,command为指令(1为写数据,0为写指令) 返回说明:无 版 本:1.0 说 明:往LCD1602写入数据、指令 ***************************************************************/ void Write1602(uchar Dat,unsigned char command) { Read1602(); SetLCD1602DValue(Dat); if(command) { LCD1602_RS_1; //RS为1写数据、为0写指令 } else { LCD1602_RS_0; } LCD1602_RW_0; //RW为低,进行写操作 LCD1602_EN_1; LCD1602_EN_0; //E端控制一个高脉冲 } /*************************************************************** 函数名称:LCD1602初始化子函数 全局变量:无 参数说明:无 返回说明:无 版 本:1.0 说 明:设置工作模式、清屏、开显示 ***************************************************************/ void Init1602(void) { LCD1602DTest(); mDelay(10); mDelay(10); Write1602(0x38,0); //8位点阵方式 mDelay(10); Write1602(0x38,0); mDelay(10); mDelay(10); Write1602(0x01,0); //清屏 mDelay(10); Write1602(0x0c,0); //开显示,光标不显示 } void WrByte1602_EX(uchar x,uchar y,uchar dat) { Write1602(0x80+(x<<6)+y,0); //合并生成地址 Write1602(dat,1); //写入数据 } void WrByte1602(uchar x,uchar y,uchar dat) { Write1602(0x80+(x<<6)+y,0); //合并生成地址 Write1602(dat,1); //写入数据 } /*************************************************************** 函数名称:LCD1602整行字符串写入子函数 全局变量:无 参数说明:x为写入的行(0或1),*p为写入的字符串数组 返回说明:无 版 本:1.0 说 明:在LCD1602任意行写入字符串 ****************************************************************/ void LCD_Write_String(uchar x1,uchar x,uchar *p) { x1 = 1; Write1602(0x80+(x<<6),0); //合并生成行首地址 while(*p) {Write1602(*p,1);p++;} //逐个字符写入 }

#include "stm32f10x.h" /************************** 引脚与参数定义 **************************/ // 循迹传感器引脚(PA0~PA4 → ADC通道0~4) #define SENSOR_CH1 ADC_Channel_0 #define SENSOR_CH2 ADC_Channel_1 #define SENSOR_CH3 ADC_Channel_2 #define SENSOR_CH4 ADC_Channel_3 #define SENSOR_CH5 ADC_Channel_4 // TB6612方向引脚定义 #define AIN1_PIN GPIO_Pin_5 // 左电机方向控制1(PA5) #define AIN2_PIN GPIO_Pin_6 // 左电机方向控制2(PA6) #define BIN1_PIN GPIO_Pin_0 // 右电机方向控制1(PB0) #define BIN2_PIN GPIO_Pin_1 // 右电机方向控制2(PB1) #define AIN_PORT GPIOA // 左电机方向端口 #define BIN_PORT GPIOB // 右电机方向端口 // TB6612 PWM引脚定义(3.9kHz,50%占空比) #define PWM_LEFT_TIM TIM3 // 左电机PWM定时器 #define PWM_RIGHT_TIM TIM2 // 右电机PWM定时器 #define PWM_PERIOD 255 // PWM周期(0~255) #define PWM_DUTY 128 // 占空比50%(128/255) #define ADC_THRESHOLD 2000 // ADC阈值(需校准) /************************** 全局变量 **************************/ uint8_t sensor_data[5] = {0}; // 传感器状态:1=黑线,0=白线 /************************** 函数声明 **************************/ void SystemInit(void); // 系统初始化(启动文件调用) void SystemClock_Config(void); // 时钟配置(72MHz) void GPIO_Config(void); // GPIO初始化 void ADC_Config(void); // ADC初始化 void TIM_Config(void); // PWM定时器初始化 void Read_Sensor(void); // 读取传感器数据 void Motor_Forward(void); // 前进 void Motor_Left(void); // 左转 void Motor_Right(void); // 右转 void Motor_Stop(void); // 停车 void Delay_ms(uint32_t ms); // 毫秒延时 /************************** 系统时钟配置(72MHz) **************************/ void SystemClock_Config(void) { RCC_DeInit(); // 重置时钟配置 RCC_HSEConfig(RCC_HSE_ON); // 使能外部高速晶振 while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLL倍频9倍(8MHz→72MHz) RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 设置系统时钟为PLL输出 RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB时钟=系统时钟 RCC_PCLK1Config(RCC_HCLK_Div2); // APB1时钟=36MHz RCC_PCLK2Config(RCC_HCLK_Div1); // APB2时钟=72MHz SystemCoreClockUpdate(); // 更新系统时钟变量 } /************************** GPIO初始化 **************************/ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); // 1. TB6612方向引脚配置(推挽输出) GPIO_InitStructure.GPIO_Pin = AIN1_PIN | AIN2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(AIN_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BIN1_PIN | BIN2_PIN; GPIO_Init(BIN_PORT, &GPIO_InitStructure); // 2. 传感器引脚配置(模拟输入) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. PWM引脚配置(复用推挽输出) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // PA7 → TIM3_CH2(左电机PWM) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PB3 → TIM2_CH3(右电机PWM) GPIO_Init(GPIOB, &GPIO_InitStructure); } /************************** ADC初始化(5路传感器) **************************/ void ADC_Config(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // ADC基本配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 多通道扫描 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐 ADC_InitStructure.ADC_NbrOfChannel = 5; // 5通道 ADC_Init(ADC1, &ADC_InitStructure); // 配置5路传感器通道(采样时间55.5周期) ADC_RegularChannelConfig(ADC1, SENSOR_CH1, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH2, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH3, 3, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH4, 4, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH5, 5, ADC_SampleTime_55Cycles5); // 使能ADC并校准 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } /************************** PWM定时器初始化 **************************/ void TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 使能定时器时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE); // 左电机PWM(TIM3_CH2,PA7) TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; // 周期255 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz/72=1MHz TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_DUTY; // 50%占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_Cmd(TIM3, ENABLE); // 右电机PWM(TIM2_CH3,PB3) TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; TIM_TimeBaseStructure.TIM_Prescaler = 71; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_DUTY; // 50%占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM2, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); } /************************** 读取传感器数据 **************************/ void Read_Sensor(void) { uint16_t adc_val; ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动ADC转换 while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完成 // 依次读取5路传感器ADC值并判断黑白线 adc_val = ADC_GetConversionValue(ADC1); // 最左传感器 sensor_data[0] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 左传感器 sensor_data[1] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 中间传感器 sensor_data[2] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 右传感器 sensor_data[3] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 最右传感器 sensor_data[4] = (adc_val > ADC_THRESHOLD) ? 1 : 0; } /************************** 电机控制函数 **************************/ // 前进(双电机正转,50%占空比) void Motor_Forward(void) { // 方向控制:左电机AIN1=高,AIN2=低;右电机BIN1=高,BIN2=低 GPIO_SetBits(AIN_PORT, AIN1_PIN); GPIO_ResetBits(AIN_PORT, AIN2_PIN); GPIO_SetBits(BIN_PORT, BIN1_PIN); GPIO_ResetBits(BIN_PORT, BIN2_PIN); // 设置PWM占空比50% TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY); TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY); } // 左转(左电机50%,右电机25%占空比) void Motor_Left(void) { Motor_Forward(); // 继承前进方向 TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY); // 左电机全速 TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY/2); // 右电机半速 } // 右转(右电机50%,左电机25%占空比) void Motor_Right(void) { Motor_Forward(); // 继承前进方向 TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY/2); // 左电机半速 TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY); // 右电机全速 } // 停车(PWM=0,方向引脚低电平) void Motor_Stop(void) { GPIO_ResetBits(AIN_PORT, AIN1_PIN | AIN2_PIN); GPIO_ResetBits(BIN_PORT, BIN1_PIN | BIN2_PIN); TIM_SetCompare2(PWM_LEFT_TIM, 0); TIM_SetCompare3(PWM_RIGHT_TIM, 0); } /************************** 毫秒延时函数 **************************/ void Delay_ms(uint32_t ms) { uint32_t i, j; for(i = 0; i < ms; i++) for(j = 0; j < 7200; j++); // 72MHz下约1ms(需校准) } /************************** 主函数 **************************/ int main(void) { SystemClock_Config(); // 配置72MHz系统时钟 GPIO_Config(); // 初始化GPIO ADC_Config(); // 初始化ADC TIM_Config(); // 初始化PWM定时器 while (1) { Read_Sensor(); // 读取传感器状态 // 循迹逻辑判断 if (sensor_data[2]) { // 中间传感器检测到黑线 → 前进 Motor_Forward(); } else if (sensor_data[0] || sensor_data[1]) { // 左侧检测到 → 右转 Motor_Right(); } else if (sensor_data[3] || sensor_data[4]) { // 右侧检测到 → 左转 Motor_Left(); } else { // 无黑线 → 停车 Motor_Stop(); } Delay_ms(50); // 50ms控制周期(20Hz) } }将这个改进

请帮我设计一些代码实现控制stm32小车直线行驶,我现在有motor模块代码如下#include "motor.h" #include "stm32f4xx.h" //pb7:3;pa4:5;pd7:6;pd6:4; void motor_init() { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD,ENABLE); GPIO_InitTypeDef G; G.GPIO_Mode = GPIO_Mode_OUT; G.GPIO_OType = GPIO_OType_PP; G.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_5; G.GPIO_Speed = GPIO_Medium_Speed; GPIO_Init(GPIOB,&G); GPIO_Init(GPIOA,&G); GPIO_Init(GPIOD,&G); GPIO_SetBits(GPIOB,GPIO_Pin_7); GPIO_SetBits(GPIOA,GPIO_Pin_4); GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_SetBits(GPIOD,GPIO_Pin_7); } void motor_up() { GPIO_SetBits(GPIOB,GPIO_Pin_7); GPIO_ResetBits(GPIOA,GPIO_Pin_4); GPIO_ResetBits(GPIOD,GPIO_Pin_6); GPIO_SetBits(GPIOD,GPIO_Pin_7); } void motor_right() { GPIO_SetBits(GPIOB,GPIO_Pin_7); GPIO_ResetBits(GPIOA,GPIO_Pin_4); GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_ResetBits(GPIOD,GPIO_Pin_7); } void motor_left() { GPIO_ResetBits(GPIOB,GPIO_Pin_7); GPIO_SetBits(GPIOA,GPIO_Pin_4); GPIO_ResetBits(GPIOD,GPIO_Pin_6); GPIO_SetBits(GPIOD,GPIO_Pin_7); } void motor_down() { GPIO_ResetBits(GPIOB,GPIO_Pin_7); GPIO_SetBits(GPIOA,GPIO_Pin_4); GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_ResetBits(GPIOD,GPIO_Pin_7); } void motor_stop(){ GPIO_SetBits(GPIOB,GPIO_Pin_7);//???? GPIO_SetBits(GPIOD,GPIO_Pin_6);//???? GPIO_SetBits(GPIOA,GPIO_Pin_4);//????? GPIO_SetBits(GPIOD,GPIO_Pin_7);//????? }请把接下来的控制小车直线行驶的模块写出来以及主模块main的代码发出来,.c.h代码都发出来

#include "soil_moisture.h" #include "stm32f10x_adc.h" #define SOIL_DRY_ADC 3800 #define SOIL_WET_ADC 1200 void SoilMoisture_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } uint16_t Get_SoilMoisture_ADC(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); } uint8_t Get_SoilMoisture_Percent(void) { uint16_t adc_val = Get_SoilMoisture_ADC(); int32_t numerator = (int32_t)(SOIL_DRY_ADC - adc_val); int32_t denominator = (SOIL_DRY_ADC - SOIL_WET_ADC); int32_t percent = (numerator * 100) / denominator; return (percent > 100) ? 100 : ((percent < 0) ? 0 : percent); }土壤数据显示000并且土壤二字乱码

#include "sys.h"#define AIN1_HIGH GPIO_SetBits(GPIOB,GPIO_Pin_11)#define AIN1_LOW GPIO_ResetBits(GPIOB,GPIO_Pin_11)#define AIN2_HIGH GPIO_SetBits(GPIOB,GPIO_Pin_10)#define AIN2_LOW GPIO_ResetBits(GPIOB,GPIO_Pin_10)#define BIN1_HIGH GPIO_SetBits(GPIOA,GPIO_Pin_3)#define BIN1_LOW GPIO_ResetBits(GPIOA,GPIO_Pin_3)#define BIN2_HIGH GPIO_ResetBits(GPIOA,GPIO_Pin_2)#define BIN2_LOW GPIO_SetBits(GPIOA,GPIO_Pin_2)#define PI 3.1415926//I#define PULSE 28*100 //??28*100???#define PROPORTION 30 //?????int counter =-1;//???????(-1???????????????????? ???-1)int counter2 =-1;int target1 =0;//??????float KP =14.7;//PID??float KI =1.4;//PID??float KD =0.0;//PID??float _speed;//???????float _speed2;//???????int _target2=0;//??????void Calculate_Motor2();void Calculate_Motor1();void MotorControl_1();void Motorcontrol_2();int get_totalPulses_1();int control();int get_totalPulses_2();int control2();void MAStop(){ AIN1_LOW; AIN2_LOW;}void MARight(){ AIN1_HIGH; AIN2_LOW;}void MALeft(){ AIN1_LOW; AIN2_HIGH;}void MBStop(){ BIN1_LOW; BIN2_LOW;}void MBRight()//??B??{ BIN1_HIGH; BIN2_LOW;}void MBLeft()//??B??{ BIN1_LOW; BIN2_HIGH;}void TB6612_Init(){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 |GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); MAStop(); MBStop();//??????}void Sensor_Init(){ GPIO_InitTypeDef GPIO_InitStructure;//??GPIOB?GPIOA??? RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 |GPIO_Pin_11 |GPIO_Pin_12 |GPIO_Pin_15; GPIO_Init(GPIOA,&GPIO_InitStructure);}void TIM3_PWM_Init(u16 arr,u16 psc){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);//??GPIOB?AFIO??? RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//?????3?? GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = arr;//??????????????????????????? TIM_TimeBaseStructure.TIM_Prescaler =psc;//??????TIMx??????????? TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM?????? TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//??TIM_TimeBaseInitStruct?????????TIx??????? TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//???????:TIM????????2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//????:TTM??????? TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3,&TIM_OCInitStructure);//??T??????????TIM3 OC2 TIM_OC1Init(TIM3,&TIM_OCInitStructure); TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//??TIM3?CcR2???????? TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE);//??TTM3}void SetServoAngle (uint8_t angle){ TIM_SetCompare3 (TIM3,1000-(int)(100*1.0/180*angle+25));}void TIM4_Encoder_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6 |GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period =PULSE * PROPORTION;//????????TIM_TimeBaseStructure.TIM_Prescaler =0;//?????TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;//????TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//??????TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising); NVIC_InitStructure.NVIC_IRQChannel =TIM4_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;//?????NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//?????NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);/*??????*/ TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter =10; TIM_SetCounter(TIM4,0);/*?????*/ TIM_Cmd(TIM4,ENABLE);}void TIM4_IRQHandler(){if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET){TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//???????????0,??counter,????counterif(TIM_GetCounter(TIM4)==0) counter ++;else counter --; }}void TIM2_Encoder_Init(void){ GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*??GPIO??GPIOA?0?1?????????,???50MHz*/GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period =PULSE*PROPORTION;//????????TIM_TimeBaseStructure.TIM_Prescaler =0;//?????TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;//????TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//??????TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising ,TIM_ICPolarity_Rising); NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//?????NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//?????NVIC_Init(&NVIC_InitStructure);/*??????(?????????)*/ TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);/*??????*/ TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter =10;//????TIM_ICInit(TIM2,&TIM_ICInitStructure);/*?????*/ TIM_SetCounter(TIM2,0);/*?????*/ TIM_Cmd(TIM2,ENABLE);}void TIM2_IRQHandler(){//?????2???????? if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET) {//???????? TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//???????????0,??counter,????counterif(TIM_GetCounter(TIM2)==0) counter2 ++;else counter2 --; }}void TIM1_Int_Init(u16 arr,u16 psc){ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); TIM_TimeBaseStructure.TIM_Period =arr;//?????????????TIM_TimeBaseStructure.TIM_Prescaler =(psc-1);//??????TIM_TimeBaseStructure.TIM_ClockDivision =0;//??????TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//??????TIM_TimeBaseStructure.TIM_RepetitionCounter =0;//??????TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//????? TIM_ClearFlag(TIM1,TIM_FLAG_Update);//?????? TIM_ITConfig( TIM1,TIM_IT_Update | TIM_IT_Trigger,ENABLE); NVIC_InitStructure.NVIC_IRQChannel =TIM1_UP_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;//?????0?NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//????0?NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM1,ENABLE);}void TIM1_UP_IRQHandler(void){if(TIM_GetITStatus(TIM1,TIM_IT_Update)!=RESET)//?????TTHI??????:TIM1???466??(467{TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//??TIHx???????:TIHI???468469/*?????1470 MotorControl_1(); Motorcontrol_2();}} void MotorControl_1(void){ int temp =0; Calculate_Motor1(&_speed); temp =control(target1,-_speed);//?????????????429 if(temp<=0)//??????432 { MARight();//??PMN???434 TIM_SetCompare2(TIM3,1000+temp);//????439 }else { MALeft();//??PMM???44 TIM_SetCompare2(TIM3,1000-temp); }}void Motorcontrol_2(void){ int temp2=0; Calculate_Motor2(&_speed2);//?????451 temp2 =control2(_target2,-_speed2);//?????????????452 if(temp2<=0) { MBLeft(); TIM_SetCompare1(TIM3,1000+temp2); }else{ MBRight(); TIM_SetCompare1(TIM3,1000-temp2);}}void Calculate_Motorl(float *speed){float templ =0;int encoder =0;static int encoder_dl =0;static float speed_dl =0.0;//??????????encoder =get_totalPulses_1();templ =((encoder -encoder_dl)*1.0/(PULSE*PROPORTION)*PI)*1000;//??????if(templ<=500 &templ >=-500)//????*speed =templ;speed_dl =*speed;encoder_dl =encoder;}void Calculate_Motor2(float *speed2){ float temp2 =0; int encoder2 =0; static int encoder_dl2 =0; static float speed_d12=0.0;//?????????? encoder2 =get_totalPulses_2();//???? temp2 =((encoder2 -encoder_dl2)*1.0/(PULSE*PROPORTION)*PI)*1000;//?????? if(temp2<=500 &temp2 >=-500)//????*speed2 =temp2; speed_d12 =*speed2; encoder_dl2 =encoder2;}int get_totalPulses_1(void){int pulses =0; if(counter >=0) pulses=counter * PULSE * PROPORTION +TIM_GetCounter(TIM4);else pulses =counter*PULSE*PROPORTION +TIM_GetCounter(TIM4);return pulses;}int get_totalPulses_2(void){int pulses2 =0;if(counter2 >=0)pulses2 =counter2*PULSE*PROPORTION +TIM_GetCounter(TIM2);else pulses2 =counter2*PULSE *PROPORTION +TIM_GetCounter(TIM2);return pulses2;}int control(float target,float actual){ int speed_val =0; static float err_last =0,err_sum =0; float err =target-actual;float d_err=err -err_last;speed_val =err*KP +err_sum*KI +d_err*KD;//?????if(speed_val >=1000)//speed_val=1000;else if(speed_val<=-1000)speed_val =-1000;if(err_sum >=10000)//?????-1000---+1000err_sum =10000; else if(err_sum<=-10000) err_sum =-10000; else err_sum +=err; err_last=err; return speed_val;}int control2(float target2,float actual2){int speed_val_2 =0;static float err_last_2=0,err_sum_2 =0;float err2 =target2 -actual2;float d_err2=err2 -err_last_2;//?????speed_val_2=err2*KP +err_sum_2*KI +d_err2*KD;if(speed_val_2 >=1000)//speed_val_2=1000;else if(speed_val_2<=-1000)speed_val_2 =-1000;//?????if(err_sum_2 >=10000)//?????-1000---+1000err_sum_2 =10000;else if(err_sum_2 <=-10000)err_sum_2 =-10000;else err_sum_2 +=err2; err_last_2=err2;return speed_val_2;}int main(void){u16 sum =0;u16 last =0;//???????????Sensor_Init();TB6612_Init();TIM3_PWM_Init(1000-1,1440-1);//50hz//???????????TIM4_Encoder_Init();TIM2_Encoder_Init();//10msTIM1_Int_Init(7200-1,100-1);//720000001007200007200100while(1) {sum=0;//??if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1)//???1???sum+=1;if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==1)//???2???sum+=2;if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==1)//???3???sum+=4;if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)==1)//???4???sum+=8;if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)==1)//???5???sum+=16;if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11)==1)//???6???sum+=32;if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_12)==1)//???7???sum+=64;if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==1)//???8??? sum+=128; if(sum==0) sum=last; switch(sum) { case 24://??,out4?out5?? SetServoAngle(90);//??????90+x????x 90-x???? target1 =15; _target2 =15; last=24; break; case 12://??10°,out3?out4?? SetServoAngle(90+10);//????A B??? target1=15; _target2 =15; last=12; break; case 8://??,??out4?? SetServoAngle(90);//????A B??? target1 =15; _target2 =15; last=8;break; case 6://??20°,out2?out3?? SetServoAngle(90+20);//????A B??? target1 =15; _target2 =15; last=6; break; case 4://??20°,??out3?? SetServoAngle(90+20);//????A B??? target1 =15; _target2 =15; last=4; break; case 3://??40°,out1?out2?? SetServoAngle(90+40);//????A B??? target1 =25; _target2 =25; break; case 2://??40°,??out2?? SetServoAngle(90+40);//????A B??? target1 =25; _target2 =25; last=2; break;//??50°,??outl?? SetServoAngle(90+50);//????A B??? target1 =25; _target2 =25; last=1; case 16://??,??out5?? SetServoAngle(90);//????A B??? target1 =15; _target2 =15; last=16; case 48://??10°,out5?out6?? SetServoAngle(90-10);//????A B??? target1=15; _target2 =15; last=48; break; case 32://??20°,??out6?? SetServoAngle(90-20);//????A B??? target1 =15; _target2 =15; last=32; break; case 96://??20°,out6?out7?? SetServoAngle(90-20);//????A B??? target1 =15; _target2 =15; last=96; break; case 192://??40°,out7?out8?? SetServoAngle(90-40);//????A B??? target1 =25; _target2 =25; last=192; case 64://??40°,??out7?? SetServoAngle(90+40);//????A B??? target1 =25; _target2 =25; last=64; break; SetServoAngle(90-50);//????A B??? target1 =25; _target2 =25; last=128; break; case 255: SetServoAngle(90);//????A B??? target1 =15; _target2 =15; last=255; break; defalt: SetServoAngle(90); target1 =0; _target2 =0; break; } }}这段代码哪里出错了

最新推荐

recommend-type

spring-ai-commons-1.0.0-M8.jar中文-英文对照文档.zip

1、压缩文件中包含: 中文-英文对照文档、jar包下载地址、Maven依赖、Gradle依赖、源代码下载地址。 2、使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 3、特殊说明: (1)本文档为人性化翻译,精心制作,请放心使用; (2)只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; (3)不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 4、温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件。 5、本文件关键字: jar中文-英文对照文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册。
recommend-type

本科毕设论文-—基于matlab的图形用户界面设计gui(1).doc

本科毕设论文-—基于matlab的图形用户界面设计gui(1).doc
recommend-type

全面掌握Oracle9i:基础教程与实践指南

Oracle9i是一款由甲骨文公司开发的关系型数据库管理系统,它在信息技术领域中占据着重要的地位。Oracle9i的“i”代表了互联网(internet),意味着它具有强大的网络功能,能够支持大规模的网络应用。该系统具有高度的数据完整性和安全性,并且其强大稳定的特点使得它成为了企业级应用的首选数据库平台。 为了全面掌握Oracle9i,本教程将从以下几个方面详细讲解: 1. Oracle9i的安装与配置:在开始学习之前,您需要了解如何在不同的操作系统上安装Oracle9i数据库,并对数据库进行基本的配置。这包括数据库实例的创建、网络配置文件的设置(如listener.ora和tnsnames.ora)以及初始参数文件的设置。 2. SQL语言基础:SQL(Structured Query Language)是用于管理和操作关系型数据库的标准语言。您需要熟悉SQL语言的基本语法,包括数据查询语言(DQL)、数据操纵语言(DML)、数据定义语言(DDL)和数据控制语言(DCL)。 3. PL/SQL编程:PL/SQL是Oracle公司提供的过程化语言,它是SQL的扩展,增加了过程化编程的能力。学习PL/SQL可以让您编写更复杂、更高效的数据库程序,包括存储过程、函数、包和触发器等。 4. Oracle9i的数据管理:这部分内容涉及数据表的创建、修改、删除以及索引、视图、同义词、序列和分区等高级特性。 5. 数据库性能优化:为了确保数据库的高效运行,需要对数据库进行性能调优。这包括了解Oracle9i的内存管理、锁定机制、SQL语句优化和数据库设计原则等。 6. 数据库备份与恢复:为防止数据丢失或损坏,需要了解Oracle9i的备份和恢复机制。您将学习到如何使用RMAN(Recovery Manager)进行数据备份和恢复,并且熟悉数据库的逻辑备份和恢复策略。 7. 安全管理:安全管理是保护数据库不受非法访问和操作的重要环节。Oracle9i提供了丰富的安全特性,如用户权限管理、审计和加密等,您需要学习如何实施这些安全措施来保证数据库的安全性。 8. Oracle9i网络管理:由于Oracle9i对网络的特别设计,您还需要掌握如何管理Oracle网络,包括监听器的配置、网络故障的诊断等。 9. 高级特性介绍:Oracle9i提供了很多高级功能,如高级复制、流复制、高级安全性、Oracle Data Guard等,这些内容将帮助您掌握Oracle9i的高级特性,从而在面对复杂业务需求时有更多解决方案。 在学习Oracle9i教程的过程中,您将通过大量实例练习加深理解,同时也会了解到最佳实践和常见问题的解决方法。本教程的目的是让您全面掌握Oracle9i数据库管理系统的使用,并具备解决实际问题的能力,无论您是数据库管理员、开发人员还是系统分析师,本教程都将成为您提升技能的有力工具。
recommend-type

【数据融合技术】:甘肃土壤类型空间分析中的专业性应用

# 摘要 数据融合技术作为一种集成多源数据信息的方法,在土壤类型空间分析中发挥着关键作用。本文介绍了数据融合技术的基本概念及其理论基础,阐述了数据预处理、同步整合及冲突解决等关键技术,并详细描述了甘肃土壤类型数据准备的流程,包括数据采集、质量评估、空间化处理及融合实践准备。通过具体案例分析,展示了数据融合在土壤类型空间分布分析、土壤质量评估及土壤保护规划中的应用。同时,文
recommend-type

模糊大津法

<think>首先,用户查询是关于“模糊大津法”的,我需要理解这个术语。从引用中,我知道大津法(Otsu's method)是一种图像二值化的全局阈值算法。用户提到“模糊大津法”,这可能是大津法与模糊理论结合的一种变体。我需要基于提供的引用和自己的知识来回答。关键引用:- [^1]:讨论了大津法在图像处理中的应用,特别是二值化。- [^2]:解释了大津法的原理和实现。- [^3]:提到大津法是全局阈值算法。- [^4]:讨论了高斯模糊对大津二值化算法的影响,指出高斯模糊可以减少噪声,提高阈值计算的准确性。用户的问题是:“我想查找关于模糊大津法的技术资料或实现方法请问模糊大津法原理实现方法技术文
recommend-type

SOA服务设计原则:2007年7月版原理深入解析

由于提供的文件信息是相同的标题、描述和标签,且压缩包中仅包含一个文件,我们可以得出文件“Prentice.Hall.SOA.Principles.of.Service.Design.Jul.2007.pdf”很可能是一本关于面向服务架构(SOA)的书籍。该文件的名称和描述表明了它是一本专门讨论服务设计原则的出版物,其出版日期为2007年7月。以下是从标题和描述中提取的知识点: ### SOA设计原则 1. **服务导向架构(SOA)基础**: - SOA是一种设计原则,它将业务操作封装为可以重用的服务。 - 服务是独立的、松耦合的业务功能,可以在不同的应用程序中复用。 2. **服务设计**: - 设计优质服务对于构建成功的SOA至关重要。 - 设计过程中需要考虑到服务的粒度、服务的生命周期管理、服务接口定义等。 3. **服务重用**: - 服务设计的目的是为了重用,需要识别出业务领域中可重用的功能单元。 - 通过重用现有的服务,可以降低开发成本,缩短开发时间,并提高系统的整体效率。 4. **服务的独立性与自治性**: - 服务需要在技术上是独立的,使得它们能够自主地运行和被管理。 - 自治性意味着服务能够独立于其他服务的存在和状态进行更新和维护。 5. **服务的可组合性**: - SOA强调服务的组合性,这意味着可以通过组合不同的服务构建新的业务功能。 - 服务之间的交互应当是标准化的,以确保不同服务间的无缝通信。 6. **服务的无状态性**: - 在设计服务时,最好让服务保持无状态,以便它们可以被缓存、扩展和并行处理。 - 状态信息可以放在服务外部,比如数据库或缓存系统中。 7. **服务的可发现性**: - 设计服务时,必须考虑服务的发现机制,以便服务消费者可以找到所需的服务。 - 通常通过服务注册中心来实现服务的动态发现和绑定。 8. **服务的标准化和协议**: - 服务应该基于开放标准构建,确保不同系统和服务之间能够交互。 - 服务之间交互所使用的协议应该广泛接受,如SOAP、REST等。 9. **服务的可治理性**: - 设计服务时还需要考虑服务的管理与监控,确保服务的质量和性能。 - 需要有机制来跟踪服务使用情况、服务变更管理以及服务质量保障。 10. **服务的业务与技术视角**: - 服务设计应该同时考虑业务和技术的视角,确保服务既满足业务需求也具备技术可行性。 - 业务规则和逻辑应该与服务实现逻辑分离,以保证业务的灵活性和可维护性。 ### SOA的实施挑战与最佳实践 1. **变更管理**: - 实施SOA时需要考虑到如何管理和适应快速变更。 - 必须建立适当的变更控制流程来管理和批准服务的更改。 2. **安全性**: - 安全是SOA设计中的一个关键方面,需要确保服务交互的安全。 - 需要实现身份验证、授权、加密和审计机制以保护数据和服务。 3. **互操作性**: - 服务应设计为可与不同平台和技术实现互操作。 - 必须确保服务之间可以跨平台和语言进行通信。 4. **质量保证**: - 对服务进行持续的质量监控和改进是实施SOA不可或缺的一部分。 - 服务质量(QoS)相关的特性如性能、可靠性、可用性等都应被纳入设计考量。 5. **投资回报(ROI)和成本效益分析**: - 从经济角度评估实施SOA的合理性。 - 在设计服务时考虑长期成本节约和ROI。 根据以上知识点的总结,可以看出“Prentice.Hall.SOA.Principles.of.Service.Design.Jul.2007.pdf”这本书很可能是系统地介绍SOA设计原则和最佳实践的专业著作,对于想要深入了解SOA设计的读者来说是一本宝贵的参考资料。
recommend-type

【空间分布规律】:甘肃土壤类型与农业生产的关联性研究

# 摘要 本文对甘肃土壤类型及其在农业生产中的作用进行了系统性研究。首先概述了甘肃土壤类型的基础理论,并探讨了土壤类型与农业生产的理论联系。通过GIS技术分析,本文详细阐述了甘肃土壤的空间分布规律,并对其特征和影响因素进行了深入分析。此外,本文还研究了甘肃土壤类型对农业生产实际影响,包括不同区域土壤改良和作物种植案例,以及土壤养分、水分管理对作物生长周期和产量的具体影响。最后,提出了促进甘肃土壤与农业可持续发展的策略,包括土壤保护、退化防治对策以及土壤类型优化与农业创新的结合。本文旨在为
recommend-type

rc滤波导致相位

<think>我们参考了关于RC滤波器的多个引用,特别是引用[3]和引用[4]中提到了相位的影响。 根据引用[3]:对于一阶RC低通滤波器,相位角θ的计算公式为:θ = -arctan(ωRC),其中ω是角频率(ω=2πf),R是电阻值,C是电容值。 引用[4]也解释了相位变化的原因:电容是储能元件,信号通过电容时会有延时,导致输出信号相对于输入信号产生相位差。 因此,对于RC低通滤波器,相位差是负的,表示输出信号滞后于输入信号。滞后的角度随频率增加而增加,在截止频率处滞后45度,当频率趋近于无穷大时,滞后90度。 对于RC高通滤波器,根据引用[3]的提示(虽然没有直接给出公式),
recommend-type

FTP搜索工具:IP检测与数据库管理功能详解

FTP(File Transfer Protocol)即文件传输协议,是一种用于在网络上进行文件传输的协议,使得用户可以通过互联网与其他用户进行文件共享。FTP Search是一款专注于FTP文件搜索的工具,其工作原理和应用场景使其在处理大规模数据共享和远程文件管理方面具有一定的优势。 **属性页控件** 属性页控件是一种用户界面元素,通常用于组织多个属性或设置页面。在FTP Search工具中,属性页控件可能被用来显示和管理FTP搜索的各项参数。用户可以通过它来设置搜索的FTP服务器地址、登录凭证、搜索范围以及结果处理方式等。属性页控件可以提高用户操作的便利性,使得复杂的设置更加直观易懂。 **Ping命令** Ping命令是互联网上广泛使用的一种网络诊断工具。它通过发送ICMP(Internet Control Message Protocol)回显请求消息到指定的IP地址,并等待接收回显应答,以此来检测目标主机是否可达以及网络延迟情况。在FTP Search工具中,Ping命令被用来检测FTP服务器的存活状态,即是否在线并能够响应网络请求。 **扫描主机端口** 端口扫描是网络安全领域中的一个基本操作,它用于检测特定主机上的哪些端口是开放的、关闭的或是被过滤的。了解端口的状态可以帮助确定目标主机上运行的服务和应用程序。在FTP Search工具中,端口扫描功能可能被用于识别FTP服务器上开放的端口,从而帮助用户找到合适的途径进行文件传输。 **数据库管理** 数据库管理在数据密集型应用中扮演着关键角色。FTP Search工具中包含的数据库操作功能,如打开、添加、查询和关闭数据库,表明该工具可能被设计为与数据库系统交互,以便更好地处理搜索到的FTP文件信息。可能涉及到的数据库管理系统(DBMS)包括MySQL、Microsoft SQL Server、SQLite等,用户可以通过工具提供的数据库管理接口来进行数据的维护和检索。 **IP地址控件** IP地址控件是一种用户界面组件,它允许用户输入或选择一个IP地址。在FTP Search工具中,IP地址控件用于输入目标FTP服务器的IP地址,使工具能够定位并连接到相应的服务器。该控件可能还具备验证IP地址有效性(如是否符合IPv4标准)的功能,并且能提供下拉列表或自动完成来提升用户体验。 综上所述,FTP Search工具是一个集成了多种网络和数据库操作功能的实用工具。通过属性页控件,用户可以方便地配置和管理工具;Ping命令和端口扫描功能则有助于用户确认服务器的状态和可用性;数据库管理功能则确保用户能够有效地存储和查询FTP搜索结果;而IP地址控件则简化了用户对服务器地址的输入流程。这些功能相互配合,使得FTP Search工具在执行FTP搜索任务时更加强大、高效和用户友好。对于网络管理员、数据分析师、IT专业人员等,这类工具能够显著提升工作效率,尤其是在处理大规模的文件共享和数据检索时。
recommend-type

【制图技术】:甘肃高质量土壤分布TIF图件的成图策略

# 摘要 本文针对甘肃土壤分布数据的TIF图件制作进行了系统研究。首先概述了甘肃土壤的分布情况,接着介绍了TIF图件的基础知识,包括其格式特点、空间数据表达以及质量控制方法。随后,文中构建了成图策略的理论框架,分析了土壤分布图的信息需求与数据处理流程,并探讨了成图原则与标准。在实践操作部分,详细阐述了制图软