码迷,mamicode.com
首页 > 其他好文 > 详细

【BLE】CC2541之PWM控制直流电机

时间:2016-04-15 12:17:06      阅读:747      评论:0      收藏:0      [点我收藏+]

标签:

本篇博文最后修改时间:2016年4月14日,18:24。


一、简介

本文介绍如何在SimpleBLEPeripheral工程中,使用PWM控制直流电机。


二、实验平台

协议栈版本:BLE-CC254x-1.4.0

编译软件:IAR 8.20.2

硬件平台:Smart RF(主芯片CC2541)


三、版权声明

博主:甜甜的大香瓜

声明:喝水不忘挖井人,转载请注明出处。

原文地址:http://blog.csdn.net/feilusia

联系方式:897503845@qq.com

技术交流QQ群(香瓜BLE之CC2541):127442605


四、实验前提

在进行本文步骤前,请先阅读以下博文:

1、《CC2541之PWM》:http://blog.csdn.net/feilusia/article/details/50459970

2、《CC2541之按键》:http://blog.csdn.net/feilusia/article/details/47336473

注:《CC2541之PWM》可只阅读,而《CC2541之按键》需要实现。


五、基础知识

1、直流电机是什么?

答:电机也就是马达,小时候玩的四驱车里的马达就是电机,能控制正反转、速度。

常用的电机有两类,直流电机与步进电机。

1)直流电机:便宜、只有2根控制线因此操作较易、转动误差大。无转动精度要求时可使用。

2)步进电机:较贵、有4根控制线因此操作较难、可根据脉冲计算步数进行精确定位。有转动精度要求可使用。


2、单片机中如何使用直流电机?

答:单片机是不能直接驱动电机的,需要有驱动电路。可以上淘宝买一个5V的直流电机+两路的H桥模块。

连接如下:

技术分享

H桥模块一共6个输入口,如上图最下面的6个引脚,从左到右依次为:B-1A、B-1B、GND、VCC、A-1A、A-1B。

H桥模块一共4个输出口,如上图最上面的4个引脚,左边两个引脚可以为一个电机使用,右边两个引脚可以为另一个电机使用。


注:本文的实验中使用如上图,也就是使用右边的通道,A-1A接P10、A-1B接P11。


六、代码修改

1、编写并添加自定义的电机驱动

1)写一个电机驱动PWM.c(存放在“……\BLE-CC254x-1.4.0\Projects\ble\SimpleBLEPeripheral\Source\GUA”路径下)

//******************************************************************************      
//name:         PWM.c      
//introduce:    香瓜自定义的PWM驱动  
//author:       甜甜的大香瓜    
//changetime:   2016.04.14  
//email:        897503845@qq.com  
//****************************************************************************** 
#include <ioCC2540.h> 
#include "PWM.h"

/*********************宏定义************************/
#ifndef BV
#define BV(n)      (1 << (n))
#endif

/*********************内部变量************************/
static U8 sPWM_P10 = 0;    //P10
static U8 sPWM_P11 = 0;    //P11

//******************************************************************************      
//name:             PWM_Init      
//introduce:        PWM的初始化    
//parameter:        none     
//return:           none    
//author:           甜甜的大香瓜           
//email:            897503845@qq.com         
//changetime:       2016.04.14               
//****************************************************************************** 
void PWM_Init(void)
{ 
  P1DIR |= BV(0)|BV(1);         //P11和P10定义为输出 
  P1SEL |= BV(0)|BV(1);         //将P11和P10设置为外设功能; 
  
  T4CTL = 0x80;                 //16分频(8K)、关timer、自由运行模式
  T4CC0 = 255 - sPWM_P10;       //P10的初始化值,warm
  T4CC1 = 255 - sPWM_P11;       //P11的初始化值,cold
  T4CCTL0 = 0x2C;               //00 101 100无中断、Clear output on compare, set on 0x00、比较模式、No Capture
  T4CCTL1 = 0x2C;               //00 101 100无中断、Clear output on compare, set on 0x00、比较模式、No Capture  
  
  T4CTL |= BV(4);               //开始定时器  
}

