首页 > 代码库 > TinyOS系列——网关接收服务器指令模块,实现的难题及解决方案

TinyOS系列——网关接收服务器指令模块,实现的难题及解决方案

今天刚刚把棘手已久的问题解决,感觉特别开心,想记录一下解决的思路。
------------------------------------------------分割线----------------------------------------------------
1)首先,假设节点内已经烧好了写好的程序,那么通过PC端的串口调试助手,完全可以完成这个任务
2)其次,节点通过串口接收数据用的是ATmega128,那ATmega128串口这块如何配置?
推荐一个网址,http://blog.chinaunix.net/uid-21658993-id-1819999.html
 Atmega128有两个串口:USART0与USART1
假设使用USART0,无非就是有下面几部分:
 1     void uart0_init()                        //串口0初始化 2     { 3         UCSR0B = 0x00;                  4         //    关闭USART0,设置波特率前,要关闭USART0的所有使用,包括使能和中断 5         UCSR0A = 0x00;            //不使用倍速发送 U2X=0 6          /* 7             UCSR0A能写的有Bit0,Bit1,Bit6,其他5位为状态位.我们一般使用的有Bit1-U2X0, 8             当这一位为1时,波特率的分频因子从16降到8,能够有效的将异步通信模式的传输速率加倍, 9             但是这一位仅对异步操作有影响,使用同步操作时应将此位清零.10         */11         UCSR0C =(1<<UCSZ01)|(1<<UCSZ00);    //8bit+1bit stop 八位数据位,一位停止位12          //    UBRR0L=(fosc/16/(baud+1))%256;13          //    UBRR0H=(fosc/16/(baud+1))/256;14          /*    15             Bit6-UMSEL0:USART0的模式选择,0为异步模式,1为同步模式16             Bit5:4-UPM01:0:奇偶校验模式,00禁止,01,保留,10偶校验,11,奇校验17             Bit3-USBS0:停止位的选择,0停止位为1bit,1停止位为2-bits18             Bit2:1-UCSZ01:0:字符长度,当UCSZ02为0时,00表示5位,01表示6位,10表示7位,19             1表示8位.当UCSZ02为1时,11表示9位.(UCSZ02为UCSR0B里的一位寄存器)20             eg:21             UCSR0C=0B00000110 //异步模式,禁止奇偶校验,停止位为1位,数据位为8位22         */23         UBRR0L=7;                            //波特率:57600 Bps24         UBRR0H=0x00;                        //误差率:0.156%25         UCSR0B =(1<<RXEN0)|(1<<TXEN0);    //RXCEN TXCEN26         call Leds.led0On();27     }
再次,那我节点如何接收服务器发送来的数据?
1     //串口0接收字符2     unsigned char getchar0()3     {4         while(!(UCSR0A& (1<<RXC0)));5         //call Leds.led1Toggle();6         return UDR0;7     }
 
接收起始与截止位分别为"$nodeId   Cmd$"
 1         while(1) 2         {         3             judge = getchar0(); 4             if(judge == $) 5             { 6                 judge = getchar0(); 7                 inputNum = 0; 8                 addr = 0; 9                 cmd = 0;10                 while(judge !=$)11                 {12                     if(judge - 0 >= 0 && judge-0 <= 9)13                     {14                         inputNum = (inputNum * 10) + (judge - 0);15                         addr = inputNum;16                     }17                     else18                     {19                         //取最后一个字符作为命令的参数20                         cmd = judge - 0;21                     }22                     judge = getchar0();23                 }24                 breakflag=1;25                 if(breakflag==1)26                 {27                     breakflag=0;28                     break;29                 }30                 31             }32         }    
紧接着,最大的问题就来了,这也是我出错的地方,搞了半天才搞好,网关接收服务器指令后,如何将消息发送出去?并且通过基站进行回显?我这里用了一个取巧的办法,广播,基站收到消息后回显
这里因为牵扯的问题比较广,我会重点阐述一下,如果要进行广播或者是单播,首先必须要开启射频无线模块AMControl.start(),但是接收数据并且发送指令这块的工作是绝对不能放到Boot函数中来执行的,否则无法正常发送,只能放在AMControl.startDone()中来执行;在循环函数体内绝对不能进行AMSend.send(),否则只能send一次,无法正常进入AMSend.sendDone()
 
我的解决方案:
 1)必要的位置加delay()延迟
 2)接收消息、发送消息在AMControl.startDone()中编写
 3)在AMSend.sendDone()中将AMControl.stop()关闭            (核心出错点!!!)
 4)在AMControl.stopDone()中对AMControl.stop()进行重新调用
 
 1     event void AMControl.startDone(error_t err) {         2         PCUartCmd* cmdpkt = (PCUartCmd*)(call Packet.getPayload(&pkt, sizeof(PCUartCmd))); 3          4          5         while(1) 6         {         7             judge = getchar0(); 8             if(judge == $) 9             {10                 judge = getchar0();11                 inputNum = 0;12                 addr = 0;13                 cmd = 0;14                 while(judge !=$)15                 {16                     if(judge - 0 >= 0 && judge-0 <= 9)17                     {18                         inputNum = (inputNum * 10) + (judge - 0);19                         addr = inputNum;20                     }21                     else22                     {23                         //取最后一个字符作为命令的参数24                         cmd = judge - 0;25                     }26                     judge = getchar0();27                 }28                 breakflag=1;29                 if(breakflag==1)30                 {31                     breakflag=0;32                     break;33                 }34                 35             }36         }37         38         cmdpkt->nodeid = addr;39         cmdpkt->data =http://www.mamicode.com/ cmd;40         41         cmdpkt->relay1 = 11;42         cmdpkt->relay2 = 12;43         cmdpkt->relay3 = 13;44         cmdpkt->relay4 = 14;45         cmdpkt->relay5 = 15;46         cmdpkt->yuliu = 0;47         48         49         if(busy==0)50         {51             busy=1;52             call Leds.led0Toggle();53             call AMSend.send(addr, &pkt, sizeof(PCUartCmd));54             call Leds.led1Toggle();                        55         }56         else57         {58         }59         60         inputNum = 0;61         addr = 0;62         cmd = 0;    63     }64 65     66     67     68     event void AMSend.sendDone(message_t* msg, error_t err) {69         call Leds.led1Toggle();70         if (err == SUCCESS) 71         {      72             call Leds.led2Toggle();73         }        74         busy=0;75         76         call AMControl.stop();77     }78     79     80     event void Timer0.fired()81     {82         //call Leds.led1Toggle();83     }84     85     86     87     event void AMControl.stopDone(error_t err) 88     {89         if (err == SUCCESS) 90         {      91             call Leds.led0Off();    92             call AMControl.start();93             94         }95         else96         {97         call AMControl.stop();98         }99     }
下面是有几个比较然的点:阐述一下
1、修改串口寄存器会不会AMSend产生影响?
不会!ATmega128修改串口寄存器,使得节点能够与PC通过串口进行通信,与CC2420射频无线模块没有任何关系。ATmega128的作用是通过串口接收数据后,发送给射频无线模块。射频无线模块的作用是调制发送数据。
2、波特率设置会不会影响两个节点间的正常通信?
不会!波特率只是规定通信双方的数据速率,一般是PC与节点,或者是其他。