《基于STM32的红外避障小车》

您所在的位置:网站首页 小车避障功能的实现 《基于STM32的红外避障小车》

《基于STM32的红外避障小车》

2024-07-09 09:06| 来源: 网络整理| 查看: 265

文章目录 前言1、项目简介2、硬件准备3 设计图4 各个模块介绍4.1 主控芯片STM32F103VET6介绍4.2 L298N直流电机驱动模块模块介绍模块原理 4.3 红外传感器 5 具体连接6 效果展示及改进建议实物展示:改进建议 7 源码展示`bsp_exti.c``bsp_exti.h``bsp_led.c``bsp_led.h``bsp_l2980n.c``bsp_l2980n.h``stm32f10x_it.c``main.c`

前言

本文主要讲解基于STM32的红外避障小车的实现(标准库)

1、项目简介

基于stm32实现的一个简单智能避障小车,具有“直行”、转弯、“避障”的功能。 直行、转弯:基于stm32的通用定时器TIM3输出PWM方波信号实现 避障:使用到stm32的外部中断以及通用定时器(使用红外中断),代码编写使用STM32F1的标准库

具体执行流程:红外传感器作为外部输入,它的OUT引脚默认输出高电平,当检测到障碍物时OUT引脚会输出低电平,因此会有一个高电平到低电平的变化,我们称之为“下降沿”。因此我们可以把stm32设置为“下降沿”触发外部中断这样一种机制,因此,当红外对管检测到障碍物时,stm32会被触发中断,由于我们在小车的左右两边都安装了一红外接口,当左边检测到障碍物时候,执行右转直到转弯完成,同理当右边检测到障碍物时候,执行左转直到转弯完成。最终完成避障功能

2、硬件准备

1、stm32f103vet6指南者开发板一块,用作主控芯片(这个学习用的开发板,建议后期用最小系统板子,例如stm32f103c8t6) 2、带编码盘的直流电机两个,编码盘在本项目里面没啥用 3、直流电机驱动模块(L298N直流电机驱动模块) 4、红外避障传感器(两个) 5、转向轮一个、塑料轮子两个 6、18650电池两节和电池盒(用作电源,需要降压到5V) 7、铜柱、螺丝螺母、杜邦线若干 8、电烙铁(用于后续焊接)

3 设计图

在这里插入图片描述

1:电源采用两节18650电池供电,每节4.2V,确保足够驱动两个电机,连接电机驱动模块的12V输入 2:由于STM32的要求输入的电压有限制,只允许输入电压是3.3或者5V的,因此需要采用降压模块LM2596S1将电压降到5V才可以连接到开发板上。但是由于L2980N又5V的电压输出口,因此直接将5V的电压输出口连接开发板即可 3:之后开发板通过通用定时器输出4路PWM方波信号连接电机驱动模块(L2980N),通过编写代码调整占空比对小车实现差速控制。

4 各个模块介绍 4.1 主控芯片STM32F103VET6介绍

stm32f103vet6芯片具有功能各异且可复用的100个引脚并集成了如USART(通用同步/异步串行接收/发送器)、I2C (I2C总线) 和SPI (串行外设接口)等常用通信接口,可用于外接各种传感器和执行器以控制其他设备。本项目主要用到外部中断和定时器。 在这里插入图片描述

4.2 L298N直流电机驱动模块 模块介绍

在这里插入图片描述

依次介绍每个部分:从左至右,由上到下, 1、输出A:可以看到输出A和B都有两个螺丝接线,每个正好接马达的正负,如何判断是哪个是正呢?正对输出口的右边是正。 2、板载5v使能:这是个跳线帽,可选项,接上表示不用5v供电,如果拔掉的话就需要5v供电了; 3、12v供电:这个供电是必须的,我用的是两节18650充电电池。 4、供电GND:这个不用说,就是电池的负极,注意这里,单片机的GND也需要连接这个,否则马达不会转动。 5、5v供电:这个也可以作为输出口,为我们的单片机来供电。 6、通道A使能:这个是使能输出A的,也要跳线帽连接,否则A侧马达不转,个人觉得没有什么用。 7、通道B使能:同A 8、逻辑输入:这里的逻辑输入有4个引脚:IN1,IN2.IN3,IN4,由这些引脚的电平状态来控制两个马达的正转,反转,停止。详细的介绍见下表。 9、输出B:同输出A。

