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

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

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

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

  使用的是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\r\n",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\r\n",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\r\n",p_data[0]);
3 printf("p_data[1]=%d\r\n",p_data[1]);
4 printf("p_data[2]=%d\r\n",p_data[2]);
5 printf("p_data[3]=%d\r\n",p_data[3]);
6 printf("p_data[4]=%d\r\n",p_data[4]);
7 printf("p_data[5]=%d\r\n",p_data[5]);
8 printf("p_data[6]=%d\r\n",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\r\n",time_now1->year);
6 printf("month:%d\r\n",time_now1->month);
7 printf("day:%d\r\n",time_now1->day);
8 //printf("weak:%d\r\n",time_now1->week);
9 printf("h:%d\r\n",time_now1->h);
10 printf("m:%d\r\n",time_now1->m);
11 printf("s:%d\r\n",time_now1->s);
12
13
14 break;
15

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

  本文源文件

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

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

最新文章

  1. Python 实现Windows开机运行某软件
  2. Java基础知识笔记(七:接口、变量作用域和参数传递)
  3. &lt;!DOCTYPE html&gt;作用
  4. 通过TStringList保存csv文件,只要循环.Add表格里面的每行记录进去,保存即可
  5. CoordinatorLayout自定义Bahavior特效及其源码分析
  6. 用jinja做了个E-Letter小项目
  7. USB 描述符
  8. struts2中访问和添加Application、session以及request属性
  9. Video标签播放视频?谷歌浏览器?safari?? 谷歌浏览器播放不了mp4格式的视频的原因
  10. 一台服务器上同时启动多个 Tomcat
  11. Floating IP in OpenStack Neutron
  12. absolute 的containing block( 容器块)计算方式跟正常流有什么不同?
  13. 关于C语言文件操作
  14. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用第三方组件
  15. Postman 使用详解
  16. docker-compose使用备忘(转)
  17. Vue父子组件之间的相互通信
  18. oracle数据库误删的表以及表中记录的恢复
  19. MySQL修改表、字段、库的字符集及字符集说明
  20. mongodb数据库中插入数据

热门文章

  1. npm 更改在线仓库镜像地址
  2. pip修改镜像源
  3. 用dig或nslookup命令查询txt解析记录
  4. matlab求解器的选择
  5. Redis 突然变慢了如何排查并解决?
  6. Paddiing 组件
  7. k8s资源清单
  8. vs2010 项目属性窗口
  9. 用find和xargs处理文件名中带空格的文件
  10. 页面-vue-功能