CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)

Posted 所长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)相关的知识,希望对你有一定的参考价值。

参考学习大神博客: http://blog.csdn.net/feilusia/article/details/51083953

        : http://blog.csdn.net/xiaoleiacmer/article/details/41723583

 

1、TI 的 CC2540跑了一个  OSAL   (Operating System Abstraction Layer)

    心得:大概 就是 一个循环查看任务 是否 产生事件,产生就 处理事件,每个任务有16个事件,其实就是一个16位的宏定义,每一位代表一个事件,其中0x8000 是固定 的代表 SYS_EVENT_MSG。(这句话看不懂,可以往下看)

     (sdk的安装请百度,工程路径:C:\\Texas Instruments\\BLE-CC254x-1.4.1.43908\\Projects\\ble\\SimpleBLEObserver\\CC2540DB)

2、在 TI 提供 的 SDK  中 ,打开 一个 观察者工程,找到任务初始化的地方。(可通过 菜单->Edit->Find and Replace->Find in Files 这个全局查找 功能 进行找到这个函数osalInitTasks)

    这里 有很多任务 的初始化 ,按顺序执行,每个任务 有一个 对应 一个 事件处理函数任务产任务生事件,就去执行这个事件处理函数),这句话很重要哦,一定要理解,记住。

 

 任务列表:

 

 

任务对应的 事件处理 函数 :如下

 

 

 

 

3、前面的任务 都不管 ,现在我 们值关心 最后一个任务(因为这个任务 是  应用任务 ,TI 就是做这个任务 就是供我们使用的。)

/* Application */
SimpleBLEObserver_Init( taskID );

对应 的事件处理函数是:

SimpleBLEObserver_ProcessEvent( uint8 task_id, uint16 events );

4、先看看这个任务SimpleBLEObserver_Init的初始化都做了什么。

 

 5、看看这个任务的 事件处理函数SimpleBLEObserver_ProcessEvent 都 做了什么。

 

 6、我们要在这个应用任务中添加一个事件(定时处理某些事情,比如LED灯 比如定时检测传感器数据等等)做法如下。

    第一步:在这个任务中,添加一个事件,名称叫:(其实就是添加一个宏定义)

    (因为事件 的变量(16位) 每一位代表一个事件,因此事件的可能值 只能是2^16,2^15,2^14,2^13,2^12,2^11,2048,1024,512,256, 128,64,32,16,8,4,2,1)

    #define SBO_PERIODIC_EVT                                  0x0004//至于为啥是 0x0004 而不是0x0002 因为0x0002 已经存在了

    添加结果如下:

    

     第二步:在事件处理函数中,添加这个事件的处理:结果如下。

    

    

具体的 处理函数 如下:

 

/*********************************************************************
 * @fn      performPeriodicTask 执行 周期 任务
 *
 * @brief   输出一个任务正在执行的语句。
 *
 *          2017年4月17日13:57:35,GXP
 *
 * @param   none
 *
 * @return  none
 */
static void performPeriodicTask( void )
{
  printf("定时器任务正在运行。\\r\\n");
}

 

 

事件添加好了:怎么启动这个事件 ,或者意思 是说怎么让系统执行这个事件那。下面就讲两种方法:(我也就会这两种目前,2017年4月17日20:24:25)

 

第一种方法:

 

  把这个事件设置为就绪状态,这样下次轮询任务时就会看这个应用任务 产生了一个 事件,具体调用的API 是

  
  osal_set_event( task_id, SBO_PERIODIC_EVT);//第一个 参数是任务ID ,第二个参数是事件名称。

  

 

因为我们这个事件 就是定时处理某些事情,因此要使用到系统的软件定时器,第二个办法就是使用系统软件定时来启动这个事件。

 

// Set timer for first periodic event
osal_start_timerEx( task_id, SBO_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );

 

 

   

下面 我 们 要 打开  CC2540 的 串口 ,进行收发数据: 参考博客:  http://blog.csdn.net/feilusia/article/details/47431659

 

    1、第一步  在 工程 的 属性 里 ,添加  HAL_UART=TRUE,进行 使能 串口

      

 

    2、添加头文件(npi.c中), #include "OSAL.h"

      

     3、新增两个串口发送函数(npi.c中)

       

/*********************************************************************
 * @fn      NPI_PrintString
 *
 * @brief   打印字符串
 *
 *          2017年4月20日16:22:27,GXP
 *
 * @param    str:字符串 
 *
 * @return  none
 */
 
void NPI_PrintString(uint8 *str)  
{  
    NPI_WriteTransport(str, osal_strlen((char*)str));
}

/*********************************************************************
 * @fn      NPI_PrintValue 打印指定的格式的数值
 *
 * @brief  打印指定的格式的数值
 *
 *         2017年4月20日16:22:27,GXP
 *
 * @param    title:前缀字符串  
 *           value:需要显示的数值   
 *           format:需要显示的进制,10或16
 *
 * @return  none
 */
 
void NPI_PrintValue(char *title, uint16 value, uint8 format)  
{  
  uint8 tmpLen;  
  uint8 buf[128];  
  uint32 err;  
  
  tmpLen = (uint8)osal_strlen( (char*)title );  
  osal_memcpy( buf, title, tmpLen );  
  buf[tmpLen] = \' \';  
  err = (uint32)(value);  
  _ltoa( err, &buf[tmpLen+1], format );  
  NPI_PrintString(buf);       
}

     4、函数声明(npi.h中) 