在这里插入图片描述 注意:我的l298n黑色部分靠近车头,得出的表格

模块原理

我们想让小车前进,转向,后退,那么就需要单片机控制这四个IN引脚的高低实现我们想要的功能。由于我使用的是通用定时器,使用定时器输出了四路PWM方波信号,分别接在IN1,IN2,IN3和IN4上,通过调节占空比实现车子的前进后退和转弯,例如要实现左转弯,则轮子倒转,右轮子正转,反之则为右转。总之,PWM主要就是用来调速的。

代码如下:

void TIM3_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructer; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructer; TIM_OCInitTypeDef TIM_OCInitStructer; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); //初始化TIM3 TIM_TimeBaseStructer.TIM_Period = 899; TIM_TimeBaseStructer.TIM_Prescaler = 0; TIM_TimeBaseStructer.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructer.TIM_ClockDivision = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructer); //初始化GPIOC6/GPIOC7 (TIM3_CH1/TIM3_CH2) GPIO_InitStructer.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructer.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructer); //初始化GPIOC8/GPIOC9 (TIM3_CH3/TIM3_CH4) GPIO_InitStructer.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructer.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructer); //PWM通道一 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC1Init(TIM3, &TIM_OCInitStructer); //Enables or disables the TIMx peripheral Preload register on CCR1. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道二 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC2Init(TIM3, &TIM_OCInitStructer); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道三 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC3Init(TIM3, &TIM_OCInitStructer); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道四 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC4Init(TIM3, &TIM_OCInitStructer); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); } //前进 void Go_Forward(void) { //Sets the TIMx Capture Compare1 Register value TIM_SetCompare1(TIM3, 300); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 300); TIM_SetCompare4(TIM3, 900); } //停止 void Stop(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 900); } //后退 void Go_Back(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 300); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 300); } //左转 void Turn_Left(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 350); TIM_SetCompare3(TIM3, 350); TIM_SetCompare4(TIM3, 900); } //右转 void Turn_Right(void) { TIM_SetCompare1(TIM3, 350); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 350); } 4.3 红外传感器

模块原理:器件有三个引脚,VCC和GND,OUT就是输出信号用的,其实输出的就是高低电平两种状态(高电平为3.3V,低电平为0V;高电平读出来就是“1”,低电平读出来就是“0”)。 这个器件上电以后,OUT引脚默认输出高电平,当检测到障碍物时OUT引脚会输出低电平,因此会有一个高电平到低电平的变化,我们称之为“下降沿”。我们可以把stm32设置为“下降沿”触发外部中断这样一种机制,因此,当红外对管检测到障碍物时,stm32会被触发中断,从而去执行我们事先编写好的一段程序。 blog.csdnimg.cn/e83916153e954c3f9b415c3e6bf8ee4d.png) 代码如下:

#include "bsp_exti.h" #include "bsp_usart.h" static void EXTI_INFRAREDAVOID_NVIC_Config(void) //static限制这个函数只能被EXTI_Key_Config()调用 { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //红外1中断 NVIC_InitStructure.NVIC_IRQChannel=INFRAREDAVOID1_INT_EXTI_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); //红外2中断 NVIC_InitStructure.NVIC_IRQChannel = INFRAREDAVOID2_INT_EXTI_IRQ; /* 抢断优先级*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /* 子优先级 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; /* 使能中断 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 初始化配置NVIC */ NVIC_Init(&NVIC_InitStructure); } //外部中断红外1配置 void EXTI_INFRAREDAVOID1_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义初始化结构体 EXTI_InitTypeDef EXTI_InitStructure; //配置中断优先级 EXTI_INFRAREDAVOID_NVIC_Config(); /*配置红外*/ //初始化用于中断的GPIO(具体的外设) RCC_APB2PeriphClockCmd(INFRAREDAVOID1_INT_GPIO_CLK,ENABLE); //开红外的时钟 GPIO_InitStructure.GPIO_Pin=INFRAREDAVOID1_INT_GPIO_PIN; //选择GPIO要控制的引脚4 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(INFRAREDAVOID1_INT_GPIO_PORT,&GPIO_InitStructure); //初始化EXTI(具体的外设) GPIO_EXTILineConfig(INFRAREDAVOID1_INT_EXTI_PortSource,INFRAREDAVOID1_INT_EXTI_PinSource); //配置输入源 EXTI_InitStructure.EXTI_Line=INFRAREDAVOID1_INT_EXTI_LINE; //因为是PA4,所以是Line4 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //配置为下降沿触发中断 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); //把结构体成员写到相应的寄存器里 } //外部中断红外2配置 void EXTI_INFRAREDAVOID2_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义初始化结构体 EXTI_InitTypeDef EXTI_InitStructure; //配置中断优先级 EXTI_INFRAREDAVOID_NVIC_Config(); /*配置红外*/ //初始化用于中断的GPIO(具体的外设) RCC_APB2PeriphClockCmd(INFRAREDAVOID2_INT_GPIO_CLK,ENABLE); //开红外的时钟 GPIO_InitStructure.GPIO_Pin=INFRAREDAVOID2_INT_GPIO_PIN; //选择GPIO要控制的引脚4 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(INFRAREDAVOID2_INT_GPIO_PORT,&GPIO_InitStructure); //初始化EXTI(具体的外设) GPIO_EXTILineConfig(INFRAREDAVOID2_INT_EXTI_PortSource,INFRAREDAVOID2_INT_EXTI_PinSource); //配置输入源 EXTI_InitStructure.EXTI_Line=INFRAREDAVOID2_INT_EXTI_LINE; //因为是PA4,所以是Line4 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //配置为下降沿触发中断 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); //把结构体成员写到相应的寄存器里 } 5 具体连接

