当前位置:   article > 正文

【雕爷学编程】Arduino 手册之数学运算 fma()_arduino矩阵相乘

arduino矩阵相乘

在这里插入图片描述
在这里插入图片描述
什么是Arduino?
Arduino 是一款开源的电子原型平台,它可以让你用简单的硬件和软件来创建各种创意的项目。无论你是初学者还是专家,Arduino 都能为你提供无限的可能性。你可以用 Arduino 来控制传感器、灯光、马达、机器人、物联网设备等等,只要你能想到的,Arduino 都能帮你实现。

如果你想了解更多关于 Arduino 的信息,你可以访问 Arduino 的官方网站,那里有丰富的资源和教程供你参考。你也可以加入 Arduino 的社区,和来自世界各地的爱好者、学生、设计师和工程师交流心得和经验。此外,你还可以使用 Arduino 的在线编程工具,在云端编写代码并上传到你的开发板上。

Arduino 是一个不断发展和创新的平台,它有着广泛的应用领域和潜力。这里希望本手册能激发你对 Arduino 的兴趣和热情,让你享受 Arduino 带来的创造力和乐趣

在这里插入图片描述

维基百科的定义
Arduino 是一个开源嵌入式硬件平台,用来供用户制作可交互式的嵌入式项目。此外 Arduino 作为一个开源硬件和开源软件的公司,同时兼有项目和用户社群。该公司负责设计和制造Arduino电路板及相关附件。这些产品按照GNU宽通用公共许可证(LGPL)或GNU通用公共许可证(GPL)许可的开源硬件和软件分发的,Arduino 允许任何人制造 Arduino 板和软件分发。 Arduino 板可以以预装的形式商业销售,也可以作为 DIY 套件购买。

Arduino 2005 年时面世,作为意大利伊夫雷亚地区伊夫雷亚互动设计研究所的学生设计,目的是为新手和专业人员提供一种低成本且简单的方法,以建立使用传感器与环境相互作用的装置。初学者和爱好者可用Arduino制造传感器、简单机器人、恒温器和运动检测器等装置。

Arduino 这个名字来自意大利伊夫雷亚的一家酒吧,该项目的一些创始人过去常常会去这家酒吧。 酒吧以伊夫雷亚的 Arduin(Arduin of Ivrea)命名,他是伊夫雷亚边疆伯爵,也是 1002 年至 1014 年期间的意大利国王。

在这里插入图片描述

十七、Arduino数学运算 fma()
Arduino数学运算fma()是一个函数,它可以计算两个数值的乘积再加上第三个数值的结果,即返回x * y + z的值。它的适用范围:
1)计算一些数学公式或算法,例如多项式、矩阵乘法、线性回归等。
2)实现一些物理模拟或控制,例如运动方程、动量守恒、电路分析等。
3)实现一些特殊的效果,例如音频合成、图像处理、加密解密等。

应用场景:
1)高精度计算:fma()函数常用于需要进行高精度计算的场景。通过执行乘加操作,可以在一次计算中同时进行乘法和加法,减少了舍入误差的累积。
2)信号处理:在数字信号处理中,fma()函数可以用于信号加权和滤波处理。通过将信号与权重相乘并累加,可以实现对信号的加权平均和滤波操作。
3)物理模拟:在物理模拟和仿真中,fma()函数可以用于计算物体的运动轨迹和相互作用。通过乘法和加法的组合,可以实现对物体位置、速度和加速度的精确计算。

使用fma()函数时,需要注意以下事项:
1)fma()函数可以接受整数或浮点数作为参数,但是返回的结果类型与参数类型相同。如果要将结果赋值给不同类型的变量,需要进行类型转换。
2)fma()函数需要接受三个参数,即乘数x,乘数y和加数z。如果要计算多个数值的乘加运算,需要嵌套调用fma()函数或使用数组或循环结构。
3)fma()函数使用浮点数运算,所以可能会产生舍入误差或溢出。如果需要更精确或更大范围的计算,可以使用其他库或方法。

以下是Arduino数学运算fma()的三个实际运用程序案例:
案例一:使用温度传感器和LCD显示屏实现温度指示功能。温度传感器输出的是电压值,需要根据公式t = v * a + b转换为温度值,其中t是温度,v是电压,a和b是常数。使用fma()函数计算温度值。

// 引入LiquidCrystal库
#include <LiquidCrystal.h>
// 定义温度传感器和LCD显示屏的引脚
#define TEMP_PIN A0
#define RS_PIN 7
#define EN_PIN 8
#define D4_PIN 9
#define D5_PIN 10
#define D6_PIN 11
#define D7_PIN 12
// 创建LiquidCrystal对象,指定引脚顺序
LiquidCrystal lcd(RS_PIN, EN_PIN, D4_PIN, D5_PIN, D6_PIN, D7_PIN);
// 定义温度转换公式中的常数a和b
#define A 100.0
#define B -50.0

void setup() {
  // 初始化LCD显示屏,并清屏
  lcd.begin(16,2);
  lcd.clear();
}

void loop() {
  // 读取温度传感器的模拟值,并将其转换为电压值,单位为伏特
  int temp_value = analogRead(TEMP_PIN);
  float voltage = temp_value * (5.0 / 1023.0);
  
   // 使用fma()函数计算温度值,单位为摄氏度
   // 温度值等于电压值乘以常数a再加上常数b,公式为t = v * a + b
   float temp = fma(voltage, A, B);
   
   // 在LCD显示屏上显示当前的温度,保留一位小数
   lcd.clear();
   lcd.setCursor(0,0);
   lcd.print("Temp: ");
   lcd.print(temp,1);
   lcd.print(" C");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

案例二:使用陀螺仪和舵机实现平衡小车功能。当小车倾斜时,舵机转动相反的角度,使小车恢复平衡。使用fma()函数计算舵机的目标角度。

// 引入Wire库和Servo库
#include <Wire.h>
#include <Servo.h>
// 定义陀螺仪的地址
#define GYRO_ADDR 0x68
// 创建舵机对象
Servo servo;
// 定义舵机的引脚和初始角度
#define SERVO_PIN 9
#define INIT_ANGLE 90

void setup() {
  // 初始化串口通信,设置波特率为9600
  Serial.begin(9600);
  // 初始化I2C通信,加入I2C总线
  Wire.begin();
  // 向陀螺仪发送指令,激活陀螺仪
  Wire.beginTransmission(GYRO_ADDR);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
  // 将舵机连接到第9号引脚,并转动到初始角度
  servo.attach(SERVO_PIN);
  servo.write(INIT_ANGLE);
}

void loop() {
   // 向陀螺仪发送指令,请求读取数据
   Wire.beginTransmission(GYRO_ADDR);
   Wire.write(0x3B);
   Wire.endTransmission(false);
   // 接收陀螺仪返回的数据,共14个字节
   Wire.requestFrom(GYRO_ADDR,14,true); 
   int acc_x = Wire.read()<<8|Wire.read(); 
   int acc_y = Wire.read()<<8|Wire.read(); 
   int acc_z = Wire.read()<<8|Wire.read(); 
   int temp = Wire.read()<<8|Wire.read(); 
   int gyro_x = Wire.read()<<8|Wire.read(); 
   int gyro_y = Wire.read()<<8|Wire.read(); 
   int gyro_z = Wire.read()<<8|Wire.read(); 
  
   // 计算X轴方向上的倾斜角度,单位为度,范围为-90到90
   // 使用sqrt()函数计算分母中的平方根项
   float angle_x = atan2(acc_x, sqrt(acc_y * acc_y + acc_z * acc_z)) * RAD_TO_DEG;
   
   // 使用fma()函数计算舵机的目标角度,使其与倾斜角度相反,实现平衡效果
   // 舵机的目标角度等于初始角度减去倾斜角度乘以一个系数,公式为a = a_init - k * angle_x
   // 其中a是舵机的目标角度,a_init是初始角度,k是一个系数,angle_x是倾斜角度
   float target_angle = fma(-angle_x, K, INIT_ANGLE);
   
   // 使用constrain()函数限制舵机的角度在0到180度之间
   target_angle = constrain(target_angle,0,180);
   
   // 将舵机转动到目标角度
   servo.write(target_angle);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

案例三:使用光敏电阻和蜂鸣器实现声光控制功能

// 定义光敏电阻和蜂鸣器的引脚
#define LDR_PIN A0
#define BUZZ_PIN 3
// 定义光敏电阻的读数的范围
#define LDR_MIN 0
#define LDR_MAX 1023
// 定义蜂鸣器的音调的范围,单位为赫兹
#define TONE_MIN 100
#define TONE_MAX 1000

void setup() {
  // 设置蜂鸣器为输出模式
  pinMode(BUZZ_PIN, OUTPUT);
}

void loop() {
  // 读取光敏电阻的模拟值,并将其映射到0-1023范围内
  int ldr_value = analogRead(LDR_PIN);
  ldr_value = map(ldr_value, LDR_MIN, LDR_MAX, 0, 1023);
  
   // 根据光敏电阻的读数计算蜂鸣器的音调,并将其映射到合理的范围内
   float tone_value = (float)ldr_value / (LDR_MAX - LDR_MIN) * (TONE_MAX - TONE_MIN) + TONE_MIN;
   tone_value = constrain(tone_value, TONE_MIN, TONE_MAX);
   // 使用floor()函数将音调转换为整数,并赋值给蜂鸣器
   int tone_value = floor(tone_value);
   tone(BUZZ_PIN, tone_value);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

案例四:高精度计算:

float a = 0.1; // 浮点数1
float b = 0.2; // 浮点数2
float c = 0.3; // 浮点数3

float result = fma(a, b, c); // 执行乘加操作

Serial.print("Result: ");
Serial.println(result);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在此案例中,使用fma()函数执行乘加操作,将浮点数a与浮点数b相乘,并将浮点数c相加到结果中。通过一次计算同时完成乘法和加法操作,可以减少舍入误差的累积,并得到更高精度的计算结果。

案例五:信号处理:

float signal[] = {0.1, 0.2, 0.3, 0.4}; // 信号数组
float weights[] = {0.4, 0.3, 0.2, 0.1}; // 权重数组

float sum = 0.0; // 累加结果

for (int i = 0; i < 4; i++) {
  sum = fma(signal[i], weights[i], sum); // 乘加操作累加结果
}

Serial.print("Weighted Sum: ");
Serial.println(sum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在此案例中,使用fma()函数对信号数组和权重数组进行乘加操作,并累加结果。通过将信号与权重相乘并累加,可以实现对信号的加权平均操作。最后,将加权和输出到串口监视器,用于显示或后续的处理。

案例六:物理模拟:

float position = 0.0; // 物体位置
float velocity = 1.5; // 物体速度
float acceleration = 0.8; // 物体加速度

float deltaTime = 0.1; // 时间步长

position = fma(velocity, deltaTime, position); // 计算位置
velocity = fma(acceleration, deltaTime, velocity); // 计算速度

Serial.print("Position: ");
Serial.println(position);
Serial.print("Velocity: ");
Serial.println(velocity);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在此案例中,使用fma()函数计算物体的位置和速度。通过乘加操作,可以根据物体的速度和加速度计算出物体在给定时间步长内的位置和速度变化。最后,将计算结果输出到串口监视器,用于显示或后续的处理。

案例七:金融计算:

#include <math.h>

float principal = 1000.0;
float interestRate = 0.05;
float time = 2.5;

void setup() {
  Serial.begin(9600);
  // ...
}

void loop() {
  float amount = fma(principal, interestRate, principal * time);  // 计算复利总金额

  Serial.println(amount);
  delay(1000);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这个案例中,使用fma()函数计算复利的总金额。将本金principal和利率interestRate相乘,并将结果与本金乘以时间principal * time相加,得到复利的总金额。

案例八:图像处理:

#include <Adafruit_ILI9341.h>

Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);

float brightness = 0.5;
float color = 0.8;

void setup() {
  // ...
  tft.begin();
  // ...
}

void loop() {
  float result = fma(brightness, color, 0.2);  // 计算最终亮度和颜色

  // 使用计算后的结果进行其他图像处理操作
  // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这个案例中,使用fma()函数计算最终的亮度和颜色值。将亮度brightness和颜色值color相乘,并将结果与常数0.2相加,得到最终的亮度和颜色值。这样可以实现更精确和高质量的图像处理效果。

案例九:物理模拟:

float position = 5.0;
float velocity = 2.0;
float acceleration = 1.5;
float deltaTime = 0.1;

void setup() {
  // ...
}

void loop() {
  float newPosition = fma(velocity, deltaTime, position + 0.5 * acceleration * deltaTime * deltaTime);  // 计算新的位置

  // 使用新的位置进行物理模拟操作
  // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这个案例中,使用fma()函数计算物体的新位置。将物体当前的速度velocity乘以时间步长deltaTime,然后将结果与当前位置position加上加速度acceleration乘以半个时间步长的平方0.5 * acceleration * deltaTime * deltaTime相加,得到物体的新位置。这样可以实现准确和可靠的物理模拟。

总结:
fma()函数是Arduino中的数学运算函数,用于执行浮点数的精确乘加操作。它在金融计算、图形图像处理和物理模拟等领域具有广泛的应用。在使用fma()函数时,需要注意数据类型的范围和精度,以确保函数的正常工作。通过合理地使用fma()函数,可以实现高精度和准确性的浮点数乘加操作,满足具体应用的需求。

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/956621
推荐阅读
相关标签
  

闽ICP备14008679号