6105|6

1234

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

BLE4.0之CC2541串口应用从基础实验到协议栈 [复制链接]

为什么要发个这个帖子呢?
   学习BLE4.0有一个月了吧,发这个帖子也是为了记录自己的学习过程

相信大家都是学过其他系列的单片机,CC2541集51内核,肯定少不了51的影子,肯定要知道串口,在学习中,串口调试是必不可少的,它能打印出很多有用的信息出来。CC2541的串口引脚是:
P0.2--------UART_RX
P0.3--------UART_TX
   先说基础实验吧,上代码:
  1. void InitUart(void)
  2. {
  3.     P0SEL |= BV(2) | BV(3);  //配置P0.2和P0.3为外设,非GPIO
  4.     U0CSR |= BV(7);          //配置当前为UART,非SPI
  5.     U0GCR |= 11;             //根据上述波特率设置表格设置115200波特率
  6.     U0BAUD |= 216;           //根据上述波特率设置表格设置115200波特率
  7.     UTX0IF = 0;              //位寄存器,直接操作,清除中断标志

  8.     U0CSR |= BV(6);          //允许接收数据
  9.     IEN0 |= BV(2);           //打开接收中断
  10.     EA=1;                    //打开总中断
  11. }
复制代码
这些寄存器的配置详细得看用户手册,当中对应的功能说相应的寄存器每个位的作用,在最后将其分享出来,这段代码需要说的就是 U0CSR |= 11;U0BAUD|=216;这两句是确定波特率的,和我们以前学的单片机不一样,至于波特率的计算公式与对应表文档有说,看图:

         
      
  
具体的去算,还真没有去算,我都是照着这个表来的,好了 初始化完成了,那就是发送了一个字节了
  1. U0DBUF = byte;
  2.       while(UTX0IF == 0);
  3.       UTX0IF = 0;
复制代码
那个byte就是要发送的字节,至于你要不要把这几句话封装起来,那是你的事了,然后就是中断函数了
  1. #pragma vector = URX0_VECTOR  
  2. __interrupt void UART0_ISR(void)  
  3. {  
  4.     URX0IF = 0;       // 清中断标志  ;
  5.     byte=U0DBUF;
  6. }
复制代码
这个格式是固定的,头文件定的串口接收的向量就是URX0_VECTOR,看到这种写法,让我不禁想到以前在学校里学习MSP430的时候,这种风格应该说是TI的风格吧,如果不理解,先照着来一遍。
此帖出自无线连接论坛

最新回复

  详情 回复 发表于 2017-11-7 15:20
点赞 关注(2)
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 

回复
举报

1234

帖子

4

TA的资源

纯净的硅(高级)

沙发
 
本帖最后由 ywlzh 于 2016-4-22 22:39 编辑

说到协议栈,哎,初次学的时候,那叫一个心酸,这方面的资料也相对比较少,但是,皇天不负有心人。嘿嘿

CC2541的协议栈是建立在OSAL上的,所以那还得了解OSAL,说白了就是个无限循环,查哪些任务事件的状态,就绪了就通过函数指针跳到相应的函数中去。对,就这么简单。不要去死磕为什么会这样,作为初学者,不求甚解,我想是最好的学习态度。等到了一定程度,自然而然的就会深究的,别操心,慢慢来。

先看主程序:

  1. int main(void)
  2. {
  3.   /* Initialize hardware */
  4.   HAL_BOARD_INIT();          //初始化系统时钟

  5.   // Initialize board I/O
  6.   InitBoard( OB_COLD );      //初始化I/O,LED,Tiemr 等

  7.   /* Initialze the HAL driver */
  8.   HalDriverInit();           //初始化芯片各个硬件模块

  9.   /* Initialize NV system */
  10.   osal_snv_init();           //初始化flash 存储器  

  11.   /* Initialize LL */

  12.   /* Initialize the operating system */
  13.   osal_init_system();        //初始化操作系统
  14.   /* Enable interrupts */
  15.   HAL_ENABLE_INTERRUPTS();    //使能全部中断

  16.   // Final board initialization
  17.   InitBoard( OB_READY );      //初始化按键

  18.   #if defined ( POWER_SAVING )
  19.     osal_pwrmgr_device( PWRMGR_BATTERY );   //开启低功耗
  20.   #endif

  21.   /* Start OSAL */
  22.   osal_start_system(); // No Return from here
  23.                            //执行操作系统,进去后不会返回
  24.   return 0;
  25. }
