此程序是在51hei單片機開發(fā)板上面做的,如需要移植到自己的電路上,修改相應的端口即可,開發(fā)板完整的電路圖下載: 點這里 (注意:只需要看相關(guān)部分的連線如液晶屏 等和單片機的連接方式,其他部分可以忽略)
/**
****************************************************************************
* @file main.c
* @author xr
* @date 2014年4月10日22:21:56
* @version V1.2.3
* @brief 在LCD1602上顯示時鐘,當前溫度值,和NEC協(xié)議的紅外解碼值
* @note 單片機STC89C52RC MCU 晶振 11.0592MHZ
****************************************************************************
*/
#include "mytype.h"
bit flag1s = 0;//1s時間標志位
bit flag200ms = 0;//200ms標志
uint8 thr0, tlr0;
uint8 counter = 0, i = 0;
uint8 code LedTable[] = {
0xC0, //"0"
0xF9, //"1"
0xA4, //"2"
0xB0, //"3"
0x99, //"4"
0x92, //"5"
0x82, //"6"
0xF8, //"7"
0x80, //"8"
0x90, //"9"
0x88, //"A"
0x83, //"B"
0xC6, //"C"
0xA1, //"D"
0x86, //"E"
0x8E //"F"
};
extern void LcdShowStr(uint8 x, uint8 y, uint8 * str);
extern bit StartDs18B20();
extern bit ReadDs18B20Temp(int * temp);
extern void DS1302BurstRead(uint8 * time);
extern bit Irflag;//紅外遙控器解碼數(shù)據(jù)接收完成標志
extern uint8 Ircode[4];//存放遙控器解碼值(用戶碼, 用戶碼反碼,鍵碼,鍵碼反碼)
void ConfigTimer0(uint16 xms);
uint8 IntToString(uint8 * str, int dat);
{
uint8 buf[4];
uint8 len = 0;
int temp;//溫度
int intT, decT;//整數(shù)部分,小數(shù)部分
uint8 str[20];
uint8 time[20];//保存時間(BCD碼值)
uint8 psec = 0xFF;//sec最大是59,所以一定能刷新顯示
InitLcd1602();
InitDS1302();
ConfigTimer0(10);//定時10ms
StartDs18B20();
InitInfrared();
while (1)
{
if (Irflag) //紅外解碼
{
Irflag = 0;
buf[0] = Ircode[2] / 10 % 10;//按鍵碼的十位數(shù)
buf[1] = Ircode[2] % 10;//按鍵碼的個位數(shù)
str[0] = buf[0] + '0';
str[1] = buf[1] + '0';
str[2] = '\0';
LcdShowStr(14, 1, str);
}
if (flag200ms) //200ms刷新時鐘顯示
{
flag200ms = 0;
DS1302BurstRead(time);
if (psec != time[0]) //time[0]保存的是sec寄存器的BCD碼值
{
//刷新顯示
//日期
str[0] = '2';
str[1] = '0';
str[2] = (time[6] >> 4) + '0';//取年十位
str[3] = (time[6] & 0x0F) + '0';//取年個位轉(zhuǎn)字符
str[4] = '-';
str[5] = (time[4] >> 4) + '0'; //月十位
str[6] = (time[4] & 0x0F) + '0'; //月個位
str[7] = '-';
str[8] = (time[3] >> 4) + '0'; //日十位
str[9] = (time[3] & 0x0F) + '0'; //日個位
str[10] = '\0';
LcdShowStr(0, 0, str);
//時間
str[0] = (time[2] >> 4) + '0';//時十位
str[1] = (time[2] & 0x0F) + '0';//時個位
str[2] = ':';
str[3] = (time[1] >> 4) + '0';
str[4] = (time[1] & 0x0F) + '0';
str[5] = ':';
str[6] = (time[0] >> 4) + '0';
str[7] = (time[0] & 0x0F) + '0';
str[8] = '\0';
LcdShowStr(0, 1, str);
//星期
str[0] = (time[5] & 0x0F) + '0';//星期只有一位數(shù)字
str[1] = '\0';
LcdShowStr(11, 0, "Week");
LcdShowStr(15, 0, str);
psec = time[0];
}
}
if (flag1s) //1s刷新溫度顯示
{
flag1s = 0;
fack = ReadDs18B20Temp(&temp);//讀取溫度
if (fack) //讀取成功
{
intT = (temp >> 4);//整數(shù)部分,將小數(shù)部分移出
decT = (temp & 0x000F);//小數(shù)部分
len = IntToString(str, intT);//將intT整數(shù)部分轉(zhuǎn)換成字符存入str中,并返回有效字符個數(shù)
str[len++] = '.';//小數(shù)點
decT = decT * 10 / 16 % 10;//小數(shù)部分轉(zhuǎn)換
str[len++] = decT + '0';
str[len] = '\0';
LcdShowStr(8, 1, "T:");
LcdShowStr(10, 1, str);
}
else
{
LcdShowStr(0, 0, "error!");
}
}
StartDs18B20();//重新啟動溫度轉(zhuǎn)換
}
}
void ConfigTimer0(uint16 xms)
{
uint16 tmp;
tmp = 65536-xms*11059200/12/1000;
thr0 = (uint8)(tmp >> 8);//取高字節(jié)
tlr0 = (uint8)(tmp & 0x00FF);//取低字節(jié)
TMOD &= 0xF0;//清零T0控制位
TMOD |= 0x01;//T0方式1
TH0 = thr0;
TL0 = tlr0;//裝入定時初值
TR0 = 1;//啟動T0定時器
EA = 1;//開總中斷
ET0 = 1;//開定時器T0中斷
//PT0 = 1;//設(shè)置T0中斷優(yōu)先級為最高級
}
unsigned char IntToString(unsigned char * str, signed int dat)
{
unsigned char len = 0;//統(tǒng)計有效字符的個數(shù)
signed char i = 0;//計數(shù)器
unsigned char buff[6];//數(shù)據(jù)分解緩沖區(qū)
if (dat < 0) //負數(shù)
{
dat = -dat;//取絕對值
*str++ = '-';//前面加上-
len++;//長度++
}
//分解整數(shù)dat到buff中
do
{
buff[i++] = dat % 10;
dat /= 10;
} while (dat > 0);//分解到dat==0為止
len += i;//長度+i,有效字符個數(shù)
while (i-- > 0) //拷貝轉(zhuǎn)換后的ASIIC碼字符到str接收指針中
{
*str++ = buff[i] + '0';//轉(zhuǎn)換成ASCII字符
}
*str = '\0';//加上串結(jié)束符
return len;//返回有效字符個數(shù)
}
void timer0_ISP() interrupt 1
{
TH0 = thr0;
TL0 = tlr0;
counter++;
if (counter >= 20)
{
counter = 0;
flag200ms = 1;
i++;
if (i >= 5)
{
i = 0;
flag1s = 1;
}
}
}
/**********自定義頭文件************/
#define _MYTYPE_H_H
typedef unsigned char uint8;
typedef unsigned long uint32;
/***************LCD1602.c*********************/
#include "mytype.h"
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_EN = P1^5;
void WaitLcd1602()
{
uint8 sta;
LCD1602_DB = 0xFF;//拉高P0口
LCD1602_RS = 0;
LCD1602_RW = 1;
do
{
LCD1602_EN = 1;
sta = LCD1602_DB;
LCD1602_EN = 0;//關(guān)閉液晶的數(shù)據(jù)輸出
} while (sta & 0x80);
}
void WriteLcd1602Cmd(uint8 cmd)
{
WaitLcd1602();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_EN = 1;//高脈沖
LCD1602_EN = 0;
}
void WriteLcd1602Data(uint8 dat)
{
WaitLcd1602();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_EN = 1;//高脈沖
LCD1602_EN = 0;
}
void InitLcd1602()
{
WriteLcd1602Cmd(0x38);//設(shè)置16*2顯示 5*7點陣 8位數(shù)據(jù)口
WriteLcd1602Cmd(0x0C);//開顯示不顯示光標
WriteLcd1602Cmd(0x06);//寫入一個字符時字符指針++且地址++
WriteLcd1602Cmd(0x01);//清屏
}
void LcdShowStr(uint8 x, uint8 y, uint8 * str)
{
uint8 addr;
if (y == 0)
{ //第一行
addr = 0x00 + x;
}
else
{ //第二行
addr = 0x40 + x;
}
WriteLcd1602Cmd(0x80 | addr);
while (*str != '\0')
{
WriteLcd1602Data(*str++);
}
}
/**
*********************************************************************
* @file infrared.c
* @author xr
* @date 2014年4月11日08:25:04
* @version V1.2.3
* @brief 紅外通信-NEC協(xié)議紅外遙控器解碼驅(qū)動
* @note 單片機STC89C52RC MCU 晶振 11.0592MHZ
*********************************************************************
*/
#include <reg52.h>
#include "mytype.h"
sbit IRD = P3^3;
uint8 Ircode[4];//存放遙控器解碼值(用戶碼, 用戶碼反碼,鍵碼,鍵碼反碼)
* @brief 紅外通信配置
* @param 無
* @retval 無
*/
void InitInfrared()
{
//使用定時器T1作為計數(shù),不定時也不進入T1中斷
TMOD &= 0x0F;//清零T1控制位
TMOD |= 0x10;//設(shè)置T1方式1
ET1 = 0;//禁止T1中斷
TR1 = 0;//在外部中斷引腳即紅外通信引腳沒有載波(低電平)和空閑(高電平)時,先關(guān)閉T1計數(shù)
TH1 = 0;
TL1 = 0;//清零T1計數(shù)值
//使能外部中斷1
IT1 = 1;//設(shè)置INT1中斷觸發(fā)方式為負邊沿觸發(fā)
EX1 = 1;//開啟外部中斷1
EA = 1;//開啟總中斷
PX1 = 1;
}
* @brief 獲取紅外通信引腳載波(低電平)計數(shù)值
* @param 無
* @retval 載波計數(shù)值(即T1計數(shù)值)
*/
uint16 GetLowCounter() //計數(shù)值*(12/11059200)即是載波時間,計數(shù)值=TH1*256+TL1
{
IRD = 1;//在檢測IRD引腳電平時要將此引腳拉高釋放
TH1 = 0;
TL1 = 0;//清零T1計數(shù)值
TR1 = 1;//開啟T1計數(shù)
while (!IRD) //若IRD=0,T1開始計數(shù)
{
//超時判斷,因為引導碼的載波時間是9ms,所以不能等待太長時間
if (TH1 > 0x40) //超過20ms就強制退出 (TH1*256*(12/11059200)s)
{
break;
}
}
TR1 = 0;//關(guān)閉T1計數(shù)
return (TH1*256 + TL1);//返回計數(shù)值(TL1加滿到256向TH1進1)
}
* @brief 獲取空閑時間計數(shù)值(高電平)
* @param 無
* @retval 空閑計數(shù)值
*/
uint16 GetHeighCounter()
{
IRD = 1;//拉高釋放引腳,以檢測IRD引腳的電平
TH1 = 0;
TL1 = 0;//清零T1計數(shù)值
TR1 = 1;//開啟計數(shù)
while (IRD)
{
if (TH1 > 0x40) //等待超出20ms,則認為是錯誤,強制退出
{
break;
}
}
TR1 = 0;//關(guān)閉T1計數(shù)
return (TH1*256 + TL1);//返回T1計數(shù)值
}
* @brief 外部中斷1服務程序(判斷解碼)
* @param 無
* @retval 無
*/
void EXINT1_ISP() interrupt 2 //INT1中斷標號:2
{
//NEC協(xié)議:引導碼(9ms載波+4.5ms的空閑) 用戶碼-用戶反碼-鍵碼-鍵碼反碼-停止位
// 比特值0:(560us的載波+560us的空閑) 比特值1:(560us的載波+1.68ms的空閑)
uint8 i, j;
uint8 byte;//接收字節(jié)
uint16 time;//獲取時間
//首先判斷引導碼
time = GetLowCounter();//time*12/11059200*1000ms
if ((time < 7834) || (time > 8755)) //如果不在8.5ms-9.5ms的范圍就清零外部中斷1標志位,退出中斷
{
IE1 = 0;//清零中斷標志
return;//退出中斷函數(shù)
}
time = GetHeighCounter();//空閑
if ((time < 3686) || (time > 4608)) //如果不在4ms-5ms的范圍就退出中斷
{
IE1 = 0;//中斷標志硬件置位,軟件清零
return;
}
//引導碼正確,開始接收解碼數(shù)據(jù)
for (i = 0; i < 4; i++) //接收4個字節(jié)數(shù)據(jù)
{
for (j = 0; j < 8; j++) //每個字節(jié)8bit
{
time = GetLowCounter();//載波時間計數(shù)
if ((time < 424) || (time > 608)) //如果載波時間不在460-660us的范圍則認為是誤碼,退出中斷
{
IE1 = 0;
return;
}
//檢測到560us的載波,開始判斷是560us的空閑還是1.68ms的空閑
time = GetHeighCounter();//空閑
if ((time > 424) && (time < 608)) //560us的空閑(即比特0)
{
//低位在先,逐位右移
byte >>= 1;//右移一位0
}
else if ((time > 1198) && (time < 1659)) //1.68ms的空閑 1.3-1.8ms
{
byte >>= 1;//低位在先,先右移出一位
byte |= 0x80;//再將這一位置1
}
else
{
//誤碼
IE1 = 0;
return;
}
}
Ircode[i] = byte;//循環(huán)接收解碼字節(jié)數(shù)據(jù)
}
//4個字節(jié)全部接收完成
Irflag = 1;
IE1 = 0;
}
/**
*******************************************************************
* @file ds1302.c
* @author xr
* @date 2014年4月10日17:31:07
* @version V1.2.3
* @brief DS1302底層驅(qū)動 單片機STC89C52RC MCU 晶振11.0592MHZ
*******************************************************************
*/
#include <reg52.h>
#include "mytype.h"
sbit DS1302_SCK = P3^5;
sbit DS1302_SIO = P3^4;
sbit DS1302_CE = P1^7;
* @brief DS1302寫一個字節(jié)數(shù)據(jù)
* @param 待寫入的字節(jié)
* @retval 無
*/
void DS1302WriteByte(uint8 byte)
{
uint8 mask = 0x01;//發(fā)送掩碼(低位在前,逐位發(fā)送)
DS1302_SCK = 0;
for (mask = 0x01; mask != 0; mask <<= 1) ////發(fā)送掩碼(低位在前,逐位發(fā)送)
{
if ((mask & byte) == 0)
{
DS1302_SIO = 0;
}
else
{
DS1302_SIO = 1;
} //將數(shù)據(jù)準備好
DS1302_SCK = 1;//先來一個上升沿,從機DS1302進行數(shù)據(jù)的采樣鎖存
DS1302_SCK = 0;//再來一個下降沿,主機進行數(shù)據(jù)的輸出
}
//當一個字節(jié)的數(shù)據(jù)發(fā)送完成后,主機(即單片機)釋放SIO數(shù)據(jù)總線,由DS1302進行數(shù)據(jù)的發(fā)送
DS1302_SIO = 1;
}
* @brief DS1302讀一個字節(jié)的數(shù)據(jù)
* @param 無
* @retval 返回讀取到的數(shù)據(jù)
*/
uint8 DS1302ReadByte()
{
uint8 byte = 0;//存放待讀取的字節(jié)
uint8 mask = 0x01;//接收掩碼(低位在先,逐位接收)
DS1302_SCK = 0;
for (mask = 0x01; mask != 0; mask <<= 1) //(低位在先,逐位接收)
{
if (DS1302_SIO == 1)
{
byte |= mask;//字節(jié)byte的相應位置1
}
else
{
byte &= ~mask;//字節(jié)byte的相應位清零
}
DS1302_SCK = 1;//先來一個上升沿,主機進行數(shù)據(jù)采樣接收
DS1302_SCK = 0;//再來一個下降沿,從機DS1302進行數(shù)據(jù)輸出
}
return (byte);
}
* @brief 向DS1302寄存器中寫入數(shù)據(jù)
* @param 待寫入數(shù)據(jù)的寄存器地址reg和待寫入的數(shù)據(jù)dat
* @retval 無
*/
void WriteDS1302(uint8 reg, uint8 dat)
{
DS1302_CE = 1;//使能DS1302
DS1302WriteByte((reg << 1) | 0x80);//寄存器的最高位固定位1第二位為RAM/CLK選擇位,A5-A1為寄存器地址位
//且有效位為A3-A1,A0位為讀寫方向位
DS1302WriteByte(dat);//寫入數(shù)據(jù)
DS1302_CE = 0;//關(guān)閉片選
DS1302_SIO = 0;//由于本版本的開發(fā)板上的DS1302的SIO口沒有加上拉電阻,在釋放SIO后SIO處于
//非0非1的不穩(wěn)定狀態(tài),由于IO口的內(nèi)部輸出通過反相器輸出,給SIO=0則SIO口
//會輸出一個高電平1,從而保持SIO數(shù)據(jù)口的穩(wěn)定!
}
* @brief 讀DS1302寄存器
* @param 待讀取的寄存器地址reg
* @retval 讀取到的數(shù)據(jù)dat
*/
uint8 ReadDS1302(uint8 reg)
{
uint8 dat = 0;
DS1302_CE = 1;//使能片選
DS1302WriteByte((reg << 1) | 0x81);//左移出一位存放讀寫位,這里選擇讀
dat = DS1302ReadByte();
DS1302_CE = 0;
DS1302_SIO = 0;
return (dat);
}
* @brief DS1302 Burst觸發(fā)模式連續(xù)寫八個寄存器
* @param 待寫入數(shù)據(jù)指針*dat
* @retval 無
*/
void DS1302BurstWrite(uint8 * dat)
{
uint8 i = 0;
DS1302_CE = 1;//使能片選
DS1302WriteByte(0xBE);//A5-A1寫入1,觸發(fā)DS1302的突發(fā)模式連續(xù)讀寫八次
for (i = 0; i < 8; i++)
{
DS1302WriteByte(dat[i]);//寫Sec-WP八個寄存器
}
DS1302_CE = 0;//關(guān)閉片選
DS1302_SIO = 0;//通過反相器SIO口輸出1,保持穩(wěn)定
}
* @brief DS1302 Burst模式連續(xù)讀取八個寄存器
* @param 待接收讀取的數(shù)據(jù)的指針*time
* @retval 無
*/
void DS1302BurstRead(uint8 * time)
{
uint8 i = 0;
DS1302_CE = 1;//使能片選
DS1302WriteByte(0xBF);//觸發(fā)突發(fā)模式讀操作
for (i = 0; i < 8; i++)
{
time[i] = DS1302ReadByte();//讀取Sec-WP八個寄存器
}
DS1302_CE = 0;//關(guān)閉片選
DS1302_SIO = 0;//使SIO口處于穩(wěn)定
}
* @brief DS1302初始化
* @param 無
* @retval 無
*/
void InitDS1302()
{
uint8 ch = 0;//用于檢測DS1302停止狀態(tài)
uint8 InitTime[] = {0x56, 0x59, 0x23, 0x10, 0x04, 0x04, 0x14, 0x00};//2014年4月10日23:59:56 WP=0
//讀取秒寄存器
ch = ReadDS1302(0);
if ((ch & 0x80) != 0) //檢測秒寄存器的最高位CH,CH為1標志DS1302已經(jīng)停止運行,要去除寫保護,寫入初始時間
{
DS1302BurstWrite(InitTime);//突發(fā)模式寫
}
}
/**
******************************************************************
* @file ds18b20.c
* @author xr
* @date 2014年4月1日21:03:47
* @version V1.2.3
* @brief 溫度傳感器DS18B20檢測溫度值程序
* @note 單片機STC89C52RC MCU 晶振 11.0592MHZ
******************************************************************
*/
#include <reg52.h>
#include <intrins.h>
sbit IO_DS18B20 = P3^2;
* @brief 軟件延時xus
* @param 無
* @retval 無
*/
void delayx10us(unsigned int xus)
{
do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (xus--); //8個_nop_()和函數(shù)的進棧出棧時間大約10us
}
* @brief DS18B20溫度傳感器初始化檢測存在脈沖
* @param 無
* @retval 無
*/
bit ReadDs18B20Ack()
{
bit ack; //存放檢測到的DS18B20的存在脈沖
EA = 0;//由于DS18B20的時序時間的要求很高,進出中斷需要十幾個us會影響時序時間
IO_DS18B20 = 0;//復位脈沖
delayx10us(60);//持續(xù)600us
IO_DS18B20 = 1;//釋放總線,來檢測DS18B20的存在脈沖
delayx10us(6);//延時60us后來讀取DS18B20的存在脈沖,這個時候肯定可以讀取到
ack = IO_DS18B20;
while (!IO_DS18B20);//等待存在脈沖的結(jié)束
EA = 1;//重新開啟中斷
return ack;//返回存在脈沖
}
* @brief DS18B20寫一個字節(jié)數(shù)據(jù)
* @param 待寫入數(shù)據(jù) dat
* @retval 無
*/
void WriteDs18B20(unsigned char dat)
{
unsigned char mask = 0x01;//低位在前,逐位發(fā)送
EA = 0;//在發(fā)送每一位時必須將總中斷關(guān)閉,避免進出中斷時間影響DS18B20的讀寫
for (mask = 0x01; mask != 0; mask <<= 1)
{
IO_DS18B20 = 0;//主機拉低
_nop_();
_nop_();//延時2us,寫1或0時延時>1us
if ((mask & dat) == 0)
{
IO_DS18B20 = 0;
}
else
{
IO_DS18B20 = 1;
}
delayx10us(6); //延時60-120us等待DS18B20來讀取數(shù)據(jù)
IO_DS18B20 = 1;//釋放總線,這時DS18B20會來采樣數(shù)據(jù)進行寫入
}
EA = 1;//寫入一個字節(jié)數(shù)據(jù)完畢,打開總中斷
}
* @brief 讀DS18B20一個字節(jié)
* @param 無
* @retval 讀取的數(shù)據(jù)
*/
unsigned char ReadDs18B20()
{
unsigned char mask = 0x01;//低位在前,逐位接收
unsigned char dat = 0;
EA = 0;//DS18B20在讀取數(shù)據(jù)前要關(guān)閉中斷,避免進出中斷時間,影響讀取
for (mask = 0x01; mask != 0; mask <<= 1)
{
IO_DS18B20 = 0;//讀0或讀1時主機要先拉低>1us再拉高釋放>1us時間,然后主機對DS18B20進行數(shù)據(jù)的采樣讀取
_nop_();
_nop_();
IO_DS18B20 = 1;
_nop_();
_nop_();
if (IO_DS18B20 == 0)
{
dat &= ~mask;//相應位置1
}
else
{
dat |= mask;//相應位清零
}
delayx10us(6);//延時60-120us,等待主機數(shù)據(jù)的采樣
}
EA = 1;//開總中斷
return dat;
}
* @brief 啟動DS18B20溫度轉(zhuǎn)換,啟動成功則返回應答ack
* @param 無
* @retval 返回復位存在脈沖
*/
bit StartDs18B20()
{
bit ack;
ack = ReadDs18B20Ack();//進行DS18B20復位,并讀取DS18B20的存在脈沖
if (ack == 0)
{
WriteDs18B20(0xCC);//跳過ROM的器件地址尋址,因為只有一個DS18B20
WriteDs18B20(0x44);//啟動溫度轉(zhuǎn)換
}
return ~ack;//ack==0則轉(zhuǎn)換成功
}
* @brief 讀取DS18B20的溫度值
* @param 無
* @retval 返回復位存在脈沖的取反值
*/
bit ReadDs18B20Temp(int * temp) //溫度值保存到temp指針指向的變量中
{
bit ack;//保存復位的存在脈沖
unsigned char lsb, msb;//溫度值的低字節(jié)和高字節(jié)
ack = ReadDs18B20Ack();//DS18B20復位,并讀取DS18B20的存在脈沖
if (ack == 0) //復位成功
{
WriteDs18B20(0xCC);//跳過ROM多個DS18B20的尋址
WriteDs18B20(0xBE);//讀暫存寄存器中的數(shù)據(jù)
lsb = ReadDs18B20();//因為讀取是從低位向高位讀取的,所以先讀取的是低字節(jié)數(shù)據(jù)
msb = ReadDs18B20();//讀取高字節(jié)數(shù)據(jù)
//將溫度值的低字節(jié)和高字節(jié)數(shù)據(jù)進行合并成16bit數(shù)據(jù),易于計算
*temp = ((int)(msb) << 8) + lsb;//先將高字節(jié)強制轉(zhuǎn)換成16為數(shù)據(jù),將高字節(jié)移到高八位,再將低字節(jié)放到低八位即可
}
return ~ack;//ack == 0表示讀取成功
}