实验 MPU-6050模块

在使用之前,需要特别注意的是:MPU-6050 本身只支持到 3.3V,如果你需要供电5V那么要特别确认一下你的板子是否有转换。我使用的下面这个模块上面带降压的,所以可以直接接5V.

T1OIRvXBXfXXXXXXXX_!!0-item_pic

另外,连接GND和VCC时一定要注意不能搞反了,否则转换芯片会急剧发热(推荐你第一次上电的时候留心这个芯片)。

首推极客工坊的文章【参考1】。但是可能是版本太老的缘故,在编译时(1.5.0)会出现core.a的错误。

随后查了一下,Arduino官方网站上有介绍和示例代码【参考2】:

// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}
void loop(){
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

 

我使用的是 Arduino Pro Micro (这并非Arduino官方出品,是一种类似 Arduino Leonardo 的兼容产品) , 电路非常简单,使用面包板即可

6050

运行结果

6050r

取得值本身很简单,但是如果想解出正确的姿态还是蛮复杂的。

参考:

1.http://www.geek-workshop.com/thread-1017-1-1.html arduino学习笔记37 – Arduino Uno + MPU6050首例整合性6轴演示实验

2.http://playground.arduino.cc/Main/MPU-6050 MPU-6050 Accelerometer + Gyro

二维码对联

前一段看张鸣老师的书,上面提到对联是一种很重要的传统文化表现形式,尤其是春节时要四处张贴的春联。据说很多地区的大学生春节回家之后还要承担起为乡亲们题写春联的重任。母亲说当年他们插队时,逢年也会给老乡写春联。内容上通常是毛语录,比如:“金猴奋起千钧棒,玉宇澄清万里埃”或者“四海翻腾云水怒 五洲震荡风雷激”,一类的。

每年春节上街我都会觉得这是越来越重要的传统——至少从春联的价格上来看是这样。让我编点春联是没问题的,至于写的话因为现在提笔忘字以及本人的字都会被老婆笑话,还是免谈了。

作为一个专业的工程技术人员,灵机一动,想到了既然我只能编不能写可以用眼下最时髦的二维码技术来生成。有好奇心的人就会去扫一扫,然后就能看到了。具体做法如下:

首先,找个二维码生成软件。选择最高的误码率,简单的理解这个就是你能够覆盖生成二维码的比率。比如:25%的误码率意味着你可以覆盖画面上25%的区域仍然能够正常扫出。

错误修正容量

L水平 7%的字码可被修正

M水平 15%的字码可被修正

Q水平 25%的字码可被修正

H水平 30%的字码可被修正

【参考 1】

image001

【参考1】

我随便选了一个软件,二维码大师,最高误码率30%,然后选择最高分辨率。文本内容中输入上联“壹零做法神通广大不服来扫我”,输入过程中就自动生成二维码了,具体在下面三个地方设置和输入。

image002

选择保存为一个BMP文件。比如上面“壹零做法神通广大不服来扫我”,生成的结果就是下面的图片。

image003

然后修改这个图片即可,我最喜欢用的就是Windows的画笔工具。

image004

修改之后结果

image005

特别的,修改之后一定要用刚才的软件校验一下,避免做完了根本无法识别的状况。

image006

同样做法,再做一下下联“纵横成形网挂众多若信任联”。

image007
上面这个对联是我父亲拟的,横批就是“二维码”。

最后多说两句,大多数情况下人们只是注意上下问对仗是否工整而不大在意内容本身,好比,有女生给班主任写条子,”老师,我怀了男朋友得孩子”。老师看到之后大吃一惊“唉,现在的学生啊,真是的!都上初中了,怎么还分不清楚‘的地得’的用法?”。我随口拟了一个联儿,念给父亲听,他听了片刻说“对的比较工整,这是一个传统的联吧?”

image008

image009

参考:

1. http://zh.wikipedia.org/wiki/QR%E7%A2%BC QR码

Arduino 显示奶瓶温度

有个网友提出一个需求“做一个能够显示温度的奶瓶。奶瓶泡好奶后放在底座上,可直接给婴儿喝的绿灯亮,过烫红灯亮,过凉蓝灯亮。”这是他的一个作业,然后我就帮着做了一下。整体思路就是直接使用上一次做的那个红外温度计的方案,我想这样的方案恐怕在网上都是独一无二的吧。

使用到的基本元件有:Arduino Uno + LED + 红外温度传感器(上面有一个激光头用于瞄准)

使用红外温度传感器能够获得下列优点:

1.无需接触,不必考虑卫生的问题
2.准确度在可以接受的范围内
3.速度快,对准之后马上显示
4.兼容性好,各种型号的奶瓶都可以

缺点:

1.贵
2.有人说无法精确得知瓶中奶的温度,测量的是奶瓶温度而已

milkb2

milkb1

#include <Arduino.h>
#include <Wire.h>
#include "TN901.h"  
TN901 tn;          
int RedLed=10;  //Red Led Pin10
int GreenLed=7;  //Green Led Pin10
int BigRedLed=4;  //Big Led Pin4
void setup()
{
    Serial.begin(9600);
    tn.Init(13,12,11);  //初 始 化 data clk ack
    pinMode(RedLed,OUTPUT);
    digitalWrite(RedLed,LOW);
    pinMode(GreenLed,OUTPUT);
    digitalWrite(GreenLed,LOW);    
    pinMode(BigRedLed,OUTPUT);
    digitalWrite(BigRedLed,LOW);      
}
void loop()
{
   tn.Read();
   SerialValue();
   delay(2000);
}

void SerialValue()
{
   String s;
   s=">O"+String(tn.OT, DEC)+"E"+String(tn.ET,DEC)+"<";
   Serial.println(s);
   if (tn.OT>5000) { // Temp too high
         digitalWrite(RedLed,HIGH);
         digitalWrite(GreenLed,LOW);
         digitalWrite(BigRedLed,HIGH);        
   }
   else {
     if (tn.OT>2100) {// Temp is OK
         digitalWrite(RedLed,LOW);
         digitalWrite(GreenLed,HIGH);
         digitalWrite(BigRedLed,HIGH);        
         }
    else { //Temp is too Low      
         digitalWrite(RedLed,HIGH);
         digitalWrite(GreenLed,HIGH);
         digitalWrite(BigRedLed,LOW);
     
    }
   }  
}

 

设计上我们使用了2个LED,一个是小LED双色红色和绿色,一个是单独的大个红色的(手边只有这两种LED,更好的设计应该换个颜色的LED便于区分)。温度传感器是红外温度传感器。

温度区间:

>50 小LED的红色亮起 表示温度过高

50-20 小LED的绿色亮起 表示温度适合

<20 大红色LED亮起 表示温度过低 工作时的视频 首先展示一下电路,然后我们有一瓶大瓶冷水;放在上面的时候温度过低,大红色 LED亮起;然后我们换成奶瓶,其中是热水,温度过高,小红色LED亮起;然后我们将大瓶子的水兑到小瓶子中,温度会变得适中,于是小LED绿色会亮起。

这个方案对于作业来说应该是足够了。就是这样。

窗花

前几天看《小说月报》,一篇讲述的是研究生毕业的漂亮女硕士,为了完成女导师的愿望,毅然决然选择从政的故事。只不过这是主旋律小说,必须有光明的尾巴:一直期望她能成为自己“李万姬”的老领导患了癌症,向革命老前辈们报到前说出了所有的事情,于是全部矛盾迎刃而解。最后女主角镀金完成,换了岗位,抱得男朋友满载而归。比较有意思的是故事中有一个情节,讲的是他们那里支柱企业是无纺布生产厂,受到经济危机影响,贷款出了问题,然后女主角想办法筹集资金,拖欠了一下当地干部和教师的工资,又下达集资的命令。看到资金的来源,我觉得这篇小说还真是写实。确实,对于教师这个职业,没有好处的很多时候不会想起来你是公务员,但是要是有需要体现精神的时候又会被推到前面。

又想起来很久之前的一个科幻小说,讲述人类发送太阳能电池到太空作为新能源,但是太空中有尘埃,每隔一段就需要清理。发送博士之类风险太大薪水又不能太低,最后作为特产,农民工就被送到太空,从事这份高工资的工作,也算是人上人了。小说还真是传承社会精神面貌的镜子。回头我找本书好好研究下宋朝的生活,顺便批判一下封建社会的腐朽的生活方式。

我这里说的窗花并非那种传统手工图样,而是凝结在窗户上的水汽形成的美丽图样。

0f53c8d303a1add716cbc1cbef375ee8

我的一位同学,是小学老师,前一段她每天早晨都会在朋友圈中晒出办公室窗花的照片。听起来很浪漫,现实中意味着寒冷—-办公室没有暖气和空调。听起来难以置信,不过据她所说就是这样。此外,因为种种安全上的考量严禁各种非生物能源转换,意思是除了蹦跳多穿衣服多吃东西之外严禁使用电器。于是她便只能望着美丽的窗花偶发感慨聊以自慰了。

以前我在的公司也有过这样的事情:大冬天为了省电不开空调,HW工程师冻的手都没有办法握稳电烙铁。具体是这样的,冬季是我国江南地区传统的用电高峰,企业在用电上会有一些限制,于是老板就在空调上打起来主意。最大的问题是老板的房间是在整栋楼的中间,好比上下各有一层脂肪,大约是感受不到多少寒冷,而我们研发非常不幸的处在顶楼,不开空调很冷啊。我们找了一楼的总务很多次,总务总是指着墙上的一直温度计辩解还没有降低到18度,由拒绝开,我甚至一直在怀疑,他那只温度计是特殊定制的,显示值会比正常的温度高那么两三度。再后来终于开放中央空调,但是还想了一个非常奇特的规则:整点的时候供电10分钟。意思是,比如九点到九点十分,中央空调是有电的,但是需要手工用遥控器打开之。于是,每逢快到整点,研发人员就像神经病一样相互提醒马上准备开空调,能暖和一段。偶然忘记了大家更是垂足顿胸。

时间一长,大家都受不鸟了。就开始研究解决方法了。做HW的工程师夏天的时候可以做几只风扇并联起来,但是冬天的时候没有太合适的工具取暖,热风枪吹起来只有外焦里生的效果。电烙铁的加热区域也太小,没办法满足四肢的需要…….通常 HW 搞不定的就要靠SW了。于是,我旁边的妹子提出:太TMD冷了,自己买个暖风机,然后我也附议了一下,一起买吧。忽然想起来那次似乎是我第一次在京东上购物。根据自己的体积,我挑选了一个2KW的暖风机,旁边的妹子挑选了一个2.5KW的。头天下午的订单,第二天就送货上门签收交易完成,那也是我第一次被京东的配送速度震撼到。用起来感觉不错,是风暖型的,中午熄灯之后吹上去暖洋洋的,我恨不得搬着一张床钻到桌子下面去。等我们用了一段,看看没啥动静,办公室的人也都一窝蜂的去买,到了最后几乎是人手一只。连研发的老大也悄悄买了一个低调的塞在座位下面:高调的理念通常只适用在别人身上,真正到了自己这边舒服一些比什么都强。大约也是到了这个岁数所谓天降大人于私人也不那么重要。没有大志终究比大痔或者冻疮强。

再后来,总务想管来着,羞羞答答的提出了除了费电之外的全部理由,比如:不安全,不环保等等。只是研发没人鸟。想必总务也是有所顾忌的,一方面大冬天不给开空调本来就不占理;另一方面也许是实在讲不过研发的人吧。再后来也就不了了之,我们吹着暖风迎来了春天………..

事后,我曾经认真的总结,这个事情之所以能成,很大程度上是总务对我们有所顾忌,也就睁一只眼闭一只眼了;更高一点层次来说,研发人员算是稀缺,上面也不愿意太过分。再后面发生太过分的事情,研发3个月走了一半的。

从另外一个角度来说,我同学那样的小学老师,生活是很稳定的,一辈子不用担心你会被开除或者因为某些变故失去工作,而这种稳定付出的代价就是自由。

Step to UEFI (26) —– Shell下Reboot System

研究一下如何 RESETSYSTEM,直接使用 RUNTIMESERVICES 是很好的选择。首先是查看资料 UEFI 2.4 是不二的选择。

7.5.1 Reset System

具体参数解释:EFI_RESET_TYPE 有: EfiResetCold,EfiResetWarm, EfiResetShutdown,和EfiResetPlatformSpecific。Cold是系统级别的完全重启。 Warm也是系统级别的重启,但主要是CPU级别的重启。(具体的话,以前确实有Warm Reset和Cold Reset的差别,但是我感觉实际BIOS设计上,这两个并不是区分的特别清晰。传统上的CPU的Warm Reset有可能导致几百次重启之后系统挂掉,而测试人员根本不会听取你关于他们差别的解释,于是最好的办法仍然是都用Cold Reset来解决)。Shutdown的话,就是关机了。EfiResetPlatformSpecific从解释上来看好像是将一个EFI_GUID指定的Reset类型存放在ResetData中(类似记录重启原因吗?)

EfiResetPlatformSpecific 太复杂,这里只是研究一下简单的 Reset 最后编写程序如下

 

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include <wchar.h>

extern EFI_BOOT_SERVICES             	 *gBS;
extern EFI_SYSTEM_TABLE			 *gST;
extern EFI_RUNTIME_SERVICES 		 *gRT;

/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
  gRT -> ResetSystem(EfiResetCold,EFI_SUCCESS,0,NULL);
  return EFI_SUCCESS;
}