复制代码
重点是osal_init_system();这个函数,跳转进去!
  1. uint8 osal_init_system( void )
  2. {
  3.   // Initialize the Memory Allocation System
  4.   osal_mem_init();

  5.   // Initialize the message queue
  6.   osal_qHead = NULL;

  7.   // Initialize the timers
  8.   osalTimerInit();

  9.   // Initialize the Power Management System
  10.   osal_pwrmgr_init();

  11.   // Initialize the system tasks.
  12.   osalInitTasks();

  13.   // Setup efficient search for the first free block of heap.
  14.   osal_mem_kick();

  15.   return ( SUCCESS );
  16. }
复制代码
重点是osalInitTasks();跳转进去,对,没错!跳进去!旁边什么东西都不要管!
  1. void osalInitTasks( void )
  2. {
  3.   uint8 taskID = 0;
  4.   //分配内存,返回指向缓存区的指针
  5.   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  6.   //设置所分配的内存空间单元值为0
  7.   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
  8.   //任务优先级由高向低依次排列,高优先级对应teskID的值反而小
  9.   /* LL Task */
  10.   LL_Init( taskID++ );

  11.   /* Hal Task */
  12.   Hal_Init( taskID++ );

  13.   /* HCI Task */
  14.   HCI_Init( taskID++ );

  15. #if defined ( OSAL_CBTIMER_NUM_TASKS )
  16.   /* Callback Timer Tasks */
  17.   osal_CbTimerInit( taskID );
  18.   taskID += OSAL_CBTIMER_NUM_TASKS;
  19. #endif

  20.   /* L2CAP Task */
  21.   L2CAP_Init( taskID++ );

  22.   /* GAP Task */
  23.   GAP_Init( taskID++ );

  24.   /* GATT Task */
  25.   GATT_Init( taskID++ );

  26.   /* SM Task */
  27.   SM_Init( taskID++ );

  28.   /* Profiles */
  29.   GAPRole_Init( taskID++ );
  30.   GAPBondMgr_Init( taskID++ );

  31.   GATTServApp_Init( taskID++ );

  32.   /* Application */
  33.   SimpleBLEPeripheral_Init( taskID );  //应用初始化,重点
  34. }
复制代码
看到注释的重点吗?就是SimpleBLEPeripheral_Init( taskID );这个就是我们平时要写的初始化的函数,在里面写初始化的内容就可以了,在BLE协议栈中,初始化也是在里面的,将协议栈安装了之后,就直接打开例程,作为初学,这里以从机实例,打开会看到以下的内容
   
这些内容都不要动,这是官方给的,先看看就行,以后再研究,那我们的串口的初始化是不是也要放在这个函数里,对,也要放在这个函数里,具体函数在这里:
  1. void serialAppInitTransport( )
  2. {
  3.   halUARTCfg_t uartConfig;

  4.   // configure UART
  5.   uartConfig.configured           = TRUE;
  6.   uartConfig.baudRate             = HAL_UART_BR_115200;//波特率
  7.   uartConfig.flowControl          = SBP_UART_FC;//流控制
  8.   uartConfig.flowControlThreshold = SBP_UART_FC_THRESHOLD;//流控制阈值,当开启flowControl时,该设置有效
  9.   uartConfig.rx.maxBufSize        = SBP_UART_RX_BUF_SIZE;//uart接收缓冲区大小
  10.   uartConfig.tx.maxBufSize        = SBP_UART_TX_BUF_SIZE;//uart发送缓冲区大小
  11.   uartConfig.idleTimeout          = SBP_UART_IDLE_TIMEOUT;
  12.   uartConfig.intEnable            = SBP_UART_INT_ENABLE;//是否开启中断
  13.   uartConfig.callBackFunc         = sbpSerialAppCallback;//uart接收回调函数,在该函数中读取可用uart数据

  14.   // start UART
  15.   // Note: Assumes no issue opening UART port.
  16.   (void)HalUARTOpen( SBP_UART_PORT, &uartConfig );

  17.   return;
  18. }
