我们发现这个打印老是出错,怎样让这个打印在消息中处理?即我们需要打印时,就发送一个消息给任务,在任务中在有空时才去打印这个消息中的内容,等打完后才去重新打印,即打印完了后,(这个可能要用一个函数来决定,再去打印下一个)这样就能把所有的消息都打印好了。打印队列中还有东西未打完,我们就不会去处理这个打印消息。只有打完了才去处理。这个要用消息队列去处理吧。消息本来就是一个队列的。 好象有点麻烦。
先看一下,我们打印时如何知道缓冲区的内容已经打印完了呢? HalUARTBusyDMA()这个函数也不知是不是?
还有一个办法是每次打印后都加一个延时才去处理下一个。但怎样加延时呢?OSAL中没有这个。只有延时发事件。
我们产生一个周期性的事件,在这个周期性的事件中,去处理打印消息,因为一个周期设为10ms,则10ms我们肯定打印完了。
这样,我们先设计一个周期性的事件,在这个事件中,我们去处理
原来的定时闪灯的方法是这样的,在我们自已定义的任务中,每隔一段时间,就去给
Hal_TaskID这个任务,发送一个事件,这个任务发现这个事件后,就调用一个Test_Send() 在这个Test_Send中,我们给消息分配了一个内存,然后,将这个系统消息发给我们的定义的任务,在我们的任务中,在系统消息处理中,将处理这个消息(闪灯)然后,将这段消息内存删除。
现在,我们要打印时,就生成一个消息,且发送给我们自已定义的任务,在这个任务中,我们处理系统消息,但这个系统消息每次只处理一条
注意到键改变这个事件它是 typedef struct {
osal_event_hdr_t hdr; //事件头,这个很重要,它包含有下列第6行部分 uint8 state; // shift 状态 uint8 keys; // keys 键值 } keyChange_t;
typedef struct {
uint8 event; ///事件,这个与上面的相呼应。 uint8 status; } osal_event_hdr_t;
在系统信息处理中,本来这个我们发过来的是一个指针keyChange_t。这个指针有比较多的成员变量。但是后来在任务中进行处理时,即变更为osal_event_hdr_t类型的指针 simpleBLECentral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );这就说明,系统信息处理中,只处理我们这个指针的前面几个字节,后面的直接忽略了,但是在调用这个处理函数时,可不能忽略,因为按键值是在后面的。
21
这个有点奇怪的是:
从队列中收消息时,它是返回的是 osal_msg_hdr_t 这是一个消息队列。 收到消息后,要读取其中的事件时,这个指针却变成 osal_event_hdr_t 在具体处理函数中,即要将同一个指针变成 keyChange_t 去处理。
以上的原因是keyChange_t的第一个指针,指向的就是osal_event_hdr_t,而消息得到的第一个数处,它是keyChange_t,这个在osal_msg_push()函数中可以看得出来。
了解了以上现象后,我们先仿这个 typedef struct {
osal_event_hdr_t hdr;
uint8 state; // shift uint8 keys; // keys } keyChange_t;
定义一个新的结构 typedef struct {
osal_event_hdr_t hdr; ///不想含这个事件 可以吗? uint8 printf_num; //我们要打印的字节的长度 uint8 printf_data[32]; ///我们最多打印32个字节 }printf_t;
我们发一个消息给它,每次我们只处理一个消息,处理完这个消息后,就将这个消息清除掉。消息中并不含事件可以吗?看来是不行的,因为发送消息时,必须是系统事件才可以。
我们这样做,串口打印发的是系统消息,这个系统消息队列中,如果时间未到,我们并不处理它,只有当时间到了,我们才将这个消息删除掉,这样,这些打印消息都会留在这个系统队列中。等待下一次又会去处理。处理一个消息串口消息就将这个计数器保留下来,看是否相同,如果不同才去处理串口消息。程序不做大的修改。还是每隔一段时间会有时间到的系统消息到来。不过这样做显然不行,因为每次运行到此时,系统消息可能都是哪个串口消息,而这个时间消息却永运等不来了。
只有这样,将这个系统消息给串口独占了。该任务的系统消息只有一个。我们先改一下,将原来的部分删除掉看一下。先让这个任务自已产生一个周期性的调用。然后加一个静态的全局变量作为计数值。
接下来,修改关键的部分,想打印时,我们就生成一个系统消息给我们自已的任务。
显然,我们在打印文档中修改它,先在npi.h中定义这个新结构。 typedef struct {
22
osal_event_hdr_t hdr; ///不想含这个事件 可以吗? uint8 printf_num; //我们要打印的字节的长度 uint8 printf_data[32]; ///我们最多打印32个字节 }printf_t;
然后生成一个新的虚拟打印语句,我们先打的是ASCII部分。如果外部要打印必须先将要打印的东西换成它才可以。而且每次打印不能超过32个字符。 Virtual_printf(char*,uint8 len)
另外写三个函数
Virtual_printf_srting(char*p) Virtual_printf_data(int data)
先简单一点的吧。Virtual_printf(char*,uint8 len)
将结构定义到npi.c中。加上这个函数。构想如下: 处理这个消息,在自已定义的任务中。
每条打印语句,转化为系统事件+消息给我们的任务。这个消息由系统事件引起。我们的任务在得到系统事件后,去找到这个消息去处理,当这个消息存在时,就看是否是打印消息,如果是,则看时间更新到否,如果到就打印,且将此消息清除,如果不到,则该消息还存在消息队列中。只要还有消息,这个系统事件就存在,没有清除掉,如果消息队列为空,则将这个系统事件清除掉。结果发现只打印了第一句就死机了。而且也不再运行到我们的事件处理程序中去了。此时就有可能是消息队列溢出了?
我们只发一条消息试一下。可以打印,但是发2条就不能打印了。
原因是第1条执行后,再执行第2条的消息处理时,开始3次还能进到处理程序中(由于时间没到不处理),但是后面就直接读消息队列时却为空了。没找到原因。暂时放一下。 发现这个从机的广播信息不符合规定的,所以一直找不到下位机,现在可以发现一个下位机了。
现在发现一个设备,可以开始下一步了。现在下位机我们用它的一个特征值
建立连接后,有一个事件会发生,就是建立连接事件会发生,于它在这个回调函数中,会直接会发送一个START_DISCOVERY_EVT给本任务,于是本任务会调用: simpleBLECentralStartDiscovery( );函数,看下位机有什么样的服务。 注意到在建立连接完成后,这个值被得到了:simpleBLEConnHandle 然后,调用发现服务后就去发现服务回调函数中处理一些事宜。
我们打算用CHAR6来做一些事情,上位机会发一个helloworld下去,下位机通过此口回一个0x01 0x02 0x03 0x04回来
怎样得以char6的句柄呢?
在发现服务中的回调函数中,我们发现了simpleBLECharHdl。这个就是通讯特征的句柄。如果要发现多个特征的句柄,估计是在这个子程序中多循环几次。一直得到最后一个。
23
得么这个句柄后,看在UP键中是如何写的?
status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId ); 但是怎么没发现simpleBLECharHdl呢?发现了,就在。。。
发现发送后,主机返回一个ERROR 再看从机,它没有设下面这个:
SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR6, SIMPLEPROFILE_CHAR6_LEN, charValue6 );
我们在初始化时将这个设一下看。
设完后,可以打印helloworld了。接下来,我们反向打印一下HELLOWORLD.即上位机发一个读命令,下位机就返回这个HELLOWORLD这10个字符。
先看一下,上位机如何读,我们想通过同一个特征值char6来读一下看。
原来的怎么读的。原来上位机按一个键(手机上按一个键)可以读温度和湿度。现在我们首先在从机中先改动一下。我们知道,原来我们是将传感器的温湿度是每隔一段时间,进行一个周期性的数据采集,放到SensorValue[i]中。 在读配置这个函数中,它将会调用:
uint8 simpleProfileReadConfig(uint16 uuid, uint8 *newValue)特别注意到这个函数返回值为len.如果我们要读10个字符串,则返回的值就是10。于是我们要将这个newValue的定义改为较长才行。还有读配置其实可能并不是一个妥当的办法,因为读配置只能读一次。每次可能只能读23个字符,这样字符多的话就要读好几次。先这样读10个看一下。最好是主动发100来个字符过去。
这里4个字节还没有改,接下来要改的。先没改,先看如何调用这个函数的。看到了,是在 static uint8 simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen ) 中调用这个函数的。
但又是谁在什么时候调这个回调的呢?特别是这个maxLen这个参数好象没有用到。
这样下位机差不多改好了,下面看一下主机该如何改呢?主机要读char6和东西。读过来有多长,再打印出来。 以下是主机部分。
先看读成功后的回调函数,它将读来的东西打印了一下,原来只打印一个字节的。现在要打印多少字节。中间有一个长度,也有一个值,其最长的长度定义为23,我们不要超过它就是了。 接下来,我们怎么知道这个char6 的特征值要读呢?我们按了一个键就是去读下位机的配置的。
在按下键中,我们没有找到有关的部分。因为它是一个外部函数,我们只执行了下列: attReadReq_t req;
req.handle = simpleBLECharHdl; ///这个就是指定的要读的特征值
status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId ); 大功初成!双向都可以通过char6来进行了。主机按UP键,发送一个helloworld到下位机,再按一次UP键,则主机发一个读下位机的char6信息,下位机的char6信息它就是大写的HELLOWORLD.来回都正确了。
时间已经指向用了一个多月,从11月25日到12月29日,太长了,也许自已太笨。
24
25
26
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库关于TI的CC2541的程序解读(5)在线全文阅读。
相关推荐: