电机控制方案
直播中

茶壶茶茶

11年用户 584经验值
私信 关注
[问答]

如何在SimpleBLEPeripheral中去使用PWM控制直流电机?

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

回帖(1)

林茜

2021-6-30 15:40:31
  一、简介
  本文介绍如何在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
  香瓜BLE之Android群:541462902
  香瓜单片机之STM8/STM32群:164311667
  甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
  四、 实验前提
  1、在进行本文步骤前,请先 阅读 以下博文:
  1)《CC2541之PWM》:http://blog.csdn.net/feilusia/article/details/50459970
  2、在进行本文步骤前,请先 实现以下博文:
  1)《CC2541之按键》: http://blog.csdn.net/feilusia/article/details/47336473
  五、基础知识
  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.0ProjectsbleSimpleBLEPeripheralSourceGUA”路径下)
  //****************************************************************************** //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; //P10static 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.0ProjectsbleSimpleBLEPeripheralSourceGUA”路径下)
  //****************************************************************************** //name: PWM.h //introduce: 香瓜自定义的PWM驱动头文件 //author: 甜甜的大香瓜 //changetime: 2016.04.14 //email: 897503845@qq.com //****************************************************************************** #ifndef PWM_H#define PWM_H/*********************宏定义************************/ #ifndef U8typedef unsigned char U8;#endif#ifndef U16typedef 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$。。。。SimpleBLEPeripheralSourceGUA
  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; //p10static uint8 sPWM_P11 = 0; //p11static 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%”的占空比。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分