zoukankan      html  css  js  c++  java
  • nRF51822蓝牙学习 进程记录 3:蓝牙协议学习--简单使用

      三天打鱼两天晒网,又学起了蓝牙,不过还好的是终于开始学习蓝牙协议部分了。

      但是,一看起来增加了蓝牙协议的例程,真是没头绪啊。本身的教程资料解说太差了,看青风的蓝牙原理详解也是一头雾水。

      经过不断地看各种资料,终于决定,不管他了,先学会例程修改再说。

      例程里面有个 蓝牙综合例程,就它了。

      使用的是LP电子的手环学习开发板。按照教程下载了协议,然后下载了编译文件,最后手机上安装了对应的LP的安卓软件。很好,启动成功,可以点灯,但是温度和授时按钮没用。而且这个例程和其他基于蓝牙协议的例程没有一个带OLED显示的例子。还想以后能手机控制开发板来操控OLED显示呢,怎么办,只有自己一步一步试试了。

      先到这个例程的main函数中看看。

     1 int main(void)
     2 {
     3     uint32_t err_code;
     4     uint8_t  start_string[] = START_STRING;
     5     led_init();
     6     DS18B20_Init();
     7     // Initialize.
     8     APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);//时钟初始化
     9     usart_init();    //串口初始化
    10     ble_stack_init();  //协议初始化
    11     gap_params_init();    //参数设置
    12     services_init();    //通信服务
    13     advertising_init();    //广播设置
    14     conn_params_init();  //连接参数
    15     
    16     printf("%s
    ",start_string);
    17 
    18     err_code = ble_advertising_start(BLE_ADV_MODE_FAST);  //¿ªÊ¼¹ã²¥
    19     APP_ERROR_CHECK(err_code);
    20     
    21     // Enter main loop.
    22     for (;;)
    23     {
    24         power_manage();
    25     }
    26 }

    额........没发现有啥基础性的东西.......

    再找找吧。往上转了转,哎,发现个东西。

     1 static void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length)//蓝牙接收
     2 {
     3       printf("p_data=%s
    ",p_data);
     4     uint32_t err_code;
     5     short temp=0;
     6     uint8_t data[3];
     7     switch(p_data[0])
     8         {
     9             case 0x31:   
    10                      nrf_gpio_pin_toggle(8);  //控制LED
    11             break;
    12             case 0x32:   // 
    13                nrf_gpio_pin_toggle(9);
    14             break;
    15             case 0x34:   // 
    16                nrf_gpio_pin_toggle(10);
    17             break;
    18             case 0x33:   // 温度接收
    19                temp=DS18B20_Get_Temp();
    20                data[0]=temp/100+0x30;
    21                data[1]=temp/10%10+0x30;
    22                data[2]=temp%10+0x30;
    23                err_code = ble_nus_string_send(&m_nus, data, 3);
    24         if (err_code != NRF_ERROR_INVALID_STATE)
    25         {
    26             APP_ERROR_CHECK(err_code);
    27         }
    28             break;
    29         
    30         }
    31 }

      这个不就是我要找的!!虽然咱还不明白蓝牙协议到底怎么用的,但是用人家写好的还是可以的。

      有了人家按钮接收对应的协议,那拿来直接用就完了。

      上面的第三行有个串口输出,输出的是p_data,这个是干什么使的?试一试吧。

      插上串口线,打开串口调试助手,发现按一个按钮显示一个数,转换为16进制正好和 case 后的数一样。这不就是输出按钮协议的吗。很好。可是很快又发现,在switch 中,p_data 是个数组!看样只是个一维数组,那这个数组到底都包括啥?都是干啥使得?仿照上面的printf 在后面加几行,将整个数组全输出,将原来的字符串输出%s换为数据输出%d,如下:

     1 //用于电脑串口输出查看p_data
     2 printf("p_data[0]=%d
    ",p_data[0]);
     3 printf("p_data[1]=%d
    ",p_data[1]);
     4 printf("p_data[2]=%d
    ",p_data[2]);
     5 printf("p_data[3]=%d
    ",p_data[3]);
     6 printf("p_data[4]=%d
    ",p_data[4]);
     7 printf("p_data[5]=%d
    ",p_data[5]);
     8 printf("p_data[6]=%d
    ",p_data[6]);
    

    得到类似数据:(这个是点击授时按钮获得的)

    p_data[0]=53
    p_data[1]=168
    p_data[2]=250
    p_data[3]=170
    p_data[4]=88
    p_data[5]=0
    p_data[6]=0

    多按几个按钮对比可得:p_data[0]为按钮对应的协议数据,p_data[1]、p_data[2]、p_data[3]与相应的按钮有关,p_data[4]都是88.

      好了,手机上的几个按钮对应的数据弄清楚了,那就将上面几个按钮没实现的功能加上去吧。比如 授时 和温度显示 按钮都没用,而 亮度显示 按钮因为开发板上没有光敏电阻,就没管它。

      首先,它的读取温度函数不知哪儿有毛病,也没工夫再找一遍了,直接删除,将我自己的ds18b20的函数移植进去。好了,串口和手机显示温度正常。可以发现, ble_nus_string_send(&m_nus, data, 3)这个函数是蓝牙的数据发送函数,很有用,只是目前还不会用,先标记着。(目前的目标是先会移植使用人家的)。

      再加入OLED显示函数吧。照着之前的移植方法将周立功的ZLG_GUI再移植上。简单写一个初始化函数并加入main()函数中,放在 协议初始化 之前。然后将OLED显示温度函数showtemp(x,y) 加在读取温度的 case 0x33:  后面,并加上缓存显示函数GUI_Exec();运行可以发现只有点击了 温度 按钮,屏幕才会更新数据,因为看main()函数可以发现,无限运行的  for (;;) 中只有一个低电量运行的函数(24行),此时的case 猜测是利用中断来运行得,所以只有触发了case 才会运行里面的函数。

    这样感觉很low(我先加上了时间显示函数,连同时间都是需要点一下按钮才更新一下屏幕,没意思),所以加上以前的中断刷屏函数试试。添加time.c,将定时器的启动初始化加到main()函数中,删去放在showtemp(x,y)后面的GUI_Exec(),运行发现可以显示。但由于温度读取还是和case挂钩,所以还是只有点了温度 按钮温度才会更新变化。(解决方法和时间函数更新一样,马上就说到)。

      加入时钟函数。按照之前编写的 万年历,添加相应的rtc文件。 本来的历程中就包含时间函数,经读取p_data 数组可以发现,按下 授时 按钮获取的p_data[1]、p_data[2]、p_data[3]就是时间数。我还简单仿写了时间转换函数,将时间转换为带年月日的结构体:

     1 int time_thansform(datetime *time_now,uint8_t *now)
     2 {
     3     
     4      uint32_t temp=0,temp_now = 0;
     5     uint16_t temp1 = 0;
     6     uint8_t a,b,c;
     7     
     8 
     9     a=now[1];
    10     b=now[2];
    11     c=now[3];
    12     temp_now=(c<<6)+(b<<3)+a;
    13     temp = temp_now / 86400; //得到天数
    14      {
    15          temp1 = 1970;    //从1970年开始
    16         while(temp >= 365)
    17         {
    18             if(Is_Leap_Year(temp1))//是闰年
    19             {
    20                 if(temp >= 366)
    21                     temp -= 366; //闰年的秒钟数
    22                 else
    23                 {
    24                     temp1++;      
    25                     break;
    26                 }
    27             }
    28             else
    29                 temp -= 365;     //平年
    30             temp1++;          
    31         }
    32         time_now->year = temp1; //得到年份
    33         temp1 = 0;
    34         while(temp >= 28) 
    35         {
    36             if(Is_Leap_Year(time_now->year) && temp1 == 1) //若是闰年
    37             {
    38                 if(temp >= 29)temp -= 29; //闰年的秒钟数
    39                 else break;
    40             }
    41             else
    42             {
    43                 if(temp >= mon_table[temp1])temp -= mon_table[temp1]; //平年
    44                 else break;
    45             }
    46             temp1++;
    47         }
    48         time_now->month = temp1 + 1;    //得到月份
    49         time_now->day = temp + 1;      //日期
    50     }
    51     temp = temp_now % 86400;             //秒钟数
    52     time_now->h = temp / 3600;         //小时
    53     time_now->m = (temp % 3600) / 60;     //分钟
    54     time_now->s = (temp % 3600) % 60;     //秒钟
    55     time_now->week = rtc_get_week(time_now->year, time_now->month, time_now->day); //»ñÈ¡ÐÇÆÚ
    56     return 0;
    57     
    58 }

    不过看了半天还是没明白怎么设置它的时钟。索性将main中的时钟初始化函数删去,加上我之前学习外设时用的时钟初始化函数和时间设置函数(见源文件中的MY_Init()函数),并在timer.c的中断函数中的屏幕刷新函数之前添加之前编写的时间显示函数 showtime(x,y),也可以替换为编写好的模拟时钟函数,当然,还可以利用手机的按钮函数来进行模拟时钟和数字时钟的切换,稍微加点函数就好 ,此处只用数字时钟。在switch 中添加 授时 按钮对应的操作:

     1     case 0x35:        //按钮 授时 对应的协议,由上面的printf测得
     2             rtc_date_get(time_now1);        //自己的时钟对应的时间函数
     3             //ble_time_set(time_now1,p_data);//本行可以得出只修改p_data的数据是无法修改例子中的计时器的底层函数的
     4             time_thansform(time_now1,p_data);
     5             printf("year:%d
    ",time_now1->year);
     6             printf("month:%d
    ",time_now1->month);
     7             printf("day:%d
    ",time_now1->day);
     8             //printf("weak:%d
    ",time_now1->week);
     9             printf("h:%d
    ",time_now1->h);
    10             printf("m:%d
    ",time_now1->m);
    11             printf("s:%d
    ",time_now1->s);
    12             
    13                 
    14                 break;
    15                     

    添加好头文件和文件后,编译通过,下载可以看到时间不断更新,按手机的 授时 按钮串口显示时间,按温度 温度也更新。

      本文源文件

      蓝牙协议的详细功能还有待慢慢发现,现在只是简单地是用别人写好的东西来入门。详细的使用还要慢慢学习。

    本文水平有限,内容很多词语由于知识水平问题不严谨或很离谱,但主要作为记录作用,能理解就好了,希望以后的自己和路过的大神对必要的错误提出批评与指点,对可笑的错误不要嘲笑,指出来我会改正的。谢谢。我是执念执战,转载请注明出处,谢谢。-------------随梦,随心,随愿,执念执战,执战苍天!

  • 相关阅读:
    手机网站调试神器之chrome控制台
    改善C#程序的建议2:C#中dynamic的正确用法
    flowplayer视频播放插件[转]
    Python类,特殊方法, __getitem__,__len__, __delitem__
    Python yield 使用浅析
    Openerp负载平衡
    linux sheel重复执行上条命令
    Python 去除列表中重复的元素
    去除Odoo主页中的提示: Your Odoo is not supported.
    Python 正则表达式学习摘要及资料
  • 原文地址:https://www.cnblogs.com/zhinianzhizhan/p/6422232.html
Copyright © 2011-2022 走看看