完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
各位大神,请教个事情,具体看下面:
1,我通过键盘(0-9)和一个确定键(sure)来输入0-99999之间的数据。 2.数据输入完毕按确定键,会存储到24C02里面,每次单片机掉电重新上电时,显示上次输入的数据。 3.我实现了0-255,256-65535的掉电存储和上电显示功能。 4.但是在显示65536-99999这个区间的数据时,每次它只能显示输入数据和65536的差值,比如说,我输入88888,上电后显示的数据233352,这是为什么? 5.起初怀疑是数据溢出,定义的num0(就是键盘输入生成的5位数)不对,就将他的属性有unsinged char改到unsigned long,但还是不行。6.主程序放到下面,请大家检查检查,提提意见。 void main() { ulong num0; ulong num1,num2; uchar ge,shi,bai,qian,wan; uchar add_HH1,add_H1,add_L1; add_HH1=read_add(0);//读取24C02中第0位值 delay0(5); add_H1=read_add(1);//读取24C02中第1位值 delay0(5); add_L1=read_add(2);//读取24C02中第2位值 delay0(5); num2=add_HH1*65536+add_H1*256+add_L1;//得到要显示的数 wan=num2/10000; qian=num2%10000/1000; bai=num2%1000/100; shi=num2%100/10; ge=num2%10; while(1) { init(); display(wan,qian,bai,shi,ge);//数码管显示函数 keyscan();//键盘扫描函数,每按一次,就数据就多一位 switch(cishu) { case 1:a0=num;b0=0;c0=0;d0=0;e0=0;break; case 2:b0=num;c0=0;d0=0;e0=0;break; case 3:c0=num;d0=0;e0=0;break; case 4:d0=num;e0=0;break; case 5:e0=num;break; } if(sure==1) //确认键按下的时候,就生成该数据,并将该数据拆分成三个字节写到24C02中去 { switch(cishu) { case 1:num0=a0;break; case 2:num0=a0*10+b0;break; case 3:num0=a0*100+b0*10+c0;break; case 4:num0=a0*1000+b0*100+c0*10+d0;break; case 5:num0=a0*10000+b0*1000+c0*100+d0*10+e0;break; } if(num0>=65536) { write_add(0,num0/65536); delay0(5); write_add(1,num0%65536/256); delay0(5); write_add(2,num0%256); delay0(5); } else { write_add(0,0); delay0(5); write_add(1,num0/256); delay0(5); write_add(2,num0%256); delay0(5); } cishu=0; } } } |
|
相关推荐
13个回答
|
|
你这算法着实令人无语!!!
虽然你定义的是long型,理论上是没有溢出的,但是单片机得开多大的空间来计算你这算法啊,当单片机开的空间不够用时,就会覆盖先前的空间,使计算出错!(这已经溢出了) 解决的办法就是换一种算法,比如 num2=add_HH1*65536+add_H1*256+add_L1;//得到要显示的数 可以换算为如下: num2=add_HH1; num2=num2<<8; num2 |=add_H1; num2=num2<<8; num2 |=add_L1;//得到要显示的数 键盘输入的数就留给楼主自己想吧!发挥你的想象力! |
|
|
|
这个程序还是有点问题的
如楼上所说,除法和取余对单片机来说效率极为底下,而程序中多为除以2的次幂 除以256可以改为 num>>8, 除以65536可以改为 num>>16,对65536取余数可以改为 num & (0xFFFF) ,类推 其次是程序,按楼主的想法,就是最大显示99999,也就是0x1869F,也是3个字节,为什么要经过一堆可能出错的运算才存起来? 假设键盘采到 num0 = 99999; 如果我来存,我一定这样写,不需要判断是否大于65536: 定义一个: unsigned char temp; temp = (num0 >> 16 ) & 0xFF write_add(0,temp ); delay0(5); temp = (num0 >> 8 ) & 0xFF write_add(1,temp ); delay0(5); temp = num0 & 0xFF write_add(2, temp ); delay0(5); 上电的时候取出来就可以了 add_HH1=read_add(0);//读取24C02中第0位值 delay0(5); add_H1=read_add(1);//读取24C02中第1位值 delay0(5); add_L1=read_add(2);//读取24C02中第2位值 delay0(5); num2= (add_HH1 << 16) | (add_H1 << 8) | add_L1;//得到要显示的数 wan=num2/10000; qian=num2%10000/1000; bai=num2%1000/100; shi=num2%100/10; ge=num2%10; ..... 逻辑运算的速度要比算术运算快很多很多,如果你把编译之后的文件反汇编回来你就知道差别了 直接存直接取,简单直接,效率提高 但是,问题应该不是这里,问题在于你的0地址上的数据被覆盖了,就是每次上电那里的数据都是0 所以0-65535是OK的,但是往上就不对了 不知道你其他地方有没有操作0地址,检查一下其他代码,还有init()这个函数是什么意思?怎么在主循环里面,会不会有问题? |
|
|
|
andy_wsj 发表于 2015-5-11 09:49 你可以验证一下,改为write(1,x),write(2,x),write(3,x) 上电的时候read1,2,3 避开0地址看看 |
|
|
|
我之前是搞PLC的,对逻辑运算会提高效率我今天终于明白了。 地址1,2,3是我最开始写程序时候用的,也是和现在一样的情况,我当时的想法和你一样,觉得地址1写不进去,我就试了地址0,也是一样。我甚至试了地址10,地址2,和地址3,也是写不进去。 你的头像不错。 |
|
|
|
yunbo.he 发表于 2015-5-11 11:02 在读(add_HH1=read_add(0);//读取24C02中第0位值)时,你应该在之前做相应延时,你不可能一开机就马上读吧!!! 还有就是算法,你看看我这个:
|
|
|
|
yunbo.he 发表于 2015-5-11 11:02 你的read_add函数可能有问题,你贴出来瞧瞧,写可能问题不大 因为第一个读的不正确,后面两个是正确的 我猜测,第一个读取的时候置位了读信号,但是信号没有准备好就去读,结果读到异常值 当后面再去读的时候,第一的置位已经完成,对时间没有要求,能正确读到数据 |
|
|
|
andy_wsj 发表于 2015-5-11 12:03 read函数 uchar read() { uchar i,k; scl=0; delay(); sda=1; delay(); for(i=0;i<8;i++) { scl=1; delay(); k=(k<<1)|sda; scl=0; delay(); } return k; } read_add函数从固定地址读取 uchar read_add(uchar address) { uchar date; start(); write(0xa0); respond(); write(address); respond(); start(); write(0xa1); respond(); date=read(); stop(); return date; } |
|
|
|
andy_wsj 发表于 2015-5-11 12:03 我刚刚又试了,把计算里面的a0,b0,c0,d0,e0这五个数定义成无符号的long型就可以了,但是我不知道这是为什么,应该还是和数据溢出有关的。 下面这个语句是用到a0,b0,c0,d0,e0的地方,之前定义的是无符号的char型的,num0就是键盘输入生成的数据,定义的是无符号long型。 case 5:num0=a0*10000+b0*1000+c0*100+d0*10+e0;break; 我不知道为什么,可以解释一下么? 感谢你们的提醒,我下一步要优化这个算法。 |
|
|
|
Aidaohuakai 发表于 2015-5-11 11:19 谢谢大师兄。 但是我觉得问题不是出在算法上面,我承认我的算法是有很大的问题(菜鸟就是菜鸟,呵呵),单片机还是能处理我这点运算量的,应该是数据溢出的问题。 我刚刚又试了,把计算里面的a0,b0,c0,d0,e0这五个数定义成无符号的long型就可以了,但是我不知道这是为什么,应该还是和数据溢出有关的。 下面这个语句是用到a0,b0,c0,d0,e0的地方,之前定义的是无符号的char型的,num0就是键盘输入生成的数据,定义的是无符号long型。 case 5:num0=a0*10000+b0*1000+c0*100+d0*10+e0;break; 我不知道为什么,可以解释一下么? 感谢你们的提醒,我下一步要优化这个算法,谢谢大师兄(头像)提醒 |
|
|
|
yunbo.he 发表于 2015-5-11 14:26 有可能是编译器的问题吧! 把case 5:num0=a0*10000+b0*1000+c0*100+d0*10+e0;break; 改为case 5:num0=(long)a0*10000+(long)b0*1000+(long)c0*100+(long)d0*10+e0;break; a0,b0,c0,d0,e0还是原来的char型,试试行不行 |
|
|
|
因为你前面把百,十,个都定义成uchar型,我也是刚学没多久 ,感觉是那个有问题,uchar最大好像就65536,你把uchar改下
|
|
|
|
谢谢楼主我也遇到和你同样的问题,现在已经解决了。就是把从24c02里面取出来的数
|
|
|
|
谢谢楼主我也遇到和你同样的问题,现在已经解决了。就是把从24c02里面取出来的数 强制类型转化为和num一样unsigned long型的 就可以了
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
726 浏览 0 评论
777 浏览 1 评论
基于瑞萨FPB-RA4E2智能床头灯项目——1编译环境搭建与点亮驱动ws2812全彩LED
680 浏览 0 评论
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-LCD显示图片编程示例之介绍mmap
1149 浏览 0 评论
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
1120 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11805 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 13:14 , Processed in 1.237957 second(s), Total 95, Slave 78 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号