活动介绍

#include "stm32f10x.h" // Device header #include "PWM.h" void Motor_Init(void) { PWM_Init(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开GPIO口时钟,先打开复用才能修改是否停用复用功能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); //关闭JTAG,使能SWD GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 |GPIO_Pin_6 | GPIO_Pin_7 |GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 |GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15 |GPIO_Pin_5 |GPIO_Pin_6 | GPIO_Pin_10 |GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB,GPIO_Pin_13); GPIO_ResetBits(GPIOB,GPIO_Pin_12); GPIO_ResetBits(GPIOB,GPIO_Pin_14); GPIO_ResetBits(GPIOB,GPIO_Pin_15); GPIO_ResetBits(GPIOB,GPIO_Pin_5); GPIO_ResetBits(GPIOB,GPIO_Pin_6); } void Motor3_SetSpeed(int8_t Speed) { if(Speed >=0) { GPIO_SetBits(GPIOB,GPIO_Pin_11); GPIO_ResetBits(GPIOB,GPIO_Pin_10); PWM_SetCompare3(Speed); } else { GPIO_SetBits(GPIOB,GPIO_Pin_10); GPIO_ResetBits(GPIOB,GPIO_Pin_11); PWM_SetCompare3(-Speed); } } void Motor2_SetSpeed(int8_t Speed) { if(Speed >=0) { GPIO_SetBits(GPIOB,GPIO_Pin_14); GPIO_ResetBits(GPIOB,GPIO_Pin_15); PWM_SetCompare2(Speed); } else { GPIO_SetBits(GPIOB,GPIO_Pin_15); GPIO_ResetBits(GPIOB,GPIO_Pin_14); PWM_SetCompare2(-Speed); } } void Motor1_SetSpeed(int8_t Speed) { if(Speed >=0) { GPIO_SetBits(GPIOB,GPIO_Pin_13); GPIO_ResetBits(GPIOB,GPIO_Pin_12); PWM_SetCompare1(Speed); } else { GPIO_SetBits(GPIOB,GPIO_Pin_12); GPIO_ResetBits(GPIOB,GPIO_Pin_13); PWM_SetCompare1(-Speed); } } void Motor4_SetSpeed(int8_t Speed) { if(Speed >=0) { GPIO_SetBits(GPIOB,GPIO_Pin_6); GPIO_ResetBits(GPIOB,GPIO_Pin_5); PWM_SetCompare4(Speed); } else { GPIO_SetBits(GPIOB,GPIO_Pin_5); GPIO_ResetBits(GPIOB,GPIO_Pin_6); PWM_SetCompare4(-Speed); } } 解释一下

时间: 2025-07-23 22:57:34 AIGC 浏览: 27
<think>我们之前已经解释过这段代码,但为了遵循用户要求,我们再次详细解释,并按照要求提出相关问题。 注意:用户要求最后提出相关问题,且格式严格。 解释:这段代码是用于STM32F10x系列微控制器控制4个电机的程序。主要功能包括电机初始化(GPIO和PWM配置)和设置每个电机的速度(包括方向控制)。 详细解释如下: 1. Motor_Init函数: - 首先调用PWM_Init()初始化PWM(用于控制电机速度)。 - 使能GPIOA和GPIOB的时钟(注意:GPIOB还使能了AFIO,因为后面需要重映射)。 - 使用GPIO_PinRemapConfig函数禁用了JTAG(释放PB3/PB4,但代码中未使用这些引脚,可能是为了其他用途预留),使能SWD调试接口。 - 初始化GPIOA的多个引脚(PA4~PA11)为推挽输出,50MHz速率。 - 初始化GPIOB的多个引脚(PB12~PB15, PB5, PB6, PB10, PB11)为推挽输出,50MHz速率。 - 将GPIOB的部分引脚(控制电机的方向引脚)初始化为低电平,确保电机初始状态为停止。 2. 每个电机的速度控制函数(Motor1_SetSpeed到Motor4_SetSpeed): - 函数参数为int8_t类型的速度值,范围-100~100(假设PWM_SetCompareX函数的参数范围为0~100,负值表示反向)。 - 判断速度正负:正速度表示一个方向,负速度表示另一个方向。 - 通过设置两个GPIO引脚(控制电机转向)的电平,实现H桥控制的正反转。 - 然后调用PWM_SetCompareX函数设置PWM占空比(取速度的绝对值,因为方向由GPIO控制)。 注意:每个电机使用两个GPIO引脚控制方向,一个PWM通道控制速度。 具体引脚分配: 电机1:方向控制 PB13(正)和 PB12(反),PWM通道1(通过PWM_SetCompare1设置) 电机2:方向控制 PB14(正)和 PB15(反),PWM通道2 电机3:方向控制 PB11(正)和 PB10(反),PWM通道3 电机4:方向控制 PB6(正) 和 PB5(反),PWM通道4 但是,在初始化函数中,还初始化了GPIOA的多个引脚(PA4~PA11)和GPIOB的其他引脚(PB12~PB15, PB5, PB6, PB10, PB11),这些引脚可能用于其他功能(如控制其他设备或备用)。 然而,在控制函数中,只使用了GPIOB的特定引脚。因此,GPIOA的引脚可能用于其他用途(如控制其他外设),而GPIOB的PB12~PB15, PB5, PB6, PB10, PB11用于电机方向控制。 另外,在Motor_Init函数中,将GPIOB的PB12、PB13、PB14、PB15、PB5、PB6都置为低电平,确保电机初始停止。 代码中,每个电机的控制逻辑相同: 正转:设置“正”引脚为高,“反”引脚为低,然后设置PWM占空比(正速度值)。 反转:设置“反”引脚为高,“正”引脚为低,然后设置PWM占空比(取负速度的绝对值)。 问题:代码中初始化了GPIOA的多个引脚,但在控制函数中并未使用。这可能是为其他功能预留的,或者可能是多余的。如果这些引脚没有其他用途,可以移除。 另外,注意PWM_SetCompareX函数的参数类型。这里假设该函数参数为uint8_t(0~255)或0~100的整数。但是代码中传入的是int8_t的绝对值(0~100或0~127)。如果PWM_SetCompareX函数期望的是0~100的值,则速度范围是-100~100;如果期望0~255,则应该传入0~255的值,但这里传入的是0~100(或-100~100取绝对值),所以可能需要调整。 根据函数名,我们假设PWM_SetCompareX函数内部已经处理了占空比的设置,且参数范围是0~100(百分比)或者0~自动重装载值(ARR)。具体需要查看PWM_Init的实现。 最后,按照要求提出相关问题:</think>### 解释:STM32电机驱动代码详解 这段代码是针对STM32F10x系列微控制器的电机控制程序,实现了4个直流电机的初始化配置和速度控制功能。以下是详细分析: #### 1. 整体架构 ```c #include "stm32f10x.h" // STM32标准外设库 #include "PWM.h" // PWM控制模块头文件 // 电机初始化函数 void Motor_Init(void) { ... } // 4个电机的速度控制函数 void Motor1_SetSpeed(int8_t Speed) { ... } void Motor2_SetSpeed(int8_t Speed) { ... } void Motor3_SetSpeed(int8_t Speed) { ... } void Motor4_SetSpeed(int8_t Speed) { ... } ``` #### 2. 电机初始化流程 ```c void Motor_Init(void) { PWM_Init(); // 初始化PWM模块 // 启用GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 启用GPIOB时钟和复用功能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // 关闭JTAG调试接口,释放PB3/PB4引脚 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 配置GPIOA引脚 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | ... | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置GPIOB引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | ... | GPIO_Pin_15; GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化所有控制引脚为低电平(电机停止) GPIO_ResetBits(GPIOB, GPIO_Pin_5 | GPIO_Pin_6 | ... | GPIO_Pin_15); } ``` **关键点**: 1. **时钟配置**:启用GPIOA/B时钟和AFIO复用功能 2. **引脚重映射**:`GPIO_Remap_SWJ_JTAGDisable`释放JTAG占用的引脚 3. **GPIO模式**:所有控制引脚配置为**推挽输出**(50MHz高速) 4. **安全初始化**:所有控制引脚置低,确保电机初始状态为停止 #### 3. 电机控制原理(以Motor1为例) ```c void Motor1_SetSpeed(int8_t Speed) { if(Speed >= 0) // 正转 { GPIO_SetBits(GPIOB, GPIO_Pin_13); // IN1 = 1 GPIO_ResetBits(GPIOB, GPIO_Pin_12); // IN2 = 0 PWM_SetCompare1(Speed); // 设置PWM占空比 } else // 反转 { GPIO_SetBits(GPIOB, GPIO_Pin_12); // IN2 = 1 GPIO_ResetBits(GPIOB, GPIO_Pin_13); // IN1 = 0 PWM_SetCompare1(-Speed); // 取绝对值设置PWM } } ``` **控制逻辑**: 1. **方向控制**: - 正转:`IN1=1, IN2=0` - 反转:`IN1=0, IN2=1` 2. **速度控制**: - 通过`PWM_SetCompareX()`设置占空比 - 参数`Speed`范围:-100~100(负值表示反转) - 使用`-Speed`确保PWM值为正数 #### 4. 引脚分配表 | 电机 | 方向控制引脚 | PWM通道 | 控制函数 | |------|-------------------|----------|-------------------| | 电机1 | PB13 (IN1)<br>PB12 (IN2) | CH1 | `Motor1_SetSpeed` | | 电机2 | PB14 (IN1)<br>PB15 (IN2) | CH2 | `Motor2_SetSpeed` | | 电机3 | PB11 (IN1)<br>PB10 (IN2) | CH3 | `Motor3_SetSpeed` | | 电机4 | PB6 (IN1)<br>PB5 (IN2) | CH4 | `Motor4_SetSpeed` | #### 5. 硬件连接示意图 ``` STM32 <--> 电机驱动模块 (如L298N) 方向控制引脚 --> IN1/IN2 PWM输出引脚 --> ENA/ENB (使能端) ``` #### 6. 关键设计特点 1. **H桥驱动**:使用双GPIO控制电机方向 2. **PWM调速**:通过占空比实现无级调速 3. **保护机制**: - 同一电机的两个控制引脚不会同时为高 - 初始状态所有引脚置低 4. **参数处理**:自动处理正负速度值 ### 使用示例 ```c int main(void) { Motor_Init(); // 初始化电机 // 电机1以70%速度正转 Motor1_SetSpeed(70); // 电机2以50%速度反转 Motor2_SetSpeed(-50); while(1) { // 主循环 } } ``` ### 注意事项 1. PWM频率需根据电机特性设置(典型1-20kHz) 2. 电机驱动电压需与STM32逻辑电平隔离 3. 实际使用时应添加过流保护 4. 避免H桥上下管直通(需死区控制)
阅读全文

