打印

LM3S811板子设计四足机器人PWM篇——(一)

[复制链接]
4257|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
收到21ic的LM3S811的板子,自己非常的高兴。自己本来一直都在学习TI的LM3S系列的芯片有一定的基础。对于TI低端的LM3S系列的芯片上手比较快。最近自己用LM3S811来做个四足的机器人,希望和大家共同的交流和学习。
    在本次设计中的步骤:
       1、把机械的结构设计出来。
       2、能够实现的舵机的控制。
       3、实现四足机器人的行走(直走、后退、转弯)。
       4、超声波测距来壁障,红外对管来实现四足机器人的运行,人体红外感应模块。
       5、为了实现四足机器人的能够在不平稳的路面行走,用飞思卡尔的MMA7455三轴模块测量加速度值和倾角来完成身体平衡的矫正。
      6、无线传输控制。用的是NRF2401的2.4G模块。
      7、摄像头,完成图像的传输。
对于最后的步骤自己现在还不确定到底LM3S811能够胜任图像的处理和传输。试验过后才能确定,有那个网友能过的话可以交流一下。
一、LM3S811的整体认识
  在时钟、看门狗、FLASH和SRAM的存储结构中看了看LM3S811的数据文档。都知道怎么回事。还有基本的I/O口的设置,这对于新接触TI的LM3S系列的人来说还得需要看看,可以看看本论坛的一个帖子 LM3S811使用心得—从零开始学Cortex-M3内核单片机 ,讲的比较详细。并且它的基本知识可以参考本论坛的 :【原创】从EK-LM3S811学LM3S811的硬件设计。作者写的比较详细。
二、元器件的购买
  在淘宝网上找了很多舵机型号,并且在百度了一下,最后考虑到性价比我买了辉生的SG90和SG995两种舵机。回来实验了一下,感觉挺不错的就是感觉SG90舵机真小。
三、舵机的控制
     在舵机的控制上有很多方案:1、用定时器产生一定的矩形脉冲。2、用I/O口模拟的实现延迟和周期性的脉冲。3、用板子自带的PWM功能来产生具有一定占空比的矩形脉冲。最后考虑一下用板子自带的PWM的功能。但是另两种我也试了试也可以。
     舵机控制原理:舵机提供的电源是4.8V-6V。需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。对于SG90它是以180度角度范围转动,那么对应的控制关系是这样的:0.5ms——-90度;1.0ms——-45度;1.5ms——0度;2.0度——45度;2.5ms——90度。但是经过我的测试这只是个参考值,在用I/O口模拟的时候用上面的时间值并不能让舵机达到相应的转过的角度。用PWM控制也有点误差,这个要根据自己的舵机测试一下。但是与这个控制关系不会错的很大。对于舵机的工作原理就不在说了。
四、LM3S811的PWM学习
     通过看LM3S811的PWM文档,自己对PWM已经理解了。主要是看了三个库函数PWM.c、PWM.h和hw_pwm.h。在这里我要说的是这个库函数不是针对LM3S811板子的硬件而编写的。有些功能LM3S811板子上并没有具有。
    LM3S811板子一共有6个PWM引脚三个PWM生成器。对于LM3S的高端的板子上是有四个生成器8个PWM引脚。
    在LM3S811的PWM学习中注意库函数编写,可以参看https://bbs.21ic.com/icview-288342-1-1.html。后续在传代码

相关帖子

沙发
guozhiyang|  楼主 | 2011-12-3 11:32 | 只看该作者
在机械上我已经设计好了一个机器人的腿,用了两个SG90的舵机可以实现它的运动,下面是我写的代码。
#include "hw_memmap.h"
#include "hw_types.h"
#include "sysctl.h"
#include "gpio.h"
#include "pwm.h"
#include "hw_ints.h"
#include "delay.h"


#define PH0_PWM2  GPIO_PIN_0
#define PH1_PWM3  GPIO_PIN_1
#define LED       GPIO_PIN_6

