一、简介
上期咱们实现了通过手机BLE远程控制板上LED0、LED1指示灯的开与关,这期咱们结合之前实现的呼吸灯显示功能,实现一个亮度可调的小台灯与一个转速可调的小风扇。
同样基于上期的“Peripheral”例程,在“simpleProfileChangeCB()”回调函数中实现控制板上PWM4,PWM5占空比输出变化。在“0xFFE1”服务特征值下进行PWM4的占空比更改逻辑处理,在“0xFFE3”服务特征值下进行PWM5的占空比更改逻辑处理。当然在主函数中先对PA12初始化为PWM4、PA13初始化为PWM5。实验中,我们将PA12与MOS出关开关驱动模块相连接,PA13与L298N电机驱动模块的通道A使能接口相连接。为保证风扇顺时针方向旋转,因此需将PA0连接至L298N电机驱动模块的IN1,PA1连接至L298N电机驱动模块的IN2,并初始化PA0为高,PA1为低,用以实现正转。
二、硬件资源
(1)小台灯驱动模块
此次实验采用市面上常见的MOS开关触发驱动模块,配上一个带保护的充电模组TP4056,方便连上18650电池后便携移动使用。日光灯选择5V/2W的即可。其硬件连接示意图如下:

(2)小风扇驱动模块
此次实验用到L298N电机驱动模块,该模块应用比较广泛,不仅可以驱动直流电机,而且支持驱动42步进电机,下面介绍一下该驱动模块。L298N电机驱动模块的实物图及管脚分布如下图所示:

由此可知,该模块支持驱动两路直流电机,当然也可以用来驱动42步进电机。L298N的供电可选择12V或5V,根据电机的供电需求来选择。由于此次DIY用来驱动一个直流电机,因此只需要着重关注通道A使能管脚,即ENA;以及逻辑IN1与IN2逻辑输入管脚。另外我们要对直流电机进行PWM调速控制,则需要设置IN1和IN2高低电平,确定电机的转动方向,然后对使能端输出PWM脉冲,即可实现调速。注意当使能信号为0时,电机处于自动停止状态;当使能信号为1,且IN1和IN2为00或11时,电机处于制动状态,阻止电机转动。各管脚的逻辑关系列表如下图:

实验中的硬件连接示意图如下:

三、实物连接
各信号脚通过杜邦线相连接

四、代码编辑
与上期贴一样,在simpleProfileChangeCB()函数中添加相应的逻辑处理代码,设置PWM占空比步进长为2%。
/*********************************************************************
* @fn simpleProfileChangeCB
*
* [url=home.php?mod=space&uid=2666770]@Brief[/url] Callback from SimpleBLEProfile indicating a value change
*
* [url=home.php?mod=space&uid=3142012]@param[/url] paramID - parameter ID of the value that was changed.
* pValue - pointer to data that was changed
* len - length of data
*
* [url=home.php?mod=space&uid=1141835]@Return[/url] none
*/
static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len)
{
switch(paramID)
{
case SIMPLEPROFILE_CHAR1:
{
uint8_t pwm4cycle = atoi(pValue);
if(pwm4cycle >= 0 && pwm4cycle <= 50)
{
PWMX_ACTOUT(CH_PWM4, (64 * pwm4cycle)/ 50, High_Level, ENABLE); //PWM4占空比平均50等份更改
PRINT("profile ChangeCB CHAR1.. \\n");
}
else {
PRINT("set pwm4cycle overflow..\\n");
}
break;
}
case SIMPLEPROFILE_CHAR3:
{
uint8_t pwm5cycle = atoi(pValue);
if(pwm5cycle >= 0 && pwm5cycle <= 50)
{
PWMX_ACTOUT(CH_PWM5, (64 * pwm5cycle)/ 50, High_Level, ENABLE); //PWM5占空比平均50等份更改
PRINT("profile ChangeCB CHAR3..\\n");
}
else {
PRINT("set pwm5cycle overflow..\\n");
}
break;
}
default:
// should not reach here!
break;
}
}
当然由于代码中用到atoi函数,因此需要在“peripheral.c”源码中添加#include <stdlib.h>头文件。注意:由于设置外设的GPIO口为高电平时为正向逻辑,因此调用PWMX_ACTOUT()函数时采用High_Level逻辑。再者需要将数据长度宏定义更改为2,因为需要发送“0”~“50”间的任意字符,如果还是默认的1个字符,则发送两个字符会报发送失败。
#define SIMPLEPROFILE_CHAR1_LEN 2
#define SIMPLEPROFILE_CHAR3_LEN 2
“peripheral_main.c”源文件中的main函数部分,需增加相应的GPIO口初始化处理,默认初始状态为关闭小台灯、小风扇。
int main(void)
{
#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
PWR_DCDCCfg(ENABLE);
#endif
HSECFG_Capacitance(HSECap_18p);
SetSysClock(CLK_SOURCE_HSE_PLL_62_4MHz);
GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_5mA);
GPIOA_ModeCfg(GPIO_Pin_13, GPIO_ModeOut_PP_5mA);
PWMX_CLKCfg(4);
PWMX_CycleCfg(PWMX_Cycle_64);
PWMX_ACTOUT(CH_PWM4, 64 / 100, Low_Level, ENABLE);
PWMX_ACTOUT(CH_PWM5, 64 / 100, Low_Level, ENABLE);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
#ifdef DEBUG
GPIOA_SetBits(GPIO_Pin_14);
GPIOPinRemap(ENABLE, RB_PIN_UART0);
GPIOA_ModeCfg(GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
UART0_DefInit();
#endif
PRINT("%s\\n", VER_LIB);
GPIOA_ModeCfg( GPIO_Pin_0, GPIO_ModeOut_PP_5mA );
GPIOA_ModeCfg( GPIO_Pin_1, GPIO_ModeOut_PP_5mA );
GPIOA_SetBits(GPIO_Pin_0);
GPIOA_ResetBits(GPIO_Pin_1);
PWMX_ACTOUT(CH_PWM4, 64 / 100, Low_Level, DISABLE);
PWMX_ACTOUT(CH_PWM5, 64 / 100, Low_Level, DISABLE);
CH58x_BLEInit();
HAL_Init();
GAPRole_PeripheralInit();
Peripheral_Init();
Main_Circulation();
}
五、实验演示
使用手机蓝牙调试助手App,方便快捷得控制小台灯亮度与风扇转速。通过0xFFE1服务特征下的发送接口,输入“0”至“50”任意字符,控制pwm4的占空比输出,即控制小台灯的亮度;通过0xFFE3服务特征下的发送接口,输入“0”~“50”任意字符,控制pwm5的占空比输出,即控制小风扇的转速。演示视频见底部视频。