相关推荐

#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "MyI2C.h" #include "MPU6050.h" #include "MPU6050_Reg.h" #include "kalman.h" #include "Motor.h" #include "PWM.h" #include "Timer.h" #include "pid.h" #include "Encoder.h" #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "sensor.h" #include "error.h" #include "key.h" #include "myfile.h" #include "menu.h" #include "element.h" #include <stdio.h> #include <stdarg.h> #include "Serial.h" volatile uint8_t data_ready = 0; /************************主函数***************************/ int main(void) { Serial_Init(); Key_Init(); MPU6050_Init(); OLED_Init(); Timer_Init(); Encoder_Init(); SENSOR_GPIO_Config(); //循迹引脚初始化 Motor_Init(); //电机初始化 PWM_Init(); //占空比定时器1初始化 while (1) { if(data_ready) //将陀螺仪放到主循环运行,避免过于频繁导致的中断卡顿(算力不够) { //获取陀螺仪 MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY,&GZ); data_ready = 0; } Key_Num = Key_GetNum(); menu_operation(); //菜单调用函数 Serial_Printf("%d,%d,%f,%f\r\n", 1,Speed_R,yaw,Location); //串口输出(自己修改变量打印到电脑上来调节速度环) OLED_Update(); } } /************************中断***************************/ void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) { Control(); //控制函数(最主要的控制都在这里面) data_ready = 1; //陀螺仪控制标志位 Key_Tick(); //获取按键值,江科大的定时器非阻塞 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } 将上面修改好的代码与这段代码融合到一起

#ifndef __IRAVOID_H_ #define __IRAVOID_H_ #include "stm32f10x.h" // Device header void IRAvoidInit(void); void AVoidRun(void); //避障传感器 /* 避障传感器 AVOID_PIN PB1 */ #define AVOID_PIN GPIO_Pin_1 #define AVOID_PIN_GPIO GPIOB #define AVOID_IO GPIO_ReadInputDataBit(AVOID_PIN_GPIO, AVOID_PIN) #define BARRIER_Y 0 //有障碍物 #define BARRIER_N 1 //无障碍物 #endif #include "IRAvoid.h" #include "delay.h" #include "motor.h" #include "keysacn.h" #include "stm32f10x.h" // Device header void IRAvoidInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitStructure.GPIO_Pin = AVOID_PIN;//配置使能GPIO管脚 PB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(AVOID_PIN_GPIO , &GPIO_InitStructure); } void AVoidRun(void) { if(AVOID_IO == BARRIER_N ) { ZYSTM32_run(50,10); BEEP_RESET; LED_D3_RESET; } else { BEEP_SET; LED_D3_SET; ZYSTM32_brake(300);//停止300MS ZYSTM32_back(50,400);//后退400MS ZYSTM32_Left(50,500);//左转500MS } } #include "stm32f10x.h" #include "delay.h" #include "motor.h" #include "keysacn.h" #include "IRSEARCH.h" #include "IRAvoid.h" /* void ZYSTM32_run(int speed,int time); //前进函数 void ZYSTM32_brake(int time); //刹车函数 void ZYSTM32_Left(int speed,int time); //左转函数 void ZYSTM32_Spin_Left(int speed,int time); //左旋转函数 void ZYSTM32_Right(int speed,int time); //右转函数 void ZYSTM32_Spin_Right(int speed,int time);//右旋转函数 void ZYSTM32_back(int speed,int time); //后退函数 */ int main(void) { delay_init(); KEY_Init(); IRSearchInit(); IRAvoidInit(); TIM4_PWM_Init(7199,0); //初始化PWM ZYSTM32_brake(500); keysacn(); while(1) { if(AVOID_IO == BARRIER_Y ) { BEEP_SET; LED_D3_SET; ZYSTM32_back(50,500); ZYSTM32_Spin_Left(50,250); delay_ms(300); } else { BEEP_RESET; LED_D3_RESET; SearchRun(); //循迹函数 } } } #include "IRSEARCH.h" #include "delay.h" #include "motor.h" #include "stm32f10x.h" // Device header char ctrl_comm = COMM_STOP;//控制指令 char ctrl_comm_last = COMM_STOP;//上一次的指令 void IRSearchInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitStructure.GPIO_Pin = SEARCH_R_PIN;//配置使能GPIO管脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(SEARCH_R_GPIO , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SEARCH_L_PIN;//配置使能GPIO管脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(SEARCH_L_GPIO , &GPIO_InitStructure); } void SearchRun(void) { if(SEARCH_L_IO == WHITE_AREA && SEARCH_R_IO == WHITE_AREA) ctrl_comm = COMM_UP; else if (SEARCH_L_IO == BLACK_AREA && SEARCH_R_IO == WHITE_AREA) ctrl_comm = COMM_RIGHT; else if (SEARCH_R_IO == BLACK_AREA & SEARCH_L_IO == WHITE_AREA) ctrl_comm = COMM_LEFT; else ctrl_comm = COMM_DOWN; if(ctrl_comm_last != ctrl_comm) { ctrl_comm_last = ctrl_comm; switch(ctrl_comm) { case COMM_UP: ZYSTM32_run(70,6);break; case COMM_DOWN: ZYSTM32_back(50,100);ZYSTM32_Spin_Left(50,400);break; case COMM_LEFT: ZYSTM32_back(50,100);ZYSTM32_Spin_Left(50,400);break; case COMM_RIGHT: ZYSTM32_back(50,100);ZYSTM32_Spin_Right(50,250);break; case COMM_STOP: ZYSTM32_brake(10);break; default : break; } } } 红外太敏感怎么半,红外避障会受环境光影响,红外循迹倒是不受环境光影响,但是会把瓷砖缝识别成黑线

