基于Arduino的电子秤设计
设计背景电子秤是一种较为方便,简单,称量精确的仪器。与日常生活中各个行业息息相关,广泛应用于各种商业,市场及零售业等公共场所。本设计是结合了传感器,基于Ardunio和HX711的多功能电子秤的设计。在Arduino平台,利用ATMEGA328单片机采集电子称模块的数据信息,将信息显示在LCD1602显示屏上,能够通过按键实现去皮计算,价格计算等功能。最后通过在Arduino模块外围搭建电路验证各项功能,达到预期目标。
研究内容为了达到电子秤的设计要求,本设计主要采用了Arduino作为控制模块,用单片机ATmega328作为处理核心,物体重量由称重传感器感受后,经由放大器和模数转换器后输入到单片机中进行处理,显示部分选择串口液晶显示重量。本设计外围电路简单,功能齐全,调试便捷。电子秤具体具有以下功能:(1)能用按键设置单价,同时显示重量和金额。(2)重量显示:单位为g;最大承重5Kg,重量小于1000g时误差小于0.5g,大于1000g时,误差小于1g。(3)具有去皮功能。
设计思路汽车出入库计时计费系统是以STC89C52单片机为核心,由数据采集、按键输入、液晶显示、蜂鸣器报警以及电机模块组成。数据采集模块包括射频卡FRID-RC522和时钟芯片,用于实时更新当前时间和采集停车入库时间。其中,射频卡的作用是通过刷卡调用当前车辆信息,然后将此信息送入STC89C52单片机中,单片机经过软件编程执行计时计费功能,电机运行,打开门禁。外围电路使用按键来设置相关信息,然后再通过单片机对数据进行处理,在整个过程中通过蜂鸣器报警提示操作是否成功,所涉及到的信息都将在液晶上进行实时显示。
研究方案控制模块方案选择方案一:控制模块采用STC89C51单片机。51系列为八位单片机,入门简单,由于问世较早,所以有着大量的开源资料,而且价格便宜。但是其主频比较低,对于某些数据的处理速度不够快,且没有丰富的外设。方案二:控制模块采用Arduino单片机。Arduino与51系列同为8位单片机,但比51系列更先进一些,编程变得简单和直观。方案三:控制模块采用32位的STM32单片机。STM32是基于ARM的32位处理器,具有强大的处理能力和DAC功能。F1系列主频可达72MHz。因此价格也比51系列稍微贵一点。
A/D转换方案选择方案一:采用ADC0832集成芯片外加放大电路。ADC0832是美国一家公司生产的一种8位分辨率芯片,它不仅与美国双相MOS芯片兼容,而且具有0~8位的高输入输出电压比。但是ADC0832没有内置的集成放大模块,所以需要一个额外的放大电路。放大器电路的稳定性和模数转换器的转换精度将直接决定了电子秤精度、准确度、响应时间等重要的平衡参数。另外,单独设计放大电路及A/D转换电路不仅费事,而且不能保证电路的准确性。方案二:采用电子秤专用模拟/数字芯片HX711。称重传感器检测到货物的重量之后,重量信息将被转换成为模拟电压信号,但是单片机只能识别出数字信号,所以要把模拟信号经过模数转换过程,最终转换成为单片机能识别的数字信号;转换成为数字信号之后,由于应变片的形变是微小的形变,导致输出电压信号很微弱,不利于直接使用,所以还要进行放大。在这个过程中,放大器电路的稳定性和转换精度直接影响称重电子设备的称量精度和反应时间。综上所述,高精确的转换芯片——HX711就是实验的最佳选择。
信号采样模块原理与方案选择方案一:信号通过惠斯通电桥采样。简称单臂电桥,工作在平衡状态。惠斯通由4个电阻组成的电桥电路,可以精确的出来电阻,利用电阻的变化测量物理量的变化。单片机采集可变电阻两端的电压然后处理,就可以计算出相应的物理量的变化。方案二:信号通过开尔文电桥采样。简称双臂电桥,工作在不均匀状态,一个或多个桥架往往是转换元件,这些元素的阻力值随一定物理量而变化。可以通过测量换能器电阻的变化来测量相应物理量的变化。它的实际意义不在于为了测量与桥架平衡对应的物理量,并且为了测量物理量的变化,使桥梁偏离平衡状态。单臂电桥:Δu=u04(ΔuR)=u04KϵDeltau=frac{u_0}{4}(frac{Deltau}{R})=frac{u_0}{4}KepsilonΔu=4u0(RΔu)=4u0Kϵ双臂电桥:Δu=2[u04(ΔRR)]=2[u04Kϵ]Deltau=2[frac{u_0}{4}(frac{DeltaR}{R})]=2[frac{u_0}{4}Kepsilon]Δu=2[4u0(RΔR)]=2[4u0Kϵ]电桥灵敏度:
Su=nu04S_u=nfrac{u_0}{4}Su=n4u0
硬件设计电子秤设计的整体方案:本设计的电子秤由数据采集模块、数据处理模块、按键处理模块、显示模块与主控制器模块等组成[。整体设计方案如图所示。
程序代码voidsetup(){//初始化函数,只执行一次pinMode(R1,OUTPUT);pinMode(R2,OUTPUT);pinMode(R3,OUTPUT);pinMode(R4,OUTPUT);pinMode(C1,INPUT_PULLUP);pinMode(C2,INPUT_PULLUP);pinMode(C3,INPUT_PULLUP);pinMode(C4,INPUT_PULLUP);Serial.begin(9600);//设置串口波特率hx.set_offset(17650);//修改偏移值lcd.init();//LCD初始化lcd.backlight();lcd.begin(16,2);}voidloop(){i=key_Scan();if(i==10)hx.tare();//清零/*称重*/doublesum0=0;doublesum1=0;for(j=0;jlcd.setCursor(0,5);//光标位置lcd.print("welcome");}/*称重显示*/lcd.setCursor(0,0);//光标位置lcd.print("kg:");lcd.setCursor(3,0);lcd.print(c);lcd.print("g");/*设置单价*/lcd.setCursor(0,1);lcd.print("pri:");lcd.setCursor(4,1);lcd.print(pri);if(ipri=0;}i=16;}/*计算总价*/lcd.setCursor(7,1);lcd.print("a:");lcd.setCursor(9,1);lcd.print(a);lcd.print("$");if(i==11){m=sum1/10;n=m/500;a=n*pri;}}/*按键扫描*/intkey_Scan(){pinHigh();//扫描第一行digitalWrite(R1,LOW);if(digitalRead(C1)==LOW){while(digitalRead(C1)==LOW);return1;}if(digitalRead(C2)==LOW){while(digitalRead(C2)==LOW);return2;}if(digitalRead(C3)==LOW){while(digitalRead(C3)==LOW);return3;}if(digitalRead(C4)==LOW){while(digitalRead(C4)==LOW);return0;}pinHigh();//扫描第二行digitalWrite(R2,LOW);if(digitalRead(C1)==LOW){while(digitalRead(C1)==LOW);return4;}if(digitalRead(C2)==LOW){while(digitalRead(C2)==LOW);return5;}if(digitalRead(C3)==LOW){while(digitalRead(C3)==LOW);return6;}if(digitalRead(C4)==LOW){while(digitalRead(C4)==LOW);return10;}pinHigh();//扫描第三行digitalWrite(R3,LOW);if(digitalRead(C1)==LOW){while(digitalRead(C1)==LOW);return7;}if(digitalRead(C2)==LOW){while(digitalRead(C2)==LOW);return8;}if(digitalRead(C3)==LOW){while(digitalRead(C3)==LOW);return9;}if(digitalRead(C4)==LOW){while(digitalRead(C4)==LOW);return11;}pinHigh();//扫描第四行digitalWrite(R4,LOW);if(digitalRead(C1)==LOW){while(digitalRead(C1)==LOW);return12;}if(digitalRead(C2)==LOW){while(digitalRead(C2)==LOW);return13;}if(digitalRead(C3)==LOW){while(digitalRead(C3)==LOW);return14;}if(digitalRead(C4)==LOW){while(digitalRead(C4)==LOW);return15;}return16;}voidpinHigh(){digitalWrite(R1,HIGH);digitalWrite(R2,HIGH);digitalWrite(R3,HIGH);digitalWrite(R4,HIGH);} 实验结果砝码值(g)测量值(g)误差值(g)55.010.011010.020.025050.010.01100100.030.03500500.10.1arduino多功能垃圾桶
舵机:指在自动驾驶仪中操纵飞机舵面(操纵面)转动的一种执行部件。分有:①电动舵机,由电动机、传动部件和离合器组成。接受自动驾驶仪的指令信号而工作,当人工驾驶飞机时,由于离合器保持脱开而传动部件不发生作用。②液压舵机,由液压作动器和旁通活门组成。当人工驾驶飞机时,旁通活门打开,由于作动器活塞两边的液压互相连通而不妨害人工操纵。此外,还有电动液压舵机,简称“电液舵机”。舵机的组成一般来讲,舵机主要由以下几个部分组成,舵盘、减速齿轮组、位置反馈电位计、直流电机、控制电路等,舵机的输入线共有三条,如图6所示,红色中间,是电源线,一边黑色的是地线,这辆根线给舵机提供最基本的能源保证,主要是电机的转动消耗。电源有两种规格,一是4.8V,一是6.0V,分别对应不同的转矩标准,即输出力矩不同,6.0V对应的要大一些,具体看应用条件;另外一根线是控制信号线,Futaba的一般为白色,JR的一般为桔黄色。另外要注意一点,SANWA的某些型号的舵机引线电源线在边上而不是中间,需要辨认。但记住红色为电源,黑色为地线,一般不会搞错。
示例程序:
Arduino编程语句:打开sweep,分析分析看看结果。
if:通过if指令,用户可以让Arduino判断某一个条件是否达到,并且根据这一判断结果执行相应的程序。
if(表达式){语句块}[/c] 上述结构表示:如果“表达式”的条件得到满足则执行语句块。否则Arduino将不执行该语句块。(如图所示)
while: while循环将会连续地无限地循环,直到圆括号()中的表达式变为假。被测试的表达式变量必须被改变,否则while循环将永远不会中止。可以在代码改变测试变量,比如让该变量递增,或者通过外部条件改变测试变量,比如将一个传感器的读数赋值给测试变量。while(表达式/循环条件){语句块/循环体}先计算表达式的值,当值为真(非0)时,执行循环体语句;执行完循环体语句,再次计算表达式的值,如果为真,继续执行循环体……这个过程会一直重复,直到表达式的值为假(0)才退出循环。其执行过程如图所示:
setup函数: 当Arduino程序开始运行时会调用setup()函数。通常我们setup()函数其中初始化一些变量、引脚状态及一些调用的库等。当Arduino控制器通电或复位后,setup函数会运行一次。Loop函数: 在setup()函数对程序完成了初始化后,loop()函数将会运行。loop函数是一个循环体,在Arduino启动后,loop()函数中的程序将会不断运行。通过loop()函数你可以利用你的程序来控制Arduino。Arduino库:通过库的使用可以拓展Arduino开发板的功能。因为有了库,我们可以很轻松的实现Arduino与外部硬件的协作或进行数据通讯。
逻辑运算符:
=比较运算符用于和if联合使用,测试某一条件是否达到。例如测试Arduino的某一个引脚输入值是否达到设定数值。如果是则执行特定程序。换句话说,如果圆括号中的语句为真,大括号中的语句就会运行。否则,程序跳过该代码。【逻辑】-【比较运算符】
模块介绍
符号
名称
功能
==
等于
如果两个输入结果相等,则返回真。
!=
不等于
如果两个输入结果不相等,则返回真。
=
大于等于
如果第一个输入结果大于或等于第二个输入结果,则返回真。
oled配置:
有了iic操作函数,接着根据oled命令表封装相关操作函数,不知道oled操作命令的可以翻我之前的文章,在oled配置那里有详细介绍,搬过来用即可
oled写命令函数:voidoled_Write_cmd(unsignedcharcmd);
oled写数据函数:voidoled_Write_data(unsignedchardat);
oled清屏函数:voidoled_clear(void);
oled初始化函数:voidoled_initial(void);
oled显示函数,这个函数是确定将要显示的位置,以及数据采样的格式:voidoled_put_char_16x16(unsignedcharx,unsignedchary,unsignedchart);//设置显示坐标函数,t为0时,字符为8x16t为1时,字符为16x16
然后通过oled_Write_data(),将采样到的字符数据写入即可显示。
ds18b20配置(在之前文章也有讲过ds18b20如何驱动及运用):
根据ds18b20操作手册:
检测是否有ds18b20:unsignedcharDS18B20_Check(void);
ds18b20初始化:voidDS18B20_Init(void);
复位信号:voidRest_sign(void);
读一位数据:unsignedcharDS18B20_Read_Bit(void);
读一字节数据:unsignedcharDS18B20_Read_Byte(void);
写一字节数据:voidDS18B20_Write_Byte(unsignedchardat);
开始信号:voidDS18B20_Start(void);
获取温度函数:voidget_Temperature(void);
案例实现:
图一
再把所作的三个程序组装,智能垃圾桶的程序就出来了。
名称
数量
ArduinoUNO开发板
1
杜邦线
1扎
OLED屏
1
面包板
1
DS18B20温度传感器
1
超声波模块
1
按钮
1
舵机
1
电池
2
案例描述:
按照电路图原理图连红色引线表示5V电源,黑色引线表示接地口,黄色引线和橙色引线表示不同的信号线连接的引脚口也会不同,下文会对不同装置不同的信号引脚口进行分析。
编写DS18B20显示于OLED程序:
首先我们要用到第4行#include“U8glib.h”这个关于OLED的库,#include
#include
OneWireoneWire_9(9);
DallasTemperaturesensors_9(&oneWire_9);
DeviceAddressinsideThermometer;这都是温度传感器的库和必备条件,
其次自定义一个函数第24行vioddraw();这个函数中的u8g.就可以通过arduino把我们想输入资料或文字输入进OLED,第七行是OLED显示必须的代码,具体不做过多解释。第30行print(temperatrue);后文会提到它在loop函数中而draw()函数也在loop中。10,11行中的数字(1,10),(100,25)是字符的位置OLED板定义是128*64行。Long函数和int差不多都是字符定义成一个数字。
43行可以通过串口监视器观察变化
编写超声波控制舵机:
首先超声波模块有多个信号引脚Trig,Echo。
如图通过7行代码我们知道,我们将两个信号口设置成了Arduino的模拟引脚口A2A3.切记这些命令是在setup和loop函数之外,因为这样便于我们任意使用于这两个函数之间。第2行可知我们调用了关于舵机(servo)的库,并了解到servo.write可控制角度变化. 4行可知我们将舵机的引脚口设置为数字9号引脚,并且我们把这个舵机取名叫mysevo 切记舵机只可连接3,5,6,9,10,11号引脚口。EchoINPUT输入信号,TrigOUTPUT输出信号,serial.begin设置串口监视器切实观察舵机角度变化。第13行中我们定义了距离如何取,并通过他的变化控制舵机角度。
7.编写按键控制LED灯程序:
将LED设置为8号引脚,使他输出高电流,其中按钮只是用作开关一样,不按按钮线路断开,按下开关线路闭合。
电路设计:
本实验主要是三部分,
通过Arduino和库实现舵机和超声波模块沟通连接.DS18B20温度值传输给OLED显示简单程序按钮控制LED灯
任务扩展:制作一个靠近舵机能通过超声波自动打开的程序制作一个温度传感器读取OLED显示屏的程序制作一个按下按键,LED灯亮,松开熄灭的程序
智能垃圾桶实验程序
程序编写:
任务要求
程序编写:
参数设置:
初始化:超声波接口EchoA2;TrigA3变量距离;舵机设置9号引脚;温度传感器4号数字引脚变量温度;OLED设置SCL设置A4;SDA设置A5;按钮设置为8号数字引脚。 延时1000毫秒。
它的程序就是以上程序的拼装,当你明白以上程序时相信你也会编写了。
#includeServoservo_9;volatileintdistance;floatcheckdistance_A2_A3(){digitalWrite(A2,LOW);delayMicroseconds(2);digitalWrite(A2,HIGH);delayMicroseconds(10);digitalWrite(A2,LOW);floatdistance=pulseIn(A3,HIGH)/58.00;delay(10);returndistance;}#include#include#include"U8glib.h"Stringi="Tepture:";ints=0;//变量秒用来显示U8GLIB_SSD1306_128X64u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);//小E开发板上面就是用的这个volatileinttemperture;OneWireoneWire_4(4);DallasTemperaturesensors_4(&oneWire_4);DeviceAddressinsideThermometer;floatds18b20_4_getTemp(intw){sensors_4.requestTemperatures();if(w==0){returnsensors_4.getTempC(insideThermometer);}else{returnsensors_4.getTempF(insideThermometer);}}voiddraw(){u8g.setFont(u8g_font_unifont);//设置字体这句必要u8g.drawStr(1,10,"Helloworld!");//第一个是x第二个是y坐标u8g.setFont(u8g_font_ncenB14);//还是先设置一个字体u8g.setPrintPos(0,44);//然后设置一个位置u8g.print(i);//然后就是数据u8g.print(temperture);}voidsetup(){servo_9.attach(9);distance=0;servo_9.write(0);delay(0);pinMode(A2,OUTPUT);pinMode(A3,INPUT);Serial.begin(9600);temperture=0;sensors_4.getAddress(insideThermometer,0);sensors_4.setResolution(insideThermometer,9);Serial.begin(9600);}voidloop(){distance=checkdistance_A2_A3();Serial.println(distance);if(distance=35){delay(1000);servo_9.write(0);delay(500);}delay(1000);temperture=ds18b20_4_getTemp(0);Serial.println(temperture);if(s!=millis()/10)s=millis()/10;//上面这一句是取系统运行秒数单位ms除以1000就是秒u8g.firstPage();do{draw();}while(u8g.nextPage());//延迟一段时间后重新生成图片delay(10);}
七.知识拓展:
而实用,垃圾桶内内置蜂鸣器和RTC时钟模块,可以进行精准定时和报时。DS18B20提供的温度数据使得垃圾桶摇身一变成为了温度播报员。当夜幕降临,桶内内置的LED小夜灯可以将垃圾桶摇身一变成为可爱的小精灵,在寂静的黑夜中发出温暖而和蔼的光芒
反思总结1.通过这节课我们学会了超声波模块是如何工作尝试了让OLED显示我们想要显示的内容,学会了按钮的工作原理,了解LED灯
2.软件方面,了解了if函数学会了自定义函数
3.本节课所学内容为垃圾箱控制,OLED显视
参考文献
arduino中文社区
https://www.arduino.cn/forum.php
太极创客
http://www.taichi-maker.com/homepage/arduino-basic-tutorial-index/
此文章不用于商业性,非盈利手段,仅用于参考学习