unsigned int jiaodu[]={12000,16000,12000,8000};
unsigned int jiaodu1[]={12000,26000,12000,4000};
unsigned int jiaodu2[]={12000,20000,12000,4000,12000,16000,12000,8000};
//unsigned int jiaodu1[]={148000,140000,148000,156000};
void H_T();
void Q_J();
void Test();
/*********************************************************************************************************
** Function name:       main()
** Descriptions:        主函数
** input parameters:    NONE
** output parameters:   NONE
** Returned value:      NONE
*********************************************************************************************************/
int  main (void)
{
    SysCtlClockSet(SYSCTL_SYSDIV_25|                                  /*  配置8Hz外部晶振作为主时钟  */
                   SYSCTL_USE_PLL|
                   SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_6HZ);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH|SYSCTL_PERIPH_GPIOB                        /*  使能PWM2和PWM3输出所在GPIO  */

    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM);                          /*  使能PWM模块                 */

    SysCtlPWMClockSet(SYSCTL_PWMDIV_1);                                 /*  PWM时钟配置:不分频         */

    GPIOPinTypePWM(GPIO_PORTB_BASE,GPIO_PIN_0);                       /*  PH0配置为PWM功能            */
    GPIOPinTypePWM(GPIO_PORTB_BASE,GPIO_PIN_1);                    /*  PH1配置为PWM功能            */
   

   
    PWMGenConfigure(PWM_BASE, PWM_GEN_1,                                /*  配置PWM发生器1:加减计数    */
                    PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);

    PWMGenPeriodSet(PWM_BASE, PWM_GEN_1, 160000);                         /*  设置PWM发生器1的周期        */
  // PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, jiaodu2[0]);                        /*  设置PWM2输出的脉冲宽度      */
  // PWMPulseWidthSet(PWM_BASE, PWM_OUT_3, jiaodu2[0]);                        /*  设置PWM3输出的脉冲宽度      */
  //  PWMSyncUpdate(PWM_BASE,PWM_GEN_1_BIT);
    PWMOutputState(PWM_BASE, (PWM_OUT_2_BIT | PWM_OUT_3_BIT), true);    /*  使能PWM2和PWM3的输出        */

    PWMGenEnable(PWM_BASE, PWM_GEN_1);                                  /*  使能PWM发生器1,            */
    GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,LED);
                                                                       /*  开始产生PWM方波             */
  //  PWMGenIntTrigEnable(PWM_BASE,PWM_GEN_1,PWM_INT_CNT_ZERO);
   // PWMIntEnable(PWM_BASE,PWM_INT_GEN_1);
   // IntEnable(INT_PWM1);
//   IntMasterEnable();
    while(1)
    {
        Q_J();
       H_T();
      //Test();
    }
}

void Q_J()
{
  unsigned char i=1,j=1;
  PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, jiaodu[i++]);                    /*  设置PWM2输出的周期          */
  //PWMPulseWidthSet(PWM_BASE, PWM_OUT_3, jiaodu[i]);                  /*  设置PWM3输出的周期          */
    delay_ms(220);
  PWMPulseWidthSet(PWM_BASE,PWM_OUT_3,jiaodu1[j++]);
    delay_ms(220);
  PWMPulseWidthSet(PWM_BASE,PWM_OUT_2,jiaodu[i]);
  delay_ms(230);
}

void H_T()
{
    unsigned char i=1,j=2;
  PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, jiaodu[i++]);                    /*  设置PWM2输出的周期          */
  //PWMPulseWidthSet(PWM_BASE, PWM_OUT_3, jiaodu[i]);                  /*  设置PWM3输出的周期          */
  delay_ms(220);
  PWMPulseWidthSet(PWM_BASE,PWM_OUT_3,jiaodu1[j++]);
  delay_ms(220);
  PWMPulseWidthSet(PWM_BASE,PWM_OUT_2,jiaodu[i]);
  delay_ms(230);
}
也可以用PWM的中断的功能来是想舵机的控制,我能过了也比较的不错。但是自己之后要想在加上ucosii,在中断的嵌套上害怕出问题,所以先不用中断来控制舵机,而用了硬件的延迟的方法。这个只是简单的两个舵机控制,周末把四条腿做出来能让它走起来再跟大家分享点好东西。

使用特权

评论回复
板凳
guozhiyang|  楼主 | 2011-12-4 13:27 | 只看该作者
在延迟函数中用硬件的系统时钟函数实现精确地延迟
#ifndef __DELAY_H
#define __DELAY_H

