基于stm32的智能电子称(开源)

功能演示

 

基于stm32的智能电子称

简介

这是最近别人让我帮他做的一个毕业设计,总体来说非常简单,半天都不需要就可以实现,我做完之后,打算开源在这里让大家进行学习,我们先看一下他的任务书吧:

主要内容与基本要求:

本设计采用单片机作为主控制芯片,通过按键和微型屏幕来实现人机交互。同时可以通过无线通讯模块来实现信息的传递。本课题的主要研究内容如下:

  1. 收集并阅读相关资料,确定系统的总体设计方案。
  2. 硬件系统的设计:包括单片机最小开发板、液晶显示模块、压力传感器、蓝牙模块ADC模块等。
  3. 在软件的编程方面采用C语言作为系统程序语言。
  4. 系统实物体的制作以及相关的调试,要求整个系统完整并且稳定运行。

基本要求如下:

  1. 按键结合液晶屏幕,实现按键切换功能。
  2. 用蓝牙模块控制实现系统相关参数的设置。
  3. 液晶屏显示功能提醒词、系统的状态、已设置的参数等。
  4. 实现压力传感器的数据采集。
  5. 实现读取重量的功能并通过液晶屏幕显示
  6. 超过最大重量报警

 硬件资料

序号元器件型号数量
#DescriptionCommentQuantity
1STM32F103C8T6最小系统板/1
20.96寸OLED屏幕/1
3语音播报模块JQ8900-16P1
4喇叭8欧3W喇叭1
54.7K电阻0603R1
6三极管SS80501
7有源蜂鸣器BUZ-TH_BD12.01
8按键SW-TH_4P4
9主从一体蓝牙模块HC-051
10PM254-1-08-Z-8.5HDR-TH_8P-P2.542
11PM254-1-04-Z-8.5HDR-TH_4P-P2.542
12PM254-1-02-Z-8.5HDR-TH_2P-P2.541
13Type-c充电线/1

PCB图以及原理图

 

 

软件分析

工程文件

Start:存放stm32配置的起始文件、内核相关文件、系统文件。

Library:存放stm32f103的标准库文件。

User:存放用户文件。

Hardware:存放硬件文件,包括蜂鸣器、HX711、OLED、JQ8900......

System:存放用户写的一些系统文件,例如延时、时钟配置、相关宏定义。

 软件流程

1、各模块初始化

Key_Init();//按键初始化

Buzzer_Init();//蜂鸣器初始化

OLED_Init();//oled初始化

Serial_Init();//蓝牙串口初始化

HX711_Init();//HX711初始化

Interface_Init();//接口初始化(屏幕初始化,显示对应内容)

JQ8900_Init();//语音模块初始化

2、初始化模块状态

HX711_SetTareWeight();//开机默认去皮一次

JQ8900_SetVolume(15);//设置音量为15

3、检测蓝牙模块是否发送消息(如果搜到消息,将消息转换成按键值,之后在进行对应按键按下的处理)

if(Serial_GetRxFlag())

{

Key_Num = Serial_GetRxData();

}

4、 扫描按键(根据按键设置对应的键值,之后进行对应按键按下的处理)

Key_Num = Key_GetNum(); //扫描按键

 5、检测是否超出电子称的最大重量

if(HX711_ReadCount()>Weight_Max) //超过设定的最大重量

{

//显示超重界面

OLED_Clear();

OLED_ShowF16x16(1,7,26);//警告

OLED_ShowF16x16(1,9,27);

OLED_ShowF16x16(2,3,28);//超出最大重量

OLED_ShowF16x16(2,5,29);

OLED_ShowF16x16(2,7,30);

OLED_ShowF16x16(2,9,31);

OLED_ShowF16x16(2,11,32);

OLED_ShowF16x16(2,13,33);

OLED_ShowF16x16(4,1,34);//请按下返回键返回

OLED_ShowF16x16(4,3,35);

OLED_ShowF16x16(4,5,36);

OLED_ShowF16x16(4,7,37);

OLED_ShowF16x16(4,9,38);

OLED_ShowF16x16(4,11,39);

OLED_ShowF16x16(4,13,37);

OLED_ShowF16x16(4,15,38);

while(Key_GetNum()!='4');

OLED_Clear();

Interface_Init();//接口初始化(屏幕初始化,显示对应内容)

}

//如果超过最大重量,显示提醒界面,等待按下返回键回到正常界面

6、刷新重量,并时刻根据商品类型刷新价格来显示在oled上 

Weight = HX711_Get_Weight(); //称重

Show_Weight(); //显示重量

Price = Commdoity_Price[Commodity_Num]*Weight;

lprice = (uint32_t)Price;

OLED_ShowNum(4,6,lprice,4);

7、根据按下的键值或者蓝牙模块发来的命令,进行对应事件的处理

if(Key_Num == '1') //去皮

{

Key_Num = 0;

JQ8900_Play(2);

HX711_SetTareWeight();

Show_States(1); //显示 状态 去皮

Delay_s(1);

Show_States(0); //显示 状态 称重

}

else if(Key_Num == '2') //切换商品

{

Key_Num = 0;

JQ8900_Play(1);

(Commodity_Num == CNUM-1)?(Commodity_Num = 0):(Commodity_Num++);

Show_Commodity(Commodity_Num);

}

else if((Key_Num >= 'a') && (Key_Num <= 'f')) //蓝牙直接切换到某商品

{

Commodity_Num = Key_Num - 'a';

Show_Commodity(Commodity_Num);

}

else if(Key_Num == '3') //打印账单

{

JQ8900_Play(3);

Key_Num = 0;

Buzzer_ON();

Delay_ms(500);

Buzzer_OFF();

Serial_SendCommodity(Commodity_Num);

Serial_SendString("0.");

Serial_SendNumber(Commdoity_Price[Commodity_Num]*100,2);

Serial_SendString("yuan/gram\n");

Serial_SendString("Bying ");

Serial_SendNumber(Weight,4);

Serial_SendString("gram and costing ");

Serial_SendNumber(lprice,3);

Serial_SendByte('.');

Serial_SendNumber(rprice,2);

Serial_SendString("yuan\n");

}

 

具体源码 

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Key.h"
#include "Buzzer.h"
#include "OLED.h"
#include "Serial.h"
#include "HX711.h"
#include "JQ8900.h"

#define Weight_Max 1000   //最大称重质量为5kg,这里不取到满,留一点缓冲
#define CNUM 6		//商品个数

uint8_t Key_Num, Commodity_Num;			//键码
uint32_t Weight;	//皮重,重量
float Price;			//多少钱一克,价格
float Commdoity_Price[CNUM] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6};	//对应每种商品单价
uint32_t Weight_last;//去皮之前的重量

void Show_States(uint8_t num);
void Interface_Init(void);
void Show_Commodity(uint8_t num);
void Show_Weight(void);
void Serial_SendCommodity(uint8_t num);

int main(void)
{
	uint32_t lprice=0, rprice;
	
	Key_Init();//按键初始化
	Buzzer_Init();//蜂鸣器初始化
	OLED_Init();//oled初始化
	Serial_Init();//蓝牙串口初始化
	HX711_Init();//HX711初始化
	Interface_Init();//接口初始化(屏幕初始化,显示对应内容)
	JQ8900_Init();//语音模块初始化
	
	HX711_SetTareWeight();//开机默认去皮一次
	JQ8900_SetVolume(25);//设置音量为15
	while (1)
	{
		if(Serial_GetRxFlag())
		{
			Key_Num = Serial_GetRxData();
		}
		else
		{
			Key_Num = Key_GetNum();			//扫描按键
		}
		if(HX711_Get_Weight()>Weight_Max-Weight_last) //超过设定的最大重量
		{
			//显示超重界面
			OLED_Clear();
			OLED_ShowF16x16(1,7,26);//警告
			OLED_ShowF16x16(1,9,27);
			
			OLED_ShowF16x16(2,3,28);//超出最大重量
			OLED_ShowF16x16(2,5,29);
			OLED_ShowF16x16(2,7,30);
			OLED_ShowF16x16(2,9,31);
			OLED_ShowF16x16(2,11,32);
			OLED_ShowF16x16(2,13,33);
			
			OLED_ShowF16x16(4,1,34);//请按下返回键返回
			OLED_ShowF16x16(4,3,35);
			OLED_ShowF16x16(4,5,36);
			OLED_ShowF16x16(4,7,37);
			OLED_ShowF16x16(4,9,38);
			OLED_ShowF16x16(4,11,39);
			OLED_ShowF16x16(4,13,37);
			OLED_ShowF16x16(4,15,38);
			
			while(Key_GetNum()!='4');
			OLED_Clear();
			Interface_Init();//接口初始化(屏幕初始化,显示对应内容)
			
		}
		
		Weight = HX711_Get_Weight();	//称重
		Show_Weight();					//显示重量
		
		Price = Commdoity_Price[Commodity_Num]*Weight;
		lprice = (uint32_t)Price;
		OLED_ShowNum(4,6,lprice,4);
		
		if(Key_Num == '1')	//去皮
		{
			Key_Num = 0;
			JQ8900_Play(1);	
			Weight_last=HX711_Get_Weight();//获取此时的重量
			HX711_SetTareWeight();
			Show_States(1);		//显示 状态 去皮
			Delay_s(1);
			Show_States(0);		//显示 状态 称重
			
		}
		else if(Key_Num == '2')	//切换商品
		{
			Key_Num = 0;
			JQ8900_Play(2);
			(Commodity_Num == CNUM-1)?(Commodity_Num = 0):(Commodity_Num++);
			Show_Commodity(Commodity_Num);
		}
		else if((Key_Num >= 'a') && (Key_Num <= 'f'))	//蓝牙直接切换到某商品
		{
			Commodity_Num = Key_Num - 'a';
			Show_Commodity(Commodity_Num);
		}
		else if(Key_Num == '3')	//打印账单
		{
			JQ8900_Play(3);	
			Key_Num = 0;
			Buzzer_ON();
			Delay_ms(500);
			Buzzer_OFF();
			Serial_SendCommodity(Commodity_Num);
			Serial_SendString("0.");
			Serial_SendNumber(Commdoity_Price[Commodity_Num]*100,2);
			Serial_SendString("yuan/gram\n");
			
			Serial_SendString("Bying ");
			Serial_SendNumber(Weight,4);
			Serial_SendString("gram and costing ");
			Serial_SendNumber(lprice,3);
			Serial_SendByte('.');
			Serial_SendNumber(rprice,2);
			Serial_SendString("yuan\n");
			
		}

		Delay_ms(50);
	}
}

void Interface_Init(void)
{
	OLED_ShowF16x16(1,1,13);	//状
	OLED_ShowF16x16(1,3,14);	//态
	OLED_ShowChar(1,5,':');
	Show_States(0);
	
	OLED_ShowF16x16(2,1,17);	//重
	OLED_ShowF16x16(2,3,18);	//量
	OLED_ShowChar(2,5,':');
	OLED_ShowF16x16(2,10,19);	//克
	
	Show_Commodity(Commodity_Num);
	OLED_ShowChar(3,5,':');
	OLED_ShowF16x16(3,10,0);	//元
	OLED_ShowChar(3,12,'/');
	OLED_ShowF16x16(3,13,19);	//克
	
	OLED_ShowF16x16(4,1,22);	//价
	OLED_ShowF16x16(4,3,23);	//格
	OLED_ShowChar(4,5,':');
	OLED_ShowF16x16(4,10,0);	//元
}

void Show_States(uint8_t num)
{
	
	switch(num){
		case 0:
			OLED_ShowF16x16(1,7,20);	//称
			OLED_ShowF16x16(1,9,17);	//重
			break;
		case 1:
			OLED_ShowF16x16(1,7,15);	//去
			OLED_ShowF16x16(1,9,16);	//皮
			break;
		case 2:
			OLED_ShowF16x16(1,7,21);	//计
			OLED_ShowF16x16(1,9,22);	//价
			break;
	}
	
}

void Show_Commodity(uint8_t num)
{
	uint8_t i;
	switch(num){
		case 0:
			OLED_ShowF16x16(3,1,1);	//苹
			OLED_ShowF16x16(3,3,2);	//果
		
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
			
			break;
		case 1:
			OLED_ShowF16x16(3,1,3);	//香
			OLED_ShowF16x16(3,3,4);	//蕉
		
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
		
			break;
		case 2:
			OLED_ShowF16x16(3,1,5);	//橘
			OLED_ShowF16x16(3,3,6);	//子
					
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
		
			break;
		case 3:
			OLED_ShowF16x16(3,1,7);	//葡
			OLED_ShowF16x16(3,3,8);	//萄
					
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
		
			break;
		case 4:
			OLED_ShowF16x16(3,1,9);	//菠
			OLED_ShowF16x16(3,3,10);	//萝
					
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
		
			break;
		case 5:
			OLED_ShowF16x16(3,1,11);	//西
			OLED_ShowF16x16(3,3,12);	//瓜
					
			i = (uint8_t)Commdoity_Price[num];
			OLED_ShowNum(3,6,i,1);
			OLED_ShowChar(3,7,'.');
			OLED_ShowNum(3,8,(uint8_t)((Commdoity_Price[num]-i)*100),2);
		
			break;
	}
	
}

void Show_Weight(void)
{
	OLED_ShowNum(2,6,Weight,4);
}

void Serial_SendCommodity(uint8_t num)
{
	switch(num){
		case 0:
			Serial_SendString("apple ");
			break;
		case 1:
			Serial_SendString("banana ");
			break;
		case 2:
			Serial_SendString("orange ");
			break;
		case 3:
			Serial_SendString("grape ");
			break;
		case 4:
			Serial_SendString("pineapple ");
			break;
		case 5:
			Serial_SendString("watermelon ");
			break;
	}
}

总结

其实你只要学过一点stm32,以上资料完全够你手动复刻,去购买我硬件清单的对应模块,然后找到商家要驱动代码,移植到你的工程,然后调用相应的函数到我给你的main.c里面,这个项目就可以轻而易举的复刻出来了,希望我这篇文章可以帮助到你,如果需要完整的工程,可以私信我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/909678.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

写过的试卷怎么打印出新的?

当您有一份已经完成的试卷&#xff0c;但又需要重新打印一份全新的试卷时&#xff0c;这似乎是一个令人头疼的问题。不用担心&#xff0c;这里为您介绍一种简便的方法——利用“扫描”或“试卷还原”的软件&#xff0c;通过拍照的方式&#xff0c;将试卷上的答案清除&#xff0…

【51单片机】串口通信原理 + 使用

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 串口硬件电路UART串口相关寄存器 编码单片机通过串口发送数据电脑通过串口发送数据控制LED灯 串口 串口是一种应用十分广泛的通讯接…

动态规划 —— dp 问题-打家劫舍II

1.打家劫舍II 题目链接&#xff1a; 213. 打家劫舍 II - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/house-robber-ii/ 2. 题目解析 通过分类讨论&#xff0c;将环形问题转换为两个线性的“打家劫舍|” 当偷第一个位置的时候&#xff0c;rob1在&#…

开车去内蒙古旅游要做什么准备?

一、车辆选择与准备 车辆类型&#xff1a; 尽量选择越野车或SUV&#xff0c;这类车辆底盘高、通过性好&#xff0c;适合草原、沙漠等复杂地形。车辆检查&#xff1a; 出发前全面检查车辆&#xff0c;包括轮胎、刹车系统、发动机等&#xff0c;确保车辆状态良好。冬季出行需特别…

【题解】—— LeetCode一周小结44

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结43 28.冗余连接 II 题目链接&#xff1a;685. 冗余连接 II 在…

视频Qoe测量学习笔记(一)

目录 流媒体协议详解 RTSP&#xff1a;实时流式协议 RTCP&#xff1a;实时运输控制协议 RTP&#xff1a;实时运输协议 H.264 流媒体协议详解 RTSP&#xff1a;实时流式协议 由IETF MMusic小组开发&#xff0c;已成为互联网建议标准[RFC 2326]。RTSP本身并不传送数据&…

使用Spring Validation实现数据校验详解

目录 前言1. Spring Validation概述2. 配置Spring Validation2.1 引入依赖2.2 启用全局校验 3. 使用注解进行参数校验3.1 基本校验注解3.2 使用Pattern进行正则校验3.3 综合示例 4. 在控制器层应用校验4.1 方法参数校验4.2 自定义错误处理 5. 高级应用&#xff1a;自定义校验注…

解决阿里云三个月证书过期 免费SSL证书部署教程

相信有上线过自己的网站、小程序经验的同学深有体会&#xff0c;给服务加上 SSL 证书还挺麻烦的&#xff0c;尤其是没有运维经验的同学。本来最省事的方法是买个证书&#xff0c;但是一看价格&#xff0c;还是算了吧&#xff0c;动辄就是几万块一年。作为个人来说&#xff0c;这…

简单走近ChatGPT

目录 一、ChatGPT整体背景认知 &#xff08;一&#xff09;ChatGPT引起关注的原因 &#xff08;二&#xff09;与其他公司的竞争情况 二、NLP学习范式的发展 &#xff08;一&#xff09;规则和机器学习时期 &#xff08;二&#xff09;基于神经网络的监督学习时期 &…

恢复Ubuntu+Windows10双系统安装前状态及分区还原详细步骤

1、恢复到安装 Ubuntu 之前的状态&#xff0c;先看看系统属性 2、选择 运行 3、 输入 msinfo32 回车 4、注意查看 BIOS 模式这一栏&#xff0c;UEFI&#xff0c;这里我们以UEFI系统为例 5、下来就可以开始进行 Ubuntu 的移除操作了 6、从Windows打开网页搜索磁盘精灵&#xff0…

一文搞定 InternStudio 开发机的使用 | 书生大模型

文章目录 创建开发机使用 SSH 远程连接开发机使用密码进行 SSH 远程连接使用 VScode 进行 SSH 远程连接 端口映射核心目标开发机端口映射的工作方式使用 VScode 进行端口映射运行 hello_world.py 代码进行测试测试成功页面 参考文献 创建开发机 InternStudio控制台 这里先做测…

WindowsDocker安装到D盘,C盘太占用空间了。

Windows安装 Docker Desktop的时候,默认位置是安装在C盘,使用Docker下载的镜像文件也是保存在C盘,如果对Docker使用评率比较高的小伙伴,可能C盘空间,会被耗尽,有没有一种办法可以将Docker安装到其它磁盘,同时Docker的数据文件也保存在其他磁盘呢? 答案是有的,我们可以…

关于我、重生到500年前凭借C语言改变世界科技vlog.15——深入理解指针(4)

文章目录 1.回调函数的介绍2. qsort使用实例2.1 qsort函数介绍2.2使用 qsort 函数排序整型数据2.3使用 qsort 排序结构数据 3. qsort的模拟实现希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01; 1.回调函数的介绍 回调函数就是一个通过函数指针调用…

内网项目,maven本地仓库离线打包,解决Cannot access central in offline mode?

背景&#xff1a; 内网项目打包&#xff0c;解决Cannot access central in offline mode? 1、修改maven配置文件&#xff1a; localRepository改为本地仓库位置 <localRepository>D:\WorkSpace\WorkSoft\maven-repository\iwhalecloud-repository\business</loca…

笔记整理—linux驱动开发部分(8)framebuffer类设备

framebuffer显示设备。 在应用层直接抽象位向DDR中存放图片。 在操作系统中&#xff0c;将上图分为两个部分&#xff1a;驱动应用。 使用复制的方法效率十分的低&#xff0c;所以有了内存映射方法实现图片的显示。 framebuffer帧&#xff08;铺满一个屏幕&#xff09;&#xff…

第三十章 章节练习商品列表组件封装

目录 一、需求说明 二、技术要点 三、完整代码 3.1. main.js 3.2. App.vue 3.3. MyTable.vue 3.4. MyTag.vue 一、需求说明 1. my-tag 标签组件封装 (1) 双击显示输入框&#xff0c;输入框获取焦点 (2) 失去焦点&#xff0c;隐藏输入框 (3) 回显标签信息 (4) 内…

EHOME视频平台EasyCVR萤石设备视频接入平台视频诊断技术可以识别哪些视频质量问题?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。萤石设备视频接入平台EasyCVR不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能&#xff0c;还支持多种主流标准协议&#xff0c;如GB28181、GB35114、RTSP/Onvif…

如何在 PyQt 中启动“绘图循环”?

在 PyQt 中实现一个“绘图循环”可以使用 定时器&#xff08;QTimer&#xff09;&#xff0c;让应用程序在指定的时间间隔内反复触发一个绘图函数。这种方法对于需要持续更新绘图&#xff08;例如动画效果&#xff09;的情况特别有用。 1、问题背景 在GUI编程中&#xff0c;我…

Linux 线程控制

一. 线程互斥 1.1 线程互斥相关概念 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源。临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区。互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临界区&…

分布式光伏发电的投融资计算

分布式光伏发电项目的成功实施离不开科学、合理的投融资计算&#xff0c;为光伏项目的前期开发提供切实可行的依据。 一、分布式光伏发电项目的投资成本 分布式光伏发电项目的投资成本包括多个方面&#xff0c;主要包括光伏组件采购成本、逆变器和支架系统成本、安装和施工成本…