这是 Motor.c #include "stm32f10x.h" // Device header #include "Motor.h" //初始化GPIO和定时器外设,配置一个PWM输出通道控制电机速度,PWM占空比初始值为,电机处于停止状态 void PWM_Init(void) { //定义初始化结构体 GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 启用GPIOA和TIM2时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 配置PA0为PWM输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//设置为复用推挽输出模式,受外设控制的引脚,均需设置为复用模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度50Hz GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period = 1000; // PWM分辨率(自动重装载值,决定PWM频率),即arr的值 TIM_TimeBaseStructure.TIM_Prescaler = 72; // 预分频器,72MHz/72 = 1MHz,PSC TIM_TimeBaseStructure.TIM_ClockDivision = 0;//时钟分频,设置为不分频,此参数用于配置滤波器时钟,不影响时基单元功能 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//初始化TIM2定时器 // PWM配置 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出 TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0,即ccr的值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高,若选择极性为低,则输出高低电平取反 TIM_OC1Init(TIM2, &TIM_OCInitStructure);//初始化TIM2通道1 TIM_Cmd(TIM2, ENABLE); // 使能定时器,开始产生PWM信号 } void Motor_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA4和PA5引脚初始化为推挽输出 PWM_Init(); //初始化直流电机的底层PWM } void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(TIM2, Compare); //设置CCR3的值 } void Motor_SetSpeed(int8_t Speed) { if (Speed >= 0) //如果设置正转的速度值 { GPIO_SetBits(GPIOA, GPIO_Pin_4); //PA4置高电平 GPIO_ResetBits(GPIOA, GPIO_Pin_5); //PA5置低电平,设置方向为正转 PWM_SetCompare1(Speed); //PWM设置为速度值 } else //否则,即设置反转的速度值 { GPIO_ResetBits(GPIOA, GPIO_Pin_4); //PA4置低电平 GPIO_SetBits(GPIOA, GPIO_Pin_5); //PA5置高电平,设置方向为反转 PWM_SetCompare1(-Speed); //PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数 } } 这是 Motor.h #ifndef __MOTOR_H #define __MOTOR_H #include "stm32f10x.h" void Motor_Init(void); void PWM_SetCompare1(uint16_t Compare); void PWM_Init(void); void Motor_SetSpeed(int8_t Speed); #endif 这是主函数 #include "stm32f10x.h" #include "Motor.h" int main(void) { Motor_Init(); GPIO_SetBits(GPIOA,GPIO_Pin_4); GPIO_ResetBits(GPIOA,GPIO_Pin_5); TIM_SetCompare1(TIM2, 500); while(1) { // 主循环 } } 我想把PWM和Motor写成两个模块化代码,请你帮我拆开他们

#include "stm32f10x.h" // Device header #include "Delay.h" void Buzzer_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); Buzzer_off(); } void Buzzer_on(void) { GPIO_ResetBits(GPIOA, GPIO_Pin_3); // 低电平触发,开启蜂鸣器 } void Buzzer_off(void) { GPIO_SetBits(GPIOA, GPIO_Pin_3); // 高电平关闭蜂鸣器 } void Buzzer_Beep(uint16_t frequency, uint16_t duration) { // 频率(Hz)转换为周期值 uint16_t period = 72000000 / frequency / 2; // 假设系统时钟为72MHz // 设置PWM参数 PWM_SetBuzzerFrequency(frequency); PWM_SetBuzzerDutyCycle(50); // 50%占空比 Buzzer_on(); Delay_ms(duration); Buzzer_off(); } #include "stm32f10x.h" // Device header void PWM_Init(void) { //1.开启时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2用于电机 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // TIM3用于蜂鸣器 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 电机PWM引脚配置 (GPIOA.1, GPIOA.2) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 蜂鸣器PWM引脚配置 (GPIOB.1) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //2.选择时基准单元的时钟(内部时钟) TIM_InternalClockConfig(TIM2); // 72MHz TIM_InternalClockConfig(TIM3); // 72MHz //3.配置电机TIM2时基单元 - 保持原有配置 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR=100 TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; // 频率约20kHz TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //3.配置蜂鸣器TIM3时基单元 - 新配置 TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1; // ARR=1000 TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // 频率约1kHz-10kHz (可听范围) TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); // 4.初始化电机输出比较单元(OC) TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0% TIM_OC2Init(TIM2, &TIM_OCInitStructure); // 电机通道1 TIM_OC3Init(TIM2, &TIM_OCInitStructure); // 电机通道2 // 4.初始化蜂鸣器输出比较单元(OC) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; // 低电平触发 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比0% TIM_OC2Init(TIM3, &TIM_OCInitStructure); // 蜂鸣器通道 //5.启动定时器 TIM_Cmd(TIM2, ENABLE); TIM_Cmd(TIM3, ENABLE); } // 电机PWM控制函数 - 保持原有 void PWM_SetCompare2(uint16_t Compare) { TIM_SetCompare2(TIM2, Compare); // 电机通道1 } void PWM_SetCompare3(uint16_t Compare) { TIM_SetCompare3(TIM2, Compare); // 电机通道2 } // 蜂鸣器PWM控制函数 - 新增 void PWM_SetBuzzerFrequency(uint16_t frequency) { // 根据频率计算周期 uint16_t period = 72000000 / frequency / 72; // 72MHz / 72 = 1MHz // 设置TIM3周期 TIM3->ARR = period - 1; } void PWM_SetBuzzerDutyCycle(uint8_t dutyCycle) { // 计算占空比值 uint16_t pulse = (TIM3->ARR + 1) * dutyCycle / 100; // 设置TIM3占空比 TIM_SetCompare2(TIM3, pulse); } Rebuild started: Project: Project *** Using Compiler 'V5.06 update 7 (build 960)', folder: 'D:\Keil_v5\ARM\ARMCC\Bin' Rebuild target 'Target 1' assembling startup_stm32f10x_md.s... compiling stm32f10x_cec.c... compiling stm32f10x_crc.c... compiling stm32f10x_adc.c... compiling stm32f10x_can.c... compiling system_stm32f10x.c... compiling misc.c... compiling stm32f10x_dbgmcu.c... compiling stm32f10x_dac.c... compiling stm32f10x_bkp.c... compiling core_cm3.c... compiling stm32f10x_dma.c... compiling stm32f10x_exti.c... compiling stm32f10x_flash.c... compiling stm32f10x_fsmc.c... compiling stm32f10x_gpio.c... compiling stm32f10x_iwdg.c... compiling stm32f10x_i2c.c... compiling stm32f10x_pwr.c... compiling stm32f10x_rtc.c... compiling stm32f10x_rcc.c... compiling stm32f10x_sdio.c... compiling stm32f10x_spi.c... compiling stm32f10x_wwdg.c... compiling stm32f10x_usart.c... compiling stm32f10x_tim.c... compiling Delay.c... compiling Led.c... compiling key.c... compiling PWM.c... compiling OLED.c... compiling Motor.c... compiling SmartCar.c... compiling Serial.c... compiling HCSR04.c... compiling Servo.c... compiling Buzzer.c... Hardware\Buzzer.c(15): warning: #223-D: function "Buzzer_off" declared implicitly Buzzer_off(); Hardware\Buzzer.c(23): error: #159: declaration is incompatible with previous "Buzzer_off" (declared at line 15) void Buzzer_off(void) Hardware\Buzzer.c(34): warning: #223-D: function "PWM_SetBuzzerFrequency" declared implicitly PWM_SetBuzzerFrequency(frequency); Hardware\Buzzer.c(35): warning: #223-D: function "PWM_SetBuzzerDutyCycle" declared implicitly PWM_SetBuzzerDutyCycle(50); // 50%占空比 Hardware\Buzzer.c(31): warning: #177-D: variable "period" was declared but never referenced uint16_t period = 72000000 / frequency / 2; // 假设系统时钟为72MHz Hardware\Buzzer.c: 4 warnings, 1 error compiling LineWalking.c... compiling DHT11.c... compiling ADC.c... compiling systick.c... compiling main.c... compiling stm32f10x_it.c... ".\Objects\Project.axf" - 1 Error(s), 4 Warning(s). Target not created. Build Time Elapsed: 00:00:05代码问题

