精华内容
下载资源
问答
  • 51超声波避障小车

    万次阅读 多人点赞 2018-12-26 13:24:11
    超声波避障小车 简介 本文小车的功能主要有两个:超声波测距避障,以及蓝牙遥控。主控芯片用的是STC89C52,电机驱动模块用的是L298N,超声波传感器HC-SR04,蓝牙模块使用的是HC-05,电机采用5V的直流电机。 总体设计...

    超声波避障小车

    简介

    本文小车的功能主要有两个:超声波测距避障,以及蓝牙遥控。主控芯片用的是STC89C52,电机驱动模块用的是L298N,超声波传感器HC-SR04,蓝牙模块使用的是HC-05,电机采用5V的直流电机。

    总体设计

    总体方案框图

    在这里插入图片描述

    硬件篇

    1. 主控芯片STC89C52
      本实验使用的最小系统主控芯片是STC89C52,功能不是很多。该最小系统是学习单片机时,在淘宝购买集成好的开发板Mini51。(建议:自己购买洞洞板和其他配件搭建最小系统,需要的功能模块再拓展,这样能学到的东西比较多)
      Mini51实物图

    2. 超声波模块HC-SR04
      能测距的传感器有很多,如红外传感器,激光传感器等等。也考虑过使用红外传感器,因为价格成本比较低,但红外传感器的抗干扰能力就没超声波好,红外传感器主要是利用光反射的原理,对于透明的障碍物就会有影响。所以本实验使用的是超声波传感器。
      其原理也并不难理解,超声波测距的原理正是基于其物理基础,当超声波模块产生超声波后,单片机的计时器开始计时。超声波在遇到障碍物后会被反射,超声波模块接收到反射波后,单片机的计时器停止计时。根据收发超声波所产生的时间差,便可计算出超声波模块与障碍物的距离。超声波模块在接收超声波时存在能量转化,当超声波接收到反射波后,声信号转换为电信号,从而使单片机的停止计时。设超声波的声速为v,时间差为t0则超声波的测距公式如下:

      S = v × t 0/2

      附上超声波传感器的实物图:
      HC-SR04超声波传感器

    3. 蓝牙模块HC-05
      该模块价格不会很高,网上基本有该模块的使用方法,首先要连接USB转TTL的模块接入电脑,使用串口调试软件,输入AT指令配置蓝牙模块。该蓝牙模块的源码资料有提供,也可从其他网站或 Github 找。
      详细的蓝牙模块的配置和使用方法参考:
      【常用模块】HC-05蓝牙串口通信模块使用详解(实例:手机蓝牙控制STM32单片机)—Yngz_Miao

    软件篇

    编程环境是使用Keil5 C51。

    展示几个流程图,代码就不放了,需要就在链接中下载。

    主程序流程图:
    主程序流程图

    超声波测距:
    在这里插入图片描述

    避障程序:
    避障程序

    总结

    本项目成本不高,功能也不多,适合课程设计,练练手,熟悉一下做项目的流程,如何写文档等。小车的功能可以继续扩展,如自动循迹,实时测速等等。或者使用更加强大的芯片,如STM32系列的芯片,可以扩展的功能就可以很多

    本文最后附上几张小车实物图:
    小车1

    小车2

    小车3

    手机蓝牙终端控制App(app商城有很多,或者自己开发):
    手机蓝牙终端控制App

    另附
    小车的详细资料源码下载:https://pan.baidu.com/s/1kyYyLXyMrLQX8SMp5YrOZg (提取密码:twk7)

    展开全文
  • 超声波避障程序随处可见,基于51单片机的超声波避障小车也很成熟,但是完整的Proteus仿真并不容易找到开源资料。这次主要给大家分享其Proteus仿真部分。涉及到的模块有:超声波模块(hc-sr04)、L293D电机驱动器和...
  • 本程序配套基于51单片机的超声波避障小车(含Proteus仿真)博客,现分享给大家学习使用,如有错误,希望批评指正,多多指教。
  • /* Main.c file generated by New Project wizard** Created: 周五 4月 3 2020* Processor: AT89C52* Compiler:Keil for 8051*/#include #include #include #defineTXP1_3#defineRXP1_2#define Forward_L_D...

    /* Main.c file generated by New Project wizard

    *

    * Created:   周五 4月 3 2020

    * Processor: AT89C52

    * Compiler:  Keil for 8051

    */

    #include

    #include

    #include

    #define  TX  P1_3

    #define  RX  P1_2

    #define Forward_L_DATA  180

    #define Forward_R_DATA  180

    /*****°′???-í??ó???¨ò?******/

    sbit L293D_IN1=P0^0;

    sbit L293D_IN2=P0^1;

    sbit L293D_IN3=P0^2;

    sbit L293D_IN4=P0^3;

    sbit L293D_EN1=P0^4;

    sbit L293D_EN2=P0^5;

    sbit BUZZ=P0^6;

    void Delay400Ms(void);

    unsigned char disbuff[4]={0,0,0,0};

    void Count(void);

    unsigned int  time=0;

    unsigned long S=0;

    bit  flag =0;

    bit  turn_right_flag;

    //**********************************************************

    //oˉêy??3?:Delay1ms(unsigned int i)

    //oˉêy1|?ü:?óê±i*1msμ?×ó3ìDò(??ó|óú22.1184Mhz?§??)

    //D?ê?2?êy:unsigned int i

    //DD2??μ?÷:?T

    //·μ??2?êy:?T

    //ê1ó??μ?÷:i?aòa?óê±μ?ê±??3¤?è£?μ¥??ê?MS£?×?′ó?éò??óê±65536 ms

    //**********************************************************

    void Delay1ms(unsigned int i)

    {

    unsigned char j,k;

    do{

    j = 10;

    do{

    k = 50;

    do{

    _nop_();

    }while(--k);

    }while(--j);

    }while(--i);

    }

    //**********************************************************

    //oˉêy??3?:Delay10us(unsigned char i)

    //oˉêy1|?ü:?óê±i*10usμ?×ó3ìDò(??ó|óú22.1184Mhz?§??)

    //D?ê?2?êy:?T

    //DD2??μ?÷:?T

    //·μ??2?êy:?T

    //ê1ó??μ?÷:i?aòa?óê±μ?ê±??3¤?è£?μ¥??ê?US£?×?′ó?éò??óê±250 ms

    //**********************************************************

    void Delay10us(unsigned char i)

    {

    unsigned char j;

    do{

    j = 10;

    do{

    _nop_();

    }while(--j);

    }while(--i);

    }

    //=========================================================================================================================

    void Forward()//           ?°??

    {

    L293D_IN1=1;

    L293D_IN2=0;

    L293D_IN3=1;

    L293D_IN4=0;

    //     PWM_Set(255-Speed_Right,255-Speed_Left);

    }

    void Stop(void)        //é23μ

    {

    L293D_IN1=0;

    L293D_IN2=0;

    L293D_IN3=0;

    L293D_IN4=0;

    //         PWM_Set(0,0);

    }

    void Turn_Retreat()         //oó

    {

    L293D_IN1=0;

    L293D_IN2=1;

    L293D_IN3=0;

    L293D_IN4=1;

    //        PWM_Set(255-Speed_Right,255-Speed_Left);

    }

    void Turn_left()         //×ó

    {

    L293D_IN1=0;

    L293D_IN2=1;

    L293D_IN3=1;

    L293D_IN4=0;

    //        PWM_Set(255-Speed_Right,255-Speed_Left);

    }

    //=========================================================================================================================

    /********?àà?????3ìDò***************/

    void Conut(void)

    {

    time=TH1*256+TL1;

    TH1=0;

    TL1=0;

    S=time*2;

    S=S*0.17;

    if(S<=300)

    {

    if(turn_right_flag!=1)

    {

    Stop();

    Delay1ms(5);

    }

    turn_right_flag=1;

    P1_7=0;

    P2_0=0;

    P0_6=0;

    Delay1ms(10);

    P1_7=1;

    P2_0=1;

    P0_6=1;

    Delay1ms(5);

    Turn_left();

    Delay1ms(10);

    }

    else

    {

    turn_right_flag=0;

    Forward();

    }

    if((S>=5000)||flag==1)

    {

    flag=0;

    }

    else

    {

    disbuff[0]=S%10;

    disbuff[1]=S/10%10;

    disbuff[2]=S/100%10;

    disbuff[3]=S/1000;

    }

    }

    /********************************************************/

    void zd0() interrupt 3

    {

    flag=1;

    RX=0;

    }

    /********3?éù2¨??μ?????3??í?è????3ìDò***************/

    void Timer_Count(void)

    {

    TR1=1;

    while(RX);

    TR1=0;

    Conut();

    }

    /********************************************************/

    void  StartModule()

    {

    TX=1;

    Delay10us(2);

    TX=0;

    }

    /********************************************************/

    /*************?÷3ìDò********************/

    void main(void)

    {

    unsigned char i;

    unsigned int a;

    Delay1ms(400);

    //        LCMInit()

    Delay1ms(5);

    TMOD=TMOD|0x10;

    EA=1;

    TH1=0;

    TL1=0;

    ET1=1;

    turn_right_flag=0;

    BUZZ=0;

    Delay1ms(50);

    BUZZ=1;

    while(1)

    {

    RX=1;

    StartModule();

    for(a=951;a>0;a--)

    {

    if(RX==1)

    {

    Timer_Count();

    }

    }

    }

    }

    }

    展开全文
  • 超声波避障程序随处可见,基于51单片机的超声波避障小车也很成熟,但是完整的Proteus仿真并不容易找到开源资料。这次主要给大家分享其Proteus仿真部分。涉及到的模块有:超声波模块(hc-sr04)、L293D电机驱动器和...
  • AT89S51单片机的智能超声波避障小车.doc
  • 基于AT89S51单片机的智能超声波避障小车.doc
  • 基于AT89S51单片机的智能超声波避障小车,里面包括超声波避障原理等==
  • 自己写的简易版本的基于51单片机的超声波避障小车的工程文件,包含输出的.hex文件。如有写的不好的地方还请多多包涵。
  • 基于STC89C51单片机的智能超声波避障小车.doc
  • 基于AT89S51单片机的智能超声波避障小车电路图.doc
  • 超声波避障程序随处可见,基于51单片机的超声波避障小车也很成熟,但是完整的Proteus仿真并不容易找到开源资料。 这次主要给大家分享其Proteus仿真部分。 涉及到的模块有:超声波模块(hc-sr04)、L293D电机驱动器和...
  • 基于at89c51单片机的智能超声波避障小车
  • 基于51单片机的超声波避障小车,使用舵机控制方向,超声波采集障碍物距离,点击可变速,使用oled显示障碍物距离,有proteus仿真,代码附有详细注释
  • 51超声波光电避障小车
  • 超声波避障小车.zip

    2019-10-02 19:34:29
    基于51单片机的超声波避障代码和资料,小车可以自动避障,走迷宫。确保代码直接可以使用,不会有错误。代码中的注释很清楚,具体的接线问题也有注明。
  • //超声波测距模块Trig sbit echo=P1^1; //超声波测距模块Echo sbit trig2=P1^3; //超声波测距模块2Trig sbit echo2=P1^4; //超声波测距模块2Echo sbit in1=P2^1; sbit in2=P2^2; sbit in3=P2^3; sbit in4=P2^4; ...
  • 基于单片开机的超声波避障小车,能实现自动避障,显示行驶过的路程 源程序
  • 不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满...

    23ba6506c195cf06f74ed4bc2d93f8dd.png

    不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满满,加油读完,保证你收货多多。

    6b8867a49202ae481d953c63524656f4.png
    基于STM32超声波避障小车https://www.zhihu.com/video/1229107254572007424

    处理器电路设计

    单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案: (1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。 (2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72MHZ,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。 通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:

    e8b352ba526c940f266c22db29fc1b22.png

    电源模块设计

    本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:

    ac2569391da223061cf0c1d439d79d86.png

    电机驱动模块设计

    要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。

    37bcc99c6291d22566ebbf672dd69c83.png

    电源驱动引脚表

    控制芯片:TB6612
    控制芯片数量:2
        1号TB6612引脚分配:
         VM         PWMA--------->TIM1_CH1(PA8)
         VCC        AIN2--------->GPIOB_12
         GND        AIN1--------->GPIOB_13
         AO1        STBY--------->GPIOB_14
         AO2        BIN1--------->GPIOB_15
         BO2        BIN2--------->GPIOA_12
         BO1        PWMB--------->TIM1_CH2(PA9)
         GND        GND
        2号TB6612引脚分配:
         VM         PWMA--------->TIM1_CH3(PA10)
         VCC        AIN2--------->GPIOB_5
         GND        AIN1--------->GPIOB_6
         AO1        STBY--------->GPIOB_7
         AO2        BIN1--------->GPIOB_8
         BO2        BIN2--------->GPIOA_9
         BO1        PWMB--------->TIM1_CH4(PA11)
         GND        GND
    真值表
         AIN1   0     1     0     1
         AIN2   0     0     1     1
         BIN1   0     1     0     1
         BIN2   0     0     1     1
               停止  正转  反转  刹车
    

    电机所用到的定时器配置

    //初始化TIMX,设置TIMx的ARR,PSC
    //arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    //定时器选择TIM1
    static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
     {
         //-----------------时基结构体初始化-------------------------/
         TIM_TimeBaseInitTypeDef TIM_TimeStructure;
         /*开启定时器1时钟,即内部时钟CK_INT=72M*/
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
        TIM_DeInit(TIMx);
        /*内部时钟作为计数器时钟,72MHZ*/
        TIM_InternalClockConfig(TIMx);
        /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
        TIM_TimeStructure.TIM_Period=arr;
        /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/
        TIM_TimeStructure.TIM_Prescaler=psc-1;
        /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
        TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        /*向上计数模式*/
        TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
        /*重复计数器*/
        TIM_TimeStructure.TIM_RepetitionCounter=0;
        /*初始化定时器*/
        TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
        /*使能ARR预装载寄存器(影子寄存器)*/
        TIM_ARRPreloadConfig(TIMx,ENABLE);
        //-----------------输出比较结构体初始化-----------------------/
        TIM_OCInitTypeDef   TIM_OCInitStructure;
        /*PWM模式设置,设置为PWM模式1*/
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
        /*PWM输出使能相应的IO口输出信号*/
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
        /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
        TIM_OCInitStructure.TIM_Pulse=duty;
        /*输出通道电平极性设置*/
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
        /*初始化输出比较参数*/
        TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1
        TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2
        TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3
        TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4
        /*自动重装载*/
        TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);
        /*使能计数器*/
        TIM_Cmd(TIMx,ENABLE);
        /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
        TIM_CtrlPWMOutputs(TIMx,ENABLE);
    }
    //高级定时器输出通道初始化函数
    static void TB6612_ADVANCE_TIM_Gpio_Config()
    {
        GPIO_InitTypeDef  GPIO_InitStruct;
        /*----------通道1配置--------------*/
        /*定时器1输出比较通道*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
        /*-----------通道二配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
         /*-----------通道三配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
         /*-----------通道四配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
    }
    

    超声波模块

    采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:

    28286fe8321895297e9dd0d63d705492.png

    该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。 在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。 模块工作原理: (1)单片机触发引脚,输出高电平信号; (2)模块发送端自动发送特定频率的方波; (3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长; (4)测试距离=(高电平时间*声速(340M/S))/2。 注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。

    0856dc0eaab6bce46c2153355cd4027b.png

    超声波重要代码(可参考)

    /* 获取接收到的高电平的时间(us*/
     uint32_t Get_HC_SR04_Time(void)
     {
         uint32_t t=0;
         t=Acoustic_Distance_Count*1000;//us
         t+=TIM_GetCounter(TIM2);//获取us
         TIM2->CNT =0;
         Acoustic_Distance_Count=0;
         Systic_Delay_us(100);
        return t;
    }
    /*获取距离*/
    void Get_HC_SR04_Distance(void)
    {
        static uint16_t count=0;
        switch(count)
        {
            case 1:
            {
                GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平
            }break;
    
            case 15:
            {
                count=0;
                GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
                while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时
                Open_Tim2();
                while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时
                Close_Tim2();
                HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
    
            }break;
            default:break;
        }
        count++;
    }
    

    舵机模块

    本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:

    743f9859020470c303e09074010da164.png

    舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。 0.5ms---------0 1.0ms---------45
    1.5ms---------90 2.0ms---------135 2.5ms-----------180 20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。

    舵机重要代码(可参考)

    /**PWM引脚初始化*/
     static void SERVO_Gpio_Init(void)
     {
         GPIO_InitTypeDef  GPIO_InitStruct;
         /*----------通道2配置--------------*/
         /*定时器3输出比较通道*/
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
         /*配置为复用推挽输出*/
         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
    }
    //定时器3初始化,设置TIMx的ARR,PSC
    //arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
    {
        //-----------------时基结构体初始化-------------------------/
        TIM_TimeBaseInitTypeDef TIM_TimeStructure;
        /*开启定时器3时钟,即内部时钟CK_INT=72M*/
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
        TIM_DeInit(TIMx);
        /*内部时钟作为计数器时钟,72MHZ*/
        TIM_InternalClockConfig(TIMx);
        /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
        TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期
        /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/
        TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ
        /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
        TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        /*向上计数模式*/
        TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
        /*重复计数器*/
        TIM_TimeStructure.TIM_RepetitionCounter=0;
            /*初始化定时器*/
        TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
        /*使能ARR预装载寄存器(影子寄存器)*/
        TIM_ARRPreloadConfig(TIMx,ENABLE);
        //-----------------输出比较结构体初始化 开始-----------------------/
        TIM_OCInitTypeDef   TIM_OCInitStructure;
        /*PWM模式设置,设置为PWM模式1*/
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
        /*PWM输出使能相应的IO口输出信号*/
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
        /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
        TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小
        /*输出通道电平极性设置*/
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
        /*初始化输出比较参数*/
        TIM_OC2Init(TIMx,&TIM_OCInitStructure);
        //-----------------输出比较结构体初始化 结束-----------------------/
        /*自动重装载*/
        TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
        /*使能计数器*/
        TIM_Cmd(TIMx,ENABLE);
        /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
        TIM_CtrlPWMOutputs(TIMx,ENABLE);
    }
    /*舵机PWM初始化
       每增加0.1ms 舵机对应增加9度
    0.5ms---------0
    1.0ms---------45
    1.5ms---------90
    2.0ms---------135
    2.5ms-----------180
    2.1ms    turn_left=150
    0.8ms    turn_right=25
    1.3ms    turn_front=75
    20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%.
    */
    void SERVO_Init(void)
    {
        SERVO_Gpio_Init();
        SERVO_TIM_Config(TIM3,1000,1440,turn_front);
    /** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则
    驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:
    1/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间
    为:1/CK_CNT*ARR=20ms。
    PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ
                   = 72 000 000/(1000*1440)=5KHZ
    */
    }
    /*舵机角度控制*/
    void SERVO_Angle_Control(uint16_t Compare2)
    {
        TIM_SetCompare2(TIM3,Compare2);
    }
    

    编码器模块

    调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:

    ef13f589608501c0064df5a53cecf9af.png

    用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。

    4aef2de16fd3d4edc47bcfb82ce34ebb.png
    展开全文
  • 【项目分享】基于STM32超声波避障小车

    千次阅读 多人点赞 2020-01-21 16:10:45
    不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满...

    微信公众号:果果小师弟
    关注可了解获取更多资料教程。问题或建议,请公众号留言;
    如果你觉得此篇文章对你有帮助,欢迎留言关注

    不管是对于初学者还是对于一个玩过单片机的电子爱好者来说,或多或少都接触到过小车项目,今天给大家介绍的的一个项目基于STM32超声波避障小车。这也是我曾经的一个课设,在此开源分享给大家,全文5000多字,干货满满,加油读完,保证你收货多多。

    震惊!某大学生竟然在宿舍做stm32避障小车

    处理器电路设计

    单片机是系统的CPU,是系统稳定、正常运行的重要前提,以下为单片机选型的两种方案:
    (1)传统的8位单片机,是通过超大规模集成电路对其进行集成为一个独立芯片的控制器。内部组件包括CPU、随机存储器、只读存储器、I/O接口、中断系统、计时器、串口通讯、数模转换等。STC89C52单片机是最常见的51单片机,但是资源较少,精确度低,处理速度相比STM32单片机差很多。
    (2)使用目前市面上最常见的STM32单片机,STM32系列单片机可分为ARMCortex-M3内核体系结构的不同应用领域。它可分为STM32F1系列和STM32F4系列,STM32F1系列单片机时钟频率最高可达72米,在同一产品中性能最好。单片机的基本处理速度为36米,16位单片机的性能也很好。微晶片的内建快闪记忆体相当大,范围从32kb到512kb,可视需要选择。单个设备的功耗非常低,仅360mA,32位单片机产品的功耗最低,每兆赫只有0.5安培。特别值得一提的是,内接单晶片汇流排是一种Harvard架构,可执行速度高达1.25 DMIPS/MHz的指令。此芯片越来越多地被用作主要控制器。
    通过对单片机的资源和处理时间的速度我们采用选择STM32103C8T6为本系统主控芯片,程序下载是只需要一个JLINK就可以轻松完成。控制器模块电路如下所示:
    单片机最小系统

    电源模块设计

    本设计采用锂电池供电, 模块的供电电压一般都为5V,同时超声波模块需要较大的电流才能正常工作,所以在降压的基础上也要保证足够大的输出电流。本设计采用可调输出版本,模块的输入电压范围广,输出电压在1.25V-35V内可调,电压转换效率高,输出纹波小。降压电路如下所示:

    电源管理电路

    电机驱动模块设计

    要完成转向是能够利用单片机实现的,然而单片机I0的带负载能力弱,因此我们选择了大功率放大器件TB6612FNG。TB6612FNG是采用MOSFET-H桥结构的双通道大电流电路输出,可以控制2个电机的驱动。相比普通的电机驱动,外围电路非常简单,只需要一个芯片和一个钽电容进行PWM输出滤波,系统尺寸小。PWM信号输入频率范围广,轻松满足本设计的需求。

    电源驱动芯片

    电源驱动引脚表

    控制芯片:TB6612
    控制芯片数量:2
        1号TB6612引脚分配:
         VM         PWMA--------->TIM1_CH1(PA8)
         VCC        AIN2--------->GPIOB_12
         GND        AIN1--------->GPIOB_13
         AO1        STBY--------->GPIOB_14
         AO2        BIN1--------->GPIOB_15
         BO2        BIN2--------->GPIOA_12
         BO1        PWMB--------->TIM1_CH2(PA9)
         GND        GND
        2号TB6612引脚分配:
         VM         PWMA--------->TIM1_CH3(PA10)
         VCC        AIN2--------->GPIOB_5
         GND        AIN1--------->GPIOB_6
         AO1        STBY--------->GPIOB_7
         AO2        BIN1--------->GPIOB_8
         BO2        BIN2--------->GPIOA_9
         BO1        PWMB--------->TIM1_CH4(PA11)
         GND        GND
    真值表
         AIN1   0     1     0     1
         AIN2   0     0     1     1
         BIN1   0     1     0     1
         BIN2   0     0     1     1
               停止  正转  反转  刹车
    

    电机所用到的定时器配置

    //初始化TIMX,设置TIMx的ARR,PSC
    //arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    //定时器选择TIM1
    static void TB6612_ADVANCE_TIM1_Mode_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
     {
         //-----------------时基结构体初始化-------------------------/
         TIM_TimeBaseInitTypeDef TIM_TimeStructure;
         /*开启定时器1时钟,即内部时钟CK_INT=72M*/
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
        TIM_DeInit(TIMx);
        /*内部时钟作为计数器时钟,72MHZ*/
        TIM_InternalClockConfig(TIMx);
        /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
        TIM_TimeStructure.TIM_Period=arr;
        /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(71+1)=1MHZ*/
        TIM_TimeStructure.TIM_Prescaler=psc-1;
        /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
        TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        /*向上计数模式*/
        TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
        /*重复计数器*/
        TIM_TimeStructure.TIM_RepetitionCounter=0;
        /*初始化定时器*/
        TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
        /*使能ARR预装载寄存器(影子寄存器)*/
        TIM_ARRPreloadConfig(TIMx,ENABLE);
        //-----------------输出比较结构体初始化-----------------------/
        TIM_OCInitTypeDef   TIM_OCInitStructure;
        /*PWM模式设置,设置为PWM模式1*/
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
        /*PWM输出使能相应的IO口输出信号*/
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
        /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
        TIM_OCInitStructure.TIM_Pulse=duty;
        /*输出通道电平极性设置*/
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
        /*初始化输出比较参数*/
        TIM_OC1Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道1
        TIM_OC2Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道2
        TIM_OC3Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道3
        TIM_OC4Init(TIMx,&TIM_OCInitStructure);//初始化TIM1 通道4
        /*自动重装载*/
        TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);
        TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);
        /*使能计数器*/
        TIM_Cmd(TIMx,ENABLE);
        /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
        TIM_CtrlPWMOutputs(TIMx,ENABLE);    
    }
    //高级定时器输出通道初始化函数
    static void TB6612_ADVANCE_TIM_Gpio_Config()
    {
        GPIO_InitTypeDef  GPIO_InitStruct;
        /*----------通道1配置--------------*/
        /*定时器1输出比较通道*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
        /*-----------通道二配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
         /*-----------通道三配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
         /*-----------通道四配置-------------*/
        /*定时器1输出比较通道*/
        /*配置为复用推挽输出*/
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
    }
    

    超声波模块

    采用HC-SR04超声波模块,该芯片具有较高的集成度以及良好的稳定性,测度距离十分精确,十分稳定。供电电压为DC5V供电电流小于10mA,探测距离为0.010m-3.5m一共有四个引脚VCC(DC5V)、Triger(发射端)、Echo(接收端)、GND(地)。HC-SR04实物图如下:

    超声波实物
    该模块是利用单片机的IO触发电平测距,单片机内部利用普通定时器产生一个高电平信号之后,超声波就可以自主发送频率为40khz的方波,然后等待信号的返回;若有信号返回,单片机IO口就立刻输出一高电平,利用高电平产生的时间可以计算小车与障碍物的距离。最终距离就是高电平持续时间乘以声音在空气中传播的速度再除以2,可以反复测量距离。
    在程序开始首先初始化超声波,利用定时器并设置时基的自动重装载初值1000,psc为预分频值72,这样的话我们产生一次中断的时间是1ms,并设置抢占优先级0,子优先级3。HC_SR04_Echo引脚接收到高电平,打开定时器,且每1ms进入一次中断。在测量时首先让Trig发送一个大于10us的高电平,然后拉高HC_SR04_Trig,当Echo为0时打开定时器计时,当Echo为1时关闭定时器,通过公式计算距离。
    模块工作原理:
    (1)单片机触发引脚,输出高电平信号;
    (2)模块发送端自动发送特定频率的方波;
    (3)如果有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波的发射时长;
    (4)测试距离=(高电平时间*声速(340M/S))/2。
    注意:在硬件操作上需要首先让模块地端先连接,否则会影响模块工作。测距时,被测物体的摆放不能太过于杂乱,否则会影响测试结果。

    超声波重要代码(可参考)

    /* 获取接收到的高电平的时间(us*/
     uint32_t Get_HC_SR04_Time(void)
     {
         uint32_t t=0;
         t=Acoustic_Distance_Count*1000;//us
         t+=TIM_GetCounter(TIM2);//获取us
         TIM2->CNT =0;
         Acoustic_Distance_Count=0;
         Systic_Delay_us(100);
        return t;
    }
    /*获取距离*/
    void Get_HC_SR04_Distance(void)
    {
        static uint16_t count=0;
        switch(count)
        {
            case 1:
            {
                GPIO_SetBits(Acoustic_Port,HC_SR04_Trig);//Trig发送一个大于10us的高电平
            }break;
    
            case 15:
            {
                count=0;
                GPIO_ResetBits(Acoustic_Port,HC_SR04_Trig);
                while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==0);//当Echo为0时打开定时器 计时
                Open_Tim2();
                while(GPIO_ReadInputDataBit(Acoustic_Port,HC_SR04_Echo)==1);//当Echo为0时打开定时器 计时
                Close_Tim2();
                HC_SR04_Distance=(float)(Get_HC_SR04_Time()/5.78);
    
            }break;
            default:break;
        }
        count++;
    }
    

    舵机模块

    本系统使用的是SG90型号的舵机,舵机是一种常见的角度驱动器,本系统需要判断不同位置的障碍物可以且对转向的力度小。舵机可以理解为方向盘称,方向盘是一个常见的名字。它实际上是一个伺服马达。舵机实物图如下:

    舵机模块接口简单,舵机模块只有三个引脚。分别引引出了三根线左右两边是电源正负接口线,中间一根是PWM信号线直接连接单片机的控制引脚。通过控制单片机的引脚输出的脉冲宽度进而控制舵机旋转的角度。舵机每增加0.1ms 舵机对应增加9度。
    0.5ms---------0
    1.0ms---------45
    1.5ms---------90
    2.0ms---------135
    2.5ms-----------180
    20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平持续时间为1.5ms,周期为20ms的方波,duty=1.5/20=7.5%。在这里设置定时器自动重装载寄存器arr的值为1000,所以当占空比为百分之75是,在程序中就要设置占空比为75/1000=7.5%, 这就是具体的算法。

    舵机重要代码(可参考)

    /**PWM引脚初始化*/
     static void SERVO_Gpio_Init(void)
     {
         GPIO_InitTypeDef  GPIO_InitStruct;
         /*----------通道2配置--------------*/
         /*定时器3输出比较通道*/
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
         /*配置为复用推挽输出*/
         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct); 
    }
    //定时器3初始化,设置TIMx的ARR,PSC
    //arr:自动重装载初值,psc为预分频值,两者配合控制定时器时钟的周期
    static void SERVO_TIM_Config(TIM_TypeDef* TIMx,uint16_t arr,uint16_t psc,uint16_t duty)
    {
        //-----------------时基结构体初始化-------------------------/
        TIM_TimeBaseInitTypeDef TIM_TimeStructure;
        /*开启定时器3时钟,即内部时钟CK_INT=72M*/
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
        TIM_DeInit(TIMx);
        /*内部时钟作为计数器时钟,72MHZ*/
        TIM_InternalClockConfig(TIMx);
        /*自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断*/
        TIM_TimeStructure.TIM_Period=arr;//1000 当定时器从0计数到999,即1000次,为一个定时周期
        /*时钟预分频系数为71,则驱动计数器的时钟CK_CNT=CK_INT/(1440-1+1)=0.05MHZ*/
        TIM_TimeStructure.TIM_Prescaler=psc-1;;//1400  //即定时器的频率为5KHZ   
        /*设置时钟分割,TIM_CKD_DIV1=0,PWM波不延时*/
        TIM_TimeStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        /*向上计数模式*/
        TIM_TimeStructure.TIM_CounterMode=TIM_CounterMode_Up;
        /*重复计数器*/
        TIM_TimeStructure.TIM_RepetitionCounter=0;
            /*初始化定时器*/
        TIM_TimeBaseInit(TIMx,&TIM_TimeStructure);
        /*使能ARR预装载寄存器(影子寄存器)*/
        TIM_ARRPreloadConfig(TIMx,ENABLE);
        //-----------------输出比较结构体初始化 开始-----------------------/
        TIM_OCInitTypeDef   TIM_OCInitStructure;
        /*PWM模式设置,设置为PWM模式1*/
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
        /*PWM输出使能相应的IO口输出信号*/
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
        /*设置占空比大小,CCR1[15:0]: 捕获/比较通道1的值,若CC1通道配置为输出:CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。*/
        TIM_OCInitStructure.TIM_Pulse=duty;   //占空比大小
        /*输出通道电平极性设置*/
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
        /*初始化输出比较参数*/
        TIM_OC2Init(TIMx,&TIM_OCInitStructure);
        //-----------------输出比较结构体初始化 结束-----------------------/    
        /*自动重装载*/
        TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
        /*使能计数器*/
        TIM_Cmd(TIMx,ENABLE);
        /*主输出使能,如果设置了相应的使能位(TIMx_CCER寄存器的CCxE、CCxNE位),则开启OC和OCN输出。*/
        TIM_CtrlPWMOutputs(TIMx,ENABLE);    
    }
    /*舵机PWM初始化
       每增加0.1ms 舵机对应增加9度
    0.5ms---------0
    1.0ms---------45   
    1.5ms---------90
    2.0ms---------135
    2.5ms-----------180
    2.1ms    turn_left=150
    0.8ms    turn_right=25
    1.3ms    turn_front=75
    20ms的时基脉冲,如果想让舵机转90度,就应该发生一个高电平为1.5ms,周期为20ms的方波,duty=1.5/20=7.5% ,而定时器自动重装载寄存器arr的值为 1000 ,所以duty=75,时占空比为75/1000=7.5%. 
    */
    void SERVO_Init(void)
    {
        SERVO_Gpio_Init();
        SERVO_TIM_Config(TIM3,1000,1440,turn_front);
    /** 我们把定时器设置自动重装载寄存器 arr 的值为 1000,设置时钟预分频器为 1440,则
    驱动计数器的时钟:CK_CNT = CK_INT / (1440-1+1)=0.05M,则计数器计数一次的时间等于:
    1/CK_CNT=20us,当计数器计数到 ARR 的值 1000 时,产生一次中断,则中断一次的时间
    为:1/CK_CNT*ARR=20ms。
    PWM 信号的频率 f = TIM_CLK/{(ARR+1)*(PSC+1)}  TIM_CLK=72MHZ
                   = 72 000 000/(1000*1440)=5KHZ    
    */    
    }
    /*舵机角度控制*/
    void SERVO_Angle_Control(uint16_t Compare2)
    {
        TIM_SetCompare2(TIM3,Compare2);
    }
    

    编码器模块

    调节小车前进的速度和避障快慢我们采用EC11旋转式编码器,可以用于光度、湿度、音量调节等参数的调节。EC11编码器的形状类似于电位器,中心有一个旋钮可以调节PWM信号,光电码盘利用光电转换原理输出三组方波脉冲。EC11编码器的实物图如下:


    用来显示小车转速,以及左右编码器数值和电池电压等参数所用的是OLED显示模块,分辨率较高,而且功耗低,正常显示时仅0.06W,供电电压范围在3.3V-5V,有IIC和SPI两种通信协议可供选择。显示模块的亮度和对比度可以通过程序设置。由于它使用寿命长以及其他的优点,OLED更加适合小系统,本系统由于单片机引脚有限,不适合利用简单的LCD1602或者12864来显示,在多方对比之下OLED效果更好。OLED显示部分相对比较简单,大家参考中景园的例程就可以实现。


    展开全文
  • 智能小车-51单片机-智能小车超声波避障 智能小车-51单片机-智能小车超声波避障
  • 基于单片机的超声波避障小车,能实现自动躲避障碍物和显示行驶过的路程
  • 本系统采用80C51单片机为控制核心,利用超声波传感器检测道路上的障碍,控制电动小汽车的自动避障,快慢速行驶,以及自动停车,并可以自动记录时间、里程和速度,自动寻迹和寻光功能。整个系统的电路结构简单,可靠...
  • 本系统以设计题目的要求为目的,采用80C51单片机为控制核心,利用超声波传感器检测道路上的障碍,控制电动小汽车的自动避障,快慢速行驶,以及自动停车,并可以自动记录时间、里程和速度,自动寻迹和寻光功能
  • 基于51单片机,驱动芯片采用L298N,两个按键模拟红外对管,当按下对应按键的时候,相应的电机开始启动,从而实现避障的功能 仿真图2: A. 由LCD1602作为显示器,具有温度显示、声光报警器,ULN2003A作为电机驱动。 ...
  • # main.py -- put your code here! import machine from machine import Pin import time left_pin1 = Pin(14,Pin.OUT) left_pin2 = Pin(12,Pin.OUT) right_pin1 = Pin(13,Pin.OUT) right_pin2 = Pin(15,Pin.OUT) ...
  • 本系统以设计题目的要求为目的,采用80C51单片机为控制核心,利用超声波传感器检测道路上的障碍,控制电动小汽车的自动避障,快慢速行驶,以及自动停车,并可以自动记录时间、里程和速度,自动寻迹和寻光功能。...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 306
精华内容 122
关键字:

51超声波避障小车