本篇博文最后修改时间:2016年11月11日,09:24。
一、简介
本文介绍如何在SimpleBLEPeripheral工程中,使用PWM控制直流电机。
二、实验平台
协议栈版本:BLE-CC254x-1.4.0
编译软件:IAR 8.20.2
硬件平台:Smart RF(主芯片CC2541)
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
五、基础知识
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%”的占空比。