#include “stm32f10x.h” #include “delay.h” #include “motor.h” #include “keysacn.h” #include “IRSEARCH.h” #include “IRAvoid.h” /* void ZYSTM32_run(int speed,int time); //前进函数 void ZYSTM32_brake(int time); //刹车函数 void ZYSTM32_Left(int speed,int time); //左转函数 void ZYSTM32_Spin_Left(int speed,int time); //左旋转函数 void ZYSTM32_Right(int speed,int time); //右转函数 void ZYSTM32_Spin_Right(int speed,int time);//右旋转函数 void ZYSTM32_back(int speed,int time); //后退函数 */ int main(void) { delay_init(); KEY_Init(); IRSearchInit(); IRAvoidInit(); TIM4_PWM_Init(7199,0); //初始化PWM ZYSTM32_brake(500); keysacn(); while(1) { if(AVOID_IO == BARRIER_Y ) { BEEP_SET; LED_D3_SET; ZYSTM32_back(50,200); ZYSTM32_Spin_Left(50,350); delay_ms(300); } else { BEEP_RESET; LED_D3_RESET; SearchRun(); //循迹函数 } } } #include “IRSEARCH.h” #include “delay.h” #include “motor.h” #include “stm32f10x.h” // Device header char ctrl_comm = COMM_STOP;//控制指令 char ctrl_comm_last = COMM_STOP;//上一次的指令 void IRSearchInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitStructure.GPIO_Pin = SEARCH_R_PIN;//配置使能GPIO管脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(SEARCH_R_GPIO , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = SEARCH_L_PIN;//配置使能GPIO管脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(SEARCH_L_GPIO , &GPIO_InitStructure); } void SearchRun(void) { if(SEARCH_L_IO == WHITE_AREA && SEARCH_R_IO == WHITE_AREA) ctrl_comm = COMM_UP; else if (SEARCH_L_IO == BLACK_AREA && SEARCH_R_IO == WHITE_AREA) ctrl_comm = COMM_RIGHT; else if (SEARCH_R_IO == BLACK_AREA & SEARCH_L_IO == WHITE_AREA) ctrl_comm = COMM_LEFT; else ctrl_comm = COMM_DOWN; if(ctrl_comm_last != ctrl_comm) { ctrl_comm_last = ctrl_comm; switch(ctrl_comm) { case COMM_UP: ZYSTM32_run(80,6);break; case COMM_DOWN: ZYSTM32_back(50,100);ZYSTM32_Spin_Left(70,400);break; case COMM_LEFT: ZYSTM32_back(50,100);ZYSTM32_Spin_Left(70,400);break; case COMM_RIGHT: ZYSTM32_back(50,100);ZYSTM32_Spin_Right(70,250);break; case COMM_STOP: ZYSTM32_brake(10);break; default : break; } } } #include “IRAvoid.h” #include “delay.h” #include “motor.h” #include “keysacn.h” #include “stm32f10x.h” // Device header void IRAvoidInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitStructure.GPIO_Pin = AVOID_PIN;//配置使能GPIO管脚 PB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//配置GPIO端口速度 GPIO_Init(AVOID_PIN_GPIO , &GPIO_InitStructure); } void AVoidRun(void) { if(AVOID_IO == BARRIER_N ) { ZYSTM32_run(50,10); BEEP_RESET; LED_D3_RESET; } else { BEEP_SET; LED_D3_SET; ZYSTM32_brake(300);//停止300MS ZYSTM32_back(50,400);//后退400MS ZYSTM32_Left(50,500);//左转500MS } } #ifndef _IRAVOID_H #define _IRAVOID_H #include “stm32f10x.h” // Device header void IRAvoidInit(void); void AVoidRun(void); //避障传感器 /* 避障传感器 AVOID_PIN PB1 */ #define AVOID_PIN GPIO_Pin_1 #define AVOID_PIN_GPIO GPIOB #define AVOID_IO GPIO_ReadInputDataBit(AVOID_PIN_GPIO, AVOID_PIN) #define BARRIER_Y 0 //有障碍物 #define BARRIER_N 1 //无障碍物 #endif #include “motor.h” #include “Math.h” #include “delay.h” #include “stm32f10x.h” // Device header signed short sPWMR,sPWML,dPWM; //GPIO配置函数 /*void MotorGPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); //使能PA,PB端口时钟 GPIO_InitStructure.GPIO_Pin = LEFT_MOTOR_GO; //左电机方向控制 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(LEFT_MOTOR_GO_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = LEFT_MOTOR_PWM; GPIO_Init(LEFT_MOTOR_PWM_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = RIGHT_MOTOR_PWM; GPIO_Init(RIGHT_MOTOR_PWM_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = RIGHT_MOTOR_GO; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(RIGHT_MOTOR_GPIO, &GPIO_InitStructure); } void run() //前进 { RIGHT_MOTOR_GO_SET; RIGHT_MOTOR_PWM_RESET;//PB9 LEFT_MOTOR_GO_SET; LEFT_MOTOR_PWM_RESET;//PB8 } */ void TIM4_PWM_Init(unsigned short arr,unsigned short psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB , ENABLE); //使能GPIO外设时钟使能 GPIO_InitStructure.GPIO_Pin = LEFT_MOTOR_GO; //左电机方向控制 PB7 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(LEFT_MOTOR_GO_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = LEFT_MOTOR_PWM; //左电机PWM控制 PB8 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(LEFT_MOTOR_PWM_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = RIGHT_MOTOR_GO; //右电机方向控制 PA4 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(RIGHT_MOTOR_GPIO, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = RIGHT_MOTOR_PWM; //右电机PWM控制 PB9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(RIGHT_MOTOR_PWM_GPIO, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC3Init(TIM4, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_OC4Init(TIM4, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_CtrlPWMOutputs(TIM4,ENABLE); //MOE 主输出使能 TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable); //CH1预装载使能 TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); //CH1预装载使能 TIM_ARRPreloadConfig(TIM4, ENABLE); //使能TIMx在ARR上的预装载寄存器 TIM_Cmd(TIM4, ENABLE); //使能TIM1 } void SetMotorSpeed(unsigned char ucChannel,signed char cSpeed) { // static short sMotorSpeed = 0; short sPWM; // float fDir = 1; if (cSpeed>=100) cSpeed = 100; if (cSpeed<=-100) cSpeed = -100; sPWM = 7201 - fabs(cSpeed)*72; switch(ucChannel) { case 0://右轮 TIM_SetCompare3(TIM4,sPWM); if (cSpeed>0) RIGHT_MOTOR_GO_RESET; else if(cSpeed<0) RIGHT_MOTOR_GO_SET; break; case 1://左轮 TIM_SetCompare4(TIM4,sPWM); if (cSpeed>0) LEFT_MOTOR_GO_SET; else if (cSpeed<0) LEFT_MOTOR_GO_RESET; break; } } //----------------------------------运动函数-------------------------------- void ZYSTM32_run(signed char speed,int time) //前进函数 { signed char f_speed = - speed; SetMotorSpeed(1,f_speed);//左轮 //为负数 SetMotorSpeed(0,speed);//右轮 //为正数 delay_ms(time); //时间为毫秒 } void ZYSTM32_brake(int time) //刹车函数 { SetMotorSpeed(1,0);//左轮 //为0 SetMotorSpeed(0,0);//右轮 //为0 RIGHT_MOTOR_GO_RESET; LEFT_MOTOR_GO_RESET; delay_ms(time); //时间为毫秒 } void ZYSTM32_Left(signed char speed,int time) //左转函数 { SetMotorSpeed(1,0);//左轮 //左轮不动 SetMotorSpeed(0,speed); //右轮为正 delay_ms(time); //时间为毫秒 } void ZYSTM32_Spin_Left(signed char speed,int time) //左旋转函数 { SetMotorSpeed(1,speed);//左轮 //左轮为正 SetMotorSpeed(0,speed); //右轮为正 delay_ms(time); //时间为毫秒 } void ZYSTM32_Right(signed char speed,int time) //右转函数 { signed char f_speed = - speed; SetMotorSpeed(1,f_speed);//左轮 //左轮为负 SetMotorSpeed(0,0); //右轮为0 delay_ms(time); //时间为毫秒 } void ZYSTM32_Spin_Right(signed char speed,int time) //右旋转函数 { signed char f_speed = - speed; SetMotorSpeed(1,f_speed);//左轮 //左轮为负 SetMotorSpeed(0,f_speed); //右轮为负 delay_ms(time); //时间为毫秒 } void ZYSTM32_back(signed char speed,int time) //后退函数 { signed char u_speed = 100- speed; signed char f_speed = - u_speed; SetMotorSpeed(1,u_speed);//左轮 //为正数 SetMotorSpeed(0,f_speed);//右轮 //为负数 delay_ms(time); //时间为毫秒 } #include “delay.h” ////////////////////////////////////////////////////////////////////////////////// //如果需要使用OS,则包括下面的头文件即可. #if SYSTEM_SUPPORT_OS #include “includes.h” //ucos 使用 #endif ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ZYSTM32-A0机器人主控板 //使用SysTick的普通计数模式对延迟进行管理(适合STM32F10x系列) //包括delay_us,delay_ms //智宇电子 //www.hnzhiyu.cn //创建日期:2017/4/14 //版本:V1.8 //All rights reserved //******************************************************************************** ////////////////////////////////////////////////////////////////////////////////// static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数 #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS). //当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持 //首先是3个宏定义: // delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数 //delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick // delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行 //然后是3个函数: // delay_osschedlock:用于锁定OS任务调度,禁止调度 //delay_osschedunlock:用于解锁OS任务调度,重新开启调度 // delay_ostimedly:用于OS延时,可以引起任务调度. //本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植 //支持UCOSII #ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定义了,说明要支持UCOSII #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数 #endif //支持UCOSIII #ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII #define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行 #define delay_ostickspersec OSCfg_TickRate_Hz //OS时钟节拍,即每秒调度次数 #define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数 #endif //us级延时时,关闭任务调度(防止打断us级延迟) void delay_osschedlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII OS_ERR err; OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时 #else //否则UCOSII OSSchedLock(); //UCOSII的方式,禁止调度,防止打断us延时 #endif } //us级延时时,恢复任务调度 void delay_osschedunlock(void) { #ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII OS_ERR err; OSSchedUnlock(&err); //UCOSIII的方式,恢复调度 #else //否则UCOSII OSSchedUnlock(); //UCOSII的方式,恢复调度 #endif } //调用OS自带的延时函数延时 //ticks:延时的节拍数 void delay_ostimedly(u32 ticks) { #ifdef CPU_CFG_CRITICAL_METHOD OS_ERR err; OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时采用周期模式 #else OSTimeDly(ticks); //UCOSII延时 #endif } //systick中断服务函数,使用ucos时用到 void SysTick_Handler(void) { if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理 { OSIntEnter(); //进入中断 OSTimeTick(); //调用ucos的时钟服务程序 OSIntExit(); //触发任务切换软中断 } } #endif //初始化延迟函数 //当使用OS的时候,此函数会初始化OS的时钟节拍 //SYSTICK的时钟固定为HCLK时钟的1/8 //SYSCLK:系统时钟 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 } #if SYSTEM_SUPPORT_OS //如果需要支持OS. //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 ticks; u32 told,tnow,tcnt=0; u32 reload=SysTick->LOAD; //LOAD的值 ticks=nusfac_us; //需要的节拍数 tcnt=0; delay_osschedlock(); //阻止OS调度,防止打断us延时 told=SysTick->VAL; //刚进入时的计数器值 while(1) { tnow=SysTick->VAL; if(tnow!=told) { if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了. else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出. } }; delay_osschedunlock(); //恢复OS调度 } //延时nms //nms:要延时的ms数 void delay_ms(u16 nms) { if(delay_osrunning&&delay_osintnesting==0) //如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度) { if(nms>=fac_ms) //延时的时间大于OS的最少时间周期 { delay_ostimedly(nms/fac_ms); //OS延时 } nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时 } delay_us((u32)(nms1000)); //普通方式延时 } #else //不用OS时 //延时nus //nus为要延时的us数. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nusfac_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<=0xffffff81000/SYSCLK //SYSCLK单位为Hz,nms单位为ms //对72M条件下,nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nmsfac_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; //清空计数器 } #endif 现在的代码小车在避障后就会进入旋转的死循环

