51单片机电子秤(HX711模块 + LCD1602)

51单片机电子秤(HX711模块 + LCD1602)

(简单易懂)

1.---------------序
2.HX711测重模块
3.LCD1602显示模块
4.电子秤整体实现原理
5.模块升级>>去皮与还原
6.源代码

零.先来一个效果展示
在这里插入图片描述
这里可以看到3个20g砝码加上去显示60g的重量
5个20g砝码加上去显示100g的重量,精度是比较准的
在这里插入图片描述
在这里插入图片描述

一.首先考虑如何把这样一个项目设计出来

1.明确目标
–做这样一个东西,我们需要实现怎样的效果–
2.思路清晰
–整个执行过程我门需要设计哪些事–
–整个执行过程我们要按照怎样的一个逻辑–
3.确保执行
–有效(花时间并不等于有效)的执行力是成功所必不可缺的–
4.总结收获
–在实现项目过程中我们学到了什么–
–以后应对不同的项目有哪些想法是可以通用的–

二.HX711测重模块原理

1.HX711模块可以看成由三个部分组成>>压力传感器,电压放大器,ad转换芯片

  压力传感器:感知物体重力,并转化为电压信号
  					 这里是0~5kg压力传感器,灵敏电压为1mv,
  				     即1kg重力产生1mv电压
  电压放大器:由于压力传感器产生电压太小,需要对电压信号放大
  					  这里用的是128倍电压增益
  ad转换芯片(24位):将模拟信号(放大后的电压值)转化为数字信号(ad值)

2.ad值转化为重力大小

  	假设重力为x kg,
  	ad = (x/5)*128*2^24*(5/5000),(满量程为5kg,128倍放大,精度为2^24)
  													(传感器满偏电压5mv,单片机为5v)
  	ad = 429496.7296x    >>    x = ad/429496.7296  (按g显示再乘1000即可)
//ad转化为重力大小公式,(float)将整除转化为小数运算,再将运算结果强制转化为无符号整型数值
Weight_Shiwu = (unsigned int)((float)Weight_Shiwu/423.15);
//理论上是除以429.5,实际上存在误差(传感器曲线以及电压的微小误差),需要根据显示情况来调整这一数值

3.HX711时序图 & ad取值代码

在这里插入图片描述

sbit HX711_DOUT = P2^1; 	//声明P2^1口接HX711数据线
sbit HX711_SCK = P2^0;		//声明P2^0口接HX711时钟线
unsigned long HX711_Read(void)
{
	unsigned long count; 	//存ad值
	unsigned char i; 
  	HX711_DOUT = 1; 	//数据端口拉高,参照时序图写
	_nop_();		//延时
	_nop_();
  	HX711_SCK = 0; 		//时钟端口拉低
  	count = 0;		//ad值初始化
  	for(i=0; i<24; i++)		//循环24次传数据,按位接收数据
	{ 
	  	HX711_SCK = 1; 		//准备转换数据
	  	count = count << 1; 	//向左移位,即向低位补0,空出最低位进行传值操作,如1<<1为10
		HX711_SCK = 0; 		//时钟脉冲下降延,数据开始转换
	  	if(HX711_DOUT)
			count++; 		//数据端为高则最低位+1,为1,数据端为低则最低位不变,为0(左移把最低位空出)
	} 
 	HX711_SCK = 1; 		//第25个脉冲延
    count = count^0x800000;		//异或输出原码
	_nop_();
	_nop_();
	HX711_SCK = 0;		//结束ad转换
	return(count);		//传出ad值
}

ad值以二进制补码输出

在这里插入图片描述

这里用的是128倍增益A通道

在这里插入图片描述

三.LCD1602液晶显示模块原理

引脚说明

在这里插入图片描述

读写说明

在这里插入图片描述

写指令/数据时序图

在这里插入图片描述

1.写指令(发送写下的指令码给LCD1602并执行)

sbit LCD1602_RS = P3^5;
//sbit LCD1602_RW = P2^5;		//郭天祥51板LCDRW端直接接了地,故省略(就不能拉高不能读指令/数据操作)
sbit LCD1602_EN = P3^4;
void LCD1602_write_com(unsigned char com)		//声明指令参数
{
	LCD1602_RS = 0;
	Delay(10);
	LCD1602_EN = 1;
	P0 = com;		//生成指令
	Delay(10);
	LCD1602_EN = 0;
}

lcd1602指令表

在这里插入图片描述

2.写数据(把数据写入LCD1602并显示)

void LCD1602_write_data(unsigned char dat)		//声明数据参数
{
	LCD1602_RS = 1;
	Delay(10);	
	P0 = dat;		//生成数据
	LCD1602_EN = 1;
	Delay(10);
	LCD1602_EN = 0;
}

3.写连续字符(字符串)

void LCD1602_write_word(unsigned char *s)
{
	while(*s>0)
	{
		LCD1602_write_data(*s);		//写指针位置处字符数据
		s++;		//指针++指向连续字符下一个位置
	}
}

4.LCD1602初始化

void Init_LCD1602()
{
	LCD1602_EN = 0;
	//LCD1602_RW = 0;			//设置为写状态
	LCD1602_write_com(0x38);		//显示模式设定
	LCD1602_write_com(0x0c);		//开关显示、光标有无设置、光标闪烁设置
	LCD1602_write_com(0x06);		//写一个字符后指针加一
	LCD1602_write_com(0x01);		//清屏指令
}

四.电子秤整体实现原理

1.HX711模块与51单片机的通信(获取到重量电压信号ad值传给单片机)
2.51单片机与LCD1602的通信(在LCD1602上显示ad值转换为的实际重量)

以下是如何显示重量值

/*0x80为移动光标到显示屏第一行首位,+0x40是光标到第二行首位,再+0x09是光标再往后挪九格,指令表中可查*/
LCD1602_write_com(0x80+0x49);	
/*取千位具体数字值,+0x30表示将该数字值转为ASCII码表地址,例int a=8,ASCII码表中8的地址为0x38,即a+0x30*/	
LCD1602_write_data(Weight_Shiwu%10000/1000 + 0X30);	
		LCD1602_write_com(0x80+0x49);		//光标移动第二行第九个位置
		LCD1602_write_data(Weight_Shiwu%10000/1000 + 0X30);		//千位
        LCD1602_write_data(Weight_Shiwu%1000/100 + 0X30);		//百位
        LCD1602_write_data(Weight_Shiwu%100/10 + 0X30);		//十位
        LCD1602_write_data(Weight_Shiwu%10 + 0X30);		//个位
		LCD1602_write_word(" g");		//显示单位克

五.模块升级>>去皮与还原

1.首先理解去皮的含义:
假如你有一个梨,你想知道它的重量,看看卖家有没有坑你,以后能不能再到这买梨,
可你觉得秤太脏了,秤一下梨都没有食欲不想吃了,灵光突然一闪想到可以用一个碗垫着秤,
想法不错可问题就来了,碗的重量怎么办呢,这时去皮的意义就出来了
先把碗放在秤盘上,这时显示屏显示的是碗的重量,小手一抖按一下去皮键,
碗的重量就没有了,显示屏显示0,这下可以安心秤梨了

2.去皮如何实现:

	I/O口声明&变量声明
sbit key1 = P3^6;		//声明按键1(去皮键)具体I/O口和单片机型号有关
sbit key2 = P3^7;		//声明按键2(还原键)
unsigned long Weight_Shiwu = 0;		//无符号长型变量存实物重量
unsigned long Weight_Maopi = 0;		//毛皮重量(相当于碗的重量)

先判断去皮键是否被按下

void Keyscan()
{
	if(key1 == 0)
		Delay(10);		//消抖
	if(key1 == 0){
		Get_Maopi();		//获取毛皮重量(相当于碗的重量)
		while(!key1);		//松手检测
	}
}

去皮键按下后,就可以获取毛皮重量(碗重量)了

void Get_Maopi()
{
	Weight_Maopi = HX711_Read();		//把ad值获取到
	Weight_Maopi = (unsigned int)((float)Weight_Maopi/423.15); 		//换算成真正的毛皮重量
}

将按键扫描放在主函数while(1)死循环的最开始,去皮键按下才执行
去皮键未按下就直接称重,跳过去皮环节

while(1)
	{
		Keyscan();
		Get_Weight();
		
		/*............*/
		
void Get_Weight()
{
	Weight_Shiwu = HX711_Read();		//把ad值获取到
	Weight_Shiwu = (unsigned int)((float)Weight_Shiwu/423.15);			//换算成真正的实物重量
	Weight_Shiwu = Weight_Shiwu - Weight_Maopi;		//毛皮重量初始为0
}

3.如何还原去皮:
在按键扫描函数中再加一个还原按键
如果还原键按下,毛皮重量被初始化(置0)
就实现了还原去皮的效果

void Keyscan()
{
	if(key1 == 0)
		Delay(10);
	if(key1 == 0){
		Get_Maopi();
		while(!key1);
	}
	if(key2 == 0)
		Delay(10);
	if(key2 == 0){
		Weight_Maopi = 0;		//毛皮重量置0
		while(!key2);
	}
}

六.源代码及注释

#include<reg52.h>
#include <intrins.h>

/*I/O口声明*/
sbit LCD1602_RS = P3^5;
//sbit LCD1602_RW = P2^5;
sbit LCD1602_EN = P3^4;
sbit HX711_DOUT = P2^1; 
sbit HX711_SCK = P2^0;
sbit key1 = P3^6;
sbit key2 = P3^7;

/*全局变量定义*/
unsigned long Weight_Shiwu = 0;
unsigned long Weight_Maopi = 0;

/*函数声明*/
void Delay(unsigned int n);
void Init_LCD1602();
void LCD1602_write_com(unsigned char com);
void LCD1602_write_word(unsigned char *s);
void LCD1602_write_data(unsigned char dat);
unsigned long HX711_Read(void);
void Keyscan();
void Get_Maopi();
void Get_Weight();

int main()
{ 
	Init_LCD1602();		//LCD1602初始化
	LCD1602_write_com(0x80);		//移动光标到第一行首位
	LCD1602_write_word(" Dian Zi Cheng! ");		//显示 Dian Zi Cheng! 
	LCD1602_write_com(0x80 + 0x40);			//移动光标到第二行首位
	LCD1602_write_word("Weight :"),			//显示Weight :
	Delay(1000);		//1s延时
	while(1)
	{
		Keyscan();
		Get_Weight();	
			
		LCD1602_write_com(0x80+0x49);		//移动光标到第二行第九位
		LCD1602_write_data(Weight_Shiwu%10000/1000 + 0X30);		
        LCD1602_write_data(Weight_Shiwu%1000/100 + 0X30);
        LCD1602_write_data(Weight_Shiwu%100/10 + 0X30);
        LCD1602_write_data(Weight_Shiwu%10 + 0X30);
		LCD1602_write_word(" g");
	}
	return 0;
}

/*称实物重*/
void Get_Weight()
{
	Weight_Shiwu = HX711_Read();
	Weight_Shiwu = (unsigned int)((float)Weight_Shiwu/423.15);
	Weight_Shiwu = Weight_Shiwu - Weight_Maopi;
}

/*延时子函数*/
void Delay(unsigned int n)
{
	int i, j;
	for(i=0; i<n; i++)
		for(j=0; j<110; j++);
}

/*写指令*/
void LCD1602_write_com(unsigned char com)
{
	LCD1602_RS = 0;
	Delay(10);
	LCD1602_EN = 1;
	P0 = com;
	Delay(10);
	LCD1602_EN = 0;
}

/*写数据*/
void LCD1602_write_data(unsigned char dat)
{
	LCD1602_RS = 1;
	Delay(10);	
	P0 = dat;
	LCD1602_EN = 1;
	Delay(10);
	LCD1602_EN = 0;
}

/*写连续字符(字符串)*/
void LCD1602_write_word(unsigned char *s)
{
	while(*s>0)
	{
		LCD1602_write_data(*s);
		s++;
	}
}

/*初始化LCD1602*/
void Init_LCD1602()
{
	LCD1602_EN = 0;
	//LCD1602_RW = 0;
	LCD1602_write_com(0x38);
	LCD1602_write_com(0x0c);
	LCD1602_write_com(0x06);
	LCD1602_write_com(0x01);
}

/*获取ad值*/
unsigned long HX711_Read(void)
{
	unsigned long count; 
	unsigned char i; 
  	HX711_DOUT = 1; 
	_nop_();
	_nop_();
  	HX711_SCK = 0; 
  	count=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;
	_nop_();
	_nop_();
	HX711_SCK = 0;  
	return(count);
}

/*称毛皮重*/
void Get_Maopi()
{
	Weight_Maopi = HX711_Read();
	Weight_Maopi = (unsigned int)((float)Weight_Maopi/423.15); 
}

/*按键扫描*/
void Keyscan()
{
	if(key1 == 0)
		Delay(10);
	if(key1 == 0){
		Get_Maopi();
		while(!key1);
	}
	if(key2 == 0)
		Delay(10);
	if(key2 == 0){
		Weight_Maopi = 0;
		while(!key2);
	}
}

版权声明:本文为CSDN博主「可渡时光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51402855/article/details/115550023

生成海报
点赞 0

可渡时光

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

ESP8266 无限重启踩坑

最近做了一个电子墨水屏万年历,在移植屏幕代码时遇到了esp8266无限软复位的问题,如果你的串口打印是以下图片所示,那么恭喜你问题解决了。 造成软复位的原因是因为,程序里有死循环&#xf

趣聊51之串口通信(概念篇)

对于刚刚接触单片机的同学们来说,串口通信似乎是一个神秘感十足的东西,笔者在刚刚开始学习51单片机时,读的是郭天祥先生的那本著名的《新概念51单片机教程》,贼厚的一本书,但是等