Arduino 科学记数法库

科学记数法是一种记数的方法。把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,a不为分数形式,n为整数),这种记数法叫做科学记数法。 例如:19971400000000=1.99714×10^13。计算器或电脑表达10的幂是一般是用E或e,也就是1.99714E13=19971400000000。[参考1]

https://github.com/RobTillaart/Arduino/tree/master/libraries/MathHelpers 提供了一个 Arduino 科学计数法的库,能够将一个浮点数转化为科学计数法的表示。

测试代码:

//
//    FILE: mathHelperTest.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.0.1
// PURPOSE:
//
// HISTORY:

#include "MathHelpers.h"

uint32_t start;
uint32_t stop;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("MATHHELPERS_VERSION: ");
  Serial.println(MATHHELPERS_VERSION);

  test1();
  test2();
  test3();
  test4();
  test5();

  test10();
  test11();
  test12();

}

void loop()
{}


void test1()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1;
  for (int i = 0; i < 40; i++)
  {
    f *= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = 1;
  for (int i = 0; i < 50; i++)
  {
    f /= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = -1;
  for (int i = 0; i < 40; i++)
  {
    f *= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();

  f = -1;
  for (int i = 0; i < 50; i++)
  {
    f /= 10;
    Serial.println(sci(f, 6));
  }
  Serial.println();
  Serial.println();
}

void test2()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1;
  for (int i = 0; i < 40; i++)
  {
    f *= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = 1;
  for (int i = 0; i < 50; i++)
  {
    f /= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = -1;
  for (int i = 0; i < 40; i++)
  {
    f *= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  f = -1;
  for (int i = 0; i < 50; i++)
  {
    f /= (PI * PI);
    Serial.println(sci(f, 6));
  }
  Serial.println();
  Serial.println();
}

void test3()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = PI;
  for (int i = 0; i < 8; i++)
  {
    Serial.println(sci(f, i));
  }
  Serial.println();
}

void test4()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = PI;
  for (int i = 0; i < 8; i++)
  {
    sci(Serial, f, i);
    Serial.println();
  }
  Serial.println();
}


void test5()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  float f = 1.0 / 0.0;
  Serial.println(sci(f, 6));
  f = 0.0 / 0.0;
  Serial.println(sci(f, 6));
  f = -1.0 / 0.0;
  Serial.println(sci(f, 6));
  // TODO find a -inf

  Serial.println();
}


void test10()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("HH:MM:SS");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.println(seconds2clock(now));
  }
  Serial.println();
}

void test11()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("HH:MM:SS.nnn");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.println(millis2clock(now));
  }
  Serial.println();
}

void test12()
{
  Serial.println();
  Serial.println(__FUNCTION__);

  Serial.println("time\tweeks\tdays\thours\tminutes");
  for (int i = 0; i < 7; i++)
  {
    uint32_t now = micros();
    Serial.print(now);
    Serial.print('\t');
    Serial.print(weeks(now), 3);
    Serial.print('\t');
    Serial.print(days(now), 3);
    Serial.print('\t');
    Serial.print(hours(now), 2);
    Serial.print('\t');
    Serial.println(minutes(now), 2);
  }
  Serial.println();
}


// END OF FILE
Arduino 科学计数法

库下载

参考:
1.https://baike.baidu.com/item/%E7%A7%91%E5%AD%A6%E8%AE%B0%E6%95%B0%E6%B3%95?fromtitle=%E7%A7%91%E5%AD%A6%E8%AE%A1%E6%95%B0%E6%B3%95&fromid=756685 科学记数法

M.2 NMVE PICE 转接卡

最近在做Modern Standby 的实验,测试结果显示CPU进入了PC10,但是一直被硬盘 Block。板子上使用的是通过 PCIE-M.2 转接板转接后插在 PCIE Slot 上的 NVME SSD 。于是,我觉得问题出在转接板上。

PCIE M.2转接卡

对于M.2 上的ModernStandby来说,NVME 上的CLKREQ 拉高通知 PCH/SOC 停止发送 PCIE Clock。如果出现问题通常都是这个Pin导致的。于是,怀疑转接卡是否将 PCIE 上的CLKREQ Pin正确转接到了 M.2 接口上。

CLKREQ 在 PCIE金手指上的位置 【参考1】

接下来找到 M.2 的引脚定义【参考2】:

M.2 引脚定义
M.2 CLKREQ Pin和实物对应(特别注意,为了方便对应右侧的照片是旋转之后再左右镜像的)

进一步追查,这个Pin连接了一个LED,然后到了GND 上(万用表测试)。

CLKREQ 在转接板上的位置