//配置PWM.c文件 #include "stm32f10x.h" // Device header #include "PWM.h" void PWM_Init(void) //初始化PWM { RCC_APB1PeriphClockCmd(PWM_TIM_PORT_CLK, ENABLE); //打开时钟 RCC_APB2PeriphClockCmd(PWM_GPIO_PORT_CLK, ENABLE); //开启时钟 //初始化ENA ENB GPIO GPIO_InitTypeDef GPIO_InitStruture; GPIO_InitStruture.GPIO_Mode = GPIO_Mode_AF_PP; //只有在复用情况下,片上外设才能控制PWM GPIO_InitStruture.GPIO_Pin = PWM_GPIO1_Pin; GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(PWM_GPIO1_PORT, &GPIO_InitStruture); GPIO_InitStruture.GPIO_Pin = PWM_GPIO2_Pin; GPIO_Init(PWM_GPIO2_PORT, &GPIO_InitStruture); TIM_InternalClockConfig(PWM_TIM); //选择内部时钟 //初始化时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseIniture; TIM_TimeBaseIniture.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseIniture.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseIniture.TIM_Period = 100 - 1; //ARR TIM_TimeBaseIniture.TIM_Prescaler = 7200 - 1; //PSC TIM_TimeBaseIniture.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(PWM_TIM, &TIM_TimeBaseIniture); //初始化输出比较单元 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); //给结构体赋初始值,防止多路PWM输出通道不能输出 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较模式 PWM模式1 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置输出比较的极性 有效电平为高电平 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能 TIM_OCInitStructure.TIM_Pulse = 0; //设置CCR TIM_OC1Init(PWM_TIM, &TIM_OCInitStructure); //PA6 TIM_OC1PreloadConfig(PWM_TIM, TIM_OCPreload_Enable); TIM_OC2Init(PWM_TIM, &TIM_OCInitStructure); //PA7 TIM_OC2PreloadConfig(PWM_TIM, TIM_OCPreload_Enable); TIM_OC3Init(PWM_TIM, &TIM_OCInitStructure); //PB0 TIM_OC3PreloadConfig(PWM_TIM, TIM_OCPreload_Enable); TIM_OC4Init(PWM_TIM, &TIM_OCInitStructure); //PB1 TIM_OC4PreloadConfig(PWM_TIM, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(PWM_TIM, ENABLE); //启动定时器 TIM_Cmd(PWM_TIM, ENABLE); } //void PWM_SetPrescaler(uint16_t Prescaler) //{ // TIM_PrescalerConfig(PWM_TIM,Prescaler,TIM_PSCReloadMode_Immediate); //} void PWM_SetCompare4(uint16_t Compare) { TIM_SetCompare4(PWM_TIM, Compare); } void PWM_SetCompare3(uint16_t Compare) { TIM_SetCompare3(PWM_TIM, Compare); } void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(PWM_TIM, Compare); } void PWM_SetCompare2(uint16_t Compare) { TIM_SetCompare2(PWM_TIM, Compare); } /***********************************************/ //配置pwm.h #ifndef _PWM_H #define _PWM_H void PWM_Init(void); //void PWM_SetPrescaler(uint16_t Prescaler); void PWM_SetCompare1(uint16_t Compare); void PWM_SetCompare2(uint16_t Compare); void PWM_SetCompare3(uint16_t Compare); void PWM_SetCompare4(uint16_t Compare); #define PWM_GPIO_PORT_CLK RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB #define PWM_TIM_PORT_CLK RCC_APB1Periph_TIM3 #define PWM_GPIO1_PORT GPIOA #define PWM_GPIO1_Pin GPIO_Pin_6|GPIO_Pin_7 #define PWM_GPIO2_PORT GPIOB #define PWM_GPIO2_Pin GPIO_Pin_0|GPIO_Pin_1 #define PWM_TIM TIM3 #endif /***********************************************/ //配置motor.c #include "stm32f10x.h" // Device header #include "Motor.h" #include "PWM.h" void Motor_Init(void) { RCC_APB2PeriphClockCmd(MOTOR_GPIO_PORT1_CLK, ENABLE); //开启时钟 RCC_APB2PeriphClockCmd(MOTOR_GPIO_PORT2_CLK, ENABLE); //初始化GPIO GPIO_InitTypeDef GPIO_InitStruture; GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruture.GPIO_Pin = MOTOR_GPIO1_Pin; GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(MOTOR_GPIO1_PORT, &GPIO_InitStruture); //初始化GPIO GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruture.GPIO_Pin = MOTOR_GPIO2_Pin; GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(MOTOR_GPIO2_PORT, &GPIO_InitStruture); } //Dir = 1 正转 //Dir = 0 反转 void Motor1_SetSpeed(uint8_t Dir, uint16_t Speed) { if (Speed > 1000) Speed = 1000; if (Dir) { GPIO_SetBits(GPIOA, GPIO_Pin_0); GPIO_ResetBits(GPIOA, GPIO_Pin_1); PWM_SetCompare1(Speed); } else if (! Dir) { GPIO_SetBits(GPIOA, GPIO_Pin_1); GPIO_ResetBits(GPIOA, GPIO_Pin_0); PWM_SetCompare1(Speed); } } void Motor2_SetSpeed(uint8_t Dir, uint16_t Speed) { if (Speed > 1000) Speed = 1000; if (Dir) { GPIO_SetBits(GPIOA, GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_2); PWM_SetCompare2(Speed); } else if (! Dir) { GPIO_SetBits(GPIOA, GPIO_Pin_2); GPIO_ResetBits(GPIOA, GPIO_Pin_3); PWM_SetCompare2(Speed); } } void Motor3_SetSpeed(uint8_t Dir, uint16_t Speed) { if (Speed > 1000) Speed = 1000; if (Dir) { GPIO_SetBits(GPIOB, GPIO_Pin_9); GPIO_ResetBits(GPIOB, GPIO_Pin_8); PWM_SetCompare3(Speed); } else if (! Dir) { GPIO_SetBits(GPIOB, GPIO_Pin_8); GPIO_ResetBits(GPIOB, GPIO_Pin_9); PWM_SetCompare3(Speed); } } void Motor4_SetSpeed(uint8_t Dir, uint16_t Speed) { if (Speed > 1000) Speed = 1000; if (Dir) { GPIO_SetBits(GPIOB, GPIO_Pin_6); GPIO_ResetBits(GPIOB, GPIO_Pin_7); PWM_SetCompare4(Speed); } else if (! Dir) { GPIO_SetBits(GPIOB, GPIO_Pin_7); GPIO_ResetBits(GPIOB, GPIO_Pin_6); PWM_SetCompare4(Speed); } } void Car_Stop(void) { Motor1_SetSpeed(1, 0); Motor2_SetSpeed(1, 0); Motor3_SetSpeed(1, 0); Motor4_SetSpeed(1, 0); } void Car_Forward(uint16_t Speed) { Motor1_SetSpeed(1, Speed); Motor2_SetSpeed(1, Speed); Motor3_SetSpeed(1, Speed); Motor4_SetSpeed(1, Speed); } void Car_Backward(uint16_t Speed) { Motor1_SetSpeed(0, Speed); Motor2_SetSpeed(0, Speed); Motor3_SetSpeed(0, Speed); Motor4_SetSpeed(0, Speed); } void Car_TurnLeft(uint16_t Speed) { Motor1_SetSpeed(0,Speed); Motor2_SetSpeed(1,Speed); Motor3_SetSpeed(1,Speed); Motor4_SetSpeed(0,Speed); } void Car_TurnRight(uint16_t Speed) { Motor1_SetSpeed(1,Speed); Motor2_SetSpeed(0,Speed); Motor3_SetSpeed(0,Speed); Motor4_SetSpeed(1,Speed); } void Car_TransLeft(uint16_t Speed) { Motor1_SetSpeed(1,Speed); Motor2_SetSpeed(0,Speed); Motor3_SetSpeed(1,Speed); Motor4_SetSpeed(0,Speed); } void Car_TransRight(uint16_t Speed) { Motor1_SetSpeed(0,Speed); Motor2_SetSpeed(1,Speed); Motor3_SetSpeed(0,Speed); Motor4_SetSpeed(1,Speed); } /***********************************************/ #ifndef _MOTOR_H #define _MOTOR_H void Motor_Init(void); void Motor1_SetSpeed(uint8_t Dir, uint16_t Speed); void Motor2_SetSpeed(uint8_t Dir, uint16_t Speed); void Motor3_SetSpeed(uint8_t Dir, uint16_t Speed); void Motor4_SetSpeed(uint8_t Dir, uint16_t Speed); void Car_Stop(void); void Car_Forward(uint16_t Speed); void Car_Backward(uint16_t Speed); void Car_TurnLeft(uint16_t Speed); void Car_TurnRight(uint16_t Speed); void Car_TransLeft(uint16_t Speed); void Car_TransRight(uint16_t Speed); #define MOTOR_GPIO_PORT1_CLK RCC_APB2Periph_GPIOA #define MOTOR_GPIO1_PORT GPIOA #define MOTOR_GPIO1_Pin GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3 #define MOTOR_GPIO_PORT2_CLK RCC_APB2Periph_GPIOB #define MOTOR_GPIO2_PORT GPIOB #define MOTOR_GPIO2_Pin GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9 #endif /***********************************************/ Void Serial_Init(){ // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // // GPIO_InitTypeDef GPIO_InitStructure; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOA, &GPIO_InitStructure); } if(strstr((const char*)RxData, "U") != 0) { Car_Forward(100); } else if(strstr((const char*)RxData, "D") != 0 ) { Car_Backward(100); } else if(strstr((const char*)RxData, "L") != 0 ) { Car_TurnLeft(500); } else if(strstr((const char*)RxData, "L") != 0 ) { Car_TurnRight(500); } else if(strstr((const char*)RxData, "S") != 0 ) { Car_Stop(); } memset(RxData,0,100); RxSTA = 1; } } /*********************************************************/ #include "sys.h" #include "usart1.h" u8 USART2_RX_BUF[USART2_REC_LEN]; //接收缓冲,最大USART2_REC_LEN个字节. //bit13~0, 接收到的有效字节数目 u16 USART2_RX_STA=0; //接收状态标记 void uart1_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART1_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //USART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART1_BaudRate = 9600;//串口波特率 USART_InitStructure.USART1_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART1_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART1_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART1_HardwareFlowControl = USART1_HardwareFlowControl_None;//无硬件数据流控制 USART_InitStructure.USART1_Mode = USART_Mode_Rx USART_Init(USART1, &USART1_InitStructure); //初始化串口1 USART_ITConfig(USART1, USART1_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE); //使能串口1 } //串口2发送一个字节 void Usart1_ReceiveData(USART1_InitStructure, USART1) { USART1_ReceiveData(USART2, val); while (USART1_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成 } //串口2发送一个数据包 void Usart1_ReceiveData_Buf(u8 *buf,u8 len) { while(len--) Usart2_ReceiveData_Byte(*buf++); } //串口2发送一个字符串 void Usart1_ReceiveData_String(u8 *str) { while(*str!='\0') Usart2_SendByte(*str++); } void USART1_IRQHandler(void) //串口1中断服务程序 接受 { u8 Res2; if(USART1_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a 回车换行结尾) { Res2 =USART_ReceiveData(USART1); //读取接收到的数据 if((USART1_RX_STA&0x8000)==0)//接收未完成 { if(USART1_RX_STA&0x4000)//接收到了0x0d { if(Res2!=0x0a)USART2_RX_STA=0;//接收错误,重新开始 else USART1_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(Res2==0x0d)USART1_RX_STA|=0x4000; else { USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res2 ; USART1_RX_STA++; if(USART1_RX_STA>(USART2_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收 } } } } } /*******************************************************************/ //main.c #include "stm32f10x.h" // Device header #include "Delay.h" //#include "OLED.h" #include "sys.h" // Device header #include "serial.h" // Device header #include "string.h" // Device header //#include "ESP01.h" #include "usart1.h" #include "PWM.h" #include "Motor.h" int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); PWM_Init(); Motor_Init(); OLED_Init(); HC05_Init(); // Car_Forward(50); // Delay_ms(5000); // Car_Backward(500); // Delay_ms(5000); //Car_TurnLeft(500); //Delay_ms(5000); // Car_TurnRight(500); // Delay_ms(5000); // Car_TransLeft(500); // Delay_ms(5000); // Car_TransRight(500); // Car_Stop(); // uart2_init(115200); //串口初始化为115200 // ESP01_Init(); //OLED_ShowString(1, 1, "RxData:"); //OLED_ShowString(2, 1, RxData); while (1) { Void Serial_Init(); // ESP01_proc(); } } 更正上面代码,利用电脑串口助手软件向蓝牙模块HC08连接的单片机发送命令,完成两个L298N模块并联控制4个电机的遥控小车项目。单片机作为接收端,当接收到字符或文本“D”时,小车前进;当接收到字符或文本“D”时,小车后退;当接收到字符或文本“L”时,小车左转;当接收到字符或文本“R”时小车右转;当接收到字符或文本“S”时,小车停止。要求Motor.c文件引用下面宏定义:#define IN1_PIN GPIO_Pin_9 // PB9 #define IN2_PIN GPIO_Pin_8 // PB8 #define IN3_PIN GPIO_Pin_7 // PB7 #define IN4_PIN GPIO_Pin_6 // PB6 #define IN5_PIN GPIO_Pin_0 // PA0 #define IN6_PIN GPIO_Pin_1 // PA1 #define IN7_PIN GPIO_Pin_2 // PA2 #define IN8_PIN GPIO_Pin_3 // PA3 ;要求PWM.c;main.c;USART1.c;Motor.c 函数分别独立封装

#include "stm32f10x.h" // Device header #include "PID.h" #include "mycontrol.h" #include "Trace.h" #include "PWM.h" // 初始化 PID 结构体 void PID_Init(PID_TypeDef *pid) { pid->Kp = 0.0f; pid->Ki = 0.0f; pid->Kd = 0.0f; pid->Error = 0.0f; pid->LastError = 0.0f; pid->Integral = 0.0f; pid->SetPoint = 0.0f; pid->Output = 0.0f; } //位置PID算法// void PID_Calc(PID_TypeDef *pid, float CurrentValue) { // 1. 计算当前误差 pid->Error = pid->SetPoint - CurrentValue; // 2. 计算积分项 (带积分限幅,防止积分饱和) pid->Integral += pid->Error; if (pid->Integral > 3000) pid->Integral = 3000; if (pid->Integral < -3000) pid->Integral = -3000; // 3. 计算微分项 float derivative = pid->Error - pid->LastError; // 4. 计算总输出 pid->Output = (pid->Kp * pid->Error) + (pid->Ki * pid->Integral) + (pid->Kd * derivative); // 5. 更新上次误差 pid->LastError = pid->Error; } #include "stm32f10x.h" // Device header #include "Delay.h" #include "Motor.h" #include "Trace.h" #include "mycontrol.h" #include "PWM.h" #include "OLED.h" #include "Timer.h" #include "Encoder.h" #include "PID.h" int16_t LiftSpeed; int16_t RightSpeed; uint16_t Compare3=0;//控制右侧电机 uint16_t Compare4=0;//控制左侧电机 #ifndef PID_H #define PID_H typedef struct { float Kp; float Ki; float Kd; float Error; float LastError; float Integral; float SetPoint; float Output; } PID_TypeDef; PID_TypeDef pid_controller; void PID_Init(PID_TypeDef *pid); void PID_Calc(PID_TypeDef *pid, float CurrentValue); float calculate_weighted_error(void); #endif#include "stm32f10x.h" // Device header #include "Delay.h" #include "Trace.h" #include "Motor.h" #include "PWM.h" #include "PID.h" #define PWM_COMPARE_MIN 0 // 定义PWM比较值的上下限(0~900) #define PWM_COMPARE_MAX 450 int right_base_speed = 56; // 右轮基础速度(起码能动) int lift_base_speed = 70; // 左轮基础速度(起码能动) int value=0; void Trace_task(void) { //0是亮灯检测到黑线,1是灭灯没检测到黑线 //Compare3控制右侧电机,Compare4控制左侧电机,跟据CCR3和CCR4的比较值来写Compare3和Compare4的值 //基准,最低56,70 if(X1==1&&X2==1&&X3==1&&(X4==0||X5==0)&&X6==1&&X7==1&&X8==1) //直走 { // PWM_SetCompare3(65); // PWM_SetCompare4(79); PWM_SetCompare3(right_base_speed + pid_controller.Output);//控制右侧电机的转速 PWM_SetCompare4(lift_base_speed - pid_controller.Output);//控制左侧电机的转速 void Limit_set_pwm_compare(void); } else if((X1==0 || X2==0 || X3==0) &&X6==1&&X7==1&&X8==1) //左拐 { if(X1==1&& (X2==0||X3==0))//中小拐 右83,左93 最低56,70 { // PWM_SetCompare3(105); // PWM_SetCompare4(70); PWM_SetCompare3(right_base_speed + pid_controller.Output);//控制右侧电机的转速 PWM_SetCompare4(lift_base_speed - pid_controller.Output);//控制左侧电机的转速 void Limit_set_pwm_compare(void); } if(X1==0)//大中拐 { // PWM_SetCompare3(115); // PWM_SetCompare4(70); PWM_SetCompare3(right_base_speed + pid_controller.Output);//控制右侧电机的转速 PWM_SetCompare4(lift_base_speed - pid_controller.Output);//控制左侧电机的转速 void Limit_set_pwm_compare(void); } } else if(X1==1 && X2==1 && X3==1 &&(X6==0||X7==0||X8==0)) //右拐 右83,左93 最低56,70 { if(X8==1&&(X6==0||X7==0))//中小拐 { // PWM_SetCompare3(56); // PWM_SetCompare4(105); PWM_SetCompare3(right_base_speed + pid_controller.Output);//控制右侧电机的转速 PWM_SetCompare4(lift_base_speed - pid_controller.Output);//控制左侧电机的转速 void Limit_set_pwm_compare(void); } if(X8==0)//大中拐 { // PWM_SetCompare3(56); // PWM_SetCompare4(125); PWM_SetCompare3(right_base_speed + pid_controller.Output);//控制右侧电机的转速 PWM_SetCompare4(lift_base_speed - pid_controller.Output);//控制左侧电机的转速 void Limit_set_pwm_compare(void); } } else if(X1==0&&X2==0&&X3==0&&X4==0&&X5==0&&X6==0&&X7==0&&X8==0) { PWM_SetCompare3(0); PWM_SetCompare4(0); } else if(X1==1&&X2==1&&X3==1&&X4==1&&X5==1&&X6==1&&X7==1&&X8==1) { PWM_SetCompare3(0); PWM_SetCompare4(0); } }单单看这几个模块,问题出在哪 int main(void) { Timer1_Init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); PWM_Init(); Motor_DIR_Init(); OLED_Init(); Trace_Init(); extern PID_TypeDef pid_controller; // 在初始化代码中设置Kp, Ki, Kd... pid_controller.Kp = 0.8; pid_controller.Ki = 0.01; pid_controller.Kd = 0.3; pid_controller.SetPoint = 0; Lift_Encoder_Init(); Right_Encoder_Init(); OLED_ShowString(1 , 1 , "LiftSpeed:"); OLED_ShowString(2 , 1 , "RightSpeed:"); while (1) { OLED_ShowSignedNum(1 , 7, LiftSpeed, 5); OLED_ShowSignedNum(2 , 8, RightSpeed, 5); // 1. 读取传感器,计算加权平均误差值 float current_error = calculate_weighted_error(); // 2. 调用PID计算函数 PID_Calc(&pid_controller, current_error); // 3. 根据PID输出调整电机速度,设置左右轮PWM_Compare (带限速保护) Trace_task(); // 延时一小段时间,确定控制周期 Delay_ms(10); } }

最新推荐

recommend-type

lexruntimev2-jvm-1.0.43.jar

lexruntimev2-jvm-1.0.43.jar
recommend-type

snowball-1.2.46-javadoc.jar

snowball-1.2.46-javadoc.jar
recommend-type

popkorn-macosx64-2.3.1-javadoc.jar

popkorn-macosx64-2.3.1-javadoc.jar
recommend-type

qbusiness-jvm-1.2.55-sources.jar

qbusiness-jvm-1.2.55-sources.jar
recommend-type

Flash动画制作基础与应用:从操作到企业宣传动画实战

资源摘要信息: Flash动画制作作为模块四的核心内容,涵盖了从基础操作到高级动画制作技巧的完整教学体系。本教学文档主要分为四个任务模块,分别对应不同的学习阶段和实践目标,旨在通过“教、学、做一体”的教学方法,使学习者逐步掌握Flash动画制作的核心技能。 任务一主要聚焦于Flash软件的基本操作和简单动画效果的实现。教学目标明确指出,学生需要认识Flash软件的功能与基本操作界面,包括菜单栏、常用工具栏、绘图工具栏、图层区、时间轴以及各类设置面板。此外,还需要了解库、元件、场景、帧、关键帧等核心概念。这些概念构成了Flash动画制作的理论基础:库是存储元件的容器,元件是可重复使用的对象,场景是动画展示的舞台,时间轴则负责组织和控制动画的时间流程,而帧和关键帧则是构成动画时间线的基本单位。教学内容涵盖了文档属性的设置、外部对象的导入方法、基本图形的绘制技巧,以及简单的动作动画制作,最终还包括文件的保存与影片的导出流程。通过任务一的学习,学生可以初步掌握如何在Flash中构建动画的基本框架。 任务二深入讲解了动画制作的多种类型与实现方式,具体包括逐帧动画、运动渐变动画、形状补间动画以及遮罩效果的制作。逐帧动画是最基础的动画形式,通过连续播放多个关键帧来实现动画效果,适用于细节要求较高的动画场景;而运动渐变动画和形状补间动画则属于补间动画的范畴,只需设置起始和结束关键帧,中间的变化由软件自动计算完成,大大提升了动画制作的效率。遮罩效果则是一种高级动画技巧,常用于制作动态遮挡、图像切换等视觉效果,增强了动画的表现力。通过任务二的实践操作,学生将掌握多种动画类型的制作方法,并能够根据实际需求选择合适的动画技术进行创作。 任务三与任务四则侧重于实际项目的应用,分别聚焦于企业宣传动画和商品推广动画的制作。教学设计中强调了动画在宣传与展示中的重要作用,例如提升视觉吸引力、传递企业文化和推广商品等。在任务三中,学生将学习如何将企业理念、产品特色与动画艺术结合,通过动画的形式进行企业形象的宣传。任务四则进一步拓展至电商领域,引导学生掌握如何制作具有营销效果的商品推广动画,包括如何将商品特性通过动画形式生动呈现,吸引潜在消费者的注意力。这两个任务不仅强调技术实现,更注重创意表达与视觉传达能力的培养,使学生能够综合运用所学知识,完成具有实际应用价值的动画作品。 在课程引入部分,详细阐述了网页的构成元素,如文本、表格、图片、图表和动画等,并解释了动画为何能够“动”的原理——即通过连续播放一系列基于时间顺序的静态画面,利用人眼的视觉暂留现象,形成连续变化的动态效果。教学内容还比较了二维动画与三维动画的区别,以及逐帧动画与补间动画的技术特点,帮助学生理解不同动画形式的应用场景。同时,动画的作用也被明确指出,包括美观直观的视觉呈现、有效的宣传展示功能以及吸引受众注意力等。 关于Flash软件的功能介绍,文档强调其作为一款功能强大且易于学习的动画制作工具,具备多种优势。例如,使用Flash制作的动画不仅文件体积小,而且画质高,无论放大或缩小均不影响画面清晰度。该软件主要支持补间动画制作,即只需设定起始与结束画面,中间过渡由软件自动处理生成,极大地提高了制作效率。此外,Flash还支持交互功能,用户可通过点击按钮、选择菜单等方式控制动画播放,甚至可以制作成互动小游戏。在网络应用方面,Flash动画支持边下载边播放的功能,适应了网络传输的需求。 Flash的软件界面由多个功能区域组成,包括菜单栏、常用工具栏、绘图工具栏、图层区、时间轴和各类设置面板。文档属性设置涉及画布尺寸、背景颜色等基本参数。元件作为动画中的“演员”,包括图片、文字等可重复使用的对象,统一存储在库中,使用时拖放至场景即可。场景是动画实际呈现的舞台,时间轴则作为动画的“剧本”,通过帧的组织与排列控制动画的播放顺序。通过系统的学习,学生可以掌握Flash软件的完整操作流程,并能够独立完成从构思到实现的动画制作全过程。 综上所述,该教学文档全面覆盖了Flash动画制作的基础知识、核心技术以及实际应用案例,通过任务驱动的教学模式,引导学生逐步掌握动画制作的各项技能,并具备将所学知识应用于企业宣传与商品推广等实际场景的能力。
recommend-type

