完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛
|
吴哥,非常感谢你的分享,我正在学习你的程序风格.在""行列按键扫描中"",你提到在switch()中,是分2次执行的,我不太明白.是如何实现的.?抽空帮忙解析下.谢谢!
|
|
|
|
|
|
|
|
|
对不起。原文中该解析的已经充分解析了,剩下要靠你个人的领悟和动手能力,我很不愿意再深入解析这个原理,希望以后不要再提问类似这样的问题了。 |
|
|
|
|
|
|
|
|
我这都是雕虫小技,说谢谢的应该是我啊,我从鸿哥这里学到了太多的东西,正是因为鸿哥的无私奉献,才让我对程序的实时性有了特别深刻的理解,感谢鸿哥! |
|
|
|
|
|
|
|
|
我是业余爱好者,正在搭建电路,学习单片机,希望看到吴哥更多的精彩文章。支持吴哥
![]() ![]()
|
|
|
|
|
|
|
|
|
本帖最后由 newsoule 于 2013-10-12 20:20 编辑
这个问题我来回答你,这就是单纯的数据传递,目的是把当前最新接收到的数据放在缓冲区RCREG_buf_temp[2]里面,把上一次接收到的数据移位到 缓冲区 RCREG_buf_temp[1]里面,把上上一次接收到的数据移位到缓冲区 RCREG_buf_temp[0]里面;因此缓冲区RCREG_buf_temp[0]到RCREG_buf_temp[2]的数据就是最新接收到的三个数据,如果这三个数据不是oxeb,0x00,0x55,则继续移动,移出去的丢弃;如果是oxeb,0x00,0x55 ,则符合数据头的条件,if程序执行接收后面的有效数据并校验!希望我的理解对你有帮助~~ 最近一直到学习鸿哥的东西,刚刚入门,在此感谢鸿哥的无私奉献~~~ |
|
|
|
|
|
|
|
|
吴老师,你好,我最近在搞单片机的串口通讯,有几个问题我想请教您一下,不知道吴老师可否抽一点宝贵时间看一下,很急。
我的单片机和PC机定的通讯协议是这样的: 0x2A,0xEB,0x8D,地址码,指令码,数据长度码,数据码,数据码,校验码,0xAD PC机控制两个单片机,属于一主多从形式,所以,设了地址码,一个数据包总共10个字节。用串口调试助手向单片机发送数据,单片机收到相应指令后向PC发送一个指定的数据。 通讯起来有点问题: 1、按照这个格式,调试助手上每点两次发送才能接收到一个数据,即,第一次点发送可以立即接收到数据,再点一次发送,就接收不到了,再点一次发送,才能接收。 当我在数据包最前面附加一个字节的数据时,就正常了,比如说,在帧头前面加个00,发送:00 2a eb 8d ......ad,就能每次接收到数据了。这是为什么呢? 2、为什么在每次单片机断电后,都会发送一个00?这是什么原因? 3、单片机上电后,不能正常通讯,上位机上点发送没有反应,总要按一下开发板上的复位键才能正常通讯。当单片机断电后,再次上电,又是这样,又要按一下复位键才行。可是单片机开发板上有上电复位啊,为什么会出现这种情况? 这是我写的程序:不全 思路就是定义了几个全局变量: uint8 rec_data; //串口通信接收数据 uint8 state_flag=0; //通信协议解析状态标志,初始化为0 uint8 retval=0; //通信协议解析函数返回值,初始化为0 uint8 cmd; //指令码 uint8 Data[4]; //数据码 uint8 data_count; //数据长度码 在串口中断服务函数中解析数据,并相应的存储到cmd、Data[]等全局变量中,并置数据解析结果标志retval,主程序中不断查询这个变量,如果查询到retval=1; 错误标志,数据包传送不正确,要求PC重发。 若查询到retval=2;接收成功标志,说明数据包传送成功,进而读取cmd变量,判断执行哪种操作。 /*-------------------------------- 串口中断服务子程序 ------------------------------------*/ void ser() interrupt 4 { RI=0; rec_data=SBUF; //读取接收到的数据 Data_analysis(); //接收数据解析 } /* * 函数名:Data_analysis * 描 述:通信协议解析函数 * 输 入:无 * 输 出:无 * 备 注:解析串口接收到的数据 /*-------------------------------- 多机通信协议格式 ------------------------------------*/ /* 数据包的格式如下所示(共10个字节组成): */ /* 0x2A,0xEB,0x8D,地址码,指令码,数据长度码,数据码,数据码,校验码,0xAD */ void Data_analysis() { static uchar recdata_sum=0; //存放累加和 static uchar lencnt=0; //数据长度计数器 switch (state_flag) { case 0: { if(rec_data == 0x2A) // 是否帧头第一个数据 state_flag = 1; else state_flag = 0; // 标志复位 break; } case 1: { if(rec_data == 0xEB) // 是否帧头第二个数据 state_flag = 2; else state_flag = 0; // 标志复位 break; } case 2: { if(rec_data == 0x8D) // 是否帧头第三个数据 state_flag = 3; else state_flag = 0; // 标志复位 break; } case 3: { if(rec_data == ID) // 判断目的地址是否正确 { state_flag = 4; recdata_sum=rec_data; //开始累加 } else state_flag = 0; // 标志复位 break; } case 4: { state_flag = 5; cmd=rec_data; //指令码存储 recdata_sum+=rec_data; //累加 break; } case 5: { lencnt = 0; //数据长度计数器清零 data_count=rec_data; //数据长度码存储 recdata_sum+=rec_data; //累加 if (data_count!=0) //后面有数据码 state_flag=6; else state_flag=8; break; } case 6: case 7: { Data[lencnt++]=rec_data; //数据码保存 recdata_sum+=rec_data; //累加 if(lencnt==data_count) { state_flag=8; lencnt = 0; } else state_flag=7; break; } case 8: { if(recdata_sum==rec_data) //数据校验,判断累加和是否相等 state_flag=9; else { retval=1; //置错误标志,数据包传送不正确。 state_flag=0; } recdata_sum=0;//累加和清零 break; } case 9: { if (rec_data==0xAD) retval=2; //置接收成功标志,数据包传送成功。 else state_flag=0; break; } } } /* * 函数名:Send * 描 述:串口数据发送函数 * 输 入:sendcmd - 待发送的数据 * 输 出:无 * 备 注: */ void Send(uint8 sendcmd) { ES=0; //关闭串口 SBUF=sendcmd; //发送数据,向PC发送。 while(!TI); TI=0; //发送完成,TI清零 ES=1; //开串口 } /*主函数 不断扫描串口接收到的指令并发送相应数据*/ void main() { PortInit(); //各端口初始化 TimerInit(); //定时器初始化 UsartInit(); //串口初始化 Send(0xce); Send(0x7b); Send(0x00); Send(0xed); while(1) { usart_cmd_scan(); //串口命令扫描 } } /* * 函数名:usart_cmd_scan * 描 述:串口命令扫描 * 输 入:无 * 输 出:无 * 备 注:扫描PC通过串口发送的命令 */ void usart_cmd_scan() { uchar sendcmd; //下位机向PC发送的命令码 switch (retval) { case 1: //数据发送错误,请求PC重发 { sendcmd=2; //向PC发送的重发数据命令,PC识别后向下位机重发数据包。 Send(0xce); Send(0x7b); Send(sendcmd); Send(0xed); //向PC发送命令 retval=0; //标志清零,防止重复扫描,重复执行。 break; } case 2: //数据发送成功,执行命令 { switch (cmd) //命令解码 { case 0x01: { Send(0xce); Send(0x7b); Send(0x11); Send(0xed); cmd=0x00; break; } case 0x02: { Send(0xce); Send(0x7b); Send(0x12); Send(0xed); cmd=0x00; break; } case 0x03: { Send(0xce); Send(0x7b); Send(0x13); Send(0xed); cmd=0x00; break; } } } retval=0; //标志清零,防止重复扫描,重复执行。 } } |
|
|
|
|
|
|
|
|
1.发送前多增加一个0x00,主要是预防硬件电路或者干扰等原因,导致第一个数据容易丢失。 2.单片机在断电和上电瞬间都有可能处于“权力真空期”,也就是有一瞬间是失控的,很多单片机都有可能在断电瞬间多发送一个0x00。 3.我已经在本篇连载文章开头声明,凡是涉及要我阅读很多源代码的问题我一律拒绝回答。因为我本人平时非常忙,不愿意抽时间去阅读网友的代码,希望你能谅解。一般比较细致和具体的问题我建议你都不要问我,这个要靠你自己去想,自己去动脑筋。 |
|
|
|
|
|
|
|
|
成为王败为寇,现在这个社会只有你成功了才不是吹牛,无论你多努力多牛,最后你没成功就会被当做吹牛和炒作。不管吹牛还是不吹牛,人家的东西对自己技术有帮助咱就得虚心学习,可能您是真正的高手,且很低调,不屑于与人分享技术,那么请您继续低调,不用在这谈王林,说贵权,相信论坛里的人绝大多数是学习技术而来,而非迷信和盲目崇拜。请认真读完鸿哥几个代码再谈这些吧。唉,网络上总有那么一批批判者,号称喷子,世界上没有一件事在他们眼里是对的,见得多了也就见怪不怪了。 |
|
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
求解外围电路实现的是4脚给持续低电平复位并正常工作,高电平不工作的原因
2382 浏览 1 评论
4241 浏览 3 评论
PIC1946程序有一个变量在运行过程中恢复初始值其他变量保持不变
2619 浏览 2 评论
3118 浏览 0 评论
PIC16F1825的RC5引脚,在主程序中操作无效,在中断中可以改变是为什么?
4576 浏览 5 评论
有套STM32与西门子200程序需要代写,有兴趣的工程师与有联系!
2488浏览 1评论
用XC8编译PIC18F25K80时提示下面Error,求怎么解决这个问题
6799浏览 0评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-14 17:13 , Processed in 1.838015 second(s), Total 85, Slave 75 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