为了验证上面的正确性,再挑选一个PICIE 金手指上的 REFCLKp pin(A侧13,参考本文第一幅),使用万用表测量,找到M.2上面的引脚如下:

这个说明参考的M.2的引脚资料是正确的。

进一步结论:转接卡没有将 PCIE 上的 CLKREQ 转接给M.2。

最终,通过飞线的方式,将 M.2 的CLKREQ 和PCIE Slot 上的 CLKREQ 相连,在 RVP (CML-V)上测试无问题,运行 ModerStandby 的 Stress Test,一晚跑50次顺利通过。这个从侧面也印证了:M.2 上的 PCIE 和 PCIE Slot 没有本质差别。很多时候如果你发现供应商提供的某些 M.2 接口的设备无法在你的设计上影响 MS 功能,不妨转接在 RVP 上验证之。

参考:

1. https://baike.baidu.com/item/pcie

2. http://read.pudn.com/downloads794/doc/project/3133918/PCIe_M.2_Electromechanical_Spec_Rev1.0_Final_11012013_RS_Clean.pdf  

DSLogic逻辑分析仪试用

最近入手了 DSLogic 逻辑分析仪,买的是 DSLogicPlus 个人版,这个是个人使用的顶配版本。选择这个品牌的原因是一个网友的推荐,还有从搜索到的资料来看这款最开始是在KickStarter上众筹的产品,总共筹集到了11万美元。想必质量有保证。

梦源实验室 DSLogic

几个版本比较如下,可以看到这个版本对于个人来说完全够用了:

DSLogic 版本比对

开箱照:

DSLogic Plus 开箱照

首先用它抓取PS2 鼠标协议,于是找了一个PS2鼠标和一个PS2转USB Dongle,这一套是能够在我的电脑上正常工作的:

刚用的时候还是能够正常抓到一些数据的:

逻辑分析仪抓取 PS2 鼠标数据

但是很快就跑偏了,下面 Channel 0 的数据是错误的,应该的大部分时间为高,部分时间为低,但是不知道为什么出现大部分时间为低,少数时候为高的情况。这种情况下数据的解析更是“太监开会—无稽之谈”。

为了搞清楚问题,我还将两个通道接到同样的引脚上,测试结果更是让人大吃一惊。

联系售后邮箱直接让我邮寄回去检测。之后我还直接给他们技术人员打电话。对方也表示这个事情比较奇怪,让我更换不同的线,实验之后也没有效果。

经历了4天的研究,我发现最好的解决办法就是:退货。趁着7天无理由退货赶紧。调试调试设备这个并不是明智的选择。所以,建议如果有购买逻辑分析仪设备需求的朋友,最好拿到手后立即实验,否则即便最简单的协议也可能存在解析问题。

WDTF 安装器

测试 MS 功能, WDTF 是必须的,但是每次通过 WDK 安装会比较麻烦【参考1】,因此制作了一个 WDTF 安装器,运行之后界面如下:

WDTF 安装器

上部显示当前 Windows 版本,中间按钮选择你要安装的,点击之后即可自动完成安装。

需要注意的是:这个版本带有自校验功能,如果你发现无法运行,那么最好进行杀毒避免因为病毒干扰测试。

参考:

1.http://www.lab-z.com/wdtfin/ WDTF的安装

C# Console 获取当前程序名称

方法来自 https://stackoverflow.com/questions/7881148/how-do-i-get-the-exe-name-of-a-c-sharp-console-application

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().Location);
            Console.ReadKey();
        }
    }
}

获得当前 Application 的路径

推荐 Toshiba 的一款 NVME

最近在 CML-V 的 RVP 上测试 MS Stress,开始使用 Samsung 的一款,后来发现总会有 fail 的情况发生(大约是 2/5 )。后来换了 Toshiba 的KXG6AZNVT02 这款(PCIE NVME M.2接口),首先感觉是速度明显变快(这个应该和容量有关系,这款是 1T 容量的);轻松跑了一晚上(30s idle, 15 min sleep ),50次都 Pass。

如果你在测试Stress 的时候遇到 fail 的情况不妨找这款进行实验,或者说多换几个NVME硬盘试试看。

20200811 补充, 使用这个硬盘在 CML-S RVP 上关闭各种设备只保留 NVME 之后测试得到的结果:

示波器直接测量 SLPS0 信号,测试水平方向一格 20s

需要说明的是:

1.SLPS0 是低有效,意思是睡下之后应该是低,醒来的时候变高。上图测试点是在LED 上,所以是反的,即高为睡,低为醒来;

2.最好的状态下,180S SLPS0 会自动唤醒一次,这个是正常现象。

3.3V Arduino Proi Micro 的使用和维修

