电子说
功能介绍放开头, 使用便捷无需愁。
这是全网最详细、性价比最高的STM32实战项目入门教程,通过合理的硬件设计和详细的视频笔记介绍,硬件使用STM32F103主控资料多方便学习,通过3万字笔记、12多个小时视频、20多章节代码手把手教会你如何开发和调试。让你更快掌握嵌入式系统开发。
V1.5.0-STM32智能小车
V1.5.0:库函数开发。功能:循迹、避障、跟随、遥控、电池电压显示等。
视频合集链接推荐观看
[https://www.bilibili.com/video/BV1SY411L7rJ/?spm_id_from=333.337.search-card.all.click]
**V3.3.0-STM32智能小车 **
V3:HAL库开发、功能:PID速度控制、PID循迹、PID跟随、遥控、避障、PID角度控制、视觉控制、电磁循迹、RTOS等功能。
视频合集链接推荐观看
[https://www.bilibili.com/video/BV16x4y1M7EN/?spm_id_from=333.337.search-card.all.click]
通过超声波的硬件介绍我们知道
MCU给Trig脚一个大于10us的高电平脉冲;然后读取Echo脚的高电平信号时间,通过公式:距离 = T*
声速/2 就可以算出来距离。
软件方面:10us高电平脉冲通过GPIO输出实现,高电平信号时间我们通过定时器的输入捕获来计算
的。
初始化脉冲引脚PA0
在led.c中的SR04初始化函数
voidSR04_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_0); }
led.h有关宏定义和声明
#defineSR04 PAout(0)// PA0voidSR04_GPIO_Init(void);
查看数据手册
初始化定时器2 通道2 输入捕获相关功能
//定时器2通道2输入捕获配置TIM_ICInitTypeDef TIM2_ICInitStructure;voidTIM2_Cap_Init(u16 arr,u16 psc){ GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能TIM2时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PA1 清除之前设置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//PA1 输入GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA,GPIO_Pin_1);//PA1 下拉//初始化定时器5 TIM5TIM_TimeBaseStructure.TIM_Period = arr;//设定计数器自动重装值TIM_TimeBaseStructure.TIM_Prescaler =psc;//预分频器TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分割:TDTS =Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//初始化TIM5输入捕获参数TIM2_ICInitStructure.TIM_Channel = TIM_Channel_2;// 选择输入端 IC2映射到TI2上 TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿捕获TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//映射到TI2上TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//配置输入分频,不分频TIM2_ICInitStructure.TIM_ICFilter =0x00;//IC1F=0000 配置输入滤波器 不滤波TIM_ICInit(TIM2, &TIM2_ICInitStructure);//中断分组初始化NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//TIM2中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =2;//先占优先级2级NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//从优先级0级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道被使能NVIC_Init(&NVIC_InitStructure);//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允许更新中断 ,允许CC2IE捕获中断 TIM_Cmd(TIM2,ENABLE );//使能定时器2} u8 TIM5CH1_CAPTURE_STA=0;//输入捕获状态u16 TIM5CH1_CAPTURE_VAL;//输入捕获值//定时器2中断服务程序voidTIM2_IRQHandler(void){if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获{if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了{if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了{ TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次TIM5CH1_CAPTURE_VAL=0XFFFF; }elseTIM5CH1_CAPTURE_STA++; } }if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获2发生捕获事件{if(TIM5CH1_CAPTURE_STA&0X40)//捕获到一个下降沿{ TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获到一次上升沿TIM5CH1_CAPTURE_VAL=TIM_GetCapture2(TIM2); TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);//CC2P=0 设置为上升沿捕获 }else//还未开始,第一次捕获上升沿{ TIM5CH1_CAPTURE_STA=0;//清空TIM5CH1_CAPTURE_VAL=0; TIM_SetCounter(TIM2,0); TIM5CH1_CAPTURE_STA|=0X40;//标记捕获到了上升沿TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);//CC2P=1设置为下降沿捕获 } } } TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update);//清除中断标志位}
在time 中声明初始化函数
voidTIM2_Cap_Init(u16arr,u16psc);
在main.c声明变量
externu8TIM5CH1_CAPTURE_STA;//输入捕获状态externu16TIM5CH1_CAPTURE_VAL;//输入捕获值
定义变量
intDistance =0;inttime=0;
调用初始化函数
SR04_GPIO_Init();TIM2_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数
完成测距的函数
delay_ms(500);//加入延时 HC_SR04 =0; delay_us(10); HC_SR04 =1;if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 {time=TIM5CH1_CAPTURE_STA&0X3F;time*=65536;//溢出时间总和time+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间printf("rnHIGH:%d usrn",time);//打印总的高点平时间 Distance =time*0.033/2;printf("cm:%drn",Distance); TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 }
封装一下方便调用
intTCRT5000_Dist(void) { HC_SR04 =1; delay_us(13); HC_SR04=0;if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 {time=TIM5CH1_CAPTURE_STA&0X3F;time*=65536;//溢出时间总和time+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间printf("rnHIGH:%d usrn",time);//打印总的高点平时间 Distance =time*0.033/2;printf("cm:%drn",Distance); TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 }returnDistance; }
使用串口助手查看结果
功能:根据根据超声波测量距离跟随前方物体
while(1){ HC_SR04 =1; delay_us(13); HC_SR04=0;if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上 升沿 {time=TIM5CH1_CAPTURE_STA&0X3F;time*=65536;//溢出时间总和time+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间printf("rnHIGH:%d usrn",time);//打印总的高 点平时间 Distance =time*0.033/2;printf("cm:%drn",Distance); TIM5CH1_CAPTURE_STA=0;//开启下一次捕获 }if(Distance >20) { Forward(); delay_ms(50); }if(Distance<15) { Backward(); delay_ms(50); } AIN1 =0; AIN2 =0; BIN1 =0; BIN2 =0; }
功能:通过舵机旋转不同角度,超声波测量左右是否存在障碍物,控制小车运动。
测试舵机的转角,不同占空比小车舵机的角度
TIM_SetCompare1(TIM3,80);TIM_SetCompare1(TIM3,50);TIM_SetCompare1(TIM3,110);
整体逻辑
if(Mode ==3) {//超声波避障TIM_SetCompare1(TIM3,80);//舵机向前 使超声波朝前方delay_ms(200);if(TCRT5000_Dist() >25)// 前方无障碍物{Forward();delay_ms(500); }if(TCRT5000_Dist()<25)//向前有障碍物{TIM_SetCompare1(TIM3,50);//舵机向右边转大约30度delay_ms(200);if(TCRT5000_Dist() >25)//右侧无障碍物判断{Rightward();delay_ms(700); }else{//右边有障碍物TIM_SetCompare1(TIM3,100);//舵机向左边转大约30度delay_ms(200);if(TCRT5000_Dist() >25)//左侧无障碍物{Leftward();delay_ms(700); }else{Backward();//后退delay_ms(700);Rightward();//右转delay_ms(700); } } } } }
功能:
while(1) {sprintf((char*)string,"Distance:%d ",TCRT5000_Dist());// 显示距离信息这里的 %d 需要几个空格OLED_ShowString(6,3,string,16);sprintf((char*)string,"Mode:%d",Mode);//显示小车模式OLED_ShowString(6,6,string,16);if(Mode ==1) {//定距离跟随TIM_SetCompare1(TIM3,80);//超声波舵机向前if(TCRT5000_Dist() >25)// 距离太远{Forward();delay_ms(200); }if(TCRT5000_Dist() <20)//距离太近{Backward();delay_ms(200); } AIN1 =0;//车辆暂定 如果不加 小车就会一直往前或者一直往后AIN2 =0; BIN1 =0; BIN2 =0; }if(Mode ==2) {//蓝牙控制小车TIM_SetCompare1(TIM3,80);//超声波舵机向前if(g_USART3_FLAG1 ==1)//前进{ g_USART3_FLAG1=0;Forward();delay_ms(500); }if(g_USART3_FLAG1 ==2)//向右{ g_USART3_FLAG1=0;Rightward();delay_ms(500); }if(g_USART3_FLAG1 ==3)//向左{ g_USART3_FLAG1=0;Leftward();delay_ms(500); }if(g_USART3_FLAG1 ==4)//向后{ g_USART3_FLAG1=0;Backward();delay_ms(500); }if(g_USART3_FLAG1 ==5)//停止{ g_USART3_FLAG1=0; AIN1=0; AIN2=0; BIN1=0; BIN2=0;delay_ms(500); } }if(Mode ==3) {//超声波避障TIM_SetCompare1(TIM3,80);//舵机向前delay_ms(200);if(TCRT5000_Dist() >25)// 前方无障碍物{Forward();delay_ms(500); }if(TCRT5000_Dist()<25)//向前有障碍物{TIM_SetCompare1(TIM3,50);//舵机右转delay_ms(200);if(TCRT5000_Dist() >25)//右侧无障碍物判断{Rightward();delay_ms(700); }else{TIM_SetCompare1(TIM3,100);//舵机向左delay_ms(200);if(TCRT5000_Dist() >25)//左侧无障碍物{Leftward();delay_ms(700); }else{Backward();delay_ms(700);//后退Rightward();delay_ms(700); } } } }if(Mode ==4) {//红外循迹TIM_SetCompare1(TIM3,80);//超声波舵机向前if(HW_1 ==0&&HW_2 ==0&&HW_3 ==0&&HW_4 ==0)//应该前进 {Forward();delay_ms(20); }if(HW_1 ==0&&HW_2 ==1&&HW_3 ==0&&HW_4 ==0)//应该右边{Rightward();delay_ms(150); }if(HW_1 ==1&&HW_2 ==0&&HW_3 ==0&&HW_4 ==0)//应该右边{Rightward();delay_ms(270); }if(HW_1 ==1&&HW_2 ==1&&HW_3 ==0&&HW_4 ==0)//应该右边{Rightward();delay_ms(370); }if(HW_1 ==0&&HW_2 ==0&&HW_3 ==1&&HW_4 ==0)//应该左边{Leftward();delay_ms(150); }if(HW_1 ==0&&HW_2 ==0&&HW_3 ==0&&HW_4 ==1)//应该左边{Leftward();delay_ms(270); }if(HW_1 ==0&&HW_2 ==0&&HW_3 ==1&&HW_4 ==1)//应该左边{Leftward();delay_ms(370); } }if(Mode ==0) {delay_ms(1); AIN1=0; AIN2=0; BIN1=0; BIN2=0; } }
串口三中断服务函数
//串口3 中断处理函数voidUSART3_IRQHandler(void){ u8 Res;if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) { Res =USART_ReceiveData(USART3);//读取接收到的数据if(Res =='A') g_USART3_FLAG1 =1;//根据接受的数据 置为标志位if(Res =='B')g_USART3_FLAG1 =2;if(Res =='C') g_USART3_FLAG1 =3;if(Res =='D')g_USART3_FLAG1 =4;if(Res =='E')g_USART3_FLAG1 =5;if(Res =='F') Mode =1;if(Res =='G') Mode =2;if(Res =='H') Mode =3;if(Res =='I') Mode =4;if(Res =='J') Mode =0; } }
按键处理函数
voidEXTI9_5_IRQHandler(void)//按键KEY_1 和KEY_2的中断服务函数{ delay_ms(10);//消抖if(KEY_1 ==1)//判断按键KEY_1 是否被按下{if(Mode ==4) Mode =1;else{ Mode = Mode +1; } LED =! LED; EXTI_ClearITPendingBit(EXTI_Line7);//清除LINE7上的中断标志位} }voidEXTI15_10_IRQHandler(void)//按键KEY_SW1 和KEY_SW2的中断服务函数{ delay_ms(10);//消抖if(KEY_2 ==0)//判断按键KEY_2 是否被按下{ Mode =0; LED =! LED; EXTI_ClearITPendingBit(EXTI_Line12);//清除LINE12上的中断标志位} }
手机APP-蓝牙调试助手设置
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !