赞
踩
目录
记录一下用压力传感器做密度计的过程
单片机:51单片机
模块:HX711
公式:
话说盘古开天地,我拿HX711做密度计。公式:
质量很简单,直接用HX711和压力传感器称出来就行了,至于怎么提高精度后面会说。
1.把带水的合适大小的烧杯放在称上,去皮;
2.用细线拴住被测物体,使其浸没在水中,注意不要碰到容器壁和容器底;
3.测此时的质量即为物块体积;
看一下大概示意图:
物块通过细线悬挂在支架(上面那条横线)上,细线对物块的拉力为F1;
现在对物块、烧杯和水进行整体受力分析:
设容器和水的质量为M1,物块的质量为M2;秤对这个整体向上的支持力为F,此时可得:
也就是:
好,记住它,一会用。
对物块受力分析可得:
F浮=M2*g-F1
这两个式子联立:
F=M1*g+M2*g-F1
F浮=M2*g-F1
是不是可以得到:
F=M1*g+F浮
再回到1.2.1中的第一步,可以看到,容器和水放在秤上之后进行了去皮操作,于是乎M1是不是就等于0了!!!
既然如此,F=F浮 了吧?
此时的压力F是在秤上以质量的形式表现出来的,我们不妨设这个“质量”为M0;
那么上式就可以写作 M0*g = p*g*v;
水的密度为1,上式简化为M0=v;
这样,物块的体积在数值上是不是就等于秤称出来的值了??
此时物块的体积就通过测质量的方式得到了。
由上述步骤可知被测物体的密度要大于水。
1.51单片机最小系统
2.HX711模块+压力传感器
3.4个按键
4.LCD1602液晶显示屏
4个按键的功能分别是:去皮、称重、记录、计算密度;
1.测出被测物体质量M1,记录;
2.将带水的烧杯放在压力传感器上,去皮;
3.用细线拴住物体,使物体浸没在水中,测其质量M2,记录;
4.M1/M2即为物体密度;
按照之前所学的按键检测方式,需要等待按键释放,感觉这样有点慢,这里借鉴了正点原子对按键的处理方式。
- /********************
- C文件
- **********************/
- uchar KEY_Read_Nwiat()
- {
- static uchar key_flag = 1;
- if(((KEY_COUNT == 0)||(KEY_MARK == 0)||(KEY_MEASURE == 0)||(KEY_PEEL == 0))&&key_flag == 1)
- {
- delay(5);
- key_flag = 0;
- if(KEY_COUNT == 0) return KEY_COUNT_value;
- else if(KEY_MARK == 0) return KEY_MARK_value;
- else if(KEY_MEASURE == 0) return KEY_MEASURE_value;
- else if(KEY_PEEL == 0) return KEY_PEEL_value;
- }
- else if(KEY_COUNT == 1&&KEY_MARK == 1&&KEY_MEASURE == 1&&KEY_PEEL == 1) key_flag = 1;
- return 0;
-
- void KEY_UserConfig()
- {
- KEY_MARK = 1;
- KEY_COUNT = 1;
- KEY_PEEL = 1;
- KEY_MEASURE = 1;
- }
-
-
-
- /*************************************
- 头文件
- *************************************/
-
- //-----按键值-----
- #define KEY_PEEL_value 1 //去皮返回值
- #define KEY_MEASURE_value 2 //称量返回值
- #define KEY_MARK_value 3 //记录返回值
- #define KEY_COUNT_value 4 //计算返回值
-
- //-----按键定义-----
- sbit KEY_PEEL = P2^2;//去皮
- sbit KEY_MEASURE = P2^3;//称量
- sbit KEY_MARK = P2^4;//记录
- sbit KEY_COUNT = P2^5;//计算
-
- uchar KEY_Read_Nwiat();//无需等待
- void KEY_UserConfig(); //初始化
LCD1602写法多种多样,此处仅供参考,不完善的地方请大家多多担待。
- /*********************************
- C文件
- *********************************/
- void Write_0com_1dat(bit choose,uchar com_dat)
- {
- LCD1602_EN = 0;
- if(choose == 0)//低命令
- {
- LCD1602_RS = 0;
- }
- else if(choose == 1)
- {
- LCD1602_RS = 1;
- }
- P0 = com_dat;
- delay(5);
- LCD1602_EN = 1;
- delay(5);
- LCD1602_EN = 0;
- }
-
- //-----
- void LCD1602_write_word(uchar location,uchar *s)
- {
- Write_0com_1dat(0,location);//显示位置
- while(*s)
- {
- Write_0com_1dat(1,*s);
- s++;
- delay(5);
- }
- }
- //-----初始化-----
- void LCD1602_UserConfig()
- {
- LCD1602_EN = 0;
- Write_0com_1dat(0,0x38);
- Write_0com_1dat(0,0x0c);
- Write_0com_1dat(0,0x06);
- Write_0com_1dat(0,0x01);
- }
-
-
- /**********************************
- 头文件
- ***********************************/
-
- #define LCD1602_PORT P0
- sbit LCD1602_RS = P2^0;
- //sbit LCD1602_RW = P2^6;//不进行忙检测,直接接地了
- sbit LCD1602_EN = P2^1;
-
-
- void Write_0com_1dat(bit choose,uchar com_dat);
- void LCD1602_write_word(uchar location,uchar *s);
- void LCD1602_UserConfig();
- /****************************
- C文件
- ****************************/
- ulong Weight_Maopi = 0;
- long Weight_Shiwu = 0;
- float Weight_float = 0;
- uchar Weight_buf[16] = " ";
-
- //-----读HX711-----
- ulong HX711_Read(void)
- {
- ulong count;
- uchar i;
- HX711_DOUT=1;
- _nop_();_nop_();
- HX711_SCK=0;
- count=0;
- EA = 1;
- while(HX711_DOUT);
- EA = 0;
- for(i=0;i<24;i++)
- {
- HX711_SCK=1;
- count=count<<1;
- HX711_SCK=0;
- if(HX711_DOUT)
- count++;
- }
- HX711_SCK=1;
- count=count^0x800000;//第25个脉冲下降沿来时,转换数据
- _nop_();_nop_();
- HX711_SCK=0;
- return count;
- }
-
- //-----获取毛皮-----
- void HX711_get_Maopi()
- {
- Weight_Maopi = HX711_Read();
- }
-
- //-----获取质量-----
- void HX711_get_Weight()
- {
- Weight_Shiwu = HX711_Read();
- Weight_Shiwu -= Weight_Maopi;
- Weight_float = ((float)Weight_Shiwu/GapValue);
- }
-
-
- /******************************************
- 头文件
- ******************************************/
- //校准参数
- //因为不同的传感器特性曲线不是很一致,
- //因此,每一个传感器需要矫正这里这个参数才能使测量值很准确。
- //当发现测试出来的重量偏大时,增加该数值。
- //如果测试出来的重量偏小时,减小改数值。
- //该值可以为小数
- #define GapValue 500
-
- sbit HX711_DOUT = P1^1;
- sbit HX711_SCK = P1^0;
-
- ulong HX711_Read(void);
- void HX711_get_Maopi();
- void HX711_get_Weight();
由 3.3 可知,我用的是float类型的变量Weight_float去接收的质量,因此,怎么把这个带小数点的数呈现在LCD1602上呢?当然你可以把数值扩大十倍百倍甚至千倍,再用上四舍五入法,就把xxx.xx的小数转化为一位一位的字符了,但是我懒得这样弄,想到C语言中不是还有sprintf这个函数吗?虽然占用了51单片机很多空间!!!
HX711模块卖家提供的代码是一直测量物体质量,这样难免数值会一直跳动,因此,我们可以加一个测量按键,按键不按下就不测量,只有按键按下才进行测量,这样又会有一个问题:我两次测同一个物体的值不一样(有误差嘛),为了减小误差,我们采取按键按下后连续测量十次质量取其平均的方式得到物块较为真实的质量(下方代码42行)。
废话不多说,上代码
- /**************************
- main.c
- **************************/
-
-
- uchar i;
- uchar key_val;
- uchar mark_flag = 0;
- extern uchar Weight_buf[16];
- extern float Weight_float;
- extern long Weight_Shiwu;
- float Weight_average = 0;
- float m,v;//质量体积
-
- void mesure_density();//测密度
-
- void main()
- {
- LCD1602_UserConfig();
- KEY_UserConfig();
- HX711_get_Maopi();
- while(1)
- {
- mesure_density();
- }
- }
-
- void mesure_density()
- {
- LCD1602_write_word(0x80,"Welcome to use..");
- key_val = KEY_Read_Nwiat();
- //-----去皮-----
- if(key_val == KEY_PEEL_value)
- {
- HX711_get_Maopi();
- LCD1602_write_word(0xc0," PEEL OK! ");
- delay(500);
- LCD1602_write_word(0xc0," ");
- }
- //-----测量-----
- if(key_val == KEY_MEASURE_value)
- {
- LCD1602_write_word(0xc0," ");
- for(i=0;i<10;i++)
- {
- HX711_get_Weight();
- Weight_average+=Weight_float;
- LCD1602_write_word(0xc0," wait.. ");
- }
- Weight_average/=10;
- LCD1602_write_word(0xc0," ");
- sprintf(Weight_buf,"%.2f g",Weight_average);
- LCD1602_write_word(0xc0,Weight_buf);
- }
- //-----记录-----
- if(key_val == KEY_MARK_value)
- {
- mark_flag++;
- if(mark_flag == 1)
- {
- m = Weight_average;
- LCD1602_write_word(0xc0," ");
- sprintf(Weight_buf,"%.2f M OK!",m);
- LCD1602_write_word(0xc0,Weight_buf);
- }
- if(mark_flag == 2)
- {
- v = Weight_average;
- LCD1602_write_word(0xc0," ");
- sprintf(Weight_buf,"%.2f V OK!",v);
- LCD1602_write_word(0xc0,Weight_buf);
- mark_flag = 0;
- mark_flag|=0x80;
- }
- }
- //-----计算-----
- if(key_val == KEY_COUNT_value&&(mark_flag&0x80))
- {
- mark_flag = 0;
- LCD1602_write_word(0xc0," ");
- sprintf(Weight_buf,"%.2f g/cm3",m/v);
- LCD1602_write_word(0xc0,Weight_buf);
- }
- }
做仪器总要讲究精度的吧。我们用称和砝码称出5g-150g的数据,填入Excel中拟合出一个函数,我们根据这个函数去算出更接近真实值的质量,下面是我测的一些数据。可以看出,测量的质量越大误差也就越大。
砝码 测量值 误差 5 4.96 0.04 10 9.85 0.15 15 14.84 0.16 20 19.69 0.31 25 24.5 0.5 30 29.43 0.57 35 34.39 0.61 40 39.25 0.75 45 44.2 0.8 50 49.1 0.9 55 54.08 0.92 60 58.92 1.08 65 63.84 1.16 70 68.7 1.3 75 73.63 1.37 80 78.55 1.45 85 83.41 1.59 90 88.36 1.64 95 93.5 1.5 100 98.17 1.83 105 103.11 1.89 110 108 2 115 112.87 2.13 120 117.84 2.16 125 122.72 2.28 130 127.66 2.34 135 132.55 2.45 140 137.41 2.59 145 142.32 2.68 150 147.27 2.73
把测量值和误差拟合出函数
x是测量的质量,y是误差,测量值加上误差不久接近真实值了嘛!!!
下面是我根据上面函数修改程序后的测量数据:
砝码 测量值 误差 5 4.56 0.44 10 9.47 0.53 15 14.46 0.54 20 19.47 0.53 25 24.51 0.49 30 29.52 0.48 35 34.51 0.49 40 39.51 0.49 45 44.56 0.44 50 49.53 0.47 55 54.56 0.44 60 59.63 0.37 65 64.58 0.42 70 69.59 0.41 75 74.55 0.45 80 79.5 0.5 85 84.49 0.51 90 89.55 0.45 95 94.5 0.5 100 99.61 0.39 105 104.59 0.41 110 109.65 0.35 115 114.65 0.35 120 119.69 0.31 125 124.67 0.33 130 129.71 0.29 135 134.74 0.26 140 139.74 0.26 145 144.8 0.2 150 149.76 0.24
相对于上一次测量,这次误差就平稳多了
再次拟合:
这个函数是多项式了,加到程序里就差不多可以了,当然为了提高精度你也可以拟合更多次。
注意:误差处理这里在上面的程序里没写,因为每个称的误差不一样,加了我的误差分析或许会使你的更不准确!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。