市面上最常见的 Arduino Pro Micro 是5V的,除此之外还有一种是 3.3V的,他们之间的区别除了电压之外还有主频不同,5V版本是16MHz,3.3V的是8Mhz。

前一段我入手了一个3.3V版本的,主要目标是给 USB Host Mini 使用。拿到手之后错误的使用了 Leonardo进行上传,马上板子就变砖了。所以,这里特别强调必须使用LilyPad USB 编译上传!

一定要选择这个

讲完了使用下面讲如何恢复,找出了 USBTinyISP(极客工坊出品的)。

USBTinyISP接口定义

接线顺序:

USBTinyISPPro Micro 3.3V
1.MISOD14.MISO
2.VCCRAW(特别注意不是VCC)
3.SCKD15.SCLK
4.MOSID16.MOSI
5.RESETRST
6.GNDGND

之后使用 Arduino 自带刷Bootloader的功能最稳妥(板子要选好 LilyPad)

Arduino 烧写 Bootloader

写入之后还会读取校验,之后板子就恢复正常了。

参考:

1.https://www.sparkfun.com/products/12640 这里可以找到电路图

控制 Tinker 上面的 LED 实现呼吸灯

这里做一个简单的实验:上电之后让 ThinkerNode NB-IoT上的 LED 实现红色的呼吸灯效果,按下 Set键之后切换为绿色呼吸灯。

硬件方面:

1. ThinkerNode NB-IoT 上面的 LED 是一个 WS2812B,可以实现任意的颜色

2.板子上的 SET按钮是接在 D3 Pin上的,按下时拉低。

RGB_LED.Breathing() 是设置一次呼吸灯效果的函数,设置一次之后是一个周期,意思是运行一次会实现一个完整的亮灭周期,如果想持续亮灭,那么需要定时运行这个函数。根据上面的资料编写如下代码:

#include <DFRobot_NeoPixel.h>

unsigned long elsp;
byte CurrentColor;

void setup() {
  RGB_LED.begin();
  //中等亮度 
 RGB_LED.setBrightness(MIDDLE);
 //初始为红色
  CurrentColor=RED;
  RGB_LED.setColor(RED);
  //设置呼吸灯,前面一个是亮的时间长度,后面一个是灭的时间长度
 // 这里是亮 2秒,灭1秒的意思
  RGB_LED.Breathing(2000, 1000);
  pinMode(D3,INPUT);
  elsp=millis();
}

void loop() {
  //如果按下 SET 键,那么切换为绿色呼吸灯
  if (digitalRead(D3)==LOW) {
      RGB_LED.setColor(GREEN);
      CurrentColor=GREEN;
  }
 //如果时间超过3秒,那么刷新一次设置
  if (millis()-elsp>2000+1000)
  {
      RGB_LED.setColor(CurrentColor);
      RGB_LED.Breathing(2000, 1000);
      elsp=millis();
  }   
}

Windows 下替换 ACPI Table补遗

之前介绍过 Windows 下替换 ACPI Table 的方法【参考1】,该方法可以替换 DSDT,但是最近工作中遇到需要修改的ACPI内容并不在 DSDT中,而是存放在 SSDT 中的情况,同时一个系统中还会有多个 SSDT。

打开注册表,在 Computer\HKEY_LOCAL_MACHINE\HARDWARE\ACPI  查找你需要的SSDT:

  打开注册表查看 ACPI Table

当然你可以先用 RW Everything 查看 ACPI Table 更加直观,SSDT 有很多个,彼此的 Signature 是相同的但是OEM Table ID 是不同的字符串:

RW Everything 查看ACPI Table

确定你要修改的SSDT,这里使用 OEM Table ID 为 “U_Rvp ”的这个 SSDT作为实验的目标:

    OEM Table ID 是 U_Rvp

上面提到的 U_Rvp 的 SSDT,在注册表中名称是SSD6:

注册表中的 SSD6 对应 RW Everything 中的 U_Rvp SSDT

接下来的操作和之前的类似

1.asl /tab=ssd6 /c保存成二进制文件:

2. 使用 iasl2016 -ve SSD60000.bin反编译之

3.修改代码,加入我们自定义的设备挂在 I2C 下面

4.再编译为 AML

5.asl /loadtable SSD60000.aml 加载这个 table

6.重启,进入设备管理器查看,再I2c 下面出现的一个 unknown 设备

设备管理器中的自定义设备
自定义设备属性

参考:

1. http://www.lab-z.com/arcpi/

2024年2月2日

iasl.exe -ve dsdt.iiii 其中的 -ve 意思是只输出错误信息,不输出 warning

iasl.exe -h 输出帮助信息