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.国内战争中”

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

USB 控制七段数码管

这次的目标是要实现用 USB 口来控制七段数码管。

硬件上面选用《圈圈教你玩USB》配套的实验板。上面的单片机为STC89S52。实验板上P0接口用来和D12通讯,P1接口连接到一组开关按钮上,P2接口上有一组LED,LED另外一端通过10K电阻上拉。下面用色块对这些端口的用途做了简单标记:

usbs1

最开始的设想是数码管(用的还是上次出场过的那一款数码管,共阳极,【参考1】)阳极连接到P1(可以理解为SEG选择 Pin接正极),阴极连接到P2(数码段 Pin接负极)。实验发现数码管根本不亮,检查很多次后尝试去掉六个数码段的连接终于能够点亮一段数字。这才恍然大悟,因为共阳极上还有板载的LED所以会使得电压很奇怪,不足以推动全部。同时显示,所以需要更改方案。

做到这里,我忽然明白极客工坊大神弘毅提到的:“驱动数码管限流电阻肯定是必不可少的,限流电阻有两种接法,一种是在d1-d4阳极接,总共接4颗。这种接法好处是需求电阻比较少,但是会产生每一位上显示不同数字亮度会不一样,1最亮,8最暗。另外一种接法就是在其他8个引脚上接,这种接法亮度显示均匀,但是用电阻较多。” 因为电压相同,数字1只需要点亮两根LED,8需要点亮七根。

修改之后,阳极连接到P2,阴极连接到P1上。实验发现即使4个数字同时显示仍然是可以清晰辨认的。连接如下图所示:

usbsc

继续尝试在上位机程序中自动扫描点亮每个LED,前面一篇Arduino就是使用类似的方法点亮的。实做之后发现这样做会导致每个数码管亮灭之间的间隔太长,这样在人类看起来是逐个亮灭的而不是同时亮。猜测这是程序本身发送和USB传输Delay太长导致的。初步估计每个数字显示间隔至少在200ms以上。如果想做一个类似跑马灯的程序用这样的方案没问题,但是如果想持续稳定的显示数字这个方案不可行。

最后上位机程序直接发送显示的数值,由Firmware本身解析,同时利用单片机上的定时器(15ms一次),不断刷新每个显示位。开始时,Firmware中定时器产生中断后,ISR中将四位数值轮流显示一次,但是实验结果肉眼只能看到最后一个点亮的数值。估计这个可能是因为ISR中每个数码位显示过快,而他们点亮的时间远远小于不在ISR中的时间。

经过无数次的调试后,终于完成了。

resize

拍了一个视频,PC来控制七段数码管

http://www.tudou.com/programs/view/-D_w29Pwavc/?resourceId=414535982_06_02_99

对应的Firmware关键点在于中断服务函数

void Timer0Isr(void) interrupt 1
{ 
//LabzDebug_Start
   static i=0; 
//LabzDebug_End

//定时器0重装,定时间隔为5ms,加15是为了修正重装所花费时间
//这个值可以通过软件仿真来确定,在这里设置断点,调整使两次运行
//时间差刚好为5ms即可。
 TH0=(65536-Fclk/1000/12*5+15)/256;	 
 TL0=(65536-Fclk/1000/12*5+15)%256;   // 

//LabZDebug_Start
	P2=1 << i;
	P1=zBuf[i];
	i++;
	if (i==4) {i=0;}
//LabZDebug_End  

}

 

Firmware下载 HID7Seg

PC端上位机主要代码

							int n=0;	
						 	 while (kbhit()==0)
								{
								WriteReportBuffer[1]=Seven_Dig[n / 1000 % 10];
								WriteReportBuffer[2]=Seven_Dig[n / 100 % 10];
								WriteReportBuffer[3]=Seven_Dig[n / 10 % 10];
								WriteReportBuffer[4]=Seven_Dig[n %10];

								printf("%d \n",n);

								//调用WriteFile函数发送数据
								Result=WriteFile(hUsb,
												WriteReportBuffer,
											    9,
											    &lpNumberOfBytesWritten,
										       	NULL);
								//如果函数返回失败,则可能是真的失败,也可能是IO挂起
								if(Result==FALSE)
										{
											//获取最后错误代码
												LastError=GetLastError();
											//看是否是真的IO挂		
												if((LastError==ERROR_IO_PENDING)||(LastError==ERROR_SUCCESS))
													{ return TRUE;	}
												//否则,是函数调用时发生错误,显示错误代码
												else	
													{
														printf("Sending error:%d \n",LastError);
														//如果最后错误为1,说明该设备不支持该函数。
														if(LastError==1)
														{printf("This device doesn't support WriteFile function \n");}
													}
										}

									n=(n++)%10000;

								}//while (kbhit()==0)

 

完整的代码下载 USB7Seg

参考:

1. http://www.lab-z.com/4digitial/ Arduino 四位数码管实验
2. http://www.geek-workshop.com/forum.php?mod=viewthread&tid=82&highlight=%CA%FD%C2%EB%B9%DC arduino学习笔记13 – 4位数码管实验

使用Arduino直接发声

通常如果想让Arduino发出声音需要额外的配备,比如:Mp3解码器,Wav专用播放器或者语音合成的模块等等。

但是理论上因为Arduino具有模拟输出,所以应该可以直接输出波形给喇叭(这个还是必须的,我随便选了一个8欧1.5瓦的)。

arduinos

随手搜索了一下,国外真有人这样做了。原理上来说就是先用工具将音频转化为WAV, Arduino 的存储空间有限,这里只能使用单声道 8000Hz 采样率,然后通过控制模拟端口将数据发送出来。从我的实验来看,Arduino Uno(Flash Memory 32 KB 【参考1】)可以存放大约4s左右的音频(编译之后在 31K左右)。

具体的做法是:

1.硬件方面,喇叭负极连接到GND,正极连接到Pin11

2.在Arduino程序中使用下面这个库

damellis-PCM-ae3f463

3.选择音频文件,然后转化为 WAV 8000Hz Mono 格式(我Switch Sound File coverter 感觉不错,免费的)

wavcover

软件下载 switchsetup

4.最后用参考2提供工具,将wav转化为数组的定义(需要注意这个工具需要 javaw.exe 支持)

EncodeAudio-windows

5.编译之后 Upload 即可

用Windows自带的录音机录下来的

狼嚎

工具转化为 wav 8K mono

狼嚎

最后生成的程序

playback

做出来的样子

http://www.tudou.com/programs/view/SzuxR6-7oKI/?resourceId=414535982_06_02_99

参考:

1.http://kb.open.eefocus.com/index.php?title=Arduino_Uno Arduino Uno

2.http://highlowtech.org/?p=1963

soundarduino

===============================================================================
2015.2.23 补充:我在编译时发生“error: ‘OCR2A’ undeclared (first use in this function)” 这样一系列的错误,搜索了一下,是因为最近一直在玩 Arduino Pro Micro,它的芯片是 ATmega32u4 ,而这个芯片没有 Timer2 , 只有 0, 1, 3 和 4。IDE中重新切换回Uno再次编译即可。参考 http://forum.arduino.cc/index.php?topic=237770.0

再补充参考2给出来的那个转换工具

EncodeAudio-windows

再给出一个完整的Arduino程序例子
playback1

OpenCV 的cvCircle函数

写了一个小程序,获得摄像头输出之后直接在上面画图。

cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int lineType=8, int shift=0)

img为图像指针,单通道多通道都行,不需要特殊要求
center为画圆的圆心坐标
radius为圆的半径
color为设定圆的颜色,比如用CV_RGB(255, 0,0)设置为红色

thickness为设置圆线条的粗细,值越大则线条越粗,为负数则是填充效果 【参考1】

#include "stdafx.h"
#include "highgui.h"
#include "cv.h"
#include "stdio.h"
#include <ctype.h>
 
int main(int argc,char ** argv)
{
		int	r=0;

       CvCapture *capture = 0;

	   //从摄像头读取
       capture = cvCaptureFromCAM(0);

 
       if(!capture)
       {
              fprintf(stderr,"Could not initialize capturing...\n");
              return -1;
       }
 
       cvNamedWindow("Laplacian",1);
 
       //循环捕捉,直到用户按键跳出循环体
       for(;;)
       {
              IplImage * frame =0;
             
              //抓起一祯
              frame = cvQueryFrame(capture);
 
              if(!frame)
                     break;

			  r>20?r=0:r++;


			  //画一个圈  
			  cvCircle(frame,cvPoint(frame->width / 2,frame->height /2 ), 45+abs(10-r), CV_RGB(150, 100,100), 4, 8, 0);

              cvShowImage("Laplacian",frame);
 
              if(cvWaitKey(10)>0)
                     break;
       }
       cvReleaseCapture(&capture);
       cvDestroyWindow("Laplacian");
       return 0;
}

 

campaint

参考:
1.http://blog.163.com/yuhua_kui/blog/static/9679964420141104385570/ OpenCV cvCircle函数
2.http://wiki.opencv.org.cn/index.php/Cxcore%E7%BB%98%E5%9B%BE%E5%87%BD%E6%95%B0 Cxcore绘图函数

带有自动提示功能的手机座

起因:有网友抱怨,因为陪着孩子在家玩,漏接了公司的重要电话,被罚款500(如果真的是人民币的话,我相信他一定乐于看到这个产品)