extern void NPI_PrintValue(char *title, uint16 value, uint8 format);
extern void NPI_PrintString(uint8 *str);

     5、关闭低功耗模式,顺便关掉 LCD,2017年4月20日16:39:44

      

     6、因为要在simpleBLEObserver.c中调用 上面添加 的 两个串口打印函数,因此 需要 在 simpleBLEObserver.c中 添加#include "npi.h"

#include "npi.h" //SuoZhang,ADD,2017年4月20日16:42:58

     7、定义并声明一个串口回调函数,在 simpleBLEObserver.c中,这个回调函数什么时候进入那?

答:

1)正常串口端无发送、无接收时,是不会进回调函数的。如果这种情况会进回调函数,TX、RX端外接上拉电阻稳定电平。

2)如果接收端有数据,立马就会进回调。事件是“接收超时事件”。

3)2541 or 2540 发送端发送完数据,会进回调函数。事件是“发送缓冲区空事件”。

 

/*********************************************************************
 * @fn      NPI_SerialCallback
 *
 * @brief   串口回调函数,2016年12月15日08:59:13,GXP
 *          
 *            1、如果接收端有数据,立马就会进回调。事件是“接收超时事件”。
 *            2、2541 or 2540 发送端发送完数据,会进回调函数。事件是“发送缓冲区空事件”。
 *
 * @param   port: 串口1 还是串口2
 *            events: 事件类型(“接收超时事件”,“发送缓冲区空事件”)
 *
 * @return  none
 */
static void NPI_SerialCallback( uint8 port, uint8 events )  
{  
    (void)port;//加个 (void),是未了避免编译告警,明确告诉缓冲区不用理会这个变量  
  
    if (events & (HAL_UART_RX_TIMEOUT | HAL_UART_RX_FULL))   //串口有数据  
    {  
        uint8 numBytes = 0;  
  
        numBytes = NPI_RxBufLen();           //读出串口缓冲区有多少字节  
          
        if(numBytes == 0)  
        {  
            return;  
        }  
        else  
        {  
            //申请缓冲区buffer  
            uint8 *buffer = osal_mem_alloc(numBytes);  
            if(buffer)  
            {  
                //读取读取串口缓冲区数据,释放串口数据     
                NPI_ReadTransport(buffer,numBytes);     
  
                //把收到的数据发送到串口-实现回环   
                NPI_WriteTransport(buffer, numBytes);    
  
                //释放申请的缓冲区  
                osal_mem_free(buffer);  
            }  
        }  
    }  
}

    8、添加上面 串口回调函数的声明,simpleBLEObserver.c中

static void NPI_SerialCallback( uint8 port, uint8 events );//SuoZhang,ADD,2017年4月20日16:55:25

    9、新增初始化代码simpleBLEObserver.c的SimpleBLEObserver_Init中

/*********************************************************************
 * @fn      SimpleBLEObserver_Init
 *
 * @brief   Initialization function for the Simple BLE Observer App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notification).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void SimpleBLEObserver_Init( uint8 task_id )
{
  simpleBLETaskId = task_id;
  
  //初始化串口0,作为串口打印数据使用,2017年4月20日16:57:31
  {
    //注册串口回调函数  
    NPI_InitTransport(NPI_SerialCallback);
        
    // 按长度输出测试
    //NPI_WriteTransport("SimpleBLETest_Init\\r\\n", 20);
        
    // 按字符串输出    
    NPI_PrintString("SimpleBLEObserver_Init.\\r\\n");  
        
    // 可以输出一个值,用10进制表示    
    NPI_PrintValue("测试10进制输出 = ", 168, 10);    
    NPI_PrintString("\\r\\n");      
        
    // 可以输出一个值,用16进制表示
    NPI_PrintValue("测试16进制输出  = 0x", 0x88, 16);    
    NPI_PrintString("\\r\\n");   
  }

  // Setup Observer Profile
  {
    uint8 scanRes = DEFAULT_MAX_SCAN_RES;
    GAPObserverRole_SetParameter ( GAPOBSERVERROLE_MAX_SCAN_RES, sizeof( uint8 ), &scanRes );
  }
  
  // Setup GAP
  GAP_SetParamValue( TGAP_GEN_DISC_SCAN, DEFAULT_SCAN_DURATION );
  GAP_SetParamValue( TGAP_LIM_DISC_SCAN, DEFAULT_SCAN_DURATION );

  // Register for all key events - This app will handle all key events
  RegisterForKeys( simpleBLETaskId );
  
  // makes sure LEDs are off
  HalLedSet( (HAL_LED_1 | HAL_LED_2), HAL_LED_MODE_OFF );
  
  // Setup a delayed profile startup
  osal_set_event( simpleBLETaskId, START_DEVICE_EVT );
}

    10、关闭流控(流控是用于防止串口阻塞的,需要多两根线用于流控。),通常串口只使用三根线 TX,RX,GND, (npi.h中)

#if !defined( NPI_UART_FC )
#define NPI_UART_FC                    FALSE //TRUE  
#endif // !NPI_UART_FC

    11、编译并且接上串口0,波特率115200,结果如下:(不清楚问什么 汉子乱码)

 

 

以上是关于CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)的主要内容,如果未能解决你的问题,请参考以下文章

CC2540/CC2541/CC254x之OSAL操作系统抽象层

用蓝牙芯片CC2541/CC2540实现一个智能恒温箱

CC2540 芯片资料浅析

CC2540蓝牙模块学习

CC2540是一款高性价比,低功耗片上系统(Soc)解决方案,它适合蓝牙低功耗应用领域

与 CC2540 蓝牙 LE 设备配对