Max6675 热电偶

入手了一个热电偶温度传感器,这种东西是专门用来测试温度的,接触式的,具有测量范围大,精度高的特点。Taobao上搜索 “Arduino 热电偶”,卖家没有几个,我是从“圣源电子制作”的店铺卖的。

他家直接提供的代码包有问题,其中对应的Arduino程序无法打开。不知道是否有其他朋友也遇到过同样的问题。好在网上搜索到了对应的库 http://www.geek-workshop.com/forum.php?mod=viewthread&tid=4554&highlight=max6675 。测试了一下工作正常。最后代码如下

#include "Max6675.h"

Max6675 ts(8, 9, 10);
// Max6675 module: SO on pin #8, SS on pin #9, CSK on pin #10 of Arduino UNO
// Other pins are capable to run this library, as long as digitalRead works on SO,
// and digitalWrite works on SS and CSK

void setup()
{
	ts.setOffset(0);
	// set offset for temperature measurement.
	// 1 stannds for 0.25 Celsius

	Serial.begin(9600);
}


void loop()
{
	Serial.print(ts.getCelsius(), 2);
	Serial.print(" C / ");
	Serial.print(ts.getFahrenheit(), 2);
	Serial.print(" F / ");
	Serial.print(ts.getKelvin(), 2);
	Serial.print(" K\n");
	delay(300);
}

运行结果

完整的代码库下载

Max6675

PT100

Step to UEFI (20) —– 再论“ CLib 获得 ImageHandle”的问题

在翻看之前写的 《Step to UEFI (16) —– CLIB下获得 SystemTable》 【参考1】的时候偶然注意到:

加入头文件 #include Library/UefiBootServicesTableLib.h ,这个头文件的内容是

#ifndef __UEFI_BOOT_SERVICES_TABLE_LIB_H__
#define __UEFI_BOOT_SERVICES_TABLE_LIB_H__

///
/// Cache the Image Handle
///
extern EFI_HANDLE gImageHandle;

///
/// Cache pointer to the EFI System Table
///
extern EFI_SYSTEM_TABLE *gST;

///
/// Cache pointer to the EFI Boot Services Table
///
extern EFI_BOOT_SERVICES *gBS;

#endif

除了之前关注到的各种Table,居然还有一个 gImageHandle !!!

马上动手写了一个程序验证:

#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;
extern EFI_HANDLE        			  gImageHandle;

//SimpleTextInputEx.harderr
//#define	EFI_SHIFT_STATE_VALID		0x80000000
//#define EFI_LEFT_CONTROL_PRESSED	0x00000002

EFI_STATUS
EFIAPI
NotificationFunction(
	IN EFI_KEY_DATA	*KeyData
)
{
	printf("This is a test from www.lab-z.com \n");		
	return(EFI_SUCCESS);
}