#include "sysctl.h"
#define TheSysClock SysCtlClockGet() //系统时钟
#define delay_us(x) SysCtlDelay(x * (TheSysClock / 3000000));             //  延时约us
#define delay_ms(x) SysCtlDelay(x * (TheSysClock / 3000));             //  延时约ms
#endif
在这里要说明的是不管你设置的晶振频率是多少,都是这个函数。3000和3000000都不变。都是实现毫秒和微妙的延迟。

使用特权

评论回复
地板
fq1110| | 2011-12-4 18:53 | 只看该作者
不错不错.学习了.

使用特权

评论回复
5
tianm| | 2011-12-4 23:24 | 只看该作者
不错 希望能继续完善

使用特权

评论回复
6
guozhiyang|  楼主 | 2011-12-5 14:30 | 只看该作者
好的,我会继续完善。

使用特权

评论回复
7
guozhiyang|  楼主 | 2011-12-7 16:53 | 只看该作者
本帖最后由 guozhiyang 于 2011-12-7 16:56 编辑

自己学习LM3S811也有一段时间了,最近在用它做个机器人,所以PWM方面看的多一点。
想把自己如何用LM3S811的PWM模块来控制舵机的学习经历跟大家分享一下。
每学习一款MCU先了解它的I/O和定时器功能是必须得,这些我都不说了,大家自己看看应该都能学会。
主要说说PWM的一些东西。
1、首先是要了解LM3S811的PWM的特点
  PWM模块由三个PWM发生器模块和1个控制模块。每个PWM发生器模块包含1个定时器,2个PWM比较器,PWM信号发生器,
四区发生器和中断/ADC-触发选择器。
  每个PWM发生器模块产生两个PWM信号,这两个PWM信号可以是独立的信号,也可以是插入死区延迟的互补信号。
  PWM模块既可以产生简单的PWM信号,也可以产生带死区延迟的成对的PWM信号。3个发生器模块也可以产生3相反相器
桥所需要的完整的6通道的门控。
2、下面针对舵机的控制上说PWM功能
   首先要搞懂PWM的模块结构图

   从左往右说的话,定时器和比较器都是在发生器的控制下产生PWM脉冲,对于舵机的控制死区延迟的功能不用用,可以不使能。所以要设置好定时器的值和比较器的值很关键。
   由于用的是先递增后递减的计数模式,所以影响PWM信号的事件有6个:零、装载、匹配A递减、匹配A递增、匹配B递减、匹配B递增。因为这次只用到了比较器A,由于要产生占空比一定的矩形波,所以只用到匹配A递减、匹配A递增、匹配B递减、匹配B递增四个事件。
   
   所以其它两种都要不使能,这样在计数器的值匹配A递增的时候可以驱动PWMA引脚产生高电平,当计数器的值匹配A递减的时候可以驱动PWMA引脚产生低电平,同理可得比较器B.这样可以产生
  
  只要把相对应的寄存器的设置好就可以,不一定光用驱动库,也要看看寄存器。
这样通过设置加载值和比较器的值就可以产生占空比可变的矩形波。
  在周期设置的时候可以,一定要看你的系统频率。假如你的系统用的8MHZ的频率,要产生20ms的周期方波,那么你的定时器的加载值就要为1600000。20=160000/8000000*1000;这样就可以了。
东西太多了不知道如何写了。想说的写不出来。文字功底还得加强啊!

使用特权

