关键词:proteus仿真、51单片机、DS1302时钟芯片、DB18B20温度芯片、AT24C02存储芯片、LCD1602液晶屏、ADC0832芯片等,文末给出了能用的底层驱动文件
考完试了,就来整理一下博客吧,哈(有种停课不停学的感jio哈哈哈哈哈哈哈)
**内容有点太过庞杂,一想也难有人看(莫名其妙水了2000字。。。)主要的,我觉得的小创新就是可以连续进行几个的检测,进入相关的模式后,就可以进行检测,当数值稳定1s后才记录存储,并开始测量下一个数值(写博客写到这里忽然想起有个优化项:就是需要测再测下一个之前需要数值改变才行不然一个数值重复测。。这是个bug),其他的就都是常见的那些模块进行的糅合了,没有我自己想的东西了。。。然后看程序图应该大家就懂了,要是想详细了解请看下面: **
1)设计一个多功能电子秤控制器。通过单片机来控制各个模块的运行,保证降低各个模块之间的耦合度,并注意时序。 2)设计交互式界面。通过8个独立按键来控制单片机不同功能的实现,在正常状态下,单片机读取RTC芯片的时间数据并控制LCD1602液晶屏显示时间,包括年份、月份、日、小时、分钟、秒,实时更新,通过用户键入不同的按键,液晶屏可以显示:时间、修改时间、环境温度、当前测量的单个物品的重量、一批物品的重量、一批物品重量的数据等;其中数据包括:测量这一批物品的时间(月份,日,小时,分钟)、测量时选取的标准重量与可接受的误差范围、测量的总量、测量的不符合预期标准的产品数量,并且加入相关的状态显示,如表示当前模式,液晶屏左上角,显示时间时为MODE1,测量单个物品时为MODE2,测量一批物品时为MODE3。并在保存数据与发送数据时进行提示等,提高人机交互体验。 3)设计独立按键来进行人机交互。通过键入不同的值,并根据设计来实现不同的功能具体如下(一共有八个独立按键): 当k1被按下时:进入时间修改矫正模式,一共有6种状态。从第一次按下开始选定秒,此时按下k5可以进行当前秒的增加,按下k6可以进行当前秒的减少。继续按下k1键,则分别可以修改分钟、小时、日、月份、年份的数值大小,并实时在液晶屏上显示;当第7次按下k1时,则返回到正常显示模式。 在时间修改过程中,除了按下增加键k5或减少键k6,其他按键均无效。 当k2被按下时:进入单个重量称量模式。只有一种状态。当第一次按下后液晶屏显示相关界面,并且此时通过改变滑动变阻器来模拟重量的改变,液晶屏实时显示,并且设置一个最大量程,可以通过k5或k6按键来调整,当当前测量的重量高于最大量程时,则指示灯点亮,且蜂鸣器开始发出声音。当再次按下后返回到时间显示模式。在测量过程中,只有k7去皮按键可以使用,按下后则实现去皮功能,其他按键均无效。 当k3被按下时:进入一批产品测量模式,一共有4种状态。从第一次按下后,进入第一种状态选择要测量的标准重量,标准重量有几个标准值可供选择,通过k5和k6来选择不同的数值作为本次标准重量;第二次按下后,进入第二种状态选择可接受的误差,有几个可接受误差工选择,通过k5和k6来选择不同的数值作为本次可接受误差;第三次按下后,开始进行产品测量,并实时显示测量一共测量的个数,并显示当前测量个数,只有当前测量的产品重量保持稳定1s后,才存储下这个数据到AT24C02中(最多存储246个数据,且每个数据不能超过255,可以通过其他单位比例换算的方式来获得超过255后的数据存储,这里没有进行拓展),并判断该重量是否是坏值,更新测量总数,同时每次记录下一个数值后,指示灯反转状态;第四次按下按键后,开始存储测量总数、坏值总数、标准重量、可接受误差、测量时间到中,液晶屏显示处理信息,完成后回到时间显示模式。在回到时间显示模式前,其他按键均无效。 当k4被按下时:进入上次数据查看模式,一共4种状态。当第一次按下时液晶屏显示上次测量的时间;第二次按下时,显示上次的测量标准:标准重量与可接受误差;第三次按下后,显示上次测量的总数与坏值总数;第四次按下时,显示屏提示是否要把数据发送到电脑端,此时若按下k8则发送,若再次按下k4则回到时间显示模式。在回到时间显示模式前,在此过程中除了第四次按下k6后可以选择按k8,其他按键均无效。 当k5被按下时:增加数值。只有上面相关的模式下按下才有效,其他时间都无效。 当k6倍按下时:减少数值。只有上面相关的模式下按下才有效,其他时间都无效。 当k7倍按下时:去皮操作。只有上面相关的模式下按下才有效,其他时间都无效。 当k8被按下时:进入温度模式或发送数据模式。当在k4第四次按下后按k8,则发送数据到电脑端,同时每成功发送一组数据(包括该数据的测量的序数和重量大小)指示灯状态反转一次;当在时间显示模式下按下k8,则进入温度显示模式;这俩种状态都要通过再次按下k8键返回时间显示模式,且在过程中其他模式均无效。 4)设计其他传感器与外设,包括滑动变阻器模拟的压力传感器,通过ADC0832芯片来进行A/D转换并把数据发送给单片机,温度传感器DS18B20进行温度检测,用DS1302时钟芯片提供准确时,用MAX232电平转换来做串口通讯,并设计一个蜂鸣器与蜂鸣器进行状态提示。
时间显示模式 时间显示模式与时间修改模式的显示相同,结果如下: 显示时间与电脑当前时间相同。
单个重量称量模式 这里只演示在超过最大量程时的情况,这里吧最大量程通过按键改为了3.47kg。 此时指示灯亮,同时蜂鸣器响。
一批产品测量模式 如图,首先延时了选择标准重量和误差时的情景,然后显示了在记录数据时,指示灯状态指示。 相关的参数选择好,就开始记录数值了:
上次数据查看模式 如图显示,这里和前面预期结果相符合,在选择发送数据时,每成功发送一个指示灯状态改变,通过串口显示器可以看到数据的传输,最后一个图为全部数据传输成功。 发送数据时指示灯亮:
温度查看模式 如图,可以通过改变DB18B20来实时显示温度:
1)温度只能显示正整数。这里只取正整数是因为上面提到的受到变量不能创建的限制。 2)记录的数据受限,只能记录246个详细数据(受到AT24C02内存的限制),同时数据不能超过255大小,这里并没有进行变量优化,来使0-255的大小可以去代表更多(但减少精度),也是受到了变量创建的限制,而proteus库中8位单片机最好的便只是89C55,而使用32位单片机又不划算。 3)在单次测量时,使用去皮功能后,就会有BUG,就是也能去皮,但是这时候报警的数值应该记录错误了 4)串口通信时,使用电脑接收的时候出现乱码,每次测试乱码也不同,感觉就是有数据发生了丢失的现象。
1)串口向计算机发送char类型的变量时,应该使(char类型变量+‘0’)变为他所代表的字符,如向LCD1602中写入数据一样。 2)对于记录数据的时间控制。考虑到现实中测量物品重量时物品会有不稳定重量的现象,于是在定时器中记录俩个重量,是1s前后检测到的,通过对比是否相同来判断当前是否稳定并记录处理,该时间可以调控。 3)在刚开使用串口通信时,发现并不能成功发送数据,仔细研究后发现是因为T0定时器与产生波特率的T1定时器互相干扰,故在串口通信时只T1工作,此时关闭T0的计数和中断,同时在T0工作时只在温度查看模式和时间显示模式每秒进行温度转换,测一批重量模式时启动,这样来减少CPU的处理,让单片机更稳定,节省资源。 4)随着程序的代码量的增大,发现以前的显示模式除了问题,于是做了简化:本来是每次进入显示处理都要读取IIC,发现此时读出的数据是错误的,后来改为了只在按下相应按键时读取一次,然后注意时序,跳出按键处理后就进入显示处理,使显示成功。 5)在串口发送数据时,字符串结尾要加“\r\n”才能进行换行,不能只输入’\n’。 6)存储和读取AT24C02时,读取温度时,及串口发送数据等要留有一定的时间间隔,否则容易出现失败。 7)最棘手的问题。因为工程的增加,导致变量也在增多,本来选用的是89C51,然后不够用便选用了89C55,最后程序设计完成后,查阅资料发现89C55与89C52的RAM大小相等,考虑实际成本变该用了89C52,在这个过程中因为RAM可存储变量,故保证工程一直在SMALL模式编译,使得程序读取变量在RAM中速度快,时序得到了保证。 8)时序逻辑很重要,有的时候改变了函数的执行位置便引起了不理想的结果,并且有时指令写错了一个括号的位置也引起了很久的查找,一定要认真看,单步调试。
1)可以再显示时间的时候来让指示灯通过定时器产生PWM波,周期固定,但是占空比随着温度在一定的范围内改变而等比例从0-100进行改变,可以通过亮度来大体感知温度,可以使用89C52新增的T2来产生PWM波,但是受到变量创建的限制,还有时间的限制并没有进行拓展。 2)进行多机通信,做四五个主机实现我的这个多功能电子秤的功能,只不过是把数据通过串口来传输给一个主机,主机再进行拓展存储,这时PC端可以与主机通信,来获得丛机的数据;并且主机可以拓展更大的存储器,来存储更多的数据,同时主机配备密码锁,与液晶屏在本机可以查看想看到的数据并可以进行删除等数据操作,与指示灯,当有数据接收时则相应代表从机的指示灯亮,等人来按任意键关闭表示知道接收数据了,考虑到时间的限制还有难度,并没有进行拓展。 3)本打算实现个密码锁功能,但发现不实用在现在想要的系统上,若继续使用矩阵按键的话,有点鸡肋,按键太多但是也没用那么多,最后选择8个独立按键,但也因此受限无法完成许多拓展功能。
主要是库文件的代码!方便大家移植 主要是库文件的代码!方便大家移植 主要是库文件的代码!方便大家移植 主程序代码,就给几个核心的看看吧(代码写的很乱,希望以后看到能笑出声来)
本来想更新我的键盘处理函数和显示函数还有发送函数的,但一看这就这么多字了- -写的还很乱,就给一个键盘处理函数吧,感兴趣可以私聊
/*******************************************按键检测处理函数**************************************************/ void key_deal() { static uchar tmp1=0; static uchar tmp2=0; char i=0; ET0 = 1; TR0 = 1; if(k1==0) { delayms(10); if(k1==0 && key_status[1]==0 && key_status[2]==0 && key_status[3]==0 && key_status[7]==0) { // 只在时间模式下进行温度采集 和温度显示模式下 key_status[0]++; if(key_status[0]==7){key_status[0]=0;} // 最多按7次可以修改年的大小时间 write_com(0x01); // 清屏 防止切换模式后花屏 } while(!k1); } if(k2==0) { delayms(10); if(k2==0 && key_status[0]==0 && key_status[2]==0 && key_status[3]==0 && key_status[7]==0) { ET0 = 0; TR0 = 0; key_status[1]++; if(key_status[1]==2) { // 初始化 同时初始化指示灯和蜂鸣器 防止bug key_status[1]=0; led = 1; beep = 1; skin = 0; } write_com(0x01); // 清屏 防止切换模式后花屏 } while(!k2); } if(k3==0) { delayms(10); if(k3==0 && key_status[0]==0 && key_status[1]==0 && key_status[3]==0 && key_status[7]==0) { key_status[2]++; if(key_status[2]==3) { ET0 = 1; TR0 = 1; // 打开串口,每次成功记录后,就把数据发送到PC端 skin=0; sum = 0; bad = 0; } if(key_status[2]==4) { ET0 = 0; TR0 = 0; led = 1; // 结束后熄灭led灯 skin=0; // 吧数字存储进去 iic_write(1,sum); delayms(200); iic_write(2,bad); delayms(200); //从3-6存放结束时的时间。 iic_write(3,adjusted.Minute); delayms(200); iic_write(4,adjusted.Hour); delayms(200); iic_write(5,adjusted.Day); delayms(200); iic_write(6,adjusted.Month); delayms(200); iic_write(7,choice_weight); delayms(200); iic_write(8,choice_error); // 由显示屏的相关状态置0, } write_com(0x01); // 清屏 防止切换模式后花屏 } while(!k3); } if(k4==0) { delayms(10); if(k4==0 && key_status[0]==0 && key_status[1]==0 && key_status[2]==0 && key_status[7]==0) // 判断如果现在是显示时间的模式的话,那么我就显示 { ET0 = 0; TR0 = 0; key_status[3]++; switch(key_status[3]) { case 1:{pro_month=iic_read(6);delayms(3);pro_day=iic_read(5);delayms(3);pro_hour=iic_read(4);delayms(3);pro_minute=iic_read(3);delayms(3);break;} case 2:{choice_error = iic_read(8);delayms(3);choice_weight=iic_read(7);delayms(3);break;} case 3:{sum = iic_read(1);delayms(3); bad = iic_read(2);break;} default:break; } if(key_status[3]==5)key_status[3]=0; // 四个模式 显示当时的时间,然后再显示当时的测量的标准(误差标准及标准重量),再显示总数据;接着再按则询问是否要详细的数据,若按确定按钮,则串口发送 write_com(0x01); // 清屏 防止切换模式后花屏 } } if(k5==0) // 增加被按下 { delay(10); if(k5==0 & (key_status[0]!=0 | key_status[1]!=0 | key_status[2]!=0)) { ET0 = 0; TR0 = 0; // 一种一种情况来判断 if(key_status[0]!=0) { switch(key_status[0]) { case 1:adjusted.Second++;break; case 2:adjusted.Minute++;break; case 3:adjusted.Hour++;break; case 4:adjusted.Day++;break; case 5:adjusted.Month++;break; case 6:adjusted.Year++;break; default: break; } } if(key_status[1]!=0) { maxweight++; } if(key_status[2]!=0) { switch(key_status[2]) { case 1:{if(tmp1!=5){tmp1++;}choice_weight = steady_weight[tmp1];break;} case 2:{if(tmp2!=2){tmp2++;}choice_error = error[tmp2];break;} default:break; } } while(!k5); } } if(k6==0) { delayms(10); if(k6==0 && (key_status[0]!=0 | key_status[1]!=0 | key_status[2]!=0)) {ET0 = 0; TR0 = 0; if(key_status[0]!=0) { switch(key_status[0]) { case 1:adjusted.Second--;break; case 2:adjusted.Minute--;break; case 3:adjusted.Hour--;break; case 4:adjusted.Day--;break; case 5:adjusted.Month--;break; case 6:adjusted.Year--;break; default: break; } } if(key_status[1]!=0) { maxweight--; } if(key_status[2]!=0) { switch(key_status[2]) { case 1:{if(tmp1!=0)tmp1--;choice_weight = steady_weight[tmp1];break;} case 2:{if(tmp2!=0)tmp2--;choice_error = error[tmp2];break;} default:break; } } while(!k6); } } if(k7==0) // 去皮 { delayms(10); if(k7==0 && key_status[1] ==1) // 只有在单次称重下去皮模式才起作用 { ET0 = 0; TR0 = 0; skin = weight; // 保存皮的重量 weight = 0; //皮给去了嘛 key_status[6]++; if(key_status[6]==2)key_status[6]=0; while(!k7); } } if(k8==0) { delayms(10); if(k8==0 && (key_status[3]==4 | key_status[7]==2)) { key_status[3]=0; key_status[7]++; if(key_status[7]==3){key_status[7]=0;} write_com(0x01); // 清屏 防止切换模式后花屏 while(!k8); } else if(k8==0 && key_status[0]==0 && key_status[1]==0 && key_status[2]==0 && key_status[3]==0) // k8的第二种模式,只有在按下的时候才能显示温度 { // 为了单独区分出来一种转态 if(key_status[7]==0)key_status[7]=6; else key_status[7]=0; while(!k8); // 直到被按下 } write_com(0x01); } }好了,以上就是全部了,希望其中的思路和能用的库文件可以帮到大家,也希望大家可以做一个自己喜欢的课程设计项目!思维的乐趣则是人生了去中最重要的一种这是最近我读的书中的一句话,虽原意不是如此,但我觉得学习中也有许多这样的乐趣。当时我做的时候花了俩天就弄完了,有点急,主要是忙着复习和其他期末的事情,真想再好好研究研究我的小设计,哈哈哈 有问题欢迎留言:) 2020年7月1日