tag 标签: cc2541

相关博文
  • 热度 19
    2015-9-21 17:10
    4057 次阅读|
    0 个评论
    上一篇主要是研究了广播者( Broadcaster ),现在再研究跟其“针锋相对”的观测者( Observer ),我老觉得应该叫 Scanner ,扫描者,这样好像跟标准里的动词能对应上。 这里还是使用 CC2541 BLE4.0 协议栈( v1.4.0 )中的例程, SimpleBLEObserver. 因为原例程是使用的 TI 官方的开发板,带 LCD 屏的,很多信息是显示在屏上。而笔者手头只有自己的一块板(做 Observer )和 TI 的 keyfob (做 Broadcaster ),所以笔者在例程中加入了 UART 的一些代码,以使信息显示在 PC 屏幕上。另外,扫描的启动和停止在原例程是上通过板上的按键触发,在这里同样使用 UART ,在 PC 上通过串口工具向 CC2541 发送字符‘ S ’表示启动和停止扫描( StartStop )。这部分功能在 UART 的中断里实现,代码片断如下: #pragma vector = URX0_VECTOR __interrupt void UART0_Isr(void) {   uint8 temp;   temp = U0DBUF;     if(temp == 'S')   {            if ( !simpleBLEScanning )            {                    simpleBLEScanning = TRUE;                    simpleBLEScanRes = 0;                    GAPObserverRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,                                                DEFAULT_DISCOVERY_ACTIVE_SCAN,                                                DEFAULT_DISCOVERY_WHITE_LIST );            }            else            {                    GAPObserverRole_CancelDiscovery();            }   }     URX0IF = 0; }   对于 Observer ,要设置的主要参数有以下几个: // Maximum number of scan responses #define DEFAULT_MAX_SCAN_RES                   8 // Scan duration in ms #define DEFAULT_SCAN_DURATION                  4000 // Discovey mode (limited, general, all) #define DEFAULT_DISCOVERY_MODE                 DEVDISC_MODE_ALL 注释也写得非常清楚,主要是最多进行扫描响应的个数、扫描时长及扫描的模式。   对于 Observer , observer.h 和 gap.h 中的几个数据结构非常重要。 1 ) typedef union {   gapEventHdr_t              gap;                 //! GAP_MSG_EVENT and status.   gapDeviceInitDoneEvent_t   initDone;            //! GAP initialization done.   gapDeviceInfoEvent_t       deviceInfo;          //! Discovery device information event structure.   gapDevDiscEvent_t          discCmpl;            //! Discovery complete event structure. } gapObserverRoleEvent_t; 这是一个联合,其中的 gapDeviceInitDoneEvent_t 是针对 Observer 自身的, gapDeviceInfoEvent_t 是针对被扫描到的设备的, gapDevDiscEvent_t 是针对扫描结果的。 2 ) /**   * GAP_DEVICE_INIT_DONE_EVENT message format.   This message is sent to the   * app when the Device Initialization is done .   */ typedef struct {   osal_event_hdr_t   hdr;               //! GAP_MSG_EVENT and status   uint8 opcode;                         //! GAP_DEVICE_INIT_DONE_EVENT   uint8 devAddr ;           //! Device's BD_ADDR   uint16 dataPktLen;                   //! HC_LE_Data_Packet_Length   uint8 numDataPkts;                   //! HC_Total_Num_LE_Data_Packets } gapDeviceInitDoneEvent_t; 主要是 Observer 自身的信息,比如自身的 MAC 等,在初始化结束后或有用。 3 ) /**   * GAP_DEVICE_INFO_EVENT message format.   This message is sent to the   * app during a Device Discovery Request, when a new advertisement or scan   * response is received.   */ typedef struct {   osal_event_hdr_t   hdr;     //! GAP_MSG_EVENT and status   uint8 opcode;              //! GAP_DEVICE_INFO_EVENT   uint8 eventType;           //! Advertisement Type: @ref GAP_ADVERTISEMENT_REPORT_TYPE_DEFINES   uint8 addrType;            //! address type: @ref GAP_ADDR_TYPE_DEFINES   uint8 addr ;    //! Address of the advertisement or SCAN_RSP   int8 rssi;                 //! Advertisement or SCAN_RSP RSSI   uint8 dataLen;             //! Length (in bytes) of the data field (evtData)   uint8 *pEvtData;           //! Data field of advertisement or SCAN_RSP } gapDeviceInfoEvent_t; gapDeviceInfoEvent_t 是关于被扫描到的设备的信息,笔者认为这应该是最重要的一个结构了。 其中的 addr 或 advertData[] 的字节数和地址。可以编写函数将广播数据包及扫描应答数据包中的信息读出来。 这里笔者只把被扫描设备的 MAC 读了出来,转换成字符串显示在 PC 端。图中的 0xBC6A29AB6588 即为扫描到广播者的 MAC 地址。
  • 热度 25
    2015-9-21 16:03
    3849 次阅读|
    2 个评论
    最近的一个项目,是用 TI 的 CC2541 做了个基于蓝牙的数据采集系统。   系统简单描述下就是传感器采样数据,通过 UART 与 CC2541 通信, CC2541 将接收到的数据通过蓝牙发送到 PC 端。 CC2541 接收的数据是通过缓冲的方式,当接收满 20 个数据时,将这 20 个数据统一通过蓝牙发送到 PC 端。   要实现的功能很简单。蓝牙部分的设计、调试似乎也都挺顺利。但是当把传感器与蓝牙部分连上后,发现 PC 端的曲线含有大量的杂波,用串口调试工具去看,也会有相当多的乱码。   开始以为是干扰,换屏蔽线、关闭板上 DCDC 改用稳压电源供电等一系统措施之后,现象仍然存在。   换一个思路,拿掉传感器,将 CC2541 的串口接到 PC 端,通过串口调试工具发送固定的数,发现曲线还是存在杂波,杂波似乎还挺有规律。下面是用 TI 的软件 DeviceMonitor 抓取的文本数据。     图中我简单标了几个受干扰的数据。   后来也是通过 TI 的官方论坛和相关文档,查找到了原因: 原来 CC2541 在出厂默认情况下,当 CC2541 的射频工作时,即蓝牙发送或接收数据时, CPU 会停机( halt ),这是为了减小射频工作时的峰值电流。所以在固件设计时,要进行相应设置,把 CC2541 在射频工作时 CPU halt 的功能去掉。可以在初始化的时候,调用下列函数:     HCI_EXT_HaltDuringRfCmd(HCI_EXT_HALT_DURING_RF_DISABLE);     关于这个函数,可以参考 TI 的文档《 TI_BLE_Vendor_Specific_HCI_Guide 》 P45 ,下面的截图就是文档中对该函数的描述。     可以看出, TI 为了减小 CC2541 的功耗真是无所不用其极,哈。按文档中的描述, Disable 掉这个功能后,峰值电流会增加。因为手头没有精密工具,只是用万用表打到电流档串到电路中,对比测了下平均电流,从这个工具上看不出什么变化来。当然,因为这个项目就是要串口一直工作,所以不能让 CPU 休息,以免乱码,我们也不在意多出来的这点功耗。     希望我遇到的这个情况,能给一些朋友有帮助或启发。当然,文中提到的函数也要慎用,以免增加额外的功耗。   附件是TI的HCI文档:
  • 热度 22
    2015-9-21 16:03
    3224 次阅读|
    1 个评论
    TI BLE 协议栈提供的例程里面有一个 TimeApp ,从文档 TI_BLE_Software_Developer's_Guide.pdf 的第 16 章介绍来看,是使用了类似 RTC 的时钟来实现一个蓝牙手表功能。这两天研究了一下,另外在网上也找到了一篇写得还算详尽的博文(参考文献 1 ),发现 TI BLE 协议栈已经封装好一个 RTC ,在 OSAL_ClockBLE.c 文件中,该文件在文后的附件中供参考,也可以去参考文献 1 ( http://blog.csdn.net/xiaoleiacmer/article/details/42458351 )中,里面有博主的一些中文注释,可以帮助大家更好的理解。 OSAL_ClockBLE.c 中的主要函数及功能: 1 ) void osalTimeUpdate( void ); 更新时间   2 ) void osal_setClock( UTCTime newTime ); 设定时间,输入参数为秒数,指的是从 2000 年 1 月 1 日 0 时 0 分 0 秒开始的秒数。 UTCTime 的定义如下: // number of seconds since 0 hrs, 0 minutes, 0 seconds, on the // 1st of January 2000 UTC typedef uint32 UTCTime;   3 ) UTCTime osal_getClock( void ); 获取当前时间,返回的是秒数, UTCTime 的定义见 2 ),秒数也是从 2000 年 1 月 1 日 0 时 0 分 0 秒开始的秒数。 4 ) void osal_ConvertUTCTime( UTCTimeStruct *tm, UTCTime secTime ); 将秒数转换成 UTCTimeStruct 结构。 UTCTimeStruct 结构的定义如下: typedef struct {   uint8 seconds;  // 0-59   uint8 minutes;  // 0-59   uint8 hour;     // 0-23   uint8 day;      // 0-30   uint8 month;    // 0-11   uint16 year;    // 2000+ } UTCTimeStruct;   5 ) UTCTime osal_ConvertUTCSecs( UTCTimeStruct *tm ); 将 UTCTimeStruct 结构转换成秒数。   简单来说, BLE 协议栈中的 RTC 是从 2000 年 1 月 1 日 0 时 0 分 0 秒开始定时的,获取和设定时间时都用的这个秒数,对于用户来说,转换成 UTCTimeStruct 最方便。所以要获取当前时间,要调用 osal_getClock( ) 后再调用 osal_ConvertUTCTime( ) ,将秒数转成 UTCTimeStruct ;要修改设定时间,可以将新的时间填充到 UTCTimeStruct 中,再调用 osal_ConvertUTCSecs( ) ,然后调用 osal_setClock( ) ,这样就重新更新了时间。   测试的步骤可以参考如下: 1 )添加一个 Time Profile ,定义一个 Time Service 和一个 Time Characteristic ,该特征值是 6 字节的的数组,用来更新时间,可以理解为手机 App 通过蓝牙来同步时间。数据用来保存年月日时分秒的信息,年只保存后两位,即,如 2015 年,只用 15 来表示,毕竟一个字节最大只能到 255. 2 )定义一个 UTCTimeStruct 变量,用来保存蓝牙更新过来的时间,同时调用相关函数来设定时间。 3 )定义一个周期事件,如 30s ,获取当前时间,通过 LCD 或通过 UART 到 PC 上来显示时间。   下面是一段通过特征值来设定时间并显示的代码片段。这里只显示了时和分,如 15 : 57       UTCTimeStruct *Time; uint8 TimeDisplayBuf ;   uint8 newValue ;       UTCTimeStruct TimeTemp;       UTCTime newTime;             TIME_GetParameter(TIME_CHAR, newValue);       TimeTemp.year = 2000 + newValue ;       TimeTemp.month = newValue ;       TimeTemp.day = newValue ;       TimeTemp.hour = newValue ;       TimeTemp.minutes = newValue ;       TimeTemp.seconds = newValue ;             newTime = osal_ConvertUTCSecs( TimeTemp );       osal_setClock( newTime );       osalTimeUpdate();       osal_ConvertUTCTime( Time, osal_getClock() );       TimeDisplayBuf = (Time-hour) / 10 + '0';       TimeDisplayBuf = (Time-hour) % 10 + '0';       TimeDisplayBuf = (Time-minutes) / 10 + '0';       TimeDisplayBuf = (Time-minutes) % 10 + '0';       TimeDisplayBuf = ‘:’;       LCD_ShowString(0,4, TimeDisplayBuf);   CC2541 的 RTC 是通过外部或内部晶振来计时,误差会比较大,所以最好在连接到蓝牙时就校时,并且最好设定为比如每隔几个小时来校时,以使时间显示得比较准确。   参考文献: 1. http://blog.csdn.net/xiaoleiacmer/article/details/42458351
  • 热度 16
    2015-9-21 15:55
    1610 次阅读|
    0 个评论
    蓝牙的 MAC 是全球唯一的,一般情况下,固件的开发中不会去使用,但也不排除二般情况。 通过 CC254x 的 User Manual ,在第 2.2.3 节,有如下描述: 可知,在 Flash 中有一块只读区域,从地址 0x780E 开始,蓝牙的 MAC 以小端方式存放在里面。 在 TI 的 Peripheral 例程里面,添加一个特征值,只读属性, 6 字节长度(蓝牙 MAC 长度为 48-bit , 6 字节)。 定义一个函数来读取 MAC   #define X_DATA(addr) ((uint8 volatile __xdata *)0)   uint8 CC254x_MAC = {0,0,0,0,0,0};   void ReadMac(void) {   uint8 Mac ;   uint8 i;   uint16 addr = 0x7813;   for(i=0;i6;i++)   {     Mac = X_DATA(addr - i);   }     osal_memcpy( CC254x_MAC, Mac, 6 ); }   这里是通过一个全局变量来传递 MAC ,当然,在实际编程中,最好尽量减少全局变量的使用。在程序的开始,可以调用这个函数,然后把 MAC 地址初始化到特征值中,到时可以通过这个接口来读取。 下面是通过 TI 的 USB Dongle 和 Device Monitor ,可以看到 MAC 是一致的:  
  • 热度 15
    2013-3-19 21:53
    717 次阅读|
    0 个评论
      特性   射频 2.4-GHz 符合低能耗规范和私有的 RF 片载系统 支持 250-kbps,500-kbps,1-Mbps,2-Mbps 的数据速率 出色的链路预算,不使用外部前段而支持长距离应用 高达 0 dBm 的可编程输出功率 出色的接收器灵敏度 (1 Mbps 时为 –94 dBm),可选择性,和阻挡性能 适合于针对符合世界范围内的无线电频率调节系统: ETSI EN 300 328 和 EN 300 440 2 类 (欧洲),FCC CFR47 15 部分(美国),和 ARIB STD-T66 (日本) 布局 极少的外部组件 提供参考设计 6-mm × 6-mm 方形扁平无引脚 (QFN)-40 封装 与 CC2540 引脚兼容 (当不使用 USB 或者 I 2 C 时) 低功率 工作模式 RX 低至: 17.9 mA 工作模式 TX (0 dBm): 18.2 mA 功率模式 1 (4-µs 唤醒): 270 µA 功率模式 2 (睡眠定时器打开): 1 µA 功率模式 3 (外部中断): 0.5 µA 宽泛的电源电压范围 (2 V–3.6 V) 工作模式下 TPS62730 兼容低功率 RX 低至: 14.7 mA (3-V 电源) TX (0 dBm):14.3 mA(3V 电源)/li 微控制器 具有代码预取功能的高性能和低功率 8051 微控制器内核 系统内可编程闪存,128 或者 256 KB 在所有功率模式下具有保持功能的 8-KB RAM 支持硬件调试 扩展基带自动化,包括自动确认和地址解码 所有功率模式中对所有相关寄存器的保持 外设 功能强大的 5 通道直接内存访问 (DMA) 通用定时器(1 个 16 位,2 个 8 位) 红外 (IR) 生成电路 具有捕捉功能的 32-kHz 睡眠定时器 精确数字接收到的数字信号强度指示器 (RSSI) 支持 电池监视器和温度感应器 含 8 通道和可配置分辨率的 12 位模数转换器 (ADC) 高级加密标准 (AES) 安全协处理器 2 个功能强大的支持几个串行协议的通用异步接收发器 (UART) 23 个通用 I/O 引脚 (21 × 4 mA,2 × 20 mA) I 2 C 接口 2 个具有 LED 驱动功能的 I/O 引脚 安全装置定时器 集成的高性能比较器 开发工具 CC2541 评估模块工具包 (CC2541EMK) CC2541 小型开发工具包 (CC2541DK-MINI) SmartRF™ 软件 提供 IAR 嵌入式 Workbench™
相关资源