评论回复
8
guozhiyang|  楼主 | 2011-12-7 16:57 | 只看该作者
我感觉这个函数在设置上有问题,我给他改改,我认为改过才对
void  PWMGenConfigure(unsigned long ulBase, unsigned long ulGen,
                unsigned long ulConfig)
{
    //
    // Check the arguments.
    //
    ASSERT(ulBase == PWM_BASE);
    ASSERT(PWMGenValid(ulGen));
    //
    // Compute the generator's base address.
    //
    ulGen = PWM_GEN_BADDR(ulBase, ulGen);
    //
    // Change the global configuration of the generator.
    //
    HWREG(ulGen + PWM_O_X_CTL) = ((HWREG(ulGen + PWM_O_X_CTL) &
                                   ~(PWM_X_CTL_MODE | PWM_X_CTL_DEBUG |
                                     PWM_X_CTL_LATCH | PWM_X_CTL_MINFLTPER |
                                     PWM_X_CTL_FLTSRC | PWM_X_CTL_DBFALLUPD_M |
                                     PWM_X_CTL_DBRISEUPD_M |
                                     PWM_X_CTL_DBCTLUPD_M |
                                     PWM_X_CTL_GENBUPD_M |
                                     PWM_X_CTL_GENAUPD_M |
                                     PWM_X_CTL_LOADUPD | PWM_X_CTL_CMPAUPD |
                                     PWM_X_CTL_CMPBUPD)) | ulConfig);
    //
    // Set the individual PWM generator controls.
    //
    if(ulConfig & PWM_X_CTL_MODE)
    {
        //
        // In up/down count mode, set the signal high on up count comparison
        // and low on down count comparison (that is, center align the
        // signals).
        //
        HWREG(ulGen + PWM_O_X_GENA) = (PWM_X_GENA_ACTCMPAU_ONE |
                                       PWM_X_GENA_ACTCMPAD_ZERO);
        HWREG(ulGen + PWM_O_X_GENB) = (PWM_X_GENB_ACTCMPBU_ONE |
                                       PWM_X_GENB_ACTCMPBD_ZERO);
    }
    else
    {
        //
        // In down count mode, set the signal high on load and low on count
        // comparison (that is, left align the signals).
        //
        HWREG(ulGen + PWM_O_X_GENA) = (PWM_X_GENA_ACTLOAD_ONE |
                                       PWM_X_GENA_ACTCMPAD_ZERO);
        HWREG(ulGen + PWM_O_X_GENB) = (PWM_X_GENB_ACTLOAD_ONE |
                                       PWM_X_GENB_ACTCMPBD_ZERO);
    }
其中的两句源码        HWREG(ulGen + PWM_O_X_GENA) = (PWM_X_GENA_ACTCMPAU_ONE |
                                       PWM_X_GENA_ACTCMPBU_ZERO);
在这里面有PWM_X_GENA_ACTCMPAU_ONE |PWM_X_GENA_ACTCMPBU_ZERO位或的操作,但是通过查hw_pwm.h我查到PWM_X_GENA_ACTCMPAU_ONE =0x00000030,PWM_X_GENA_ACTCMPBU_ZERO=0x00000020,但是位或以后不就是0x00000050;这样的话ActCmpAU=0x01,ActCmpAD=0x01,都是将输出信号反向。我认为它的驱动库有点问题。我把PWM_X_GENA_ACTCMPAD_ZERO<<2就可以实现一定的占空比得矩形波。我实验了可以。希望给大家的建议。

使用特权

评论回复
9
xlhtracy| | 2011-12-7 17:23 | 只看该作者
这个得研究研究

使用特权

评论回复
10
guozhiyang|  楼主 | 2011-12-9 13:59 | 只看该作者
在PWM的中断方面,谈谈它的应用:

     1、首先PWM发生器可以捕获相同的4个(或6个)计数器事件,并使用它们来产生中断或ADC触发信号。自己可以选择这些事件中的任一个或一组作为中断源;只要其中一个所选事件发生就会产生中断。
   
      2、对于本次用的PWM功能,选择匹配A递增和匹配B递增的方式来产生中断。所以在产生此事件的时候可以产生PWM中断,在中断处理中可以改变比较器A的值和比较器B的值来产生占空比可变的方波。但是对于舵机在用PWM中断的时候,要延迟一般240~300ms来让舵机完成上次的转动的角度,这点要注意的。
     3、自己也可以选择相同事件、不同事件、同组事件、不同组事件作为ADC触发源;只要其中一个所选事件发生就会产生ADC触发脉冲。选择的事件不同,在PWM信号内产生中断或ADC触发的位置也不同。所以在舵机用PWM的中断控制的时候用的是匹配A事件和匹配B事件为产生中断的位置,其他事件不再考虑。要注意的是中断和ADC触发触发都是基于原始事件的;而不考虑死区发生器在PWM信号边沿上产生的延迟。

使用特权

评论回复
11
thlight| | 2011-12-13 14:05 | 只看该作者
回去试一试

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

67

帖子

3

粉丝