STM32蓝牙控制循迹避障小车源代码——3.舵机、超声波测距模块

注意-所需模块:

US-015超声波模块

SG90舵机云台

接线:舵机超声波:
A1–P2.7
B8–Trig
B9–Echo

代码

所有的代码都是直接从工程里面复制的,实测是没有问题的。

参考文章: stm32 智能避障小车(二)之sg90

我这里再简单总结一下:

  • 舵机:
    橙色信号号线,红色5V,棕色GND;
    舵机控制需要一个周期为20ms的方波,方波的高电平部分在0.5ms~2.5ms中,会转动一定的角度。
    t=0.5ms——舵机转动0°
    t=1.0ms——舵机转动45°
    t=1.5ms——舵机转动90°
    t=2.0ms——舵机转动135°
    t=2.5ms——舵机转动180°
    设置在转动90°时为舵机的正前方,这样就可以左右转动了。

  • 代码思路:利用定时器输出一个占空比可调的PWM,且PWM周期为20ms

  • A1接舵机的橙色线

SG90.c

#include "SG90.H"void SG90_PWM_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_OCInitTypeDef TIM_OCInitStruct;//开启定时器2,GPIOA,AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//初始化A1GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化定时器2TIM_TimeBaseInitStruct.TIM_Period=199;TIM_TimeBaseInitStruct.TIM_Prescaler=7199;TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_ClockDivision=0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//PWM周期为:(7200*200)/72000000=0.02=20ms//定时器2通道二初始化TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//当计时器值小于比较器设定值时输出有效低电平;大于等于时输出有效高电平TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;//初试极性为LowTIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;TIM_OC2Init(TIM2,&TIM_OCInitStruct);TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);TIM_Cmd(TIM2,ENABLE);}

正在学习STM32的同学可以跟着下面的步骤自己配置一下

SG90_PWM_Init()函数配置:

1.开启时钟,定时器2:RCC_APB1PeriphClockCmd();开启IO口时钟、AFIO:RCC_APB2PeriphClockCmd();//GPIOA
2.初始化A1:GPIO_Init();//复用推挽输出 AF_PP
3.定时器2初始化:TIM_TimeBaseInit();//周期199,预分频系数7199,计数器模式 up,时钟分割 0
4.初始化定时器2的通道2:并使能定时器:TIM_OC2Init();//模式:PWM1,极性:low,输出状态:ENABLETIM_OC2PreloadConfig();TIM_Cmd();

SG90.h:

#ifndef __SG90_H
#define __SG90_H#include "stm32f10x.h"
#include "delay.h"#define SG90_Right_90   TIM_SetCompare2(TIM2,195)
#define SG90_Right_45   TIM_SetCompare2(TIM2,190)//右转45#define SG90_Front           TIM_SetCompare2(TIM2,185)//方向摆正,(15/200)*20ms=1.5ms#define SG90_Left_45        TIM_SetCompare2(TIM2,180)
#define SG90_Left_90        TIM_SetCompare2(TIM2,175)//左转45void SG90_PWM_Init(void);#endif

想要测试舵机模块是否正确的可以自己在主函数里直接调用SG90_Front,SG90_Left_45,SG90_Right_45等,注意加上延迟。

接下来是超声波测距,这个程序是当时我花了最长时间才调试好的

参考资料:STM32的超声波测距程序

  • 超声波模块工作原理:
    采用IO口TRIG触发测距,需要给最少10us的高电平信呈;
    模块自动发送8个40KHZ的方波,自动检测是否有信号返回;
    有信号返回,通过IO口ECHO输出高电平,高电平持续时间就是超声波从发射到返回的时间;
    测试距离=高电平持续时间*声速/2

  • 我是用定时器计数来获取时间的。小伙伴最好已经熟练掌握STM32的定时器中断实验。代码的原理一模一样,看不懂代码的可以看看原子哥的视频讲解。我这里不再详细讲解了。

代码直接给你们

cj.c