运行之后系统就重启了。

下载   MainRST

Arduino 的MD5库

这是来自 http://playground.arduino.cc/Main/LibraryList 的Arduino MD5库【参考1】。我实验了一下挺好用的。

#include "MD5.h"
/*
This is en example of how to use my MD5 library. It provides two
easy-to-use methods, one for generating the MD5 hash, and the second
one to generate the hex encoding of the hash, which is frequently used.
*/
void setup()
{
  //initialize serial
  Serial.begin(9600);
  //give it a second
  delay(1000);
  //generate the MD5 hash for our string
  unsigned char* hash=MD5::make_hash("hello world");
  //generate the digest (hex encoding) of our hash
  char *md5str = MD5::make_digest(hash, 16);
  //print it on our serial monitor
  Serial.println(md5str);

  char* test="hello world";
  unsigned char* hash2=MD5::make_hash(test);
  md5str=MD5::make_digest((unsigned char*)hash2, 16);
  Serial.println(md5str);   

}

void loop()
{
}

 

运行结果

md5result

这个结果和我在一个在线MD5的网站【参考2】计算结果是一致的

md5compare

例子下载
MD5_Hash

我只是简单的测试了一下对Char做MD5,头文件中的另外几个函数的用法没搞清楚。从经验上来看,应该是能够不断累积计算一系列MD5值(比如说刚开始有个字符串”ABC”后来又来了一个字符串“DEF”可以继续加入计算中)。试验了一下没搞清楚。