看到这个需求,我忽然想是否可以用 Arduino来打造一个能够提醒的盒子呢? 当然,解决方法还有很多,严小姐听了我的目标之后第一个反应是为什么不换一个山寨机,大屏幕啊有没有,超长待机啊有没有,八个喇叭啊有没有,只要499啊有没有。我回答有很多人喜欢老物件有感情而已。她又在问为什么,终于被我意味深长的眼神说服了。

下面就开始动手实做了。从触发的角度来说最稳妥的办法还是安装APP,Android和iOS都是可行的,只是…….默默的轻抚了一下自己的 Nokia E72,放弃了这个方案。翻翻元件箱,里面有振动开关,那就凑合着用吧。提示方面,最近入手了一个具有录音放音功能的模块ISD1820,使用非常简单,GPIO足以搞定(多说一句,上面有麦克风和一个录音按钮,按下这个按钮对着它高歌一曲即记录在芯片中。时间比较短,只能记录10秒)。选用了 8×8 LED模块作为提示灯光,它在之前的《电子骰子系列》登场过。

原理上很简单,就是检测连续振动确定是振铃–>触发装置,每隔10秒提示一次–>如果有人按下Stop按钮就停止提示。

用到的配件

IMG_2553

用面包板来验证电路

IMG_2502

 

侧面有一个喇叭,一个按钮

IMG_2517

 

正面俯视,有一个 8×8点阵

 

IMG_2518

 

振动传感器

IMG_2550

 

内部线路看起来有点复杂

IMG_2551

 

另外一边做出一个洞,给 Arduino供电

 

IMG_2516

 

#include "LedControl.h"

const int ShockTestPin = 4; //Pin for vibration sensor
const int AlartPin = 5;     //LED Alert
const int StopPin = 6;      //Stop button
int sta=0;

//pin 12 is connected to the DataIn
//pin 11 is connected to the CLK
//pin 10 is connected to LOAD
//We have only a single MAX72XX.
LedControl lc=LedControl(12,11,10,1);

void showface() {
/* here is the data for the characters */
byte face[8]={
B00000100,
B00100010,
B01000110,
B01000000,
B01000000,
B01000110,
B00100010,
B00000100};

lc.setRow(0,0,face[0]);
lc.setRow(0,1,face[1]);
lc.setRow(0,2,face[2]);
lc.setRow(0,3,face[3]);
lc.setRow(0,4,face[4]);
lc.setRow(0,5,face[5]);
lc.setRow(0,6,face[6]);
lc.setRow(0,7,face[7]);

}

void setup() {

  Serial.begin(9600);

  pinMode(ShockTestPin, INPUT);   
  pinMode(AlartPin,OUTPUT);
  digitalWrite(AlartPin,LOW),
  pinMode(StopPin,INPUT);  //Stop pin for input

  //The MAX72XX is in power-saving mode on startup,
  //we have to do a wakeup call

  lc.shutdown(0,false);
  //Set the brightness to a medium values
  lc.setIntensity(0,8);
  //and clear the display
  lc.clearDisplay(0);

} // End of Setup

void loop() {
 long int start;
  
  if (0==sta) {       //Status One: Test status
     boolean shock=false;
     
     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);
     
     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);

     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);
    
     //It means we have test vibration in 3 seconds 
     sta=1;
  Sta1End:
      ;  
  }
  
  if (1==sta) {
      //Play the voice that we have record
      digitalWrite(AlartPin,LOW);
      digitalWrite(AlartPin,HIGH);
      delay(100);
      digitalWrite(AlartPin,LOW);
      
      //Delay 10 seconds
      start=millis();
     
      while (millis()-start<=15000L)
      {
        if (LOW==digitalRead(StopPin)) { //We will stop the playing ,if we test the stop button is pressed
          sta=0;
          lc.clearDisplay(0);   
          break;
        }
        if (0==(millis()-start)/1000L % 2) {
           showface(); 
        }
       else
        {
            lc.clearDisplay(0);          
        } 
      }//while (millis()-start<=15000L)

  }//if (1==sta)
}

 

具体的使用方法拍了一个简单的视频,本人倾力献

最后放两张靓照

IMG_2544

IMG_2547

这只是很粗糙的原型,如果真想做出来实用的还有很长的路要走。比如:让检测更灵敏更可靠,或者干脆使用手机的声音作为触发条件。提示音量再大一些。或者再加上充电功能就更加实用,也给需要一直插着让Arduino供电找到更好的借口。

然后严小姐的问题是:如果忽然有很强的振动,误触发了怎么办,如果家里确实没有人它又一直在叫怎么办,如果隔壁在装修,有振动有噪音怎么办?好吧,如果你肯再品准500+以上的预算,让我买块蓝牙开发板,我相信一定不是问题。哦,对了还要换一个支持Android的手机才好啊。