/***
  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
  )
{
	EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
	EFI_KEY_DATA	KeyData;
	EFI_STATUS		Status;
	EFI_HANDLE		CtrlCNotifyHandle = NULL;
	INTN			i;

 	Status = gBS -> OpenProtocol(
		gST -> ConsoleInHandle,
		&gEfiSimpleTextInputExProtocolGuid,
		(VOID**)&SimpleEx,
		gImageHandle,
		NULL,
		EFI_OPEN_PROTOCOL_GET_PROTOCOL);

	if (EFI_ERROR(Status)) {
		printf("OpenProtocol ERROR!!\n");
	}		

	KeyData.KeyState.KeyToggleState = 0;
	KeyData.Key.ScanCode			= 0;
	KeyData.KeyState.KeyShiftState 	= EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED;
	KeyData.Key.UnicodeChar			= L's';

	Status = SimpleEx -> RegisterKeyNotify (
			SimpleEx,
			&KeyData,
			NotificationFunction,
			&CtrlCNotifyHandle);

	for (i=0;i<200;i++)
	 {
		printf("Test\n");		
		gBS -> Stall (5000);
      }

	Status = SimpleEx -> UnregisterKeyNotify(SimpleEx, CtrlCNotifyHandle);

  return EFI_SUCCESS;
}

运行结果和之前文章一样,就是说这个方法是OK的!

mainh2

 

程序下载 Mainh2

==============================================================================

这样的话,之前提到的方法完全就是“脱了裤子放屁—-多此一举”。

另外,再说点好玩的事情,前几天朋友圈里有人转了一篇文章,吹嘘他的“重要”发明“竖版世界地图”。文章的观点基本上是:中国最大的敌人是美国。美国和中国有多远?正常人看普通的世界地图会被误导,以为要横跨太平洋。但是实际上中国和美国如果从北极的方向走才是最近的。结论:看普通的世界地图会导致如此不堪的错误,用我发明的竖版世界地图就万事大吉。文章还在暗示设计北斗导航系统,差点因为看普通的地图而导致大错。

这里放一个“竖版的世界地图”【来自红网,Baidu搜出来的结果】

U9383P704DT20140623085032

怎么说呢,看着是挺别扭的,地球仿佛将菊花对准了你…………

我想看国家疆域,你把一个水球给我干嘛?

上小学和初中时学过一点地理知识。对于地图来说,基本上就是准确的看着不舒服,舒服看着不准确(投影决定的),根本原因是地球不是立方体,再仔细追究丫也不是标准的球体。

又想起来看过一篇文章,经常出国的人看每个国家的地图都觉得很别扭“为毛中国不是在中间?”

除了习惯的力量,还有这种竖版的地图,上面是北还是南?另外,莫非搞卫星的人不知道世界上还有一种“用空间中到定点的距离小于或等于定长的所有点组成图形的结构”结合“通用标记地面地理特性的方法”贴图在一起的通常我们称之为“地球仪”的东西吗?

说到这里,我也想有一个“伟大”的发明,那就是按照地球表面的凸凹形状做一个地球仪—-已经有了?没关系,那我就按照表面G的不同绘制吧。我也编一个故事:NK发射火箭没人考虑G点差别,一直无法满意。后来偶尔最高统帅看到我的地球仪,茅塞顿开………现在我的地球仪对NK是禁运的………

建议将 Google Earth 禁掉,我相信我的发明能更加“伟大”。

参考:

1.http://www.lab-z.com/step-to-uefi-16%EF%BC%89-clib%E4%B8%8B%E8%8E%B7%E5%BE%97-systemtable/ Step to UEFI (16) —– CLIB下获得 SystemTable

USB 控制七段数码管(II)

换个免驱的方式。前面之所以能免驱动,是因为我走的是USB HID协议。除了这个,更常见的是USB Mass Storage协议,就是我们常见的U盘走的协议。对于这个协议在《圈圈教你玩USB》中有详细介绍。下面就讲一下如何把我这个设备移植到MSD协议上。

首先说一下Firmware设计上的改变。

驱动数码管同样使用之前HID中的那种,用一个Timer不断循环点亮每一个数码管。因此,在Main.c中加入Timer0的初始化和中断服务程序。它会按照zBuf中给出来的依次点亮四个数码管。

volatile uint8 zBuf[]={1,2,3,4}; //用来保存8字节的输出报告。

/********************************************************************
函数功能:定时器0初始化,用来做键盘扫描。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void InitTimer0(void)
{
 TMOD&=0xF0;
 TMOD|=0x01;
 ET0=1;
 TR0=1;
}

/********************************************************************
函数功能:定时器0中断处理。
入口参数:无。
返    回:无。
备    注:22.1184M晶体约5ms中断一次。
********************************************************************/
void Timer0Isr(void) interrupt 1
{ 
   static i=0; 

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

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

 

PC对USB Mass Storage 设备传数据,使用的是 WRITE(10) 命令,具体的数据会在批量传输协议中的批量数据阶段传输给设备。具体对应在代码中 SCSI.C 中的 procScsiOutData 中,我们在这里将收到的输局赋值给 zBuf.

/********************************************************************
函数功能:处理输出数据。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void ProcScsiOutData(void)
{
 uint8 Len;
 int i;

 //读端点2数据
 Len=D12ReadEndpointBuffer(4,EP2_SIZE,Ep2Buffer);

 //LabzDebug_Start 
 zBuf[0]=Ep2Buffer[0]; zBuf[1]=Ep2Buffer[1]; zBuf[2]=Ep2Buffer[2]; zBuf[3]=Ep2Buffer[3];

  PrintHex(zBuf[0]);
  PrintHex(zBuf[1]);
  PrintHex(zBuf[2]);
  PrintHex(zBuf[3]);
  Prints("\r\n");

 #ifdef DEBUG1
 Prints("收到 \r\n");
 for ( i=0; i <4;i++)
 {
  PrintHex(*(Ep2Buffer+i));  //如果需要显示调试信息,则显示发送的数据
  if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次
  PrintHex(zBuf[0]);
  PrintHex(zBuf[1]);
  PrintHex(zBuf[2]);
  PrintHex(zBuf[3]);
  if((Len%16)!=0)Prints("\r\n"); //换行
 }
 #endif
 //LabZDebug_End
 Ep2DataLength-=Len;
 //清除端点缓冲区
 D12ClearBuffer();
 //由于没有存储器,这里将缓冲区清0模拟数据处理
 while(Len)
 {
  Ep2Buffer[Len]=0; //缓冲区清0
  Len--;
 }
 
 //数据传输完毕,进入到状态阶段
 if(Ep2DataLength==0)
 {
  //此时Ep2DataLength为0,并且处于数据阶段,调用发送数据函数将返回CSW
  Ep2SendData();
 }
}

 

只要做这一点Change,Firmware即可支持。

其次说一下上位机程序的设计。

因为模拟成一个U盘,因此,按照访问硬盘的方式即可传输数据。先是使用CreateFile打开PhysicalDriverX (特别注意:从PhysicalDriver0开始),之后就用 WriteFile 进行写入,特别注意,写入的最小单位是512字节,不能小于这个值。最后CloseHandle关闭即可。

最初,程序设计出来是这样的

CreateFile(PhysicalDrive3)

while Keypressed=false
{
WriteFile (512 Byte)
}

CloseHandle

结果发现非常奇怪,只有第一次能够顺利写入512Bytes,之后会不断出现 Error 5 ERROR_ACCESS_DENIED 5 (0x5) Access is denied. 的问题。为了防止是我设备不稳定造成的,我还用一个U盘进行试验(特别注意,操作会导致U盘内容不可读!!!)在Windows 7 x64和WindowsXP 32 都有同样的现象。请教天杀,他回复“想起来了,Win7的确有这个问题,可以写分区表,但是不能写后续的分区位置,是会被拒绝的。要写数据必须通过分区去写,或者将分区删除。你可以把设备识别成USB HDD,然后没有分区,这样应该可以全盘去写。如果是没有分区的那种U盘形式,是可能会被禁止写入的。”

这样的话,第一个方案就出来了,每次都要用CreateFile打开硬盘,写入之后再Close。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

int main(int argc, char *argv[])
{
   HANDLE hFile;
   BOOL fSuccess;
   char txchar[512];
   DWORD iBytesWritten;
   byte Seven_Dig[10]={   0x40,  // = 0
						  0x79,  // = 1	
						  0x24,  // = 2
						  0x30,  // = 3
                          0x19,  // = 4	
						  0x12,  // = 5
						  0x02,  // = 6
                          0x78,  // = 7	
						  0x00,  // = 8
						  0x10,  // = 9
                             }; 



 int n=1234;	
 while (kbhit()==0)
  {
	  hFile = CreateFile(L"\\\\.\\PhysicalDrive2",
                    GENERIC_WRITE,
                    FILE_SHARE_WRITE,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hFile == INVALID_HANDLE_VALUE) 
   {
       // Handle the error.
        printf ("CreateFile failed with error %d.\n", GetLastError());
		system("PAUSE");
        return (1);
   }

   txchar[0]=Seven_Dig[n / 1000 % 10];
   txchar[1]=Seven_Dig[n / 100 % 10];
   txchar[2]=Seven_Dig[n / 10 % 10];
   txchar[3]=Seven_Dig[n %10];
								
  for (int i=1;i<512 /4;i++) 
   {
 txchar[i*4]=txchar[0];
 txchar[i*4+1]=txchar[1];
  txchar[i*4+2]=txchar[2];
  txchar[i*4+3]=txchar[3];
   }

fSuccess=WriteFile(hFile, &txchar, 512, &iBytesWritten,NULL);
printf ("done send %d bytes.Status [%d] \n", iBytesWritten,fSuccess);
printf ("Get lasterror %d\n", GetLastError());
printf("%d \n",n);

n=(n++)%10000;
FlushFileBuffers(hFile);
Sleep(1000);
 CloseHandle(hFile);
}//while (kbhit()==0)

   system("PAUSE");


   return (0);
}

 

第二个方案就是每次用WriteFile写入之后,我们再重置指针,再从最开始写入。类似下面的方案。

CreateFile(PhysicalDrive3)

while Keypressed=false
{
SetFilePointer(hFile,0,0,FILE_BEGIN);
WriteFile (512 Byte)
}

CloseHandle

实际的效果和之前的HID的方式相同。

Firmware下载 USB7SegFW

第一种上位机程序下载
exp1

第二种上位机程序下载
exp2

PWM 控制LED亮度

写了一个简单的程序,使用Arduino Uno上 PWN Pin 来控制一个LED的亮度。

代码方面是从串口接收信息,“[”减小,“]”增加

int  n=100;
void setup()
{
    Serial.begin(9600);
    pinMode(6,OUTPUT);      //该端口需要选择有#号标识的数字口
}

void loop()
{
  char  c;

    while (Serial.available() > 0)  
    {
        c=Serial.read();
        if (']'==c) 
          {
            n=n+5;
          }
        if ('['==c) 
          {
            n=n-5;
          }
       if (n>255) {n=0;}
       if (n<0) {n=255;}   
       analogWrite(6,n); 
       Serial.println(n);

    }
}

电路连接仿照【参考1】.刚开始使用220欧的电阻,发现亮度变化不均匀,在100以上之后看不出来亮度有多少变化,之后,改成 2.4K  电阻(2个1.2K串联),表现更好。

PWMLED1 PWMLED2

 

参考:

1.http://www.geek-workshop.com/forum.php?mod=viewthread&tid=1054&highlight=pwm Arduino入门教程–第五课–按钮PWM控制LED亮度

Step to UEFI (19) —– Shell Command Stall 命令的分析

随手翻了一下 UEFI Shell 的 Source ,看了一下 Stall 命令觉得挺有意思,研究了一下。

这个命令的介绍如下,实现了一个很简单的功能:暂停 xxx 微妙 (MicroSeconds 百万分之一秒)

stallcmd

对应的代码在 \Shell\stall\stall.c 可以看到

关键部分的代码是:

  Microseconds = Atoi (ChkPck.VarList->VarStr);  //要暂停的时间 UINTN Microseconds;
  PrintToken (STRING_TOKEN (STR_STALL_FOR), HiiStallHandle, Microseconds);
  Remaining = Microseconds % 100000;
  Status    = RT->GetTime (&TmpTime, NULL);      //取当前时间 
  if (EFI_ERROR (Status)) {
    Status = EFI_ABORTED;
    goto Done;
  }

  MilliSeconds1 = (TmpTime.Hour * 3600 + TmpTime.Minute * 60 + TmpTime.Second) * 1000; //当前时间转化为毫秒
  while (Microseconds - Remaining) {
    //
    // Break the execution?
    //
    if (GetExecutionBreak ()) {  //允许打断
      goto Done;
    }

    BS->Stall (100000);          //暂停 1秒
    Status = RT->GetTime (&TmpTime, NULL);
    if (EFI_ERROR (Status)) {
      Status = EFI_ABORTED;
      goto Done;
    }

    MilliSeconds2 = (TmpTime.Hour * 3600 + TmpTime.Minute * 60 + TmpTime.Second) * 1000;
    if (MilliSeconds2 < MilliSeconds1) { //如果发生跨天的情况,算了一下 0xFFFFFFFF 个微秒最多只能跨一天
      MilliSeconds2 += (24 * 3600 * 1000);
    }

    if ((Microseconds - Remaining) / 1000 <= (MilliSeconds2 - MilliSeconds1)) {
      break;
    }
  } // while (Microseconds - Remaining) 结束

  BS->Stall (Remaining);

 

看起来整个过程就是:使用 BS 的 Stall 不断做短时间的暂停,直到完成预订的Stall 时间。不过想不太明白,这样做同直接 BS -> Stall 指定的时间相比能获得什么好处?莫非是给一个能够用 Ctrl-Break 的机会么?

参考:
1. Shell Stall 命令的介绍,来自 UEFI Shell Specification Rev 2.1
2. BS->Stall 的介绍,来自 UEFI Spec 2.4
bsstall

通过WriteFile对硬盘发送数据

下面这个程序首先用 CreateFile 打开 PhysicalDiskX 然后使用 CreateFile 向里面写入数据。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>

int main(int argc, char *argv[])
{
   HANDLE hFile;
   BOOL fSuccess;
   char txchar[512];
   DWORD iBytesWritten;

   hFile = CreateFile(L"\\\\.\\PhysicalDrive1",
                    GENERIC_WRITE,
                    FILE_SHARE_WRITE,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hFile == INVALID_HANDLE_VALUE) 
   {
       // Handle the error.
        printf ("CreateFile failed with error %d.\n", GetLastError());
		system("PAUSE");
        return (1);
   }

   txchar[0]='l'; txchar[1]='a';txchar[2]='b';txchar[3]='z';

   //有资料说用这个函数对磁盘写的最小值是 512 bytes 我实验了一下如果小于此会出现error
   fSuccess=WriteFile(hFile, &txchar, 512, &iBytesWritten,NULL);
   printf ("done send %d bytes.Status [%d] \n", iBytesWritten,fSuccess,iBytesWritten);
   printf ("Get lasterror %d\n", GetLastError());

   system("PAUSE");
   CloseHandle(hFile);

   return (0);
}

 

我的实验是在虚拟机中进行的。特别提醒:本次实验可能会损害你的数据,请务必小心。如果系统有安装杀毒软件,有可能被判定为病毒行为。实验的目标盘是一个U盘,盘符为 G:

a

之后,先用 Winhex 打开,我们可以看到开始的几个字符是 abcd

b

运行我们的程序(可以看到发送 512 Bytes Status=1 表示 Success GetLastError=0 表示无错误)
c

我们需要重新打开一次硬盘(WinHex有磁盘修改感知功能,但是在这里不好用)
e

我们可以看到最开始的几个字符被修改了,这说明我们的程序是由效果的的。
d

完整的程序下载:

sendbywritefile

参考:

1.http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx MSDN WriteFile function

2.http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx MSDN System Error 对于确定 GetLastError 返回值很有用

3.http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx MSDN CreateFile function

小问题:UEFI 下,Print 怎样显示十进制的64位的无符号数呢?

有人【参考1】,提了一个问题:UEFI 下,Print 怎样显示十进制的64位的无符号数呢?

首先查了一下资料【参考2】

printfll

于是,试试 %llu 看看, ll 表示 long long, u表示十进制无符号数,代码

int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{

  printf("%llu\n",0xffffffffL);  

  return EFI_SUCCESS;
}

 

执行结果

quest1

参考:

1.http://biosren.com/viewthread.php?tid=7419&highlight= UEFI 下,Print 怎样显示十进制的64位的无符号数呢?

2.http://www.cplusplus.com/reference/cstdio/printf/

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在线计算网站

Step to UEFI (18) —– CLib 获得 ImageHandle

前面介绍了,用CLib我们可以编写出普通C语言一样的代码。入口是 main (int Argc, char **Argv),但是如何获得当前的 ImageHandle 呢?【参考1】给出了一个答案。查看实际的入口ShellCEntryLib (ShellPkg\Library\UefiShellCEntryLib\UefiShellCEntryLib.c)

EFI_STATUS
EFIAPI
ShellCEntryLib (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  INTN                           ReturnFromMain;
  EFI_SHELL_PARAMETERS_PROTOCOL *EfiShellParametersProtocol;
  EFI_SHELL_INTERFACE           *EfiShellInterface;
  EFI_STATUS                    Status;

 

就是说 Shell Call进来的时候实际上和普通的EFI 程序没有差别,都是给了ImageHandle的,只是后面调用的时候去掉了。调用的顺序是 ShellCEntryLib –> ShellAppMain –> main.c(自己写的),所以如果我们能够加入一个参数,那么可以直接把ImageHandle传进去。
那就手动加入这个参数吧,需要修改的文件和内容如下:
1. ShellPkg\Library\UefiShellCEntryLib\UefiShellCEntryLib.c

if (!EFI_ERROR(Status)) {
    //
    // use shell 2.0 interface
    //
    ReturnFromMain = ShellAppMain (
					   ImageHandle,  //

 

2. ShellPkg\Inlcude\Library\ShellCEntryLib.h

INTN
EFIAPI
ShellAppMain (
  IN EFI_HANDLE        ImageHandle, //

 

3. StdLib\LibC\Main\Main.c

INTN
EFIAPI
ShellAppMain (
IN EFI_HANDLE ImageHandle, //<——-Added
IN UINTN Argc,
IN CHAR16 **Argv
)

4.我们自己的程序 main.c ,和之前文章提到的只有main被修改了

/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
    This program and the accompanying materials
    are licensed and made available under the terms and conditions of the BSD License
    which accompanies this distribution. The full text of the license may be found at
    http://opensource.org/licenses/bsd-license.

    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#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;

//SimpleTextInputEx.harderr
//#define	EFI_SHIFT_STATE_VALID		0x80000000
//#define EFI_LEFT_CONTROL_PRESSED	0x00000002

EFI_STATUS
EFIAPI
NotificationFunction(
	IN EFI_KEY_DATA	*KeyData
)
{
	printf("This is a test from www.lab-z.com \n");		
	return(EFI_SUCCESS);
}

/***
  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 EFI_HANDLE        ImageHandle,  //

 

之后还是使用 build –a IA32 –p AppPkg\AppPkg.dsc 来编译,之前如果里面还有编译器他的Application,那么需要从 AppPkg.dsc中先去掉其余的Application。
编译之,通过;运行之和之前的结果一样,好用。

buildimge

本文提到的程序可以在这里下载
Main

上面的程序看起来有些复杂,还会破坏自己的编译环境,后面我会继续研究找到更好的解决方法。就是这样。

参考:
1. 论坛上有人提出了类似的问题
http://biosren.com/viewthread.php?tid=4651&highlight=ShellCentrylib
一直有這個疑問~
目前寫的Shell APP的進入點,參數都是argc,argv
那要怎麼得到他的ImageHandle呢?

UefiShellCEntryLib.c
EFI_STATUS
EFIAPI
ShellCEntryLib (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)

MyShellApp.c
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)

实验 DS1307 RTC 模块

之前入手过一个 DS1307 模块,但是一直没有实验,今天拿出来玩玩。

实验之前先研究硬件,上面有一个电池,上面写的是 Rechargable ,拆下电池用万用表测试了一下,没有电。不过后来连接USB之后由拔下来稍微放置了一点时间再插上,发现计时仍在继续。应该是充进去一点电了。

1

I2C 接口的,接线很简单【参考1】:

ds1307con

接下来测试程序,当然为了简单起见还是直接用库。但是不知道为什么连续找了几个库编译都无法完成。最终,找到一个好用的库【参考2】

编写简单的测试程序如下

#include <Wire.h>
#include "DS1307A.h"
DS1307A ds = DS1307A(2000);
DS1307A_RAM ram;
void setup()
{     
    Serial.begin(9600);                //init serial

    //ds.setDate(2014,10,1);
    //ds.setTime(20,17,40);
    //ds.setWeek(MONDAY);

}  
void loop()   
{ 
    Time t = ds.getTime();

    Serial.print( t.year);
    Serial.print(".");     
    Serial.print(t.month);     
    Serial.print(".");     
    Serial.print(t.date);     
    Serial.print("  ");     
    Serial.print(t.hour);     
    Serial.print(":");     
    Serial.print(t.minute);     
    Serial.print(":");     
    Serial.print(t.second);     

    Serial.println(); 

    //Serial.print(ds.getDateString("YMD",'-'));
    //Serial.print(" ");
    //Serial.println(ds.getTimeString("HMS",':'));    

    delay(1000);

}

 

运行结果如下

DS1307

代码和测试程序在此 DS1307

参考:

1.http://www.geek-workshop.com/forum.php?mod=viewthread&tid=207&extra=&highlight=ds1307&page=4 arduino学习笔记27 – DS1307 RTC时钟芯片与DS18B20数字温度传感器实验 (特别提醒,这篇文章中给出的库编译无法通过)

2.http://www.geek-workshop.com/thread-2317-1-1.html 自己封装的arduino1.0.1时钟库,使用DS1307芯片
你可以在这里下载文章中提到的库 DS1307A

====================================================================================================================================================================
2015/04/24 特别注意:这个模块对电压比较敏感,特别如果你是 Pro Micro之类的板子,VCC出来的电压可能是 4.6V ,这时候是无法正常工作的,会出现各种稀奇古怪的问题。