1、电源:将两节电池串联,电源的正极连接L2980N的12V输入,电源的负极连接L2980N的GND。

2:接下来是STM32的连接

红外中断:由于我使用的是外部中断3和外部中断4,对应的IO口分别是PA3和PC4,因此将PA3->OUT, 3.3V->VCC, GND->DND。同理PC4->OUT, 3.3V->VCC, GND->DND。L2980N:上面有L2980N的介绍,这里就不多赘述了。我使用的是通用定时器TIM3的4个通道。CH1的PC6口,CH2的PC7口,CH3的PC8口,CH4的PC9口。 12V供电->电源正极GND->电源负极和开发板GND5V供电->开发板的VCC5V供电->开发板的VCC逻辑输入分别接开发板的PC6,PC7,PC8,PC9逻辑输出A连接电机分别连接电机的正负极,正对输出口的右边是正逻辑输出B连接电机分别连接电机的正负极,正对输出口的右边是正通道A使能:这个是使能输出A的,也要跳线帽连接,否则A侧马达不转,个人觉得没有什么用一开始就连接好了,不用动。通道B使能:这个是使能输出B的,也要跳线帽连接否则A侧马达不转,个人觉得没有什么用,,一开始就连接好了,不用动。

连接图如下: 在这里插入图片描述

6 效果展示及改进建议 实物展示:

在这里插入图片描述

改进建议 1:使用超声波模块代替红外模块 由于红外传感器会受到光线和距离的限制,从而会导致最后实验的结果不是特别理想尽管能达到简单避障效果,但是还有待提高。建议后续使用超声波模块hc-sr04代替红外模块。超声波的检测距离长,且稳定性十分好。

超声波模块原理:用声音在空气中传播并且遇到障碍物会反射的效果,再根据声音在空气中的传播速度,计算出前方的距离。

2:使用舵机模块SG90 既然碰到障碍物要转弯,那到底转多少角度呢?使用舵机模块就可以很好的解决这一问题。

舵机模块原理:

其实舵机可以分为两种,一种是模拟舵机,一种是数字舵机,这两者的区别是:模拟舵机需要一直给与要转的角度命令,直到到自己想要的角度,注意这个给定的时间许多不许少,就像是小孩子一样,你要不断的给与鼓励和奖赏,才会达到自己的要求;而数字舵机是只需要给定一次角度命令就行了,就像是长大了的孩子,你可以把事情很放心的交给他,说一次就好。说了半天,那么角度命令是什么呢?其实就是我们熟悉的pwm信号,下面给出占空比与旋转的角度之间的关系: 在这里插入图片描述

注意: 1)、高电平加上低电平等于 20ms,那是因为要求的pwm频率是50hz,1s/50 = 20ms,所以周期就是20ms。 2)、角度怎么看,想象自己站在xy轴的0坐标上,正对着y轴,y轴就是0度。负度在左手边,正度在右手边。 3)、其实低电平的时间并没有那么死板,只要在0.5ms和20ms之间就可以。

