精华内容
下载资源
问答
  • 主要介绍下蓝牙协议栈开发板跑传统蓝牙串口协议SPP AT指令以及上位机操作步骤,以及原理 一. 声明 本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下: 第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些...

    零. 概述

    主要介绍下蓝牙协议栈开发板跑传统蓝牙串口协议SPP AT指令以及上位机操作步骤,以及原理

    一. 声明

    本专栏文章我们会以连载的方式持续更新,本专栏计划更新内容如下:

    第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。

    第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等

    第三篇:传统蓝牙controller介绍,主要介绍传统蓝牙芯片的介绍,包括射频层(RF),基带层(baseband),链路管理层(LMP)等

    第四篇:传统蓝牙host介绍,主要介绍传统蓝牙的协议栈,比如HCI,L2CAP,SDP,RFCOMM,HFP,SPP,HID,AVDTP,AVCTP,A2DP,AVRCP,OBEX,PBAP,MAP等等一系列的协议吧。

    第五篇:低功耗蓝牙controller介绍,主要介绍低功耗蓝牙芯片,包括物理层(PHY),链路层(LL)

    第六篇:低功耗蓝牙host介绍,低功耗蓝牙协议栈的介绍,包括HCI,L2CAP,ATT,GATT,SM等

    第七篇:蓝牙芯片介绍,主要介绍一些蓝牙芯片的初始化流程,基于HCI vendor command的扩展

    第八篇:附录,主要介绍以上常用名词的介绍以及一些特殊流程的介绍等。

    另外,开发板如下所示,对于想学习蓝牙协议栈的最好人手一套。以便更好的学习蓝牙协议栈,相信我,学完这一套视频你将拥有修改任何协议栈的能力(比如Linux下的bluez,Android下的bluedroid)。

    -------------------------------------------------------------------------------------------------------------------------

    CSDN学院链接(进入选择你想要学习的课程):https://edu.csdn.net/lecturer/5352?spm=1002.2001.3001.4144

    蓝牙交流扣扣群:970324688

    Github代码:https://github.com/sj15712795029/bluetooth_stack

    入手开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22329603896.18.5aeb41f973iStr&id=622836061708

    蓝牙学习目录https://blog.csdn.net/XiaoXiaoPengBo/article/details/107727900

    --------------------------------------------------------------------------------------------------------------------------

    二. STM32蓝牙协议栈封装使用AT command实现串口协议SPP的通信

    使用步骤操作如下:

    步骤 1)准备好代码,从github下载下来最新的代码(在上面有介绍Github连接)

    步骤 2)连接好硬件(把模组插好,ST-LINK接上,TYPE-C debug先接上,按下按钮可以看到蓝色电源等亮起)

    步骤 3)打开Keil工程文件夹下的project\stm32f10x_bb_csr8x11_bt\stm32f10x_bb_csr8x11.uvprojx,配置SPP使能(在bt_config.h把PROFILE_SPP_ENABLE定义为1)

    步骤4)编译下载

    此部分注意几点:

    • 下载需要ST-LINK驱动,我已经放在下载资料中的软件工具文件夹中
    • STM32 F1的pack要有,我已经放在软件工具文件夹中的MDK下,没有没安装过要安装下,名字如下:

       

    • 下载的debug要选ST-LINK

         

    • 下载的时候要勾选Use micro lib

         

    步骤6)打开串口工具(我用的是XCOM),然后做初始化动作,在发送串口敲BT_START,点击发送,出来以下log就证明初始化通过了,接下来我们就准备开始测试SPP注意一点:不能勾选发送新行,否则会解析错误)

    步骤6)使用手机的SPP软件(在3-软件工具\bt_spp_apk)来连接我们的开发板,连接成功如图,然后敲SPP_SEND就可以发送固定字符串(在代码中写死,你可以随便来修改),然后apk发送的数据我们也可以通过开发板接受到了

    三.STM32蓝牙协议栈使用上位机实现串口协议SPP的通信

    上位机的使用前4步跟AT一样,我们我们就直接来讲第五步。

    打开我们工程源码1-BLUETOOTH\mcu_bt_tool\mcu_bt_tool\mcu_bt_tool\bin\Debug中的mcu_bt_tool.exe,当然你也可以直接用VS2010打开工程

    步骤5)打开上位机,开启串口,开启蓝牙功能

    步骤6)进入蓝牙串口界面,连接上后连接状态跟连接地址以及空间都会可用,界面简单易用,没啥不懂的

    另外:使用上位机的时候注意几点:

    ① mcu_bt_tool.exe你如果想把可执行文件拿到别的路径单独执行,那么必须要把Newtonsoft.Json.dll跟exe放在同一个路径下,因为上位机是跟STM32用json沟通的

    ② 因为目前搜索是开启的EIR,带RSSI的,所以他会重复性上来同一个设备,我没做根据同一个蓝牙地址做显示过滤,如果有兴趣的人可以加上这一块

    四. 串口工具AT command以及上位机实现搜索的原理

    https://blog.csdn.net/XiaoXiaoPengBo/article/details/108414679

    原理在以上链接的第四小节

     

     

    展开全文
  • 以cc2541平台为例,我在调试广播对广播包进行分析的时候发现,广播包由广播数据和广播扫描数据组成。最开始我以为广播包的数据就是advertDate[],除了自己设置的数据后面的都是随机生成的,但是在一次操作中发现不是...

        以cc2541平台为例,我在调试广播对广播包进行分析的时候发现,广播包由广播数据和广播扫描数据组成。

    最开始我以为广播包的数据就是advertDate[],除了自己设置的数据后面的都是随机生成的,但是在一次操作中发现不是这样的。数据包室友广播数据和扫描响应数据组成,一个31字节,不够62位的后面全部默认为0。还有就是扫描响应数据的名称那个十六进制数为英文字母的ASCII码,这也是在一次实验过程中发现的。

    下面是操作实例:

    这个是广播包的数据:


    这个是扫描响应数据的内容:


    这个是数据包在手机APP上面的显示:


    就是这个样子的,两个数据的组合,按到这个趋势,我猜一个广播包可以包含62字节的数据,扫描响应和广播各占一半,还有其他的rssi这些信息都在那个结构体中,和包一起发送。



    展开全文
  • CC2540/CC2541蓝牙4.0BLE协议开发

    千次阅读 2019-11-21 13:00:27
    转载地址:... 低功耗蓝牙(BluetoothLow Energy),简称BLE。蓝牙低能耗无线技术利用许多智能手段最大限度地降低功耗。  蓝牙2.1+EDR/3.0+HS版本(通常指“标准蓝牙技术”)与蓝牙低能耗(B...

    转载地址:https://e2echina.ti.com/question_answer/wireless_connectivity/bluetooth/f/103/t/69222

     低功耗蓝牙(BluetoothLow Energy),简称BLE。蓝牙低能耗无线技术利用许多智能手段最大限度地降低功耗。

      蓝牙2.1+EDR/3.0+HS版本(通常指“标准蓝牙技术”)与蓝牙低能耗(BLE)技术有许多共同点:它们都是低成本、短距离、可互操作的鲁棒性无线技术,工作在免许可的2.4GHz ISM射频频段。

      不过它们之间有一个重要区别:蓝牙低能耗技术从一开始就设计为超低功耗(ULP)无线技术,而标准蓝牙技术主要是能够构成“低功耗的”无线连接。

    标准蓝牙技术是一种“面向连接”的无线技术,具有固定的连接时间间隔,因此是移动电话连接无线耳机等高活动连接的理想之选。相反,蓝牙低能耗技术采用可变连接时间间隔,这个间隔根据具体应用可以设置为几毫秒到几秒不等。另外,因为BLE技术采用非常快速的连接方式,因此平时可以处于“非连接”状态(节省能源),此时链路两端相互间只是知晓对方,只有在必要时才开启链路,然后在尽可能短的时间内关闭链路。

    BLE技术的工作模式非常适合用于从微型无线传感器(每半秒交换一次数据)或使用完全异步通信的遥控器等其它外设传送数据。这些设备发送的数据量非常少(通常几个字节),而且发送次数也很少(例如每秒几次到每分钟一次,甚至更少)。

        蓝牙低能耗架构共有两种芯片构成:单模芯片和双模芯片。蓝牙单模器件是蓝牙规范中新出现的一种只支持蓝牙低能耗技术的芯片——是专门针对ULP操作优化的技术的一部分。蓝牙单模芯片可以和其它单模芯片及双模芯片通信,此时后者需要使用自身架构中的蓝牙低能耗技术部分进行收发数据。双模芯片也能与标准蓝牙技术及使用传统蓝牙架构的其它双模芯片通信。

        双模芯片可以在目前使用标准蓝牙芯片的任何场合使用。这样安装有双模芯片的手机、PC、个人导航设备(PND)或其它应用就可以和市场上已经在用的所有传统标准蓝牙设备以及所有未来的蓝牙低能耗设备通信。然而,由于这些设备要求执行标准蓝牙和蓝牙低能耗任务,因此双模芯片针对ULP操作的优化程度没有像单模芯片那么高。

        单模芯片可以用单节钮扣电池(如3V、220mAh的CR2032)工作很长时间(几个月甚至几年)。相反,标准蓝牙技术(和蓝牙低能耗双模器件)通常要求使用至少两节AAA电池(电量是钮扣电池的10至12倍,可以容忍高得多的峰值电流),并且更多情况下最多只能工作几天或几周的时间(取决于具体应用)。注意,也有一些高度专业化的标准蓝牙设备,它们可以使用容量比AAA电池低的电池工作。

    蓝牙4.0已经走向了商用,在最新款的Xperia Z、Galaxy S3、S4、Note2、SurfaceRT、iPhone 5、iPhone 4S、魅族MX3、Moto Droid Razr、HTC One X、小米手机2、The New iPad、iPad 4、 MacBook Air、Macbook Pro,Nokia Lumia系列以及台商ACER AS3951系列/Getway NV57系列,ASUS UX21/31三星NOTE系列上都已应用了蓝牙4.0技术。

     接下来我们从环境的搭建到蓝牙4.0协议栈的开发来深入学习蓝牙4.0的开发过程。

    目录导航:

    第一节 BLE开发环境的搭建

    第二节 BLE快速体验

    第三节 创建IAR工程-点亮LED

    第四节 控制LED

    第五节 LCD12864显示

    第六节 独立按键之查询方式

    第七节 独立按键之中断方式

    第八节 CC254x内部温度传感器温度采集

    第九节 五向按键

    第十节 蜂鸣器

    第十一节 串口通信

    第十二节 Flash的读写

    第十三节 BLE协议栈简介

    第十四节 OSAL工作原理

    第十五节 BLE蓝牙4.0协议栈启动分析

    第十六节 协议栈LED实验

    第十六节 协议栈LCD显示

    第十七节 协议栈UART实验

    第十八节 协议栈五向按键

    第十九节 协议栈Flash数据存储

    第二十节 DHT11温湿度传感器

    第二十一节 蓝牙协议栈之从机通讯

    第二十二节 蓝牙协议栈主从一体之主机通讯

    第二十三节 OAD空中升级

    第二十四节 SBL串口升级

    第二十五节 UBL-USB升级

    第二十六节 MT-iBeacon基站使用iPhone空中升级

    第二十七节 MT-iBeacon基站在PC端实现OAD空中升级

    第二十八节 MT-iBeacon基站关于LightBlue软件的使用

    第二十九节 如何使用MT-USBDongle的透传功能

    深圳市馒头科技有限公司,供应CC254X蓝牙4.0模块、蓝牙4.0工具、蓝牙4.0开发板、蓝牙4.0BLE方案。http://mantoukeji.taobao.com/

    第一节  BLE开发环境的搭建
    1.1  硬件准备

        要进行BLE的开发,首先我们需要一个硬件环境。

    (1)  MT254xBoard开发板(最好有两块,方便进行数据收发实验);

    (2)  USBDongle-BLE抓包工具(多个固件,一个硬件多种用途),协议开发时辅助我们分析数据包;

    (3)  开发必备CC-Debug,用于下载和调试程序;

        在后期的学习中,这些工具我们都会使用到!

    1.2  BLE协议栈的安装

        我们使用的是最新版本的协议栈BLE-CC254x-1.4.0,首先在配套的资料文件夹中的tools文件夹下找到BLE-CC254x-1.4.0.exe文件。

     我们提供了一个安装包和一个免安装的源码,根据我的开发经验,建议使用安装包安装到C盘,直接使用免安装源码在后期的开发中会遇到一些莫名其妙的问题。下面开始安装协议栈,安装方式很简单,和安装软件一样,直接下一步到底即可。
    开始安装:

    同意安装:

    选择C盘:

     按照上述步骤,直到完成安装即可。在安装的最后阶段,默认的会安装Btool。

    安装BTool:

    安装完成:

    至此,说明我们已经成功安装了协议栈。完成后将会出现说明文件。

    在说明文件中我们可以看到,这个版本的协议栈需要使用IAR for 8051 8.20.2版本的软件。

    注:如果使用的是Win8以上的系统建议使用IAR for 8051 8.30.2版本的软件,安装方式和8.20.2是一样的。

        下面我们就开始安装这个版本的软件。

    1.3 IAR安装

        在配套的文件目录下找到如下文件。

    安装IAR:

    点击是开始安装Dongle驱动。

    这样IAR的安装就完成了。先开启软件来体验一下安装成果吧!

    1.4 安装烧写软件

    解压后可以看到如下文件:

    安装此软件即可,安装步骤:

    直接下一步到最终即可。

        至此,我们目前需要用到的开发软件就安装完成了,来个全家福吧!

        

    第二节  BLE快速体验

        经过前面的安装,我们的开发环境已经搭建好了,现在我们先来体验一下BLE,给自己点动力,comeon!使用SmartRFFlash Programmer烧写从机固件:CC2540_SmartRF_SimpleBLEPeripheral.hex,烧写方法见SmartRF Flash Programmer的使用章节。

        协议栈默认自带了一些已经编译好的文件,可以直接烧写,具体路径如下图:

         从机固件路径:

     读取设备的IEEE地址:

     烧写完成后,如果你有支持Ble的手机或平板就可以搜索到设备了,或者使用本公司开发的USBDongle(抓包固件或HostTestRelease固件)也可以搜索到设备,具体的使用可以阅读相应的产品使用手册,我这里用andriod平板搜索:

      通过MAC地址可以知道我们的设备已经在正常的广播了,我这里使用本公司开发的andriod端软件TruthBlue可以正常搜索到我们的设备。如果用户手上有支持BLE的设备并且系统在andriod4.3以上也可以安装我们的这个软件。

        连接上设备后如图,这里我们不要求大家能够看懂这些,这里仅仅是为了体验,后面的章节中我们会详细的讲述这些知识。

    第三节  创建IAR工程-点亮LED

        经过前面的准备工作,这章开始我们开始正式的开发过程。万事开头难,针对MT254xboard开发板的详细介绍参见《MT254xBoard-V1.0-硬件手册.pdf》,在这里我不做详述。

        这个教程是为有一定51基础和C基础的人准备的,如果读者这方面还欠缺,请找相关方面的书籍恶补一下。CC2540的本质就是一个8051的单片机,所以我们裸机开发就可以作为一个51单片机来开发,裸机开发的目的是为了让大家熟悉整个硬件以及开发环境,这并不是我们的最终目的,但这是一个必须的过程,为后面开发协议栈奠定基础。

        打开我们前面安装的IAR软件,创建一个新的工程:

    因为我们使用的CC2540是增强型51单片机,这里我们创建一个空的8051工程,具体配置选项如图:

    选择目录保存工程:

    我们这里创建一个最简单的例程,点亮一个LED,这个例程就像我们学习每种编程语言是都是先来个Hello World!。虽然简单,但是能够让我们最快的掌握一个开发环境的使用。

    新的工程为空工程,没有任何文件,我们这里新建一个文件并且保存为C文件。

    添加文件到工程:


    保存WorkSpace,在IAR中每个工程都必须要有一个Workspace,而且一个Workspace中可以有多个工程,所以这里我也必须要保存一个Workspace,点击file->save Workspace As就会弹出如下对话框,这里和保存文件一样需要对这个WorkSpace命名,我们这里一样取名LED。

    接下来我们需要对工程进行一些配置,使它适应我们的CPU。在工程处右击,进入配置界面。

    CPU配置:

    这里我们第一个要做的就是选择我们的CPU,我们使用的是TI公司生产的CC2540F256,所以这里选择CC2540F256。配置好CPU后,我们还需要配置编译输出的文件格式,选择到Linker选项,配置如下图:

    debug选项:

    选项配置:

    经过这些配置后,我们可以开始编码了,下面开始编写我们的第一个代码,功能是点亮2个LED,开发板上有两个LED灯,分别对应P1.0和P1.1。

        代码如下,可能觉得都是注释,这里我还是建议大家有一个好的编码风格,在开发大项目时就能够看到它的优势。

    /******************************************************************************
    
                      版权所有 (C), 2013-2020, 深圳市馒头科技有限公司
    
     ******************************************************************************
      文 件 名   : LED.c
      版 本 号   : V1.0
      作    者   : 朱兆祺
      生成日期   : 2014年6月6日
      功能描述   : 点亮一个LED
      函数列表   :
                  main
      修改历史   :
      1.日    期   : 2014年6月6日
        作    者   : 朱兆祺
        修改内容   : 创建文件
    
    ******************************************************************************/
    
    /*----------------------------------------------*
     * 包含头文件                                   *
     *----------------------------------------------*/
    #include <ioCC2540.h>
    
    #include "delay.h"
    
    /*****************************************************************************
     函 数 名  : main
     功能描述  : 主函数,C程序入口
     输入参数  : void
     输出参数  : 无
     返 回 值  : 
    
     修改历史      :
      1.日    期   : 2014年6月6日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    int main(void)
    {
        P1SEL &= ~0X03;     // 将P1.1、0设置为IO功能
        P1DIR |= 0X03;      // 设置P1.1、0为输出功能
        
        while(1)
        {
        P1  = (P1 & 0XFC) | 0X01;         // 设置P1.0输出高电平
        }
        return 0;
    }

    编写好代码后,就可以编译下载到开发板上了。点击图中所示图标全速运行。

    根据原理图,P1.0对应的是LED2,这里我们能够看到LED2处于点亮的状态。

    根据CC254X的数据手册,我们可以很快知道P1SEL是设置IO功能,P1DIR是设置输入输出。至于为什么程序是这么写,我们来看下,CC254X芯片的P1口一共有8个IO口,那就是说刚刚好由两位十六进制进行控制:1111 1111(FF),这里仅仅是LED1和LED2,也就是P1.1和P1.0两个IO口,为了不影响其他引脚的使用,我们这里巧妙使用与或控制其功能。比如:P1 = (P1 & 0XFC) | 0X01;    P1与上1111  1100,这样不影响其他引脚的基础上,清除了P1.0和P1.1的输出,再或上0X01,这样将P1.0设置为高电平,根据原理图,高电平是点亮LED2.

    第四节  控制LED

    上一节点亮了单个LED灯,我们这堂课接着控制LED灯。这堂课我们要完成的是LED闪烁10次,蜂鸣器响1s钟。这里我们先使用延时函数进行。
        我们的程序一定要做到结构清晰,可移植性强,阅读性高。程序设计不仅仅是实现了功能,如果那样的代码,那只有你自己可以看懂,是一手垃圾。真正的漂亮代码具有阅读性高、可移植性强、代码规范性好。
     

    delay.h:
    /******************************************************************************
    
                      版权所有 (C), 2013-2020, 深圳市馒头科技有限公司
    
     ******************************************************************************
      文 件 名   : delay.h
      版 本 号   : V1.0
      作    者   :  朱兆祺
      生成日期   : 2014年06月07日
      功能描述   : 主函数
      函数列表   :
                  
      修改历史   :
      1.日    期   : 2014年06月07日
        作    者   :  朱兆祺
        修改内容   : 创建文件
    
    ******************************************************************************/
    #ifndef  __DELAY_H__
    #define  __DELAY_H__
    
    
    /*****************************************************************************
     函 数 名  : Delay1ms
     功能描述  : 延时函数
     输入参数  : unsigned int uiDelay:延时1ms的数量
     输出参数  : 无
     返 回 值  : 
    
     修改历史      :
      1.日    期   : 2014年6月7日
        作    者   :  朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    extern void Delay1ms(unsigned int uiDelay);
    
    #endif
    
    
    /* end  file */

    延时函数的执行程序delay.c:

    /******************************************************************************
    
                      版权所有 (C), 2013-2020, 深圳市馒头科技有限公司
    
     ******************************************************************************
      文 件 名   : delay.c
      版 本 号   : V1.0
      作    者   :  朱兆祺
      生成日期   : 2014年06月07日
      功能描述   : 主函数
      函数列表   :
                  
      修改历史   :
      1.日    期   : 2014年06月07日
        作    者   :  朱兆祺
        修改内容   : 创建文件
    
    ******************************************************************************/
    /* 包含delay延时的头文件 */
    #include "delay.h"
    
    
    /*****************************************************************************
     函 数 名  : Delay1ms
     功能描述  : 延时函数
     输入参数  : unsigned int uiDelay:延时1ms的数量
     输出参数  : 无
     返 回 值  : 
    
     修改历史      :
      1.日    期   : 2014年6月7日
        作    者   :  朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    void Delay1ms(unsigned int uiDelay)
    {
        unsigned int i;
        
        for ( ; uiDelay > 0; uiDelay--)
        {
            /* 大约延时1ms */
            for (i = 0; i < 320; i++);
        }
    }
    
    
    /* end  file */

    主函数其实也很简单:

    /******************************************************************************
    
                      版权所有 (C), 2013-2020, 深圳市馒头科技有限公司
    
     ******************************************************************************
      文 件 名   : main.c
      版 本 号   : V1.0
      作    者   :  朱兆祺
      生成日期   : 2014年06月06日
      功能描述   : 主函数
      函数列表   :
                  
      修改历史   :
      1.日    期   : 2014年06月06日
        作    者   :  朱兆祺
        修改内容   : 创建文件
    
    ******************************************************************************/
    /* 包含CC254X的头文件 */
    #include <ioCC2540.h>
    #include "delay.h"
    
    /*****************************************************************************
     函 数 名  : main
     功能描述  : 主函数
     输入参数  : 无
     输出参数  : 无
     返 回 值  : 
    
     修改历史      :
      1.日    期   : 2014年6月6日
        作    者   :  朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    
    int main(void)
    {
        /* 控制LED灯闪烁 */
        unsigned char i;
        /* 驱动无源蜂鸣器 */
        unsigned int j;
        
      
        /* 将P1.0、P1.1设置为IO口 */
        P1SEL &= ~0x03;
        /* 将P1.0、P1.1设置为IO口的输出 */
        P1DIR |= 0x03;
        
        /* 将P2.0设置为IO口 */
        P2SEL &= ~0x01;
        /* 将P2.0设置为IO口输出 */
        P2DIR |= 0x01;
        
        /* 主循环 */
        while(1)
        {
            /* LED1,LED2闪烁10次 */
            for (i = 0; i < 10; i++)
            {
                /* P1.0----LED2,P1.1----LED1 */
                /* P1.0,P1.1输出高电平,即点亮LED2,LED1 */
                /* FC :  1111 1100*/
                P1 = (P1 & 0xFC) | 0x03;
                Delay1ms(1000);
            
                /* P1.0,P1.1输出低电平,即熄灭LED2,LED1 */
                /* FC :  1111 1100*/
                P1 = (P1 & 0xFC) & (~0x03);
                Delay1ms(1000);
            }
            
            /* 给出500HZ的方波驱动 */
            for(j = 0; j < 1000; j++)
            {
                /* P2.0----蜂鸣器 */
                P2 = (P2 & 0xFE) & (~0x01);
                Delay1ms(1);
                P2 = (P2 & 0xFE) | 0x01;
                Delay1ms(1);
            }
    
        }
         
    }
    
    
    
    
    /* end  file */

    这里需要注意的是,MT254X蓝牙4.0开发板使用的无源蜂鸣器,那么我们需要产生一个方波来驱动。如这代码:

    /* 给出500HZ的方波驱动 */
    for(j = 0; j < 1000; j++)
    {
        /* P2.0----蜂鸣器 */
        P2 = (P2 & 0xFE) & (~0x01);
        Delay1ms(1);
        P2 = (P2 & 0xFE) | 0x01;
        Delay1ms(1);
    }

    如果是有缘蜂鸣器,则没有那么麻烦,直接给出低电平驱动。为什么是低电平,我们看下原理图:

    使用的PNP三极管,并且使用续流二极管保护蜂鸣器。

    第五节  LCD12864显示

        上一节我们成功控制了LED和蜂鸣器,这一节我们马不停蹄接着LCD12864的控制。关于LCD12864的手册可以在网盘下载:

    为了系统能够稳定的工作,首先我们将系统时钟切换到32M的外部晶振,为了自由配置所需要的时钟,主要借助于CLKCONCMD.OSC选择系统主时钟,而借助于CLKCONCMD.OSC32K则用于选择芯片32K时钟源!而低功耗模式设置时,需要借助于SLEEPCMD寄存器,在《CC253x-CC2540-41Applications User's Guide.pdf》中并没有说明SLEEPCMD第二位功能,如下所示:

    但是参考cc2430芯片的说明书可以发现,对应的SLEEP寄存器则有说明,如下所示,这个是TI有意隐藏芯片细节,当SLEEPCMD.OSC_PD为0时,32MHz晶振与16MHz RC振荡器都会起振:

     对于SLEEPSTA寄存器中BIT6/BIT5说明在cc2530说明书中也并没有说明,可以参考cc2430说明书中内容,其中第6位XOSC_STB表明外部高速32M晶振是否上电并稳定起振,当稳定时该位为1;同样对于第5位HFRC_STB则表明内部16MHz高速RC振荡器是否起振,并是否稳定,当16MHz RC振荡器稳定时该位为1。

    void SysStartXOSC(void)
    {
        SLEEPCMD &= ~0x04;                      // 启动所有晶振
        while (!(SLEEPSTA & 0x40));             // 等待晶振稳定
    
        CLKCONCMD = (CLKCONCMD & 0x80) | 0x49;  // 使用16M晶振作为主时钟
        while ((CLKCONSTA & ~0x80) != 0x49 );   // 等待主时钟切换到16M晶振
    
        CLKCONCMD = (CLKCONCMD & ~0x80) ;       // 使用外部32K晶振作为休眠时钟
        while ( (CLKCONSTA & 0x80) != 0 );      // 等待睡眠时钟切换到外部32K晶振
    
        CLKCONCMD = (CLKCONCMD & 0x80) ;        // 使用32M晶振作为主时钟
        while ( (CLKCONSTA & ~0x80) != 0 );     // 等待主时钟切换到32M晶振
    
        SLEEPCMD |= 0x04;                       // 关闭未使用的晶振
    }

     按照上述方式配置后,我们就可以工作在外部的32M晶振上了,配置好系统时钟和SPI后,剩下的工作只需要按照液晶屏的说明书发送相应的指令就可以将液晶屏驱动起来了,具体的驱动代码详见下一堂课程。这里使用的是ASCII的点阵表,所以只能显示英文,如果需要显示中文,就需要中文字库的支持了。
       
    LCD12864的驱动程序:

    /******************************************************************************
    
                      版权所有 (C), 2013-2020, 深圳市馒头科技有限公司
    
     ******************************************************************************
      文 件 名   : Lcd12864.c
      版 本 号   : V1.0
      作    者   : 朱兆祺
      生成日期   : 2014年6月18日
      功能描述   : LCD12864驱动
                  //control
                  P0.1 - LCD_MODE
                  P1.2 - LCD_CS
    
                  //spi
                  P1.5 - CLK
                  P1.6 - MOSI
      函数列表   :
      修改历史   :
      1.日    期   : 2014年6月18日
        作    者   : 朱兆祺
        修改内容   : 创建文件
    
    ******************************************************************************/
    
    /*----------------------------------------------*
     * 包含头文件                                   *
     *----------------------------------------------*/
    #include <ioCC2540.h>
    #include "Lcd12864.h"
    #include "common.h"
    
    /*----------------------------------------------*
     * 宏定义                                       *
     *----------------------------------------------*/
    
    /* LCD lines */
    #define LCD12864_MAX_LINE                64
    #define LCD12864_MAX_ROW                 128
    
    #define HAL_LCD_FONT_LINES                8
    #define HAL_LCD_FONT_ROWS                 6
    
    /* LCD Max Chars and Buffer */
    #define HAL_LCD_MAX_LINES            (LCD12864_MAX_LINE/HAL_LCD_FONT_LINES)       // 6*8点阵最大行数
    #define HAL_LCD_MAX_CHARS            (LCD12864_MAX_ROW/HAL_LCD_FONT_ROWS)         // 6*8点阵最大列数
    
    /* LCD Control lines */
    #define HAL_LCD_RS_PORT             0
    #define HAL_LCD_RS_PIN              1
    
    #define HAL_LCD_CS_PORT             1
    #define HAL_LCD_CS_PIN              2
    
    /* LCD SPI lines */
    #define HAL_LCD_CLK_PORT            1
    #define HAL_LCD_CLK_PIN             5
    
    #define HAL_LCD_MOSI_PORT           1
    #define HAL_LCD_MOSI_PIN            6
    
    // 12864 命令
    #define                LCD_CMD_DISPLAY_ON                                0xAF
    #define                LCD_CMD_DISPLAY_OFF                                0xAE
    #define                LCD_CMD_BEGIN_LINE                                0x40
    #define                LCD_CMD_PAGE_LINE                                0xB0
    #define                LCD_CMD_ROW_HIG                                        0x10
    #define                LCD_CMD_ROW_LOW                                        0x00
    #define                LCD_CMD_READ_STATE                                0x00
    #define                LCD_CMD_ROW_ADDR_NORMAL                        0xA0                // 从左到右
    #define                LCD_CMD_ROW_ADDR_REVERSE                 0xA1                // 从右到左
    #define                LCD_CMD_DISPLAY_NORMAL                        0xA6
    #define                LCD_CMD_DISPLAY_REVERSE                        0xA7
    #define                LCD_CMD_DISPLAY_POINT_ALL                0xA5
    #define                LCD_CMD_DISPLAY_POINT_NORMAL        0xA4
    #define                LCD_CMD_BIAS_SET                                0xA2                // 0XA2:BIAS=1/9 (常用)  0XA3:BIAS=1/7
    #define                LCD_CMD_SOFT_RESET                                0xE2
    #define                LCD_CMD_LINE_NORMAL                                0xC0                // 从上到下
    #define                LCD_CMD_LINE_REVERSE                        0xC8                // 从下到上
    #define                LCD_CMD_POWER_ONE                                0x2C
    #define                LCD_CMD_POWER_TWO                                0x2E
    #define                LCD_CMD_POWER_THREE                                0x2F
    #define                LCD_CMD_CONTRAST_ONE_LEVEL                0x22  // 0x20-0x27
    #define                LCD_CMD_CONTRAST_TWO_CMD                0x81  // 0x00-0x3F
    #define                LCD_CMD_STATIC_PICTURE_ON                0xAD
    
       /* SPI interface control */
    #define LCD_SPI_BEGIN()     HAL_CONFIG_IO_OUTPUT(HAL_LCD_CS_PORT,  HAL_LCD_CS_PIN,  0); /* chip select */
    #define LCD_SPI_END()                                                         \
    {                                                                             \
      asm("NOP");                                                                 \
      asm("NOP");                                                                 \
      asm("NOP");                                                                 \
      asm("NOP");                                                                 \
      HAL_CONFIG_IO_OUTPUT(HAL_LCD_CS_PORT,  HAL_LCD_CS_PIN,  1); /* chip select */         \
    }
    /* clear the received and transmit byte status, write tx data to buffer, wait till transmit done */
    #define LCD_SPI_TX(x)                   { U1CSR &= ~(BV(2) | BV(1)); U1DBUF = x; while( !(U1CSR & BV(1)) ); }
    
    /* Control macros */
    #define LCD_DO_WRITE()        HAL_CONFIG_IO_OUTPUT(HAL_LCD_RS_PORT,  HAL_LCD_RS_PIN,  1);
    #define LCD_DO_CONTROL()      HAL_CONFIG_IO_OUTPUT(HAL_LCD_RS_PORT,  HAL_LCD_RS_PIN,  0);
    
    /*全体ASCII 列表:5x7点阵库*/
    const static uint8 aucAsciiTable5x7[][5]={
    0x00,0x00,0x00,0x00,0x00,//space
    0x00,0x00,0x4f,0x00,0x00,//!
    0x00,0x07,0x00,0x07,0x00,//"
    0x14,0x7f,0x14,0x7f,0x14,//#
    0x24,0x2a,0x7f,0x2a,0x12,//$
    0x23,0x13,0x08,0x64,0x62,//%
    0x36,0x49,0x55,0x22,0x50,//&
    0x00,0x05,0x07,0x00,0x00,//]
    0x00,0x1c,0x22,0x41,0x00,//(
    0x00,0x41,0x22,0x1c,0x00,//)
    0x14,0x08,0x3e,0x08,0x14,//*
    0x08,0x08,0x3e,0x08,0x08,//+
    0x00,0x50,0x30,0x00,0x00,//,
    0x08,0x08,0x08,0x08,0x08,//-
    0x00,0x60,0x60,0x00,0x00,//.
    0x20,0x10,0x08,0x04,0x02,///
    0x3e,0x51,0x49,0x45,0x3e,//0
    0x00,0x42,0x7f,0x40,0x00,//1
    0x42,0x61,0x51,0x49,0x46,//2
    0x21,0x41,0x45,0x4b,0x31,//3
    0x18,0x14,0x12,0x7f,0x10,//4
    0x27,0x45,0x45,0x45,0x39,//5
    0x3c,0x4a,0x49,0x49,0x30,//6
    0x01,0x71,0x09,0x05,0x03,//7
    0x36,0x49,0x49,0x49,0x36,//8
    0x06,0x49,0x49,0x29,0x1e,//9
    0x00,0x36,0x36,0x00,0x00,//:
    0x00,0x56,0x36,0x00,0x00,//;
    0x08,0x14,0x22,0x41,0x00,//<
    0x14,0x14,0x14,0x14,0x14,//=
    0x00,0x41,0x22,0x14,0x08,//>
    0x02,0x01,0x51,0x09,0x06,//?
    0x32,0x49,0x79,0x41,0x3e,//@
    0x7e,0x11,0x11,0x11,0x7e,//A
    0x7f,0x49,0x49,0x49,0x36,//B
    0x3e,0x41,0x41,0x41,0x22,//C
    0x7f,0x41,0x41,0x22,0x1c,//D
    0x7f,0x49,0x49,0x49,0x41,//E
    0x7f,0x09,0x09,0x09,0x01,//F
    0x3e,0x41,0x49,0x49,0x7a,//G
    0x7f,0x08,0x08,0x08,0x7f,//H
    0x00,0x41,0x7f,0x41,0x00,//I
    0x20,0x40,0x41,0x3f,0x01,//J
    0x7f,0x08,0x14,0x22,0x41,//K
    0x7f,0x40,0x40,0x40,0x40,//L
    0x7f,0x02,0x0c,0x02,0x7f,//M
    0x7f,0x04,0x08,0x10,0x7f,//N
    0x3e,0x41,0x41,0x41,0x3e,//O
    0x7f,0x09,0x09,0x09,0x06,//P
    0x3e,0x41,0x51,0x21,0x5e,//Q
    0x7f,0x09,0x19,0x29,0x46,//R
    0x46,0x49,0x49,0x49,0x31,//S
    0x01,0x01,0x7f,0x01,0x01,//T
    0x3f,0x40,0x40,0x40,0x3f,//U
    0x1f,0x20,0x40,0x20,0x1f,//V
    0x3f,0x40,0x38,0x40,0x3f,//W
    0x63,0x14,0x08,0x14,0x63,//X
    0x07,0x08,0x70,0x08,0x07,//Y
    0x61,0x51,0x49,0x45,0x43,//Z
    0x00,0x7f,0x41,0x41,0x00,//[
    0x02,0x04,0x08,0x10,0x20,// 斜杠
    0x00,0x41,0x41,0x7f,0x00,//]
    0x04,0x02,0x01,0x02,0x04,//^
    0x40,0x40,0x40,0x40,0x40,//_
    0x01,0x02,0x04,0x00,0x00,//`
    0x20,0x54,0x54,0x54,0x78,//a
    0x7f,0x48,0x48,0x48,0x30,//b
    0x38,0x44,0x44,0x44,0x44,//c
    0x30,0x48,0x48,0x48,0x7f,//d
    0x38,0x54,0x54,0x54,0x58,//e
    0x00,0x08,0x7e,0x09,0x02,//f
    0x48,0x54,0x54,0x54,0x3c,//g
    0x7f,0x08,0x08,0x08,0x70,//h
    0x00,0x00,0x7a,0x00,0x00,//i
    0x20,0x40,0x40,0x3d,0x00,//j
    0x7f,0x20,0x28,0x44,0x00,//k
    0x00,0x41,0x7f,0x40,0x00,//l
    0x7c,0x04,0x38,0x04,0x7c,//m
    0x7c,0x08,0x04,0x04,0x78,//n
    0x38,0x44,0x44,0x44,0x38,//o
    0x7c,0x14,0x14,0x14,0x08,//p
    0x08,0x14,0x14,0x14,0x7c,//q
    0x7c,0x08,0x04,0x04,0x08,//r
    0x48,0x54,0x54,0x54,0x24,//s
    0x04,0x04,0x3f,0x44,0x24,//t
    0x3c,0x40,0x40,0x40,0x3c,//u
    0x1c,0x20,0x40,0x20,0x1c,//v
    0x3c,0x40,0x30,0x40,0x3c,//w
    0x44,0x28,0x10,0x28,0x44,//x
    0x04,0x48,0x30,0x08,0x04,//y
    0x44,0x64,0x54,0x4c,0x44,//z
    0x08,0x36,0x41,0x41,0x00,//{
    0x00,0x00,0x77,0x00,0x00,//|
    0x00,0x41,0x41,0x36,0x08,//}
    0x04,0x02,0x02,0x02,0x01,//~
    };
    const uint8 asciiTableSize = sizeof( aucAsciiTable5x7 ) / sizeof( aucAsciiTable5x7[0]);
    
    
    /*****************************************************************************
     函 数 名  : LCD12864_Cmd
     功能描述  : 发送控制命令
     输入参数  : uint8 cmd
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年5月28日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    static void LCD12864_Cmd(uint8 cmd)
    {
        LCD_SPI_BEGIN();
        LCD_DO_CONTROL();
        LCD_SPI_TX(cmd);
        LCD_SPI_END();
    }
    
    /*****************************************************************************
     函 数 名  : LCD12864_Dat
     功能描述  : 发送数据
     输入参数  : uint8 data
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年5月28日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    static void LCD12864_Dat(uint8 data)
    {
        LCD_SPI_BEGIN();
        LCD_DO_WRITE();
        LCD_SPI_TX(data);
        LCD_SPI_END();
    }
    
    
    void LCD12864_Init(void)
    {
        PERCFG |= 0x02;       // 设置UART alt2 为 SPI
        // 配置引脚为SPI功能
        HAL_CONFIG_IO_PERIPHERAL(HAL_LCD_CLK_PORT,  HAL_LCD_CLK_PIN);
        HAL_CONFIG_IO_PERIPHERAL(HAL_LCD_MOSI_PORT, HAL_LCD_MOSI_PIN);
    
        /* Configure SPI */
        U1UCR  = 0x80;      // 清除原来的数据
        U1CSR  = 0x00;      // SPI 主机模式
        // 高位在前,第一个上升沿发送数据,波特率为2M
        U1GCR  = HAL_SPI_TRANSFER_MSB_FIRST | HAL_SPI_CLOCK_PHA_0 | HAL_SPI_CLOCK_POL_LO | 0x0F;
        U1BAUD = 0xFF;
    
        // CS RS 配置为输出
        HAL_CONFIG_IO_OUTPUT(HAL_LCD_RS_PORT, HAL_LCD_RS_PIN, 1);
        HAL_CONFIG_IO_OUTPUT(HAL_LCD_CS_PORT, HAL_LCD_CS_PIN, 1);
    
        SoftWaitUs(15000); // 15 ms
        LCD12864_Cmd(LCD_CMD_SOFT_RESET);        //软复位
            SoftWaitUs(15000); // 15 ms
            LCD12864_Cmd(LCD_CMD_POWER_ONE);        //升压步聚1
            SoftWaitUs(15); // 15 us
            LCD12864_Cmd(LCD_CMD_POWER_TWO);        //升压步聚2
            SoftWaitUs(15); // 15 us
            LCD12864_Cmd(LCD_CMD_POWER_THREE);        //升压步聚3
            SoftWaitUs(150); // 15 us
            LCD12864_Cmd(LCD_CMD_CONTRAST_ONE_LEVEL);        //粗调对比度,可设置范围0x20~0x27
            LCD12864_Cmd(LCD_CMD_CONTRAST_TWO_CMD);        //微调对比度
            LCD12864_Cmd(0x3a);        //0x1a,微调对比度的值,可设置范围0x00~0x3f
            LCD12864_Cmd(LCD_CMD_BIAS_SET);        // 1/9偏压比(bias)
            LCD12864_Cmd(LCD_CMD_LINE_NORMAL);        //行扫描顺序:从上到下
            LCD12864_Cmd(LCD_CMD_ROW_ADDR_REVERSE);        //列扫描顺序:从左到右
            LCD12864_Cmd(LCD_CMD_BEGIN_LINE);        //起始行:第一行开始
            LCD12864_Cmd(LCD_CMD_DISPLAY_ON);        //打开显示
        LCD12864_Cmd(LCD_CMD_DISPLAY_POINT_NORMAL);
        LCD12864_Cmd(LCD_CMD_DISPLAY_NORMAL);       //设置为正显模式
            SoftWaitUs(150); // 150 us
    }
    
    
    /*****************************************************************************
     函 数 名  : LCD12864_SetAddr
     功能描述  : 设置起始地址
     输入参数  : uint8 line
                 uint8 col
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年6月1日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    static void LCD12864_SetAddr(uint8 line, uint8 col)
    {
        uint8 ucLine, ucRow;
        //line += 5;
        col  += 4;
        if((line >= LCD12864_MAX_LINE) || (col >= LCD12864_MAX_ROW))
        {
            return;
        }
    
        ucLine = LCD_CMD_PAGE_LINE | (line&0x0f);
        LCD12864_Cmd(ucLine);
        SoftWaitUs(15);
    
        ucRow = LCD_CMD_ROW_HIG | (col>>4);
        LCD12864_Cmd(ucRow);
        SoftWaitUs(15); // 15 us
    
        ucRow = LCD_CMD_ROW_LOW | (col&0x0f);
        LCD12864_Cmd(ucRow);
        SoftWaitUs(15); // 15 us
    }
    
    /*****************************************************************************
     函 数 名  : LCD12864_Dis5X8
     功能描述  : 将一个字符用5*8的点阵显示
     输入参数  : char ch
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年6月1日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    static void LCD12864_Dis5X8(char ch)
    {
        uint8 ucCnt;
        if((ch >= 0x20)&&(ch < 0x7f))
        {
            uint8 ucChar = ch - 0x20;
            for(ucCnt=0; ucCnt<5; ucCnt++)
            {
                LCD12864_Dat( aucAsciiTable5x7[ucChar][ucCnt]);
            }
            //LCD12864_Dat(0x00);
        }
        else if(ch==0x00)     //不需要显示,清空指定位置
        {
                    for(ucCnt=0; ucCnt<5; ucCnt++)
            {
                LCD12864_Dat(0x00);
            }
            }
        LCD12864_Dat(0x00);
    }
    
    
    /*****************************************************************************
     函 数 名  : LCD12864_Clear
     功能描述  : 清屏
     输入参数  : void
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年6月1日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    void LCD12864_Clear(void)
    {
        uint8 ucLine, ucRow;
        for(ucLine=0; ucLine<LCD12864_MAX_LINE; ucLine++)
        {
            LCD12864_SetAddr(ucLine, 0);
            for(ucRow=0; ucRow<LCD12864_MAX_ROW; ucRow++)
            {
                    LCD12864_Dat(0x00);
            }
        }
    }
    
    /*****************************************************************************
     函 数 名  : LCD12864_DisChar
     功能描述  : 在指定位置显示一个字符
     输入参数  : uint8 line
                 uint8 col
                 char ch
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年6月1日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    void LCD12864_DisChar(uint8 line, uint8 col, char ch)
    {
        if (( line < HAL_LCD_MAX_LINES)&&(col < HAL_LCD_MAX_CHARS))
        {
            LCD12864_SetAddr(line, col*HAL_LCD_FONT_ROWS);
            LCD12864_Dis5X8(ch);
        }
    }
    
    /*****************************************************************************
     函 数 名  : LCD12864_DisStr
     功能描述  : 将字符串显示到指定行
     输入参数  : uint8 line         显示的行 0~7
                 char* pStr         显示的字符串首地址
     输出参数  : 无
     返 回 值  :
    
     修改历史      :
      1.日    期   : 2014年6月2日
        作    者   : 朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    void LCD12864_DisStr(uint8 line, char* pStr)
    {
        uint8 ucCnt = 0;
        for ( ucCnt = 0 ; ucCnt < HAL_LCD_MAX_CHARS; ucCnt++ )
        {
            if ( '\0' == *pStr )
            {
                break;
            }
            LCD12864_DisChar( line, ucCnt, pStr[ucCnt]);
        }
    
        for (  ; ucCnt < HAL_LCD_MAX_CHARS; ucCnt++ )
        {
            LCD12864_DisChar( line, ucCnt, 0);
        }
    }
    
    /*----------------------------------------------*
     *              end of file                     *
     *----------------------------------------------*/

    主程序:

    /*****************************************************************************
     函 数 名  : main
     功能描述  : 主函数
     输入参数  : 无
     输出参数  : 无
     返 回 值  : 
    
     修改历史      :
      1.日    期   : 2014年6月6日
        作    者   :  朱兆祺
        修改内容   : 创建
    
    *****************************************************************************/
    
    int main(void)
    {
        /* 启动外部晶振 */
        SysStartXOSC();
        
        /* LCD12864的初始化 */
        LCD12864_Init();
        
        /* 清屏 */
        LCD12864_Clear();
        
        
        while(1)
        {
            /* 显示字符 */
            LCD12864_DisStr(3, "ShenZhenShiManTouKeJi");
        }
        
        return 0;
    }

    这样我们就点亮的LCD12864屏幕:

    第六节  独立按键之查询方式

        在MT254xboard上有一个独立按键KEY1,如图 ,独立按键和复位键在整个班子的左上角。按键通过P0.0口和CPU连接,在没有按键时为高电平,按下后为低电平。下面我们通过LCD来显示独立按键的状态。

    其对应的原理图如下:

     我们先用查询的方式读取按键的状态。因为按键接入在P0.0口,所以我们读取P0.0口的电平即可知道按键的状态。

    uint8 KeyValue(void)                                // 读取按键状态
    {
        if((P0&0X01) == 0X00 )      // 按下为低电平
        {
            return KEY_DOWN;
        }
        else
        {
            return KEY_UP;
        }
    }

    这里我们在while循环中不断的读取按键状态,并且判断是否改变,如果改变则改变LCD的显示。

    int main(void)
    {
        uint8 OldKeyValue = 0;                
        uint8 NewKeyValue = 0;
        SysStartXOSC();
        LCD12864_Init();
        LCD12864_DisStr(1, "    Key Test");
            // 按键初始化
        P0SEL &= ~0X01;        // 设置为 IO功能
        P0DIR &= ~0X01;        // 设置为输入功能
    
        while(1)
        {
            NewKeyValue = KeyValue();   // 读取按键状态
            if(OldKeyValue != NewKeyValue)  // 按键状态改变
            {
                OldKeyValue = NewKeyValue;  // 保存当前按键状态
                if(OldKeyValue == KEY_DOWN)
                {
                    LCD12864_DisStr(3, "    Key Down ");
                }
                else
                {
                    LCD12864_DisStr(3, "    Key Up ");
                }
            }
        }
        return 0;
    }

    运行程序,效果如图所示:

     

    展开全文
  • 蓝牙协议架构扫盲 蓝牙协议架构图真的是五花八门的,我们以前见过,以hci层区分host和controller的楚河汉界,然后两边细分,hci层以下有lc、lmp层,hci以上有l2cap和profile。 我们再来看这张图,这张图又有所...

    蓝牙协议架构扫盲

    http://www-x-wowotech-x-net.img.abc188.com/content/uploadfile/201601/55182faff2cc9b359b52f6001d239d7720160114142019.gif

    蓝牙的协议架构图真的是五花八门的,我们以前见过,以hci层区分host和controller的楚河汉界,然后两边细分,hci层以下有lc、lmp层,hci以上有l2cap和profile。

    我们再来看这张图,这张图又有所区别了,l2cap层以下是logical layer和physical layer。

    是不是又晕了?

    其实只是角度不同而已,以前的架构图更侧重的是软件协议,这张图的侧重点则是物理链路、逻辑链路等等大量被抽象出来的基带概念。

    看一下下面这张图就更清晰了。

     

    首先是physical channel。

    蓝牙通信最基础的条件就是收端和发端把频率调到一个频段上,这里的频段就是物理channel的概念了。

    BR、EDR中根据是否支持自适应调频分成basic piconet physical channel和adapted piconet physical channel。

    注意只有这两种physical channel是由向上层的physical link的连接线的,为什么page scan和inquiry scan没有呢,因为连接、扫描这两种情况是蓝牙的一种特殊状态,只在特定时间使用,且无法控制任何属性,基本上就是host向controller下个命令,就进入该状态了,所以不在physical link中体现。

    Physical link是抽象出來的概念,不对应任何实体,对于功率、收发周期的管理就是这一层干的,active、park对应不同的功耗,上层不必知情。

    Logical链路层则对应了不同的包格式了,我们在第三章已经讲到过通过packet header中的llid来区分acl-c和acl-u的情况了。当然这只是对应图中br/edr acl这种链路,其实还有很多种其他链路,基本上的规律是,凡是结尾带个“c”的都是控制链路,比如amp-c、acl-c、le-c等等,凡是结尾带个“u”的都是上层profile数据,比如acl-u、psb-u、le-u等等。

    所有的链路,都有对应的格式,每种格式有对应的logical transport层为其提供服务,包括每种格式不同的流控、重传机制等等。

    来一个知识点:逻辑链路和逻辑信道的区别——

    很多人喜欢讲逻辑链路,其实主要讲的就是上述这个controller层的概念,但是逻辑信道呢,通常意义上,是讲l2cap层向上层开放的cid。这是两个概念的东西。

    以上这些,在core spec的controller一章中有详细的阐述,有些概念很抽象,不容易理解。

    Controller的协议栈结构相对简单,就是LMP和LC两层,LMP就是link manager protocol,LC就是link controller,因为这个一般是蓝牙模块内部的东西,所以读者了解到的东西可能不多,但是理解一下具体的功能,还是很有必要的。

    我们看一下这个图

    比以前那个host协议栈的图简单多了是不是?

    其实也不简单的,细分的话有很多东西好讲。

    在HCI层以下,首先是LMP,LMP的功能顾名思义就是链路管理,上面所说的这些physical link、logical link、logical transport都是LMP去管理的。

    LMP上承HOST协议栈,接收来自HOST的hci command,下可以管理LINK controller和基带,向远端蓝牙设备发送LMP pdu(上文我们提到过的ACL-C包还记得吗?就是LMP包),实现链路的连接、控制和维护。

    老规矩,我们还是看看我们的抓包,看看连接过程发生了什么。

    首先,我们的host向controller发送了建链命令

    看看蓝牙core spec中的图,是这样的:

    Host发完指令后就撂挑子了,剩下的事情都是LMP在做,看一下空中包,LMP首先和远端设备交换feature,看看彼此都支持些什么,然后发送了一个LMP host connection request给对端。注意看一下下面红色标出的部分,我们之前提到LMP向下是控制LC的,LC填充了这个LMP包的包头,包头中包含了流控、ARQ、包格式等等信息,这里的包格式是DM1,ARQN是个ACK标志,意味着这个LMP包是需要回复的;然后payload header中LLID标识了这个包是个ACL-C包,也就是LMP包。

    远端在收到LMP包后,会向host上传一个请求连接的event,由host来判断是否接受连接,假如接受的话,就是如下的流程图,我们这次也确实是收到了LMP accepted包,表示连接是成功的。

     

    这个时候,一条acl的逻辑链路就已经建立了,蓝牙协议规定,两个设备之间是只能有一条acl链路的。但是sco链路可以有几条的。

    Sco主要是用于免提通话,在固定时隙(reserved slots)发送,主要保证通信的同步性,不确保,数据丢了就是丢了。

    看一下建立sco 链路的流程图:

    同样是host发命令,lmp执行,具体的不再赘述了,还是比较清楚的。

     

    Link controller的功能会更靠近底层一点。

    总的来说,就是根据当前物理链路的状态,跑一个状态机,执行该状态(page?inquiry?connection?park?)所必须执行的任务,在不同物理信道上调频收发page包、inquiry 包或者其他数据包等等,执行piconet 切换、主从切换等等底层直接和硬件打交道的工作。

    组包的时候蓝牙的每个包的包头都是LC的map,其中的ARQ、FLOW这些位就是link controller 加上去的,要注意,蓝牙只有ID包是没有packet header的。

     

     

     

     

    展开全文
  • 基于CoreBluetooth与蓝牙4.0设备通讯非常方便,一句话总结就是中心-设备-服务-特征...可以通过LightBlue查看你的蓝牙设备相关信息,也可以发送简单指令。 CBCentralManager scanForPeripherals时需要注意两点: AP...
  • 蓝牙AVRCP协议分析

    千次阅读 2019-04-01 20:49:19
    AVRCP(audio vidoe remote control protocol) 协议,用于远程控制音视频设备. 底层传输基于AVCTP传输协议,在蓝牙中,主要用于蓝牙音乐的控制,比如...CT通过指令控制TG播放音乐,比如蓝牙耳机时CT,而手机可以作为T...
  • 蓝牙协议

    千次阅读 2020-05-20 21:40:35
    adb shell setprop persist.bluetooth.btsnoopenable true,开启蓝牙hci-snoop的开关。 persist.bluetooth.btsnoopenable 全局变量的存储路径因安卓版本而有些许差异: Android 8的存储路径:/...初始化协议栈: 1.蓝牙
  • 一个简单的蓝牙指令测试工具

    万次阅读 热门讨论 2017-05-26 19:55:44
    https://github.com/duoshine/simpleBt 这是我封装的一个Ble通信的库,几行代码即可调用,感兴趣的...用法比较简单:首先进入首页会显示附近的蓝牙设备,注意蓝牙要打开,没打开的话就扫描不到了 选择一个设备后,会...
  • 蓝牙pbap协议源码解析

    万次阅读 2017-01-11 22:14:27
    PBAP协议 使用场景:智能车载中同步联系人等信息 其实,不仅可以同步联系人,还可以同步通话记录等信息。 1.协议概述 协议代码路径:  ...frameworks\opt\bluetooth\src\...所以进行开发时,在mk文件中需要添加这个包,
  • 近日,接到需要用到蓝牙解锁硬件设备的新需求,开发过程中呢也遇到许多硬件的坑,开发协议文档较简单,几句话就完了,第一次搞得我自己一脸懵逼,本来一两个小时就能写完并测试完成的过程用了两三天。哎!默默地回到...
  • iOS开发 之 可穿戴设备 蓝牙4.0 BLE 开发

    万次阅读 热门讨论 2015-06-10 16:55:09
    1 前言当前有越来越多的可...对于硬件开发有了解的朋友应该知道,在之前使用低版本的蓝牙的设备,要连接到iOS设备上,需要注册MFI,拥有MFI协议才能进行相应的开发。如果大家关注我之前对LEGO EV3的研究,就可以发现
  • 上一篇简单介绍了蓝牙4.0的iOS实现代码,详细的东西大家可以去github上搜babyBluetooth,里面有一些学习资料,接下来分享的是OTA升级的东西,我们假定看这篇文章的时候,关于iOS和外设间的蓝牙收发数据已经掌握的很6...
  • 由于蓝牙协议栈在实际应用中已被封装起来,博主介绍的蓝牙协议不会过多涉及具体细节,比如数据包形式、指令形式等,更多的是围绕着功能与作用,便于理解与吸收。在建立整体认识的基础上再进行深入研究。 这片博客只...
  • 需要做一个类似于美团单车小程序扫码开锁的程序,需要使用到微信小程序的蓝牙模块功能与蓝牙锁进行交互 一、这里我先把我遇到的两个天坑在这里先说明一下: 1、根据锁的开发文档描述:读特征值是000036F6-0000-1000...
  • 蓝牙协议简介

    2021-04-20 13:45:25
    从左到右依次为:经典蓝牙(BR/EDR)、双模蓝牙(同时支持BR/EDR/LE)和低功耗蓝牙(BLE)。其中经典蓝牙和低功耗蓝牙互不兼容。 其实看结构也可以看出双模蓝牙是经典蓝牙和低功耗蓝牙的合集。 (二)、蓝牙原理及...
  • 零. 概述 主要介绍下用正点原子的战舰(STM32F103...第二篇:Transport层介绍,主要介绍蓝牙协议栈跟蓝牙芯片之前的硬件传输协议,比如基于UART的H4,H5,BCSP,基于USB的H2等 第三篇:传统蓝牙controller介绍,主要介绍传
  • 本文针对一对一的蓝牙进行通讯,适合没有开发蓝牙的同学来看,也适合大部分物联网简单开发,没有深入蓝牙开发。对于没有开发蓝牙的来说,我先说下逻辑。比如先拿自己手机的蓝牙来说,打开蓝牙,列出列表,包含...
  • 最近一直在忙Android的工控软件设计,写一点心得,希望对这方面开发的有一点带你帮助。1)从蓝牙接收了数据又如何保存?之前没有想过接收的数据如何保存,就简单的用一个字节数组进行保存,后来处理数据的时候就遇到...
  • 蓝牙协议分析工具

    千次阅读 2020-02-27 17:20:36
    市面上有各种各样的蓝牙协议分析工具,但专业开发蓝牙的公司里基本都是使用Ellisys Bluetooth Analyzer和Frontline这两种协议分析工具,与之配套的软件也是各有千秋,但本人觉得Ellisys软件的界面及使用方法对开发...
  • 常见蓝牙协议

    千次阅读 2013-06-28 10:07:13
    蓝牙协议规范的目标是允许遵循规范的应用能够进行相互间操作.蓝牙SIG规范的完整蓝牙协议栈如图: 蓝牙核心协议 蓝牙的核心协议由基带,链路管理,逻辑链路控制与适应协议和服务搜索协议等4部分组成. (1)基带...
  • 零. 概述 本文章主要讲下电话免提协议HFP(Hands-Free Profile)Connection management。...第一篇:蓝牙综合介绍 ,主要介绍蓝牙的一些概念,产生背景,发展轨迹,市面蓝牙介绍,以及蓝牙开发板介绍。 ...
  • 安卓系统蓝牙协议栈 bluedroid 使能流程分析 本文承接上篇文章《安卓中蓝牙系统服务层的使能流程分析》,接续分析协议栈层相关的使能流程,所以蓝牙协议栈bluedroid的使能始于JNI层enableNative()中调用协议栈接口...
  • 其中首先调用a2dp_and_avrcp_setup函数进行了一系列的初始化,从这个函数名就知道,初始化的内容包括了a2dp协议和avrcp协议,a2dp之前我们已经讲了其基础协议avdtp,avrcp的话呢是基于avctp协议的,AVCTP协议.
  • 安卓系统蓝牙协议栈 bluedroid 使能流程分析本文承接上篇文章《安卓中蓝牙系统服务层的使能流程分析》,接续分析协议栈层相关的使能流程,所以蓝牙协议栈bluedroid的使能始于JNI层enableNative()中调用协议栈接口...
  • 一:什么是BT snoop log 首先问题: 1.为什么远端发来的消息没有收到? 2.为什么搜索不到设备 ...这些就是log,回到正题,除了开发自定义的打印信息,Android蓝牙中有一个很重要的debug方式就是btsnoo
  • 文章目录一、UUID基础知识二、基于AT指令开发自定义修改UUID三、基于SDK开发自定义修改UUID联系我们 一、UUID基础知识        BLE通用属性(GATT)协议规定了服务端和客户端这两种...
  • android 蓝牙BLE 开发

    2017-10-20 10:59:03
    蓝牙开发分为传统蓝牙开发和低耗蓝牙开发(BLE),这边我就讲解下BLE的开发过程中的一些注意事项。 大致流程一般开发蓝牙的流程是 1.校验蓝牙是否开启,是否可用。 2.搜索设备,获取设备列表。 3.根据要链接的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,083
精华内容 1,633
关键字:

蓝牙指令协议开发