功能演示
基于stm32的智能电子称
简介
这是最近别人让我帮他做的一个毕业设计,总体来说非常简单,半天都不需要就可以实现,我做完之后,打算开源在这里让大家进行学习,我们先看一下他的任务书吧:
主要内容与基本要求:
本设计采用单片机作为主控制芯片,通过按键和微型屏幕来实现人机交互。同时可以通过无线通讯模块来实现信息的传递。本课题的主要研究内容如下:
- 收集并阅读相关资料,确定系统的总体设计方案。
- 硬件系统的设计:包括单片机最小开发板、液晶显示模块、压力传感器、蓝牙模块ADC模块等。
- 在软件的编程方面采用C语言作为系统程序语言。
- 系统实物体的制作以及相关的调试,要求整个系统完整并且稳定运行。
基本要求如下:
- 按键结合液晶屏幕,实现按键切换功能。
- 用蓝牙模块控制实现系统相关参数的设置。
- 液晶屏显示功能提醒词、系统的状态、已设置的参数等。
- 实现压力传感器的数据采集。
- 实现读取重量的功能并通过液晶屏幕显示
- 超过最大重量报警
硬件资料
序号 | 元器件 | 型号 | 数量 |
# | Description | Comment | Quantity |
1 | STM32F103C8T6最小系统板 | / | 1 |
2 | 0.96寸OLED屏幕 | / | 1 |
3 | 语音播报模块 | JQ8900-16P | 1 |
4 | 喇叭 | 8欧3W喇叭 | 1 |
5 | 4.7K电阻 | 0603R | 1 |
6 | 三极管 | SS8050 | 1 |
7 | 有源蜂鸣器 | BUZ-TH_BD12.0 | 1 |
8 | 按键 | SW-TH_4P | 4 |
9 | 主从一体蓝牙模块 | HC-05 | 1 |
10 | PM254-1-08-Z-8.5 | HDR-TH_8P-P2.54 | 2 |
11 | PM254-1-04-Z-8.5 | HDR-TH_4P-P2.54 | 2 |
12 | PM254-1-02-Z-8.5 | HDR-TH_2P-P2.54 | 1 |
13 | Type-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里面,这个项目就可以轻而易举的复刻出来了,希望我这篇文章可以帮助到你,如果需要完整的工程,可以私信我。