本文以SimpleBLEPeripheral以项目为例,介绍如何通过按钮控制P10与P11两路PWM,依次变为0%、50%、100%,以控制相应的空比led渐变亮度。
协议栈版:BLE-CC254x-1.4.0
编译软件: IAR 8.20.2
博主:甜甜的大香瓜
声明:喝水不忘挖井人。请注明转载来源。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
答:PWM是脉冲宽度调制的意思,是通过调整PWM的占空比来实现电机转动速度、led亮度等。
答:占空比就是高电平所占一个周期时间的比值。
比如一个周期是4S,而0~1S都是高电平、1S~4S都是低电平,那么占空比=1/4=25%
比如一个周期是6S,而0~3S都是高电平、3S~6S都是低电平,那么占空比=3/6=50%
比如一个周期是8S,周期内的8S都是高电平,那么占空比=8/8=100%
注意:占空比都是先高电平、后低电平。
答:比如香瓜想利用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%。
#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放在前面减,是因为上面的配置是先低电平后高电平,与实际需要的先高后低的占空比相反了。 因此取补后即可得到正确的占空比。 #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 #include "PWM.h" typedef struct
{
uint8 PWM_P10; //P10的pwm值
uint8 PWM_P11; //P11的pwm值
}LED_CONFIG;
LED_CONFIG led_config; 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%占空比。
#define SBP_PWM_DEAL_EVT 0x4000 //PWM处理事件
#define SBP_PWM_DEAL_EVT_PERIOD 1这里定义为1ms,每1ms就会执行一次PWM处理事件 //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);
} 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渐变亮度,实验成功。
答:协议栈的LCD部分代码,在初始化时将P10设置为了IO输出状态,而后又被PWM设置为第二功能,因此电平会有个波动。
解决办法是:
HAL_LCD=FALSE