//******************************************************************************      
//name:             PWM_SetLed     
//introduce:        PWM的两通道值设置    
//parameter:        nPWM_P10:p10的pwm值     
//                  nPWM_P11:p11的pwm值   
//return:           none   
//author:           甜甜的大香瓜           
//email:            897503845@qq.com         
//changetime:       2016.04.14               
//******************************************************************************
void PWM_SetLed(U8 nPWM_P10, U8 nPWM_P11)
{
  sPWM_P10 = nPWM_P10;
  sPWM_P11 = nPWM_P11;
}

//******************************************************************************      
//name:             PWM_GetLed     
//introduce:        PWM的两通道值读取    
//parameter:        nPWM_P10:p10的pwm值     
//                  nPWM_P11:p11的pwm值   
//return:           none   
//author:           甜甜的大香瓜           
//email:            897503845@qq.com         
//changetime:       2016.04.14               
//******************************************************************************
void PWM_GetLed(U8 *nPWM_P10, U8 *nPWM_P11)
{
  *nPWM_P10 = sPWM_P10;
  *nPWM_P11 = sPWM_P11;
}

//******************************************************************************      
//name:             PWM_ControlData_Deal     
//introduce:        将占空比的数据与电机控制情况,转换成p10、p11的pwm数    
//parameter:        nPWM_P10:p10的pwm值     
//                  nPWM_P11:p11的pwm值   
//                  nDuty_Cycle:占空比
//                  nMotor_Status:停止、正转、反转
//return:           none   
//author:           甜甜的大香瓜           
//email:            897503845@qq.com         
//changetime:       2016.04.14               
//******************************************************************************
void PWM_ControlData_Deal(U8 *nPWM_P10, U8 *nPWM_P11, U8 nMotor_Duty_Cycle, U8 nMotor_Status)
{
  switch(nMotor_Status)
  {
    case sMotor_Status_OFF:
        *nPWM_P10 = 0;
        *nPWM_P11 = 0;
        break;
			
    case sMotor_Status_POSITIVE:
        *nPWM_P10 = 0;
        *nPWM_P11 = (U8)(0xFF*nMotor_Duty_Cycle*0.01);
        break;

    case sMotor_Status_negative:
        *nPWM_P10 = (U8)(0xFF*nMotor_Duty_Cycle*0.01);
        *nPWM_P11 = 0;
        break;

    default:
        *nPWM_P10 = 0;
        *nPWM_P11 = 0;
        break;       
  }
}

//******************************************************************************      
//name:             PWM_Pulse      
//introduce:        PWM的值更新   
//parameter:        none     
//return:           none    
//author:           甜甜的大香瓜           
//email:            897503845@qq.com         
//changetime:       2016.04.14               
//****************************************************************************** 
void PWM_Pulse(void)
{
  // Set up the timer registers
  T4CC0 = 255 - sPWM_P10;             //P10的初始化值,warm
  T4CC1 = 255 - sPWM_P11;             //P11的初始化值,cold

  // Reset timer
  T4CTL &= ~BV(2);  
  
  // start timer
  T4CTL |= BV(4); 
}

2)写一个电机驱动头文件PWM.h(存放在“……\BLE-CC254x-1.4.0\Projects\ble\SimpleBLEPeripheral\Source\GUA”路径下)

//******************************************************************************      
//name:         PWM.h      
//introduce:    香瓜自定义的PWM驱动头文件  
//author:       甜甜的大香瓜    
//changetime:   2016.04.14  
//email:        897503845@qq.com  
//****************************************************************************** 
#ifndef PWM_H
#define PWM_H


/*********************宏定义************************/ 
#ifndef U8
typedef unsigned char U8;
#endif

#ifndef U16
typedef unsigned short U16;
#endif