static const void *body(void *ctxBuf, const void *data, size_t size);
static void MD5Init(void *ctxBuf);
static void MD5Final(unsigned char *result, void *ctxBuf);
static void MD5Update(void *ctxBuf, const void *data, size_t size);

参考:
1.https://github.com/tzikis/ArduinoMD5/ 完整代码下载 ArduinoMD5-master
2.http://md5calculator.chromefans.org/ 一个MD5在线计算网站

用 1602实现进度条

在 https://www.electronicsblog.net/arduino-lcd-horizontal-progress-bar-using-custom-characters/ 这里发现比较有趣的代码:用1602LCD 实现一个进度条。根据文章指引,我也试验了一下。

弄明白了原理,程序非常简单:

//https://www.electronicsblog.net/
//Arduino LCD horizontal progress bar using custom characters
#include <Wire.h> 
#include "LiquidCrystal_I2C.h"

#define lenght 16.0

double percent=100.0;
unsigned char b;
unsigned int peace;
int value=100;

// custom charaters

LiquidCrystal_I2C lcd(0x27,16,2);

//定义进度块
byte p1[8] = {
                0x10,
                0x10,
                0x10,
                0x10,
                0x10,
                0x10,
                0x10,
                0x10};

byte p2[8] = {
                0x18,
                0x18,
                0x18,
                0x18,
                0x18,
                0x18,
                0x18,
                0x18};

byte p3[8] = {
                0x1C,
                0x1C,
                0x1C,
                0x1C,
                0x1C,
                0x1C,
                0x1C,
                0x1C};

byte p4[8] = {
                0x1E,
                0x1E,
                0x1E,
                0x1E,
                0x1E,
                0x1E,
                0x1E,
                0x1E};

byte p5[8] = {
                0x1F,
                0x1F,
                0x1F,
                0x1F,
                0x1F,
                0x1F,
                0x1F,
                0x1F};

void setup() {
                lcd.init();                      //初始化LCD
                lcd.backlight();		 //打开背光

			//将自定义的字符块发送给LCD
			//P1 是第一个,P2 是第二个,以此类推
                lcd.createChar(0, p1);			 
                lcd.createChar(1, p2);
                lcd.createChar(2, p3);
                lcd.createChar(3, p4);
                lcd.createChar(4, p5);
}

void loop()
{
                //设置光标在左上角
                lcd.setCursor(0, 0);

                percent = value/1024.0*100.0;

		//当超过100%的时候自动校正为 100%
		if (percent>100) {percent=1;value=0;}

                lcd.print("     ");
                lcd.print(percent);
                lcd.print(" % ");

		//移动光标到第二行
                lcd.setCursor(0,1);

                double a=lenght/100*percent;

                // drawing black rectangles on LCD
		// 显示全黑块。
                if (a>=1) {
                    for (int i=1;i<a;i++) {
                                lcd.write(4);
                                b=i;
                        } //for (int i=1;i<a;i++) 
                    a=a-b;
                }
                else {b=0;}

                peace=a*5;

                // drawing charater's colums
		// 显示除去全黑块之后的零头
                switch (peace) {
                  case 0:
                        break;
                  case 1:
                        lcd.write(0);
                        break;
                  case 2:
                        lcd.write(1);
                        break;
                  case 3:
                        lcd.write(2);
                        break;
                  case 4:
                        lcd.write(3);
                        break;
                  } //switch (peace)

               // clearing line
	       // 用空格填充剩下的位置
              for (int i =0;i<(lenght-b);i++) {
                lcd.print(" ");
                }

		//递增
                value=value+10;				
		delay(300);

  }

 

