您的位置:首页 > 其它

【BLE】CC2541之PWM

2016-01-05 06:39 656 查看
[b]本篇博文最后修改时间:2017年01月06日,11:06。
[/b]

一、简介

本文以SimpleBLEPeripheral工程为例,介绍如何通过按键来控制P10与P11两路PWM,依次变化为0%、50%、100%的占空比,从而控制对应的led灯亮度渐变。

二、实验平台

协议栈版本: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、在进行本文步骤前,请先阅读以下博文:
暂无

2、在进行本文步骤前,请先实现以下博文:

暂无

五、基础知识
1、什么是PWM?

答:PWM是脉冲宽度调制的意思,是通过调整PWM的占空比来实现电机转动速度、led亮度等。

2、什么是占空比?

答:占空比就是高电平所占一个周期时间的比值。

比如一个周期是4S,而0~1S都是高电平、1S~4S都是低电平,那么占空比=1/4=25%

比如一个周期是6S,而0~3S都是高电平、3S~6S都是低电平,那么占空比=3/6=50%

比如一个周期是8S,周期内的8S都是高电平,那么占空比=8/8=100%

注意:占空比都是先高电平、后低电平。

3、如何利用定时器实现PWM?

答:比如香瓜想利用timer4的第0通道(P10)实现30%的占空比。大体的重要步骤如下:

1)根据占空比和计数方式算出T4CC0的值

选择计数方式为循环计数0x00~0xFF,也就是counter计数器会不断地从0跑到255。

则计算出T4CC0=255*30%=76。

2)将timer4的第0通道设置为输出比较模式。

3)设置当counter与T4CC0相等时,输出0;当counter为0时,输出1。

上面这几个重要步骤,就能在counter计数到0时输出高电平,在counter计数到76时为低电平,也就实现了占空比为30%。

六、实验步骤

1、工程中添加PWM.c

#include <ioCC2540.h>
#include "PWM.h"

#ifndef BV
#define BV(n)      (1 << (n))
#endif

static U8 sPWM_P10 = 0;    //P10的pwm
static U8 sPWM_P11 = 0;    //P11的pwm

//******************************************************************************
//name:             PWM_Init
//introduce:        PWM的初始化
//parameter:        none
//return:           none
//author:       甜甜的大香瓜
//changetime:       2016.01.05
//******************************************************************************
void PWM_Init(void)
{
P1DIR |= BV(0)|BV(1);         //P11和P10定义为输出
P1SEL |= BV(0)|BV(1);         //将P11和P10设置为外设功能;

T4CTL = 0x00;                 //1分频(32M/256=125K)、关timer、自由运行模式

T4CC0 = 255 - sPWM_P10;       //P10的初始化值
T4CC1 = 255 - sPWM_P11;       //P11的初始化值

T4CCTL0 = 0x2C;               //00 101 100无中断、Set output on compare, clear on 0xFF、比较模式、No Capture
T4CCTL1 = 0x2C;               //00 101 100无中断、Set output on compare, clear on 0xFF、比较模式、No Capture

T4CTL |= BV(4);               //开始定时器
}

//******************************************************************************
//name:             PWM_SetLed
//introduce:        PWM的两通道值设置
//parameter:        nPWM_P10:p10的pwm值
//                      nPWM_P11:p11的pwm值
//return:           none
//author:       甜甜的大香瓜
//changetime:       2016.01.05
//******************************************************************************
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:       甜甜的大香瓜
//changetime:       2016.01.05
//******************************************************************************
void PWM_GetLed(U8 *nPWM_P10, U8 *nPWM_P11)
{
*nPWM_P10 = sPWM_P10;
*nPWM_P11 = sPWM_P11;
}

//******************************************************************************
//name:             PWM_Pulse
//introduce:        PWM的值更新
//parameter:        none
//return:           none
//author:       甜甜的大香瓜
//changetime:       2016.01.05
//******************************************************************************
void PWM_Pulse(void)
{
//重新配置PWM值
T4CC0 = 255 - sPWM_P10;
T4CC1 = 255 - sPWM_P11;

//复位timer4的counter
T4CTL &= ~BV(2);

//使能定时器4
T4CTL |= BV(4);
}
上述代码中,T4CC0的赋值之所以需要255放在前面减,是因为上面的配置是先低电平后高电平,与实际需要的先高后低的占空比相反了。

因此取补后即可得到正确的占空比。

2、工程中添加PWM.h

#ifndef PWM_H
#define PWM_H

#ifndef U8
typedef unsigned char U8;
#endif

#ifndef U16
typedef unsigned short U16;
#endif

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_Pulse(void);

#endif

3、应用层代码中包含PWM头文件(simpleBLEPeripheral.c中)

#include "PWM.h"

4、定义一组led的PWM结构体(simpleBLEPeripheral.c中)

