2022.3——2022.5课设项目,电子小白入门作品

目录

一、各模块使用

LCD1602模块

矩阵按键模块

HC—05蓝牙模块

二、待改进之处

LCD1602模块

在项目后期使用IIC,省去了连一堆杜邦线的麻烦事。主要可操作的地方在于设置光标位置,清除功能。每行的范围事0-15一共16个格子,做到清除功能,用的是设置光标然后打印空格。一开始有考虑做滚屏功能,但后来发现用不上就没再深究。起初也是碰到了麻烦,滚屏我没法做到连续,这个日后解决。

下面是LCD1602寻找地址的代码。

#include <Wire.h> 
void setup(){
  Wire.begin();
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
void loop(){
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++ ){
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0){
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println(" !");
      nDevices++;
    }else if (error == 4){
      Serial.print("Unknow error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  delay(5000); // wait 5 seconds for next scan
}

矩阵按键模块

这个模块折磨了我非常长的时间,主要是刚入门啥也不懂。

android 电子秤 蓝牙连接 电子秤蓝牙怎么连_android 电子秤 蓝牙连接

自己当时看的电路图

这里主要是想能够让程序实时检测到按键的输入,就想着加入外部中断功能,arudino uno只有两个中断引脚,分别是pin2和pin3。我还去稍稍了解了下矩阵按键的工作原理,说是行(或列)置高电平,列(或行)置低电平,当按键按下时,对应的行/列会发生电平的变化,就能判断是哪个按键被按下。这个场景我现在还记得,上图中pin2对应的那列(即3 6 9 #)按下很少能触发中断程序,其他按键能正常触发中断程序。希望以后能力提升能明白为啥。

#include "Keypad.h"
const int ROWS = 4;
const int COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
//每次使用记得修改引脚
byte rowPins[ROWS] = {6,5,4,3};
byte colPins[COLS] = {A2,2,A1};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//uno 的两个中断引脚
int pinInterrupt1 = 2;
int pinInterrupt2 = 3;
void onChange()
{
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    Serial.println(key);
  }
}
void setup()
{
  Serial.begin(9600);
  pinMode( pinInterrupt1, INPUT);
  pinMode( pinInterrupt2, INPUT);
  //Enable中断管脚, 中断服务程序为onChange(), 监视引脚变化
  attachInterrupt(digitalPinToInterrupt(pinInterrupt1), onChange, CHANGE);
  attachInterrupt(digitalPinToInterrupt(pinInterrupt2), onChange, CHANGE);
}
void loop()
{
  //模拟长时间运行的进程/复杂的任务。
  for (int i = 0; i < 100; i++)
  {
    delay(20);
  }
}

在后来又找到个解决方法,参考了个老哥的文章[Arduino 库] 适用于 Arduino Uno 的多任务调度程序 – Blanboom,使用多线程任务来解决,就是不停在检测是否有按键输入?后来我又看到定时中断,以后试试。

HC—05蓝牙模块

这个模块关键是先进入AT模式,再就是上传时记得拔掉TX和RX引脚。和按键的操作逻辑稍有不同,以后深入使用时记得改成能直接调用按键那些代码。

二、待改进之处

1矩阵按键原理部分

现在能力不够,还不太能看懂矩阵按键库的代码,也就没法解决为什么3*4按键和列引脚相连的那列按键很难触发中断程序,而其他却可以。

2代码冗长/难理解

代码中出现了很多那种只是保存一个Event的变量,少了还好,多了可能就让人很难读懂,还有就是写代码时确实花费了比较长时间,现在代码水平很低,又臭又长....看以后编程能力提升后能不能简洁一点。

//引用库函数
#include "Keypad.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "TaskScheduler.h"

//LCD1602设备地址
LiquidCrystal_I2C lcd(0x27, 16, 2);

///函数声明
extern unsigned long HX711_Read(void);
extern long Get_Weight();
void Origin();
void Enter_Mode();
void BlueToothKey();
void Buzzer();
void LcdPrint(float a);
void Pin_init();
void Blue_Tooth();
void Weight_only();
void Weight_price();

///变量定义
const int ROWS = 4;
const int COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2};
byte colPins[COLS] = { A0, A1, A2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

float WeighNor = 0; //Weight when Normal
float Weight = 0;
float Display; //储存当前屏幕显示的是WeighNor还是Weight
float normal = 0; // normal event
static int event = 1; //judge Normal or Zero event
double val;//Val per kg
double Value;//store value above
int cnt1;
int cnt2;//To confirm the position of the .
int Event;//First or Second press #
int Mode;//Switch Mode
int buzzer = 13;
int HX711_SCK = 6;  ///     作为输出口
int HX711_DT = 7;   ///     作为输入口
long HX711_Buffer = 0;
long Weight_Maopi = 0, Weight_Shiwu = 0;
#define GapValue 399     ///该值需校准 每个传感器都有所不同

void setup()
{
  lcd.init();
  lcd.backlight();
  Pin_init();
  Serial.begin(38400);
  Serial.print("Welcome to use!\n");
  delay(1500);
  Sch.init();
  //添加任务,多线程
  Sch.addTask(Origin, 0, 100, 1);
  Sch.addTask(BlueToothKey, 0, 10, 1);
  //优先抢断
  Sch.addTask(Enter_Mode, 10, 10, 0);
  //启动任务调度器
  Sch.start();
  //获取毛皮重量
  Weight_Maopi = HX711_Read();
  Weight = Get_Weight();
}

void loop()
{
  Sch.dispatchTasks();
}

///ALL_Function
//Origin loop function
void Origin()
{
  Buzzer();
  Blue_Tooth();
  if (Mode)Weight_only();
  if (!Mode)Weight_price();
  Weight = Get_Weight();//计算放在传感器上的重物重量
  WeighNor = Get_Weight() + normal;
}

//变量定义
//==============================================
int BlueKey_Event;//进入BlueToothKey中if的判断条件
int BlueKey;//储存蓝牙发送的信息
//==============================================

void BlueToothKey()
{
  if (BlueKey_Event)
  {
    BlueKey_Event = !BlueKey_Event;

    if (BlueKey == '#' )
    {
      if (!Event) Serial.println("-----Enter_Mode:Begin-----");
      if (Event && cnt2 != 0)
      {
        val = val / pow(10, cnt1 - cnt2);
        Value = val;
      }
      val = 0;
      cnt1 = 0;
      cnt2 = 0;
      Event = !Event;
    }
    else if (Event)
    {
      cnt1++;
      if (BlueKey != '*')
      {
        Serial.print(BlueKey);
        val = val * 10 + BlueKey - 48;
        Value = val;
      }
      else if (BlueKey == '*')
      {
        Serial.print(".");
        cnt2 = cnt1;
      }
    }
  }
}

//Enter_Mode
void Enter_Mode()
{
  char key = keypad.getKey();
  static int sign;
  if (key != NO_KEY )
  {
    if ((int)val == 2580) Mode = !Mode;
    //Zero and Normal
    if (key == '*') sign++;
    if (sign == 3 && event == 1)
    {
      normal = Display; //把当前屏幕读取的数值给normal
      Weight_Maopi = HX711_Read();
      Serial.println("Zero");
      sign = 0;
      event = 0;
    }
    if (sign == 3 && event == 0)
    {
      Weight += normal;
      Serial.println("Normal");
      sign = 0;
      event = 1;
    }

    //Enter Value
    if (key == '#' )
    {
      if (!Event) Serial.println("-----Enter_Mode:Begin-----");
      if (Event && cnt2 != 0) {
        val = val / pow(10, cnt1 - cnt2);
        Value = val;
      }
      val = 0;
      cnt1 = 0;
      cnt2 = 0;
      Event = !Event;
    }
    else if (Event)
    {
      cnt1++;
      if (key != '*') {
        Serial.print(key);
        val = val * 10 + key - 48;
        Value = val;
      }
      else if (key == '*') {
        Serial.print(".");
        cnt2 = cnt1;
      }
    }
  }
}

//Weigh function
long Get_Weight()
{
  HX711_Buffer = HX711_Read();    ///读取此时的传感器输出值
  Weight_Shiwu = HX711_Buffer;     ///将传感器的输出值储存
  Weight_Shiwu = Weight_Shiwu - Weight_Maopi; //获取实物的AD采样数值。
  Weight_Shiwu = (long)((float)Weight_Shiwu / GapValue);  //AD值转换为重量(g)
  return Weight_Shiwu;
}

unsigned long HX711_Read(void) //选择芯片工作方式并进行数据读取
{
  unsigned long count;   ///储存输出值
  unsigned char i;

  digitalWrite(HX711_DT, HIGH);    // digitalWrite作用: DT=1;
  delayMicroseconds(1);
  digitalWrite(HX711_SCK, LOW);    //digitalWrite作用: SCK=0;
  delayMicroseconds(1);
  count = 0;
  while (digitalRead(HX711_DT));   //当DT的值为1时,开始ad转换
  for (i = 0; i < 24; i++) ///24个脉冲,对应读取24位数值
  {
    digitalWrite(HX711_SCK, HIGH);   // digitalWrite作用: SCK=0;
    /// 利用 SCK从0--1 ,发送一次脉冲,读取数值
    delayMicroseconds(1);
    count = count << 1; ///用于移位存储24位二进制数值
    digitalWrite(HX711_SCK, LOW);    //digitalWrite作用: SCK=0;为下次脉冲做准备
    delayMicroseconds(1);
    if (digitalRead(HX711_DT))   ///若DT值为1,对应count输出值也为1
      count++;
  }
  digitalWrite(HX711_SCK, HIGH);    ///再来一次上升沿 选择工作方式  128增益
  count ^= 0x800000;   //按位异或  不同则为1   0^0=0; 1^0=1;
  ///对应二进制  1000 0000 0000 0000 0000 0000  作用为将最高位取反,其他位保留原值
  delayMicroseconds(1);
  digitalWrite(HX711_SCK, LOW);
  delayMicroseconds(1);
  return (count);
}

//Buzzer
void Buzzer() {
  if (float(Weight / 1000) > 10.0)
  {
    digitalWrite(buzzer, HIGH);
    delay(20);
    lcd.setCursor(0, 1);
    lcd.print("Overload");
    lcd.setCursor(0, 1);
    lcd.print("        ");//clear "Overload"
  }
  else if (float(Weight / 1000) < 10.0)
  {
    digitalWrite(buzzer, LOW);
    delay(10);
  }
}
//Pin_init
void Pin_init() {
  pinMode(buzzer, OUTPUT); //buzzer
  pinMode(HX711_SCK, OUTPUT);  //SCK 为输出口 ---输出脉冲
  pinMode(HX711_DT, INPUT); //DT为输入口 ---读取数据
}

//Display and Serialprint
void LcdPrint(float a) {
  Serial.print(float(a / 1000), 3); //串口显示重量,3意为保留三位小数
  Serial.print(" kg\n");
  Serial.print("\n");
  lcd.setCursor(0, 0);
  lcd.print(float(a / 1000), 3);
  lcd.print("      ");//清除多余数字
  lcd.setCursor(7, 0);
  lcd.print("kg");
  Display = a;
}

//BlueTooth
void Blue_Tooth() {
  while (Serial.available())
  {
    delay(100);//保证串口字符接收完毕
    char c = Serial.read(); //一次只读一个字符,读完删除
    switch (c) {
      case 'z':
        Serial.write("State: Zero");
        normal = Display; //把当前屏幕读取的数值给normal
        Weight_Maopi = HX711_Read();
        event = 0;
        break;
      case 'n':
        Serial.write("State: Normal");
        Weight += normal;
        event = 1;
        break;
      case 'a':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '#';
        break;
      case 'b':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '#';
        break;
      case 'c':
        Mode = !Mode;
        break;
      case 'd':
        Mode = !Mode;
        break;
      case '0':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '0';
        break;
      case '1':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '1';
        break;
      case '2':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '2';
        break;
      case '3':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '3';
        break;
      case '4':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '4';
        break;
      case '5':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '5';
        break;
      case '6':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '6';
        break;
      case '7':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '7';
        break;
      case '8':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '8';
        break;
      case '9':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '9';
        break;
      case '.':
        BlueKey_Event = !BlueKey_Event;
        BlueKey = '*';
        break;
    }
    ///对应功能
    /*
       zero---z
       normal---n
       price input---a
       confirm---b
       Mode Weight---c
       Mode Price---d
    */
  }
}


void Weight_only() {
  lcd.clear();
  if (event == 0)
  {
    lcd.setCursor(9, 1);
    lcd.print("      ");//clear "Normal"
    lcd.setCursor(12, 1);
    lcd.print("Zero");
    LcdPrint(Weight);
  } else if (event == 1) {
    lcd.setCursor(10, 1);
    lcd.print("Normal");
    LcdPrint(WeighNor);
  }
}

void Weight_price()
{
  if (event == 0)
  {
    lcd.setCursor(9, 1);
    lcd.print("      ");//clear "Normal"
    lcd.setCursor(12, 1);
    lcd.print("Zero");
    LcdPrint(Weight);
    lcd.setCursor(0, 1);
    lcd.print("          ");
    lcd.setCursor(0, 1);
    lcd.print("Val:");
    lcd.print((Weight / 1000) * Value, 1);
    lcd.setCursor(10, 0);
    lcd.print(Value);
    lcd.setCursor(9, 0);
    lcd.print("/");
  }
  else if (event == 1)
  {
    lcd.setCursor(10, 1);
    lcd.print("Normal");
    LcdPrint(WeighNor);
    lcd.setCursor(0, 1);
    lcd.print("          ");
    lcd.setCursor(0, 1);
    lcd.print("Val:");
    lcd.print((WeighNor / 1000) * Value, 1);
    lcd.setCursor(10, 0);
    lcd.print(Value);
    lcd.print("      ");
    lcd.setCursor(9, 0);
    lcd.print("/");
  }
}

3电路板绘制

怎么把这些元件安装起来也是个事,杜邦线一堆一堆很不稳定,在一开始其实不知道PCB是干啥的,慢慢看了些视频后慢慢觉得这个项目加个PCB也许会更简洁一些。看这两天学着画一个出来。画是画出来了,但画的时候出了一堆问题,第一是不知道我想要的元件去哪里找,二是我在标注的时候是一个个打上去的,感觉很麻烦,三是目前布线可以说是没有经验,又慢又难看,最后直接用了自动布线。