原创博客,如有转载,注明出处——在金华的电子民工林。
前面说过,CC2640R2F的外设驱动,协议栈都已经写好,非常方便调用,现在就来说说,怎么调用这些特殊的外设,而且,所有的外设添加思路一样,这篇博文,就介绍下添加的思路,以后的博客,只介绍添加的步骤,不讲思路。学会以后,大家可以更加方便的使用CC2640R2F进行项目的开发。
本人使用CCS,也强烈推荐同行们开发CC2640R2F也使用CCS,契合度最高。
首先,我们看底层文件CC2640R2_LAUNCHXL.C。很多人看到这个文件,一头雾水,那么多的数组,结构体等等,不知道做什么用。其实这些都是范例,给大家参考如何调用底层驱动的范例。比如PWM部分的代码如下:
/*
* =============================== PWM ===============================
* Remove unused entries to reduce flash usage both in Board.c and Board.h
*/
#include
#include
PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWMCOUNT];
const PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWMCOUNT] = {
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3B },
};
const PWM_Config PWM_config[CC2640R2_LAUNCHXL_PWMCOUNT] = {
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM0], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM0] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM1], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM1] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM2], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM2] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM3], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM3] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM4], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM4] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM5], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM5] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM6], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM6] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[CC2640R2_LAUNCHXL_PWM7], &pwmtimerCC26xxHWAttrs[CC2640R2_LAUNCHXL_PWM7] },
};
const uint_least8_t PWM_count = CC2640R2_LAUNCHXL_PWMCOUNT;
这些的数组定义有什么用呢?好吧,我们看看在那些地方,会使用到这些object,HwAttrs。我们打开PWMTimerCC26XX.c这个文件,有一个子程序:PWM_Handle PWMTimerCC26XX_open(PWM_Handle handle, PWM_Params *params)。这条是需要在初始化的时候调用。
作用是什么?就是我们申请一个操作PWM的HANDLE,我们初始化PWM的内容都存在内存的一个位置,而接下来我们对PWM的操作,只要传递这个地址,CPU就能知道我们是要对哪个外设进行操作,更加方便。所以,这个子函数的返回值,就是一个handle,当我们成功申请了一个外设使用(就是调用这个子程序返回一个不是0的数值,表示系统已经分配了一个handle),在接下来的使用中,我们只需要对这个handle进行操作即可。
然后看括号里的形参,第一个参数,也是handle?怎么回事?怎么有两个handle?和返回值是一样的属性? 我们来说明一下,形参这个handle,就是我们预想的要初始化的端口,就是我们前面PWM_Config PWM_config[CC2640R2_LAUNCHXL_PWMCOUNT] 这个数组里的成员,0-7,分别代表了8个端口。PWM最多可以分配8个端口。这样是不是对应起来了? 又有人要问,PWM_Config和PWM_Handle 的定义是不一样的啊?这个请朋友们自己去看这两者的定义,其实就是一个是数组形式,一个是指针形式,这个指针指向的内容格式是一样的。
然后看第二个形参,params,这个就是我们初始化的内容了。
再总结一下,这个子程序,返回一个handle,是我们后面操作的基础参数,输入的形参,一个是我们要配置的IO端口,一个是我们要配置的初始化参数。清晰明了。
下面贴上这个子程序的代码:
/* Open the specific PWM peripheral with the settings given in params.
Will return a PWM handle if successfull, NULL if failed.
PWM will output configured idle level when opened.
Function sets a dependency on the underlying timer and adds the PWM pin to
its internal PIN handle.
*/
PWM_Handle PWMTimerCC26XX_open(PWM_Handle handle, PWM_Params *params)
{
PWMTimerCC26XX_HwAttrs const *hwAttrs = handle->hwAttrs;
PWMTimerCC26XX_Object *object = handle->object;
/* Check if PWM already open */
uint32_t key = Hwi_disable();
if (object->isOpen)
{
Hwi_restore(key);
Log_error1("PWM_open(%x): Unit already in use.", (UArg) handle);
return NULL;
}
…………
}
为什么我只撸这么一小段代码?因为我主要就是让大家看看这个子程序中的头两句,就是定义了两个参数,这两个参数的格式是什么样的?就是我们在上面看到过的两个数组的格式,是吧?就是说,协议栈,已经把底层驱动写好,把驱动需要的格式也给我们写好了,我们只要拿来用就行了。
怎么拿来用呢?
首先,先建议一个.c的文件,比如就叫GUA_PWM.c,然后我们把上面那段协议栈已经帮我们定义好的代码拷贝到这个.c里,如下面的代码:
注意,代码我把名称改过了,和底层的不同,避免冲突。
#include
#include
#include
#include
#include
#include
#include "ti/drivers/PWM.h"
#include "ti/drivers/pwm/PWMTimerCC26XX.h"
#include "ti/drivers/timer/GPTimerCC26XX.h"
#include "board.h"
#include "UserPwm.h"
PWMTimerCC26XX_Object pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWMCOUNT];
const PWMTimerCC26XX_HwAttrs pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWMCOUNT] = {
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN0, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN1, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN2, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN3, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN4, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN5, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2B },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN6, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3A },
{ .pwmPin = CC2640R2_LAUNCHXL_PWMPIN7, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3B },
};
const PWM_Config UPWM_config[CC2640R2_LAUNCHXL_PWMCOUNT] = {
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM0], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM0] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM1], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM1] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM2], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM2] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM3], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM3] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM4], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM4] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM5], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM5] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM6], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM6] },
{ &PWMTimerCC26XX_fxnTable, &pwmtimerCC2640Objects[CC2640R2_LAUNCHXL_PWM7], &pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWM7] },
};
const uint_least8_t UPWM_count = CC2640R2_LAUNCHXL_PWMCOUNT;
这个拷贝出来我们就能使用了,所以说,底层的代码是供我们参考的,我们拿来用就行,不需要去修改他。
接下来,就是怎么初始化了,下面贴上初始化的代码:
PWM_Params userPwm[CC2640R2_LAUNCHXL_PWMCOUNT]; //params
PWM_Handle Huserp[CC2640R2_LAUNCHXL_PWMCOUNT];
uint8_t UserPwmInit(uint8_t channel,uint8_t initlevel)
{
if(channel>=UPWM_count) return 0; //PWM最大就8个。
if(initlevel)
{
userPwm[channel].idleLevel = PWM_IDLE_HIGH; //没有打开PWM时的状态,高或者低
userPwm[channel].dutyValue = 100 ; //设置一个初始值。
}
else
{
userPwm[channel].idleLevel = PWM_IDLE_LOW; //没有打开PWM时的状态,高或者低
userPwm[channel].dutyValue = 0 ; //设置一个初始值。
}
/* userPwm.periodUnits = PWM_PERIOD_HZ;
userPwm.periodValue = 8e6;
userPwm.dutyUnits = PWM_DUTY_FRACTION;
userPwm.dutyValue = PWM_DUTY_FRACTION_MAX ;*/ //这里是定义HZ数
userPwm[channel].periodUnits = PWM_PERIOD_US; //定义时间,单位是us
userPwm[channel].periodValue = 100; //最大是100us,频率就是10KHZ
userPwm[channel].dutyUnits = PWM_DUTY_US; //单位US
// userPwm[channel].dutyValue = 0 ; //设置一个初始值。
Huserp[channel] = UPWM_config[channel].fxnTablePtr->openFxn((PWM_Handle)&UPWM_config[channel],&userPwm[channel]);
//定义一个HANDLE,因为后期对PWM的操作都是对HANDLE操作,先用CONFIG注册,获得一个HANDLE。具体程序在PWM。h.第一个PWM_configp[]里的数字,0-7都是一样的,指向同一个程序
//这条指令指向了程序里的open程序,就是初始化用一次。
if(Huserp[channel]==NULL) return 0; //如果获得不到数据,说明开启失败。
return 1;
}
以上就是初始化的程序,接下来的应用就简单了,来来回回就是开启,关闭,设置占空比等,我们也写一个子程序,轻松调用,代码如下:
void PWMSetDuty(uint32_t ddat,uint8_t channel) //设置占空比,不能超过最大的占空比值。
{
if(channel>=UPWM_count) return ;
if(ddat>100) ddat = 100;
UPWM_config[channel].fxnTablePtr->setDutyFxn(Huserp[channel], ddat);
}
void StartPwmOut(uint8_t channel) //开始PWM输出,没开启这条指令,不会输出。
{
if(channel>=UPWM_count) return ;
UPWM_config[channel].fxnTablePtr->startFxn(Huserp[channel]);
}
void StopPwmOut(uint8_t channel) //关闭PWM输出,关闭后的状态是初始状态。建议关闭输出前,先赋予PWM的初始值
{
if(channel>=UPWM_count) return ;
PWMSetDuty(100,channel);
UPWM_config[channel].fxnTablePtr->stopFxn(Huserp[channel]);
}
最后,一个很重要的点,就是怎么把PWM输出口定义到我们想要的端口上呢?
参考我的IO口设置那一篇,就是把HwAttrs这个数组里的PIN口定义,给重新定义一下,
#define GUA_PWMPIN0 IOID_00
#define GUA_PWMPIN1 IOID_01
#define GUA_PWMPIN2 IOID_02
#define GUA_PWMPIN3 IOID_03
#define GUA_PWMPIN4 IOID_04
#define GUA_PWMPIN5 IOID_05
#define GUA_PWMPIN6 IOID_06
#define GUA_PWMPIN7 IOID_07
const PWMTimerCC26XX_HwAttrs pwmtimerCC2640HWAttrs[CC2640R2_LAUNCHXL_PWMCOUNT] = {
{ .pwmPin = GUA_PWMPIN0, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0A },
{ .pwmPin = GUA_PWMPIN1, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER0B },
{ .pwmPin = GUA_PWMPIN2, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1A },
{ .pwmPin = GUA_PWMPIN3, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER1B },
{ .pwmPin = GUA_PWMPIN4, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2A },
{ .pwmPin = GUA_PWMPIN5, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER2B },
{ .pwmPin = GUA_PWMPIN6, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3A },
{ .pwmPin = GUA_PWMPIN7, .gpTimerUnit = CC2640R2_LAUNCHXL_GPTIMER3B },
};
如上面的代码这样,那么你就可以将PWM输出映射到任意IO口啦,是不是很方便,很好用?如果觉得这篇博文对你有帮助,一起来群里探讨学习吧!
原创博客,如有转载,注明出处——在金华的电子民工林。
1)友情伙伴:甜甜的大香瓜
2)声明:喝水不忘挖井人,转载请注明出处。
3)纠错/业务合作:[email protected]
4)香瓜BLE之CC2640R2F群:557278427
5)本文出处:原创连载资料《简单粗暴学蓝牙5》
6)完整开源资料下载地址:
https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i