#include "CJ.H"
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"//配置中断优先级
void NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStruct.NVIC_IRQChannel=TIM4_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;//响应优先级NVIC_Init(&NVIC_InitStruct);}void CH_SR04_Init(u16 reload,u16 psr)
{GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_ICInitTypeDef TIM_ICInitStruct;//开启定时器4,GPIOBRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//PB8 TRIG触发信号GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);      //PB8接TRIGGPIO_ResetBits(GPIOB,GPIO_Pin_8);//PB9 ECHO回响信号GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;GPIO_Init(GPIOB,&GPIO_InitStruct);//定时器4初始化  设置分频系数TIM_TimeBaseInitStruct.TIM_Period=reload;TIM_TimeBaseInitStruct.TIM_Prescaler=psr;TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);TIM_ICInitStruct.TIM_Channel=TIM_Channel_4;                 //通道4TIM_ICInitStruct.TIM_ICFilter=0x00;                                   //不滤波TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;            //捕获模式,这里设置为上升沿捕获TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;    //配置输入分频,不分频 TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;TIM_ICInit(TIM4,&TIM_ICInitStruct);TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC4,ENABLE);NVIC_Config();}

cj.h

#ifndef __CJ_H
#define __CJ_H#include "stm32f10x.h"
#include "delay.h"#include "sys.h"
#define uint unsigned int
#define TRIG_Send PBout(8)
#define ECHO_Receive PBout(9)void CH_SR04_Init(u16 reload,u16 psr);//超声波模块配置void NVIC_Config(void);//中断配置#endif
  • 我将中断溢出放在主函数里面了。

main.c

#include "stm32f10x.h"
#include "moter.h"
#include "delay.h"
#include "SG90.H"
#include "cj.h"
#include "usart.h"
#include "sys.h"
#include "stdio.h"#define CLK_TIME 1.0/8000000.0u8  TIM4CH4_CAPTURE_STA=0;   //输入捕获状态
u16 TIM4CH4_CAPTURE_VAL;    //输入捕获值
u8 cap_flag=0;
float  length_res[5];  //用来存放测距结果
u32 time_cnt;
double long_chang;float sensor(void)
{PBout(8)=1; //拉高信号,作为触发信号delay_us(20); //高电平信号超过10usPBout(8)=0;while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET);TIM_Cmd(TIM4,ENABLE);//回响信号到来,开启定时器计数while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==SET);//回响信号消失TIM_Cmd(TIM4,DISABLE);//关闭定时器if(cap_flag){time_cnt=(TIM4CH4_CAPTURE_STA&0x3f)*65536;time_cnt+=TIM4CH4_CAPTURE_VAL;//printf("%d\r\n",time_cnt);long_chang=time_cnt*CLK_TIME*340/2.0*100.0;//printf("%f cm\r\n",long_chang);cap_flag=0;TIM4CH4_CAPTURE_STA=0;TIM4CH4_CAPTURE_VAL=0;delay_ms(10);}return long_chang;}int main(void)
{// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
//  uart_init(115200);delay_init();    //延时初始化      TIM3_PWM_Init();    //电机pwm   TIM3SG90_PWM_Init();  //舵机初始化CH_SR04_Init(0xffff,8);      //超声波定时器初始化TIM_Cmd(TIM4,ENABLE);//开启超声波测距定时器while(1){SG90_Front;delay_ms(700);length_res[0]=sensor();delay_ms(10);//printf("fornt:%f\r\n",length_res[0]);if(length_res[0]>40.0000)       //如果前方距离大于40cm  前进{Forward();}else if(length_res[0]<40.0000)     //如果前方距离小于40厘米  停车测左右距离{STOP();  SG90_Left_45;      //舵机左转45度测距delay_ms(700);        length_res[1] =sensor();    //把测量结果放进数组delay_ms(10);//printf("left:%fcm left45 \r\n",length_res[1]);SG90_Right_45;     //舵机右转45度测距delay_ms(700); length_res[4] =sensor();     //把测量结果放进数组   delay_ms(10);//printf("right:%fcm right 45\r\n",length_res[4]);               SG90_Front;           //舵机摆正//delay_ms(700); if(length_res[1]<40.00&&length_res[4]<40.00&&length_res[1]>length_res[4]){SG90_Front; //舵机摆正delay_ms(700);length_res[0] =sensor();   //重复测前方的距离同时delay_ms(10);                       Backward();delay_ms(700);Turn_left();
//                  delay_ms(500);}if(length_res[1]<40.00&&length_res[4]<40.00&&length_res[1]<length_res[4]){SG90_Front; //舵机摆正delay_ms(700);length_res[0] =sensor(); //重复测前方的距离同时delay_ms(10);                       Backward();delay_ms(700);Turn_right();
//                  delay_ms(500);}if(length_res[1]>length_res[4])    //如果左边的距离大于右边的距离{SG90_Front; //舵机摆正delay_ms(700);length_res[0] =sensor(); //重复测前方的距离同时左转delay_ms(10);                     Turn_left();if(length_res[0]>35.0000)Forward();}if(length_res[1]<length_res[4])    //如果右边的距离大于左边的距离{SG90_Front;delay_ms(700);length_res[0] =sensor();  //重复测前方的距离同时右转delay_ms(10);                       Turn_right();if(length_res[0]>35.0000)Forward();}}}}void TIM4_IRQHandler(void)//中断溢出
{if((TIM4CH4_CAPTURE_STA&0x80)==0){if(TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET){            //判断定时器是否溢出if(TIM4CH4_CAPTURE_STA&0x40)//判断之前是否已经接收到上升沿{                            if((TIM4CH4_CAPTURE_STA&0X3F)==0X3F)          //如果计数已经满了 直接停止{//cap_flag=1;TIM4CH4_CAPTURE_STA|=0x80;TIM4CH4_CAPTURE_VAL=0XFFFF;}else TIM4CH4_CAPTURE_STA++;         //如果计数没满,继续计数}}}if(TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET){             //表示捕获到来上升沿if(TIM4CH4_CAPTURE_STA&0x40)//表明之前已经接收到了一个边沿(这一次捕获边沿表示捕获结束){   cap_flag=1;TIM4CH4_CAPTURE_STA|=0x80;TIM4CH4_CAPTURE_VAL=TIM_GetCapture4(TIM4);          //读取捕获的值TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Rising);      //重新设置为上升沿捕获}else{      //表示首次进入捕获边沿cap_flag=0;TIM4CH4_CAPTURE_STA=0;TIM4CH4_CAPTURE_VAL=0;TIM4CH4_CAPTURE_STA|=0X40;                   //标记为捕获了一次上升沿TIM_SetCounter(TIM4,0);TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Falling); }}TIM_ClearITPendingBit(TIM4, TIM_IT_CC4|TIM_IT_Update); //清除中断标志位}

将以上程序写入工程里,下载到板子上,实验现象为:

舵机摆正,不断测量前方的距离;

当前方距离大于40cm时,小车前进;

当前方距离小于40cm时,停车;舵机左右摆,测两边的距离,同时判断情况。

​ ---------当左右两边都小于40cm,但左边距离大于右边时,后退,然后左转。

​ --------- 当左右两边都小于40cm,但右边距离大于左边时,后退,然后右转。

​ ---------当左边距离大于右边时,左转。

​ ---------当左边距离小于右边时,右转。

任意时刻,当前方距离大于40cm时,小车前进。


想要观察测量距离的同学,可以把我主函数里的串口通信的代码取消注释,在串口调试助手里面可以随时看到测试的数据。(这些都是我自己调试过程中保留的代码,我没有删掉。你们也可以根据实际小车的运动来改一下参数)

代码配置不成功的伙伴,可以直接下载这个工程,全部实测过没有问题:

STM32小车-超声波避障-超声波测距.zip-嵌入式文档类资源-CSDN文库


下一节写蓝牙控制程序

STM32蓝牙控制循迹避障小车源代码——3.舵机、超声波测距模块相关推荐

  1. STM32蓝牙控制循迹避障小车源代码——4.蓝牙控制

    STM32蓝牙控制循迹避障小车源代码--4.蓝牙控制 注意-所需模块: 蓝牙模块 接线: 串口通信 A2–RX A3–TX 所有的代码都是直接从工程里面复制的,实测是没有问题的. 蓝牙控制原理: 设计 ...

  2. STM32蓝牙控制循迹避障小车源代码——5.最终程序

    STM32蓝牙控制循迹避障小车源代码--5.最终程序 将前面4讲的内容整合一起.主函数里用switch函数或者if语句来判断接收到的数据,改变小车的运动. 注意要将控制循迹和避障的参数单独定义一个.否 ...

  3. STM32蓝牙控制循迹避障小车——2.循迹模块

    STM32蓝牙控制循迹避障小车源代码--2.循迹模块 注意-所需模块: 接线:四个循迹模块(从左到右分别为1,2,3,4) B4–第1个循迹模块的D0 B5–第2个循迹模块的D0 B6–第3个循迹模块 ...

  4. 基于STM32的智能循迹避障小车实验(小车运动部分)

    写在前面 这个实验是关于智能小车的实验,现在的想法就是先做出一个循迹和避障功能,后续可能会再添加一些其他的模块. 我在做这个实验之前基本了解了F1系列开发板的大部分模块,如果没有学习之前的模块,建议先 ...

  5. 基于STM32的智能循迹避障小车

    [1]研究背景 随着计算机,微电子技术的快速发展,智能化技术的开发越来越快,智能程度也越来越高,应用的范围也得到了极大的扩展.因此,基于嵌入式技术的智能小车应运而生. 近来两年,智能小车在生活中有着广 ...

  6. STM32循迹避障小车制作代码详解(简单实现版)

    感谢几年来大家的支持,看到大家对工程的呼声很高,所以来把工程上传了,大家自行下载即可哈,谢谢大家支持 这个代码是进阶版的,就是可以跑的很快的,和上面博客的主要区别就是这个代码的避障机制并不是做在主ma ...

  7. 基于STM32F103C8T6的循迹避障小车完整制作过程(详细)----上篇(第123点)

    基于STM32F103C8T6的循迹避障小车完整制作过程 本文适合小白观看 由于本人的一个小项目,要做一个基于STM32的循迹避障小车,前后花了约1周的时间,这个过程中也参考了很多大神分享的资料,学到 ...

  8. 基于STM32F103的红外循迹避障小车设计(含Proteus仿真)

    基于STM32F103的红外循迹避障小车设计 红外循迹及红外避障实现较简单,无论是51单片机还是STM32单片机,其例程随处可见.但是完全可以运行的Proteus仿真,开源的并不多,更不要说基于STM ...

  9. c语言智能车跑道检测程序,基于单片机的智能循迹避障小车(附电路原理图,程序清单)...

    基于单片机的智能循迹避障小车(附电路原理图,程序清单)(论文10000字) 摘要:目前,移动机器人的开发和研究越来越令人瞩目,而智能循迹壁障小车作为移动机器人的一个重要分支,非常值得我们探索和讨论.智 ...

最新文章

  1. 预示敏捷方法走偏的15个标志——第1部分
  2. 第一次react-native项目实践要点总结
  3. .net程序员面试考试题目
  4. linux删除文件后,空间未释放的一种情况,使用lsof查看
  5. 最小二乘法与最大似然函数的区别
  6. C++统计10亿以内所有的质素(素数)的实现算法(附完整源码)
  7. Tensorflow 2 Auto-Encoder
  8. Loonframework-DAO-Alpha-0.1.0发布
  9. restsharp简单使用
  10. python 删除文件到回收站 SHFileOperation
  11. 苏宁易购正在“酝酿”下一场蝶变?
  12. xctf攻防世界 MISC高手进阶区 我们的秘密是绿色的
  13. 谷歌AI人工智能:我们的原则
  14. Switchhosts Mac 安装
  15. NTP 服务的配置和使用
  16. 网络直播课程:神马是敏捷?(直播时间:2014-7-14 20:00-21:00)
  17. 入行 AI,如何选个脚踏实地的岗位
  18. 电脑没有鼠标怎么打开计算机,电脑鼠标右键菜单没有打开方式选项怎么办
  19. js的NaN和isNaN
  20. IOS-UIWebView字体控制

热门文章

  1. 计算机四级 信息安全工程师——操作系统题库
  2. Redis(6)——GeoHash查找附近的人
  3. 自己写的C盘清理工具 Ver1.0.0
  4. 图书预订系统:书店向顾客发放订单,顾客将所填订单交由系统处理,系统首先依据图书目录对订单进行检查并对合格订单进行处理,处理过程中根据顾客情况和订单数目将订单分为优先订单与正常订单两种,随时处理优先订单
  5. JavaApp自动化测试系列[v1.0.0][Appium开发环境搭建]
  6. unix 时间戳 c语言,C语言实现字符转unix时间戳
  7. KDD2022推荐系统论文集锦
  8. B_随笔_关于网站记录(2)
  9. php%3e%3etxt_《3e迅雷》_3e迅雷最新版下载
  10. 程序员写博客的意义何在?为什么推荐程序员写个人博客?