7 源码展示

我是使用野火的指南者板子,用的是标准库首先创建文件

bsp_exti.c: 用于保存红外中断函数代码 bsp_exti.h: 用于保存红外中断函数的声明 bsp_led.c: 用于保存开发板上的LED灯函数的代码,我们要实现红外模块遇到障碍物触发中断,亮红灯。 bsp_led.h: 用于保存开发板上的LED灯函数的声明的代码,我们要实现红外模块遇到障碍物触发中断,亮红灯 bsp_l2980n.c: 用于保存电机驱动模块函数的代码(通用定时器输出4路PWM方波信号) bsp_l2980n.h: 用于保存电机驱动模块函数声明的代码 stm32f10x.c:这个文件库函数本来就有,主要保存我们自己写的中断服务函数(触发中断后要让单片机干啥事情) main.c:主函数

完整源码如下:可直接跑的哦

bsp_exti.c #include "bsp_exti.h" static void EXTI_INFRAREDAVOID_NVIC_Config(void) //static限制这个函数只能被EXTI_Key_Config()调用 { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //红外1中断 NVIC_InitStructure.NVIC_IRQChannel=INFRAREDAVOID1_INT_EXTI_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); //红外2中断 NVIC_InitStructure.NVIC_IRQChannel = INFRAREDAVOID2_INT_EXTI_IRQ; /* 抢断优先级*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /* 子优先级 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; /* 使能中断 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 初始化配置NVIC */ NVIC_Init(&NVIC_InitStructure); } //外部中断红外1配置 void EXTI_INFRAREDAVOID1_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义初始化结构体 EXTI_InitTypeDef EXTI_InitStructure; //配置中断优先级 EXTI_INFRAREDAVOID_NVIC_Config(); /*配置红外*/ //初始化用于中断的GPIO(具体的外设) RCC_APB2PeriphClockCmd(INFRAREDAVOID1_INT_GPIO_CLK,ENABLE); //开红外的时钟 GPIO_InitStructure.GPIO_Pin=INFRAREDAVOID1_INT_GPIO_PIN; //选择GPIO要控制的引脚4 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(INFRAREDAVOID1_INT_GPIO_PORT,&GPIO_InitStructure); //初始化EXTI(具体的外设) GPIO_EXTILineConfig(INFRAREDAVOID1_INT_EXTI_PortSource,INFRAREDAVOID1_INT_EXTI_PinSource); //配置输入源 EXTI_InitStructure.EXTI_Line=INFRAREDAVOID1_INT_EXTI_LINE; //因为是PA4,所以是Line4 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //配置为下降沿触发中断 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); //把结构体成员写到相应的寄存器里 } //外部中断红外2配置 void EXTI_INFRAREDAVOID2_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义初始化结构体 EXTI_InitTypeDef EXTI_InitStructure; //配置中断优先级 EXTI_INFRAREDAVOID_NVIC_Config(); /*配置红外*/ //初始化用于中断的GPIO(具体的外设) RCC_APB2PeriphClockCmd(INFRAREDAVOID2_INT_GPIO_CLK,ENABLE); //开红外的时钟 GPIO_InitStructure.GPIO_Pin=INFRAREDAVOID2_INT_GPIO_PIN; //选择GPIO要控制的引脚4 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(INFRAREDAVOID2_INT_GPIO_PORT,&GPIO_InitStructure); //初始化EXTI(具体的外设) GPIO_EXTILineConfig(INFRAREDAVOID2_INT_EXTI_PortSource,INFRAREDAVOID2_INT_EXTI_PinSource); //配置输入源 EXTI_InitStructure.EXTI_Line=INFRAREDAVOID2_INT_EXTI_LINE; //因为是PA4,所以是Line4 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //配置为下降沿触发中断 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); //把结构体成员写到相应的寄存器里 } bsp_exti.h #ifndef _BSP_EXTI_H #define _BSP_EXTI_H #include "stm32f10x.h" //infrared红外 obstacle avoidance避障 //红外1 #define INFRAREDAVOID1_INT_GPIO_PIN GPIO_Pin_3 #define INFRAREDAVOID1_INT_GPIO_PORT GPIOA #define INFRAREDAVOID1_INT_GPIO_CLK (RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB) #define INFRAREDAVOID1_INT_EXTI_PortSource GPIO_PortSourceGPIOA #define INFRAREDAVOID1_INT_EXTI_PinSource GPIO_PinSource3 #define INFRAREDAVOID1_INT_EXTI_LINE EXTI_Line3 #define INFRAREDAVOID1_INT_EXTI_IRQ EXTI3_IRQn #define INFRAREDAVOID1_IRQHandler EXTI3_IRQHandler //红外2 #define INFRAREDAVOID2_INT_GPIO_PIN GPIO_Pin_4 #define INFRAREDAVOID2_INT_GPIO_PORT GPIOC #define INFRAREDAVOID2_INT_GPIO_CLK (RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO |RCC_APB2Periph_GPIOB) #define INFRAREDAVOID2_INT_EXTI_PortSource GPIO_PortSourceGPIOC #define INFRAREDAVOID2_INT_EXTI_PinSource GPIO_PinSource4 #define INFRAREDAVOID2_INT_EXTI_LINE EXTI_Line4 #define INFRAREDAVOID2_INT_EXTI_IRQ EXTI4_IRQn #define INFRAREDAVOID2_IRQHandler EXTI4_IRQHandler void EXTI_INFRAREDAVOID1_Config(void); void EXTI_INFRAREDAVOID2_Config(void); #endif bsp_led.c #include "bsp_led.h" void LED_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 定义初始化结构体 RCC_APB2PeriphClockCmd(LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE); //开灯时钟 GPIO_InitStructure.GPIO_Pin=LED1_GPIO_PIN; //选择GPIO要控制的引脚0 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(LED1_GPIO_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=LED2_GPIO_PIN; //选择GPIO要控制的引脚1 GPIO_Init(LED2_GPIO_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=LED3_GPIO_PIN; //选择GPIO要控制的引脚5 GPIO_Init(LED3_GPIO_PORT,&GPIO_InitStructure); //熄灭所有灯 GPIO_SetBits(LED1_GPIO_PORT,LED1_GPIO_PIN); GPIO_SetBits(LED2_GPIO_PORT,LED2_GPIO_PIN); GPIO_SetBits(LED3_GPIO_PORT,LED3_GPIO_PIN); } bsp_led.h #ifndef _BSP_LED_H #define _BSP_LED_H #include "stm32f10x.h" /* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */ // G-绿色 #define LED1_GPIO_PORT GPIOB /* GPIO端口 */ #define LED1_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define LED1_GPIO_PIN GPIO_Pin_0 /* 连接到SCL时钟线的GPIO */ // B-蓝色 #define LED2_GPIO_PORT GPIOB /* GPIO端口 */ #define LED2_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define LED2_GPIO_PIN GPIO_Pin_1 /* 连接到SCL时钟线的GPIO */ // R-红色 #define LED3_GPIO_PORT GPIOB /* GPIO端口 */ #define LED3_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define LED3_GPIO_PIN GPIO_Pin_5 /* 连接到SCL时钟线的GPIO */ #define ON 1 #define OFF 0 #define LED1_G(a) if(a) \ GPIO_ResetBits(LED1_GPIO_PORT,LED1_GPIO_PIN);\ else GPIO_SetBits(LED1_GPIO_PORT,LED1_GPIO_PIN); #define LED2_B(a) if(a) \ GPIO_ResetBits(LED2_GPIO_PORT,LED2_GPIO_PIN);\ else GPIO_SetBits(LED2_GPIO_PORT,LED2_GPIO_PIN); #define LED3_R(a) if(a) \ GPIO_ResetBits(LED3_GPIO_PORT,LED3_GPIO_PIN);\ else GPIO_SetBits(LED3_GPIO_PORT,LED3_GPIO_PIN); #define LED1_TOGGLE {LED1_GPIO_PORT->ODR ^=LED1_GPIO_PIN;} //绿灯状态翻转 #define LED2_TOGGLE {LED2_GPIO_PORT->ODR ^=LED2_GPIO_PIN;} //蓝灯状态翻转 #define LED3_TOGGLE {LED3_GPIO_PORT->ODR ^=LED3_GPIO_PIN;} //红灯状态翻转 void LED_GPIO_Config(void); #endif bsp_l2980n.c #include "bsp_l298n.h" void TIM3_PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructer; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructer; TIM_OCInitTypeDef TIM_OCInitStructer; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); //初始化TIM3 TIM_TimeBaseStructer.TIM_Period = 899; TIM_TimeBaseStructer.TIM_Prescaler = 0; TIM_TimeBaseStructer.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructer.TIM_ClockDivision = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructer); //初始化GPIOC6/GPIOC7 (TIM3_CH1/TIM3_CH2) GPIO_InitStructer.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructer.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructer); //初始化GPIOC8/GPIOC9 (TIM3_CH3/TIM3_CH4) GPIO_InitStructer.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructer.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOC, &GPIO_InitStructer); //PWM通道一 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC1Init(TIM3, &TIM_OCInitStructer); //Enables or disables the TIMx peripheral Preload register on CCR1. TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道二 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC2Init(TIM3, &TIM_OCInitStructer); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道三 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC3Init(TIM3, &TIM_OCInitStructer); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //PWM通道四 TIM_OCInitStructer.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructer.TIM_OutputState = TIM_OutputState_Enable; /*比较输出使能,决定信号是否通过外部引脚输出。value:0(Disable)、1(Enable)。*/ TIM_OCInitStructer.TIM_OCPolarity = TIM_OCPolarity_High; /*比较输出极性,决定定时器通道有效电平的极性。*/ TIM_OCInitStructer.TIM_Pulse = 900; TIM_OC4Init(TIM3, &TIM_OCInitStructer); TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); } //前进 void Go_Forward(void) { //Sets the TIMx Capture Compare1 Register value TIM_SetCompare1(TIM3, 300); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 300); TIM_SetCompare4(TIM3, 900); } //停止 void Stop(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 900); } //后退 void Go_Back(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 300); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 300); } //左转 void Turn_Left(void) { TIM_SetCompare1(TIM3, 900); TIM_SetCompare2(TIM3, 350); TIM_SetCompare3(TIM3, 350); TIM_SetCompare4(TIM3, 900); } //右转 void Turn_Right(void) { TIM_SetCompare1(TIM3, 350); TIM_SetCompare2(TIM3, 900); TIM_SetCompare3(TIM3, 900); TIM_SetCompare4(TIM3, 350); } bsp_l2980n.h #ifndef __L298N_H #define __L298N_H #include "stm32f10x.h" void TIM3_PWM_Init(void); void Go_Forward(void); void Go_Back(void); void Stop(void); void Turn_Left(void); void Turn_Right(void); #endif /*__L298N_H*/ stm32f10x_it.c #include "stm32f10x_it.h" #include "bsp_led.h" #include "bsp_exti.h" #include "bsp_l298n.h" //EXTI3_IRQHandler中断服务函数 void INFRAREDAVOID1_IRQHandler(void) { if(EXTI_GetITStatus(INFRAREDAVOID1_INT_EXTI_LINE) !=RESET) { LED3_R(1); // Stop() ; flag1=1; Turn_Right(); EXTI_ClearITPendingBit(INFRAREDAVOID1_INT_EXTI_LINE); } } //EXTI4_IRQHandler中断服务函数 void INFRAREDAVOID2_IRQHandler(void) { if(EXTI_GetITStatus(INFRAREDAVOID2_INT_EXTI_LINE) !=RESET) { LED3_R(1); flag2=1; // Stop() ; Turn_Left(); EXTI_ClearITPendingBit(INFRAREDAVOID2_INT_EXTI_LINE); } } main.c #include "stm32f10x.h" #include "bsp_led.h" #include "bsp_exti.h" #include "bsp_l298n.h" extern uint16_t flag1; extern uint16_t flag2; int main(void) { LED_GPIO_Config(); EXTI_INFRAREDAVOID1_Config(); EXTI_INFRAREDAVOID2_Config(); TIM3_PWM_Init(); Go_Forward(); while(1) { if(flag1 == 1) { if(GPIO_ReadInputDataBit(INFRAREDAVOID1_INT_GPIO_PORT,INFRAREDAVOID1_INT_GPIO_PIN) == 1) //外部中断跳回0 { flag1 = 0; LED3_R(0); Go_Forward(); } } if(flag2 == 1) { if(GPIO_ReadInputDataBit(INFRAREDAVOID2_INT_GPIO_PORT,INFRAREDAVOID2_INT_GPIO_PIN) == 1) //外部中断跳回0 { flag2 = 0; LED3_R(0); Go_Forward(); } } } }

以上就是本项目需要手写的全部代码了,觉得不错的记得一键三连哦!有问题也可私聊我哦



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3