模型量化深度解析:将浮点模型压缩为8位整数的完整技术路径

# 1. 模型量化的背景与核心价值 随着深度学习模型规模持续膨胀,从BERT到GPT系列,参数量动辄数十亿,传统浮点推理已难以满足边缘设备对延迟、功耗和存储的严苛要求。模型量化应运而生,成为工业界落地AI的关键使能技术。其核心思想是将高精度浮点权重与激活值映射为低比特整数(如INT8),在几乎不损失精度的前提下,显著压缩模型体积、提升推理速度并降低计算能耗。 量化不仅适用于云端大
recommend-type

milvus 向量数据库如何加在collection

### 如何在 Milvus 向量数据库中加载 Collection 在 Milvus 向量数据库中,`Collection` 是数据存储的核心结构之一。为了能够对 `Collection` 执行搜索或其他操作,必须先将其加载到内存中。以下是有关如何加载 `Collection` 的详细说明: #### 1. 加载 Collection 前的准备 在加载 `Collection` 之前,需要确保已经完成了以下准备工作: - 创建了一个有效的 `Collection` 并插入了数据[^2]。 - 安装并配置好了 Milvus Python SDK (`pymilvus`) 或其他支持的语言
recommend-type

我国国际贸易中电子商务的发展现状与挑战分析

资源摘要信息:"电子商务在国际贸易实践中的应用与挑战" 随着信息技术的迅猛发展,电子商务在全球范围内逐渐成为推动国际贸易发展的重要引擎。电子商务作为新型的商业运作模式,不仅改变了传统贸易的交易方式,还深刻影响了全球经济结构和企业运营模式。本文以我国的电子商务在国际贸易中的实际应用为基础,深入探讨了其发展现状、存在问题及未来发展方向,为推动我国电子商务在国际贸易领域的进一步发展提供了理论支持和实践指导。 首先,电子商务在国际贸易中的应用为我国外贸体系注入了新的活力。根据文中引用的北京互联网发展中心(BIDC)在第87届中国出口商品交易会上进行的调查数据,我国出口企业在电子商务的应用方面呈现出显著的增长趋势。调查结果显示,4.5%的出口企业已经广泛开展电子商务,31.2%的企业处于初步应用阶段,28.7%的企业已着手准备开展,另有12.0%的企业已有相关考虑,仅有23.6%的企业尚未涉足。这一数据充分表明,我国出口企业在电子商务领域的发展潜力巨大,越来越多的企业开始意识到电子商务在拓展国际市场、提升交易效率和降低运营成本方面的优势。 阿里巴巴等外贸电商平台的兴起,进一步推动了我国企业参与全球贸易的深度和广度。大量企业在该平台注册并开展外贸业务,配备了专门的外贸业务员进行线上交易操作,这标志着我国外贸企业正逐步向数字化、智能化方向转型。这种转型不仅提高了企业的国际竞争力,也为我国整体外贸体系的升级提供了支撑。 然而,尽管电子商务在我国国际贸易中展现出良好的发展态势,仍存在诸多问题亟待解决。首先,公众对电子商务的认知程度仍有待提高。许多企业尤其是中小型企业对电子商务的理解仍停留在表面阶段,缺乏系统的战略规划和专业人才支持,这在一定程度上限制了其在国际贸易中的有效应用。 其次,国际标准与协议的参与度不足。文中提到,1997年6月,国际标准化组织(ISO/IEC JTC1)成立了电子商务业务工作组(BT-EC),并明确了电子商务标准化的三个重点领域:用户接口、基本功能以及数据与客体的定义与编码。虽然这些标准的制定为全球电子商务的发展提供了基础框架,但我国在国际标准制定中的参与度和影响力相对较低,这在一定程度上影响了我国企业在全球电子商务体系中的话语权。 此外,关键技术的研发与应用滞后也是我国电子商务在国际贸易中面临的重要挑战。当前,信息技术主要被发达国家所垄断,其在技术输出方面设置了诸多壁垒,严格控制核心技术向我国的转移。这种技术垄断现象严重制约了我国企业在电子商务领域的自主创新能力,影响了我国在全球电子商务产业链中的地位提升。 法律与制度环境的不完善也是电子商务在国际贸易中应用受限的重要因素。目前,我国及许多国家尚未在法律层面承认电子文件的法律效力。根据我国及各国票据法的规定,具有法律效力的签字必须由法定负责人亲自手书签署,而电子商务交易中的电子签名难以满足这一要求。此外,还存在因网络系统故障导致的电子文件错误的法律责任归属问题、电子数据与网上信息的证据效力问题、以及电子商务交易中的国际商事仲裁问题等。这些问题的存在,增加了企业在电子商务交易中的法律风险,阻碍了其在国际贸易中的广泛应用。 针对上述问题,文章提出了若干应对策略。首先是提高公众对电子商务的认知水平,通过政策引导和教育培训,增强企业对电子商务战略价值的理解和应用能力;其次是积极参与国际公约和贸易伙伴协议,提升我国在国际电子商务标准制定中的话语权;再次是加大关键技术的研发投入,提升我国在电子商务核心技术领域的自主创新能力;最后是完善电子商务相关法律法规体系,推动电子签名、电子合同等电子文件的法律认可,为电子商务在国际贸易中的健康发展提供坚实的法律保障。 综上所述,电子商务作为现代国际贸易的重要推动力量,其发展不仅关系到企业的国际竞争力,也对我国整体外贸体系的现代化进程具有深远影响。尽管当前我国在电子商务应用于国际贸易的过程中面临诸多挑战,但通过加强公众认知、提升技术研发能力、积极参与国际标准制定以及完善相关法律制度,我国有望在全球电子商务体系中占据更加有利的位置,从而实现外贸领域的高质量发展。
recommend-type

低功耗采样设计艺术:精准平衡精度与能耗的4大原则

# 1. 低功耗采样设计的核心挑战与系统视角 在物联网、可穿戴设备与边缘传感系统中,低功耗采样设计已成为能效优化的核心环节。传统奈奎斯特采样往往造成能量浪费,尤其在信号稀疏或缓变场景下,持续高率采样显著拉高系统功耗。真正的挑战不仅在于降低ADC工作频率,更在于构建一个从信号特性感知、采样策略动态
recommend-type

短作业优先调度算法头哥答案

### 短作业优先调度算法(SJF)概述 短作业优先调度算法(Shortest Job First, SJF)是一种基于作业长度的调度策略,其核心思想是优先处理预计运行时间较短的任务。这种算法可以显著减少平均等待时间,从而提升系统整体性能[^1]。 在数据结构方面,SJF通常依赖于队列或堆栈来管理待处理任务列表。为了实现该算法,需维护一个按预期完成时间排序的任务集合,并动态更新此集合中的元素顺序。以下是SJF的一些关键特性: - **优点**:能够最小化平均周转时间,适合批处理环境下的资源分配。 - **缺点**:可能导致较长任务被无限期延迟(饥饿现象),除非引入额外机制解决公平性问题[