typedef struct
{
uint8 PWM_P10;              //P10的pwm值
uint8 PWM_P11;              //P11的pwm值
}LED_CONFIG;
LED_CONFIG led_config;

5、初始化PWM(simpleBLEPeripheral.c中)

void SimpleBLEPeripheral_Init( uint8 task_id )
{
simpleBLEPeripheral_TaskID = task_id;

//给结构体数据赋初值
led_config.PWM_P10 = 0xFF;
led_config.PWM_P11 = 0xFF;

//PWM初始化
PWM_SetLed(led_config.PWM_P10, led_config.PWM_P11);
PWM_Init();

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

……
}


两路led都初始化为100%占空比。

6、添加一个PWM处理事件

1)添加PWM处理事件的宏(simpleBLEPeripheral.h中

#define SBP_PWM_DEAL_EVT                        0x4000  //PWM处理事件


2)添加PWM处理的事件周期(simpleBLEPeripheral.c中

#define SBP_PWM_DEAL_EVT_PERIOD         1
这里定义为1ms,每1ms就会执行一次PWM处理事件

3)添加PWM处理事件代码(simpleBLEPeripheral.c的SimpleBLEPeripheral_ProcessEvent函数中

//PWM处理事件
if ( events & SBP_PWM_DEAL_EVT )
{
U8 nPWM_P10 = 0;
U8 nPWM_P11 = 0;

//获取当前的pwm值
PWM_GetLed(&nPWM_P10, &nPWM_P11);

//nPWM_P10的pwm值更新,慢慢变化1的pwm值
if(nPWM_P10 > led_config.PWM_P10)//当前的值比预计值大时
{
PWM_SetLed(--nPWM_P10, nPWM_P11); //先更新pwm值
PWM_Pulse();                      //执行到计数器上
osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );
return (events ^ SBP_PWM_DEAL_EVT);
}
else if(nPWM_P10 < led_config.PWM_P10)//当前的值比预计值小时
{
PWM_SetLed(++nPWM_P10, nPWM_P11); //先更新pwm值
PWM_Pulse();                      //执行到计数器上
osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );
return (events ^ SBP_PWM_DEAL_EVT);
}

//nPWM_P11的pwm值更新,慢慢变化1的pwm值
if(nPWM_P11 > led_config.PWM_P11)//当前的值比预计值大时
{
PWM_SetLed(nPWM_P10, --nPWM_P11); //先更新pwm值
PWM_Pulse();                      //执行到计数器上
osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );
return (events ^ SBP_PWM_DEAL_EVT);
}
else if(nPWM_P11 < led_config.PWM_P11)//当前的值比预计值小时
{
PWM_SetLed(nPWM_P10, ++nPWM_P11); //先更新pwm值
PWM_Pulse();                      //执行到计数器上
osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );
return (events ^ SBP_PWM_DEAL_EVT);
}

return (events ^ SBP_PWM_DEAL_EVT);
}

7、添加按键测试代码(simpleBLEPeripheral.c中

static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
{
VOID shift;  // Intentionally unreferenced parameter
static uint8 sPWM_status = 0;

if ( keys & HAL_KEY_SW_6 )
{
switch(sPWM_status)
{
//0%占空比、灭灯
case 0:  led_config.PWM_P10 = 0x00;
led_config.PWM_P11 = 0x00;
sPWM_status = 1;
break;

//50%占空比、半亮灯
case 1:  led_config.PWM_P10 = 0x7F;
led_config.PWM_P11 = 0x7F;
sPWM_status = 2;
break;

//100%占空比、亮灯
case 2:  led_config.PWM_P10 = 0xFF;
led_config.PWM_P11 = 0xFF;
sPWM_status = 0;
break;

//其他情况时都为0%占空比、灭灯
default: led_config.PWM_P10 = 0x00;
led_config.PWM_P11 = 0x00;
sPWM_status = 1;
break;
}

//执行pwm处理事件变化led
osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PWM_DEAL_EVT, SBP_PWM_DEAL_EVT_PERIOD );
}
}
上述代码的意思是通过按键,实现0%、50%、100%占空比的切换。

七、注意事项

暂无

八、实验结果

开发板上电为P10和P11对应的D1和D2灯亮。

第一次按下按键S1,灯从D1渐灭,随后D2也渐灭。此时P10与P11的电压值均为0V。

第二次按下按键S1,灯从D1渐亮,随后D2也渐亮。但亮度均不够明亮。此时P10与P11的电压值均为1.5V。

第三次按下按键S1,D1与D2的亮度均达到最亮值。此时P10与P11的电压值均为3.1V。

因此,实现了通过按键触发改变LED渐变亮度,实验成功。

八、PWM相关问题

1、板子上电时P10对应的LED为什么会闪烁一下?

答:协议栈的LCD部分代码,在初始化时将P10设置为了IO输出状态,而后又被PWM设置为第二功能,因此电平会有个波动。

解决办法是:

HAL_LCD=FALSE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: