(续)一种简陋的CC1100/CC1101主从通信协议

来源:互联网 发布:单片机软件调试 编辑:程序博客网 时间:2024/04/30 19:04

/* 热火实现了卫冕,詹姆斯背负的骂名也渐渐少去,马刺和GDP的失利,让人无限唏嘘,失败者落寞的身影让人感叹岁月的无情,马刺王朝就此解体了吗,看着呆呆满脸和满眼的遗憾,心中竟不能替热火高兴,也许人们总是对“曾经”感到留恋,曾经离冠军只有5.2秒,但从天堂到地狱也只是5.2秒。。。戏剧化的让人以为这是一部电影,一部符合美国人胃口的电影,迫入绝境,然后峰回路转,诸葛波波最后换下呆呆让人觉着这是联盟干爹给热火的机会,但是如果阿伦不能进下那个救命球,那也是徒劳的,所以,我觉着这就是宿命,TIM-D已然证明了自己的老而弥坚,NBA史上最厉害的大前,这是毫无疑问的。我是热蜜,但不黑任何人,不明白为什么有些人会这么黑詹姆斯,就是因为打球比较丑陋?最好笑的是有人因为詹姆斯的天赋而恨他,恨他为什么打球不受伤(这里真要吐槽一下,球员受伤你心里就舒服是吧?),恨他为什么那么暴力,还拿凌晨四点钟的洛杉矶来暗喻着什么。。。真是无语,哪个牛逼的球员不是靠天赋去打球?乔丹不是公认的天赋最好的那个?。。。。。。。。。其实,不管你黑谁,密谁,当我们这代人逐渐退出社会舞台的时候,当人们回顾NBA历史时,邓肯,科比,詹姆斯都将是载入史册的人,恨与不恨,爱或不爱,这就是事实,NBA是个生意更是事实。最后想说一下,AV5频道出了一部小短片,大体意思说的就是“詹姆斯缺少一种超级巨星的气质,关键时刻舍我其谁的王者气质”,的确,关键时刻猩猩是有点不太相信自己,这是他需要加强的地方! forsakening @hdu 2013/6/22 */


还是说说上次自己写的CC1101无线通信协议吧,周一的时候完成了协议的主体部分,周二在LINUX下进行了模拟,大致上是没什么问题了,周三在具体的硬件上进行移植,主要是在CC1101无线模块和51mcu上面进行,这里遇到了不少麻烦,当天晚上留在了实验室搞到了3点,周四早晨8点多又开始搞,终于调通了,貌似时序上面有点不稳定,一直觉得是因为中断的原因,所以在周四晚上的时候又重新基于51mcu制定了一个逻辑性更强一点的方案,并且测试完全没问题,很稳定:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

主节点

主节点:51mcu + cc1101无线模块(当接收到数据的时候便会产生一个下降沿,用于和51mcu相连,产生外部中断)

主节点主要完成的工作:

1)发送CMD_Init命令,获取有多少从节点可以连接至主节点

2)发送CMD_UsrCmd命令,用户命令

这里面有个问题,就是cc1101在发送的时候无法保证其余的模块一定可以接收到这个数据,所以有了所谓“面向连接”一说,我的面向连接指的是:主节点发送一命令后,从节点必须对这个命令进行响应,否则的话主节点就一直发送这条命令,直至发送到最大重发次数为止。这里仿照了TCP协议的实现,用了一个seqno来标记每次发送的序号,只有收到当前seqno的响应,才算是一次正确的“面向”连接发送

还有一个主要修改的地方:主节点在发送命令之后,就开启接收中断,等待从节点发来的响应报文,而在其余时刻主节点的接收中断是处在关闭状态的。这也是51mcu ram较小的一种折中方法,否则进入中断深度过大的话,会产生程序跑飞重新启动mcu的问题。

主节点侧的“面向连接”发送:

/* 面向连接的发送:除非收到ack报文,否则会重复发送 */unsigned int pcc_server_link_send(PCC_FRAME *frame, unsigned long time_init){int resend_cnt = 0;    /* 重发次数 *//* STEP 1:切换主节点的状态,改变主节点的全局信息 */pcc_server_state_change(frame, SEND_FRAME);server_info.pcc_server_conn_address = frame->address.dstaddr;putstring("pcc_server_link_send start......");putstring("--------------------------------");for (; resend_cnt < RESEND_CNT; resend_cnt++){putstring_no_nr("pcc_server_link_send trying time:");put_hex(sizeof(resend_cnt), (resend_cnt + 1));putstring("......");/* 每次发送就增加一次seqno 以保证面向连接 */(server_info.pcc_server_seqno)++;frame->seqno = server_info.pcc_server_seqno;print_pcc_frame_flow(frame);/* STEP 2:在不超过最大重发次数情况下循环发送 */send_pack((unsigned char*)frame, sizeof(PCC_FRAME));/* STEP 3:开中断 */enable_int();/* STEP 4:启动定时器:这里定时器其实是一个软件延时,用于等待接收中断,若接收到响应报文,则跳出定时器,证明此次发送成功 */if (0 == linksend_timeout(time_init)){/* STEP 5:若超时了,则关中断后继续发送,知道超过重发次数 */disable_int();continue;}else{putstring_no_nr("pcc_server_link_send success, and resend_cnt:");put_hex(sizeof(resend_cnt), resend_cnt);putstring("......");return 1;}}/* STEP 6:大于重发次数,关中断并且打印提示信息 */if (RESEND_CNT == resend_cnt){disable_int();putstring("pcc_server_link_send over max resend_cnt......");putstring("-----------------------------------------------");send_nr();return 0;}return 0;}
/* 返回0代表超时,非0表示未超时 */unsigned int linksend_timeout(unsigned long time_init){unsigned int ret = 0;#ifdef DEBUG_51putstring("start linksend_timeout......");#endifwhile(time_init > 0){time_init--;/* 若接收到中断则去处理中断 */if (Rcv_Status){if (pcc_server_handle_interrupt()){putstring_no_nr("handle_interrupt success, break timeout:");put_hex(sizeof(time_init), time_init);putstring("......");ret = 1;break;}}}if (0 == time_init){putstring("timeout......");}return ret;}
/* 返回0表示非pccframe 或者 是不符合server侧的协议 */unsigned int pcc_server_handle_interrupt(void){int ret = 0;/* 处理中断的时候要把中断先关掉 */disable_int();putstring("Start handle_interrupt ......");/* 这里进行处理接收到得数据 *//**********************************************/print_pcc_frame_flow((PCC_FRAME *)&frame_rcv);ret = pcc_server_dispatchFrame((unsigned char *)&frame_rcv);/**********************************************/putstring("End handle...");putstring("------------------------");send_nr();Rcv_Status = 0;return ret;}
void exint1()  interrupt 2{unsigned char len = BUF_LEN;if(halRfReceivePacket((unsigned char *)&frame_rcv, &len)){LED = ~LED;Rcv_Status = 1;/* 中断处理不宜过长,只是标识一个标志位 */}}


从节点

从节点的话,更改后的方案:只用于接收报文,只有在处理中断的过程中,才关闭中断:

void pcc_client_handle_interrupt(void){/* 处理中断的时候要把中断先关掉,结束处理后再打开 */disable_int();putstring("Receive buffer...Start handling......");/* 这里进行处理接收到得数据 *//**********************************************/print_pcc_frame_flow((PCC_FRAME *)&frame_rcv);pcc_client_dispatchFrame((unsigned char *)&frame_rcv);/**********************************************/putstring("End handle...");putstring("------------------------");send_nr();Rcv_Status = 0;enable_int();}
/* 从节点侧的解析报文,从中断中调用 */void pcc_client_dispatchFrame(unsigned char *rcvbuf){PCC_FRAME *frame;PCC_FRAME_TYPE frame_type;SUB_FRAME_TYPE subtype;PCC_ADDRESS address;SUB_FRAME_TYPE sub_frame_type;//PCC_USER_CMD flag_user_cmd;/* 强制转换为PCC格式 */frame = (PCC_FRAME *)rcvbuf;#ifdef DEBUG_51putstring("Client dispatchFrame......");#endif/* 验证是否符合PCC */if (PCC_PROTOCOL != frame->protocol){putstring("client dispatchFrame PCC_PROTOCOL error!");return;}if (Ser2Cli != frame->type){putstring("client dispatchFrame Ser2Cli error!");return;}if (((unsigned char)server_addr != frame->address.srcaddr) ||((unsigned char)client_addr != frame->address.dstaddr)){putstring("client dispatchFrame addr error!");return;}/* 处理到这步应该可以确认是正确的PCC报文,继续处理命令 */frame_type = frame->frame_type;subtype = frame->subtype;switch (frame_type){/* 处理CMD命令 */case CMD:{if (CMD_InitLink == subtype.subtype_cmd){/* 从节点收到CMD_InitLink后发送ACK_InitLink给主节点 */putstring("client process CMD_InitLink......");frame_clear(&frame_send);address.dstaddr = server_addr;address.srcaddr = client_addr;sub_frame_type.subtype_ack = ACK_InitLink;build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_NULL, NULL, 0);frame_send.seqno = frame->seqno;send_pack((unsigned char *)&frame_send, sizeof(frame_send));return ;}if (CMD_UserCmd == subtype.subtype_cmd){/* 从节点收到CMD_UserCmd后发送ACK_UserCmd给主节点,以告知主节点不用继续发送命令字 */putstring("client process CMD_UserCmd......");frame_clear(&frame_send);address.dstaddr = server_addr;address.srcaddr = client_addr;sub_frame_type.subtype_ack = ACK_UserCmd;/********************************************************//* 这里是对echo函数的真正响应,如读取温度值等 *//********************************************************/build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_NULL, "12", 2);frame_send.seqno = frame->seqno;send_pack((unsigned char *)&frame_send, sizeof(frame_send));return ;}}/* 目前为止从节点只处理ACK_UserCmd_Ret @2013/6/17 */case ACK:{if (ACK_InitLink == subtype.subtype_ack){return;}if(ACK_UserCmd == subtype.subtype_ack){return ;}}/* 其余情况出错 */default:return;}}

后记

1)这个简单的主从无线通信协议呢,可以满足选址,以及可靠性的要求,虽然简陋,但五脏俱全。。。

2)通过写这么一个简单的主从协议,发现了自身的很多不足,其实本应该对整体方案有个充分的考虑的情况下再去动手敲代码,无奈对于51mcu已经忘的差不多了,对于中断的处理,时序上的考虑都不够完善,所以在协议自身的设计上一开始就存在缺陷,在code的过程中才慢慢发现,虽然对自身帮助挺大,但这其实非常的浪费时间。。。

3)From 2013/6/17 to 2013/6/20 with FeedBack。。。



原创粉丝点击