#define sMotor_Status_OFF                       0x00    //停止(P11低、P10低)
#define sMotor_Status_POSITIVE                  0x01    //正转(P11高、P10低)   
#define sMotor_Status_negative                  0x02    //反转(P11低、P10高)


/*********************函数声明************************/ 
extern void PWM_Init(void);
extern void PWM_SetLed(U8 nPWM_P10, U8 nPWM_P11);
extern void PWM_GetLed(U8 *nPWM_P10, U8 *nPWM_P11);
extern void PWM_ControlData_Deal(U8 *nPWM_P10, U8 *nPWM_P11, U8 nMotor_Duty_Cycle, U8 nMotor_Status);
extern void PWM_Pulse(void);

#endif

3)工程中添加PWM.c和PWM.h

技术分享


4)在IAR设置中添加按键驱动源文件路径

$PROJ_DIR$\..\..\SimpleBLEPeripheral\Source\GUA  

2、定义PWM相关事件

1)定义PWM相关事件(SimpleBLEPeripheral.c的SimpleBLEPeripheral_ProcessEvent中)

//香瓜  
  //PWM处理事件 
  if ( events & SBP_PWM_DEAL_EVT )
  {       
    //更新PWM
    PWM_ControlData_Deal(&sPWM_P10, &sPWM_P11, motor_config.Duty_Cycle, sMotor_Status);//根据占空比和电机转动情况,计算pwm值      
    PWM_SetLed(sPWM_P10, sPWM_P11);             //先更新pwm值        
    PWM_Pulse();                                //执行到计数器上  
    
    //如果有定时,则会定时一段时间后停止
    if((sMotor_Status != sMotor_Status_OFF) && (motor_config.Time!= 0))//开启定时器
    {
      osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_STOP_EVT, motor_config.Time );    
    }
    
    return (events ^ SBP_PWM_DEAL_EVT);    
  }
  
  //PWM停止事件 
  if ( events & SBP_PWM_STOP_EVT )
  {       
    sMotor_Status = sMotor_Status_OFF;          //0(停止)、1(正转)、2(反转)
    PWM_ControlData_Deal(&sPWM_P10, &sPWM_P11, motor_config.Duty_Cycle, sMotor_Status);//根据占空比和电机转动情况,计算pwm值      
    PWM_SetLed(sPWM_P10, sPWM_P11);             //先更新pwm值        
    PWM_Pulse();                                //执行到计数器上  

    return (events ^ SBP_PWM_STOP_EVT);     
  }  
//香瓜

2)定义PWM相关事件的宏(SimpleBLEPeripheral.h中)

//香瓜  
#define SBP_PWM_DEAL_EVT                                  0x0004  //PWM的处理事件
#define SBP_PWM_STOP_EVT                                  0x0008  //PWM停止事件    
//香瓜  

3)定义PWM事件的定时执行时间(SimpleBLEPeripheral.c中)

//香瓜
#define SBP_PWM_DEAL_EVT_PERIOD         1 
//香瓜  

上面的SBP_PWM_STOP_EVT事件,只有在有定时控制电机时才使用到。

下文中会将定时部分代码注释,有需要时再添加使用。


3、初始化PWM相关

1)添加PWM的头文件(SimpleBLEPeripheral.c中)

//香瓜
#include "PWM.h" 
//香瓜

2)定义PWM使用到的变量(SimpleBLEPeripheral.c中)

//香瓜
typedef struct   
{  
    uint8  Duty_Cycle;                  //电机转速(0~64)  
    uint32 Time;                        //转动时间   
}MOTOR_CONFIG;  
MOTOR_CONFIG motor_config;  

static uint8 sPWM_P10 = 0;                              //p10
static uint8 sPWM_P11 = 0;                              //p11
static uint8 sMotor_Status = sMotor_Status_OFF;         //0(停止)、1(正转)、2(反转)
//香瓜

3)初始化变量、PWM驱动等(SimpleBLEPeripheral.c的SimpleBLEPeripheral_Init中)

//香瓜
 //给结构体数据赋初值  
  motor_config.Duty_Cycle = 0x00;     
  
  //根据占空比和电机转动情况,计算pwm值
  PWM_ControlData_Deal(&sPWM_P10, &sPWM_P11, motor_config.Duty_Cycle, sMotor_Status); 
  
  //PWM初始化  
  PWM_SetLed(sPWM_P10, sPWM_P11);     
  PWM_Init();    

  //默认是ENABLE的,会让RF期间停止MCU  
  HCI_EXT_HaltDuringRfCmd(HCI_EXT_HALT_DURING_RF_DISABLE); 
//香瓜

4、修改按键处理函数(SimpleBLEPeripheral.c中)

//香瓜
static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
{
  VOID shift;  // Intentionally unreferenced parameter     

  //切换电机开关机情况
  if ( keys & HAL_KEY_UP )  
  {  
    switch(sMotor_Status)  
    {  
      //停止电机状态,切换到正转状态
      case sMotor_Status_OFF: 
        {
          sMotor_Status = sMotor_Status_POSITIVE;  
          break;           
        }
        
      //正转状态,切换到反转状态
      case sMotor_Status_POSITIVE: 
        {
          sMotor_Status = sMotor_Status_negative;  
          break;           
        }
 
      //反转状态,切换到停止状态
      case sMotor_Status_negative: 
        {
          sMotor_Status = sMotor_Status_OFF;  
          break;           
        }

      //其他情况,切换到停止状态 
      default:
        {
          sMotor_Status = sMotor_Status_OFF;  
          break;                
        }                     
    }   
  }

/*  
  if ( keys & HAL_KEY_DOWN )  
  {  
    switch(motor_config.Time)  
    {  
      //无定时状态,切换到2S停止状态
      case 0: 
        {
          motor_config.Time = 2000;  
          break;           
        }
        
      //2S停止状态,切换到10S停止状态
      case 2000: 
        {
          motor_config.Time = 10000;  
          break;           
        }
 
      //10S停止状态,切换到无停止状态
      case 10000: 
        {
          motor_config.Time = 0;   
          break;           
        }

      //其他情况,切换到无停止状态 
      default: 
        {
          motor_config.Time = 0;   
          break;           
        }        
    }   
  }
*/
  
  //切换占空比
  if ( keys & HAL_KEY_SW_6 )  
  {  
    switch(motor_config.Duty_Cycle)  
    {  
      //占空比为0的状态,切换到占空比为50的状态
      case 0x00: 
        {
          motor_config.Duty_Cycle = 0x32;  
          break;           
        }
        
      //占空比为50的状态,切换到占空比为100的状态
      case 0x32: 
        {
          motor_config.Duty_Cycle = 0x64;  
          break;           
        }
 
      //占空比为100的状态,切换到占空比为0的状态
      case 0x64: 
        {
          motor_config.Duty_Cycle = 0x00;  
          break;           
        }

      //其他情况,切换到占空比为0的状态 
      default:
        {
          motor_config.Duty_Cycle = 0x00; 
          break;      
        }                         
    }    
  } 
  
  //执行pwm处理事件变化电机 
  osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );    
}
//香瓜
为了不使例子过于复杂,代码中将电机转动定时部分的代码注释。

需要定时控制电机时可参考上面的注释代码进行添加。


5、将IAR设置中的LCD宏关闭

技术分享

如果不关闭,在上电时会造成P10、P11的电平不稳,这个电平不稳就是LCD驱动造成的。

因此,需要在此禁止LCD的驱动初始化。


七、实验结果

1、通过按Smart RF板上的UP键,可以不停地切换“停止、正转、反转”的停转状态。

2、通过按Smart RF板上的S1键,可以不停地切换“0%、50%、100%”的占空比。






【BLE】CC2541之PWM控制直流电机

标签:

原文地址:http://blog.csdn.net/feilusia/article/details/51152743

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!