三天打鱼两天晒网,又学起了蓝牙,不过还好的是终于开始学习蓝牙协议部分了。数组
可是,一看起来增长了蓝牙协议的例程,真是没头绪啊。自己的教程资料解说太差了,看青风的蓝牙原理详解也是一头雾水。缓存
通过不断地看各类资料,终于决定,无论他了,先学会例程修改再说。函数
例程里面有个 蓝牙综合例程,就它了。oop
使用的是LP电子的手环学习开发板。按照教程下载了协议,而后下载了编译文件,最后手机上安装了对应的LP的安卓软件。很好,启动成功,能够点灯,可是温度和授时按钮没用。并且这个例程和其余基于蓝牙协议的例程没有一个带OLED显示的例子。还想之后能手机控制开发板来操控OLED显示呢,怎么办,只有本身一步一步试试了。学习
先到这个例程的main函数中看看。ui
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 }
额........没发现有啥基础性的东西.......spa
再找找吧。往上转了转,哎,发现个东西。调试
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 }
这个不就是我要找的!!虽然咱还不明白蓝牙协议到底怎么用的,可是用人家写好的仍是能够的。code
有了人家按钮接收对应的协议,那拿来直接用就完了。orm
上面的第三行有个串口输出,输出的是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
添加好头文件和文件后,编译经过,下载能够看到时间不断更新,按手机的 授时 按钮串口显示时间,按温度 温度也更新。
本文源文件
蓝牙协议的详细功能还有待慢慢发现,如今只是简单地是用别人写好的东西来入门。详细的使用还要慢慢学习。
本文水平有限,内容不少词语因为知识水平问题不严谨或很离谱,但主要做为记录做用,能理解就行了,但愿之后的本身和路过的大神对必要的错误提出批评与指点,对好笑的错误不要嘲笑,指出来我会改正的。谢谢。我是执念执战,转载请注明出处,谢谢。-------------随梦,随心,随愿,执念执战,执战苍天!