连接

1602pg

大图

1602pg2

代码下载 pb1602

================================================================================
2015年3月13日 特别注意:自定义字符一次不能超过8个,如果需要自定义很多个,可以用动态的方法进行切换,参考 http://www.geek-workshop.com/thread-5190-1-1.html 1602自定义字符的另一种思路,实现超过8种自定义字符的显示

我的网站打开比较慢有一段时间了,刚开始检查过几次,直接Ping出去速度都还可以。加之大多数情况下我都是写好了再上传,打开页面慢点并不碍事。最近几次在网站上直接写文章,稍微留心了一下,发现缓慢的时候浏览器左下角显示在访问Google的什么。忽然灵光一闪:莫非是因为我的网站调用Google一些东西,而Goolge因为“众所不知”的原因无法访问因此会导致巨慢的问题?Baidu了一下发现真是这么回事。

http://www.gox.name/Article/2775.html 谷歌被墙!解决WordPress访问速度慢的问题
http://www.wind88.net/news/news-125.html WordPress最近速度很慢的解决方法

简单的解释:Wordpress调用了Google的一些服务,在打开的时候浏览器需要和服务器进行交互,而Google 肯定是Timeout因此会有问题。

按照文章中的说法,按转一个插件,绕开了Google的服务,再次页面速度马上快了起来。

这是“城门失火殃及池鱼”吗? 不是的,因为你生活在墙中,那是一个看不见摸不着,但是每时每刻你都可能撞上的“墙”。

隐约记得列宁有过一段关于拆墙的论述,查了一下,还真有,应该是出现在历史课本中的。

“当列宁因参加学生运动而被抓捕时,只有17岁。一个警察局长不解地问他:“我不明白,你为什么要起来造反?年轻人,要知道你面前是一堵墙。你不是在用脑袋往墙上撞吗?”列宁藐视地回答:“是的,一堵墙,不过已经腐朽了,一推就倒。我们可以从上面跨越过去。”文中的“一堵墙”被推倒应该是在

A.二月革命中 B.七月事件中

C.十月革命中 D.国内战争中”

唉,最后再次祝愿病魔早日战胜北邮前校长方滨兴先生吧。