标签:
本篇博文最后修改时间: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); } //香瓜
//香瓜 #define SBP_PWM_DEAL_EVT 0x0004 //PWM的处理事件 #define SBP_PWM_STOP_EVT 0x0008 //PWM停止事件 //香瓜
//香瓜 #define SBP_PWM_DEAL_EVT_PERIOD 1 //香瓜
上面的SBP_PWM_STOP_EVT事件,只有在有定时控制电机时才使用到。
下文中会将定时部分代码注释,有需要时再添加使用。
1)添加PWM的头文件(SimpleBLEPeripheral.c中)
//香瓜 #include "PWM.h" //香瓜
//香瓜 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(反转) //香瓜
//香瓜 //给结构体数据赋初值 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); //香瓜
//香瓜 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%”的占空比。
标签:
原文地址:http://blog.csdn.net/feilusia/article/details/51152743