复制代码
你会发现有一些不认识的变量,不要紧,这是典型的库函数的开发例子,我们寻找头halUARTCfg_t,调到它的定义的地方,发现它在hal_uart.h中,不深究,知道它在里面就行。后续的,你们要是想改那个变量,调到它的定义的地方,附近就有它的“兄弟姐妹”,可以替换,将这段函数添加到那个初始化的函数中,还有一个地方要注意,库函数终究是库函数,它需要宏定义

这个一定要,好了函数的初始化完成,怎么写东西,进中断怎么接受呢?
仔细看初始化函数中有一句,uartConfig.callBackFunc         = sbpSerialAppCallback;
这个sbpSerialAppCallback就是用户自己的函数,你也写根据自己的想法把sbpSerialAppCallback改成woleyi都行,只不过你要自己写void woleyi(uint8 port, uint8 event),为什么有两个参数,这库hal_uart.c和hal_uart.h给规定的,这两个参数除了前面的,后面的几乎没用。不要去纠结,在这个函数中,你还得定义一个数组,这个数组就是存串口接收的数据。接收有个函数HalUARTRead(),不过它有三个参数,第一个是端口,就把port传过去,第二个参数就是你自己定义的数组名(数组的头地址),第三个参数是你要接收数据的长度,这个参数怎么确定呢?还得通过一个函数Hal_UART_RxBufLen(port),这个函数的返回值就是此次串口接收的数据的长度。调用一下就好了,其实hal_uart.c都做好了,等着调用就行。
  1. void sbpSerialAppCallback(uint8 port, uint8 event)
  2. {
  3.   uint8  pktBuffer[SBP_UART_RX_BUF_SIZE];
  4.   // unused input parameter; PC-Lint error 715.
  5.   (void)event;           //避免警告和错误
  6.    uint16 numBytes;
  7.   //SerialPrintString("SerialControl\r\n");
  8.   //返回可读的字节
  9.   if ( (numBytes = Hal_UART_RxBufLen(port)) > 0 ){
  10.           //读取全部有效的数据,这里可以一个一个读取,以解析特定的命令
  11.         (void)HalUARTRead (port, pktBuffer, numBytes);
  12.         //这里接收完后我就将它直接显示在LCD上了
  13.         HalLcdWriteString(pktBuffer, HAL_LCD_LINE_5 );   
  14.   }
  15. }
复制代码
说到接收,那发送呢?
  1. HalUARTWrite (SBP_UART_PORT, uint8 *str,uint8  len);
复制代码
也是三个参数,第一个是串口的端口,第二个是要发送的数据的头地址,第三个是发送的长度,通常都是把这个函数给封装起来

  1. void SerialPrintString(uint8 str[])
  2. {
  3.   HalUARTWrite (SBP_UART_PORT, str, osal_strlen((char*)str));
  4. }
复制代码
比如我要发送一个数组pptr,我就写:     
SerialPrintString(pptr);

哈哈 废话不多说了,自己也慢慢体会吧



此帖出自无线连接论坛
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 
 
 

回复

1234

帖子

4

TA的资源

纯净的硅(高级)

板凳
 
附上三个有用的东西


CC2540EM_V1.0原理图.pdf

254.17 KB, 下载次数: 22

CC253x4x User Guide. (Rev. C).pdf

2.6 MB, 下载次数: 25

Developer.pdf

5.03 MB, 下载次数: 36

此帖出自无线连接论坛
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 
 
 

回复

253

帖子

1

TA的资源

一粒金砂(高级)

4
 
感谢分享,表示云里雾里                                                              
此帖出自无线连接论坛
 
 
 

回复

98

帖子

0

TA的资源

一粒金砂(中级)

5
 
在用arm 写串口。
此帖出自无线连接论坛
 
 
 

回复

4

帖子

0

TA的资源

一粒金砂(初级)

6
 
此帖出自无线连接论坛
 
 
 

回复

4

帖子

0

TA的资源

一粒金砂(初级)

7
 
此帖出自无线连接论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表