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