目录
0、初始化外设
1、数码管
2、独立按键
3、矩阵键盘
4、定时器初始化
5、iic和E2PROM
6、AD采集电压
7、DS18B20
8、DS1302
9、超声波
2019年3月5日更新
历时一个多月,终于把蓝桥杯的模块整完了,今天开始写比赛题,现在把常用的程序封装一下。
/*******************************************************************************
* 函数名 :All_Init
* 输入值 :无
* 返回值 :无
* 作者 :小默haa
* 时间 :2019年1月15日
* 功能描述:外设初始化
* 备注 :关闭所有外设
*******************************************************************************/
void All_Init(void)
{
P2 = (P2 & 0x1f) | 0x80; //打开Y4C(LED)
P0 = 0xff; //关闭LED
P2 = (P2 & 0x1f) | 0xe0; //打开Y7C(数码管)
P0 = 0xff; //关闭数码管
P2 = (P2 & 0x1f) | 0xa0; //打开Y5C
P0 = 0x00; //关闭蜂鸣器、继电器
P2 = P2 & 0x1f; //关闭所有使能
}
unsigned char code Nixie[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //共阳数码管码字
unsigned char NixieBuff[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; //数码管显示缓冲区,初值0xff确保启动时都不亮
unsigned char smg1,smg2,smg3,smg4,smg5,smg6,smg7,smg8;
//数码管显示
void Nixie_Scan(void)
{
static unsigned char index = 0;
P2 = (P2 & 0x1f) | 0xc0; //数码管片选
P0 = 0x01 << index;
P2 = (P2 & 0x1f) | 0xe0; //数码管消隐
P0 =0xff;
P2 = (P2 & 0x1f) | 0xe0; //数码管段选
P0 = NixieBuff[index];
P2 &= 0x1f;
index ++;
index &= 0x07;
}
sbit s4 = P3^3;
sbit s5 = P3^2;
sbit s6 = P3^1;
sbit s7 = P3^0;
//定时器0初始化
void Time0_Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9a; //设置定时初值2ms
TH0 = 0xa9; //设置定时初值2ms
TF0 = 0; //清除TF0标志
ET0 = 1; //允许定时器0中断
TR0 = 1; //定时器0开始计时
EA = 1; //开总中断
}
//定时器0程序
void Time0(void) interrupt 1
{
static u16 t0 = 0,m = 0,n = 0;
t0 ++;
Key_Scan();
if(t0 == 500)
{
if(Led_flag == 0)
Led_dat = _cror_(Led_dat,1);
else if(Led_flag == 1)
Led_dat = _crol_(Led_dat,1);
else if(Led_flag == 2)
{
switch(m)
{
case 0:Led_dat = 0x7e;break;
case 1:Led_dat = 0xbd;break;
case 2:Led_dat = 0xdb;break;
case 3:Led_dat = 0xe7;break;
}
m ++;
m = m & 3; //m到4清零
}
else if(Led_flag == 3)
{
switch(n)
{
case 0:Led_dat = 0xe7;break;
case 1:Led_dat = 0xdb;break;
case 2:Led_dat = 0xbd;break;
case 3:Led_dat = 0x7e;break;
}
n ++;
n = n & 3; //n到4清零
}
Led_illume(Led_dat);
t0 = 0;
}
}
void Key_Scan(void)
{
u16 i;
static u8 keybuff[] = {0xff,0xff,0xff,0xff};
keybuff[0] = (keybuff[0] << 1) | s4;
keybuff[1] = (keybuff[1] << 1) | s5;
keybuff[2] = (keybuff[2] << 1) | s6;
keybuff[3] = (keybuff[3] << 1) | s7;
for(i = 0;i < 4;i ++)
{
if(keybuff[i] == 0xff) //连续扫描8次都是1,16ms内都是弹起状态,按键已松开
{
KeySta[i] = 1;
}
else if(keybuff[i] == 0x00) //连续扫描8次都是0,16ms内都是按下状态,按键已按下
{
KeySta[i] = 0;
}
else //其他状态键值不稳定,不作处理
{}
}
}
//按键处理
void Key_Deal(void)
{
u8 i;
for(i = 0;i < 4;i ++)
{
if(KeySta[i] == 0)
{
switch(i)
{
case 0:Led_dat = 0xfe;Led_flag = 0;break;
case 1:Led_dat = 0x7f;Led_flag = 1;break;
case 2:Led_flag = 2;break;
case 3:Led_flag = 3;break;
}
}
}
}
//检测按键是否按下,在main函数调用
void Key_press(void)
{
u8 i;
for(i = 0; i < 4; i ++)
{
if(KeySta[i] != Keybackup[i])
{
if(Keybackup[i] != 0) //按键松开时操作
Key_Deal(i);
Keybackup[i] = KeySta[i];
}
}
}
void main(void)
{
unsigned char i;
Time0_Init();
while(1)
{
Key_press();
}
}
sbit KEY_IN_1 = P4^4;
sbit KEY_IN_2 = P4^2;
sbit KEY_IN_3 = P3^5;
sbit KEY_IN_4 = P3^4;
sbit KEY_OUT_1 = P3^0;
sbit KEY_OUT_2 = P3^1;
sbit KEY_OUT_3 = P3^2;
sbit KEY_OUT_4 = P3^3;
//定时器0初始化
void Time0_Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xcd; //设置定时初值1ms
TH0 = 0xd4; //设置定时初值1ms
TF0 = 0; //清除TF0标志
ET0 = 1; //允许定时器0中断
TR0 = 1; //定时器0开始计时
}
/*******************************************************************************
* 函数名 :Time0
* 输入值 :无
* 返回值 :无
* 作者 :小默haa
* 时间 :2019年1月29日
* 功能描述:定时器0中断函数
* 备注 :定时器0中断函数,定时器0定时1ms,
执行Key_Scan()函数。
*******************************************************************************/
void Time0(void) interrupt 1
{
Key_Scan();
}
/*******************************************************************************
* 文件名:key.c
* 描 述:
* 作 者:小默haa
* 版本号:v1.0
* 日 期: 2019年1月28日
* 备 注:矩阵键盘核心程序
*
*******************************************************************************/
#include "sys.h"
u8 KeySta[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}; //当前按键状态
u8 Key_backup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}; //按键状态备份,保存前一次的按键值
u8 code KeyCodeMap[4][4] = {{0x31, 0x32, 0x33, 0x26}, //1,2,3,↑
{0x34, 0x35, 0x36, 0x25}, //4,5,6,←
{0x37, 0x38, 0x39, 0x28}, //7,8,9,↓
{0x30, 0x1b, 0x0d, 0x27}}; //0,ESC,ENTER,→
/*******************************************************************************
* 函数名 :Key_Scan
* 输入值 :无
* 返回值 :无
* 作者 :小默haa
* 时间 :2019年1月29日
* 功能描述:矩阵按键扫描
* 备注 :按键扫描函数,在定时器中断程序里调用,定时器间隔1ms
*******************************************************************************/
void Key_Scan(void)
{
u8 i;
static u8 keyout = 0; //矩阵按键扫描输出索引
static u8 keybuff[4][4] = {{0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff},
{0xff, 0xff, 0xff, 0xff}}; //矩阵按键扫描缓存区
keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1; //将每一行的4个按键值移入缓存区
keybuff[keyout][1] = (keybuff[keyout][1] << 1) | KEY_IN_2;
keybuff[keyout][2] = (keybuff[keyout][2] << 1) | KEY_IN_3;
keybuff[keyout][3] = (keybuff[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for (i = 0;i < 4;i ++)
{
if ((keybuff[keyout][i] & 0x0f) == 0x00)
KeySta[keyout][i] = 0; //连续4次扫描值都是0,即4×4ms内都是按下状态,认为按键已平稳按下
else if ((keybuff[keyout][i] & 0x0f) == 0x0f)
KeySta[keyout][i] = 1; //连续4次扫描值都是1,即4×4ms内都是松开状态,认为按键已稳定弹起
}
//执行下一次的扫描输出
keyout ++;
keyout = keyout & 0x03; //索引加到4就归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default:break;
}
}
/*******************************************************************************
* 函数名 :Key_Drive
* 输入值 :无
* 返回值 :无
* 作者 :小默haa
* 时间 :2019年1月29日
* 功能描述:矩阵按键驱动程序
* 备注 :检测矩阵键盘的动作,调用相应的函数,需要在主循环里调用
*******************************************************************************/
void Key_Drive(void)
{
u8 i, j;
for (i = 0; i < 4; i ++) //循环检测4×4的矩阵按键
{
for (j = 0; j < 4; j ++)
{
if (Key_backup[i][j] != KeySta[i][j]) //检测按键当前动作
{
if (Key_backup[i][j] != 0) //按键按下时执行动作
{
Key_Action(KeyCodeMap[i][j]); //调用按键活动函数
}
Key_backup[i][j] = KeySta[i][j]; //更新前一次的备份值
}
}
}
}
/*******************************************************************************
* 函数名 :Key_Action
* 输入值 :键值 keycode
* 返回值 :无
* 作者 :小默haa
* 时间 :2019年1月29日
* 功能描述:矩阵按键动作函数
* 备注 :矩阵键盘动作函数,根据键值执行相应程序
*******************************************************************************/
void Key_Action(u8 keycode)
{
static u32 addend = 0;
static u8 num_bit = 0; //记录输入位数
if ((keycode >= 0x30) && (keycode <= 0x39) && num_bit < 8) //输入0~9数字
{
addend = (addend * 10) + (keycode - 0x30); //整体十进制左移,新数字进入个位
num_bit ++; //每输入一个数字,位数加1
Show_Num(addend); //数码管显示
}
}
//定时器定时指定us
void Timer0Init(u16 us) //@11.0592MHz
{
float tmp = 0;
u16 temp = 0;
tmp = (12 * 1000000) / FOSC * 1.0;
temp = (u16)(us / tmp);
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
a = (65535 - temp) / 256;
b = (65535 - temp) % 256;
TH0 = a;
TL0 = b;
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); _nop_(); _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
//应答位控制
void IIC_Ack(bit ackbit)
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
/*******************************************************************************
* 函数名 :E2Read
* 输入值 :unsigned char *buf, unsigned char addr, unsigned char led
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月25日
* 功能描述:连续读取多个数据
* 备注 :buf为数据接收指针,addr为E2PROM中要读取的数据起始地址,len为读取长度
*******************************************************************************/
void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)
{
do{ //用寻址操作查询当前是否可进行读写操作
IIC_Start();
IIC_SendByte(0xa0); //发送器件地址
if(IIC_WaitAck() == 1) //应答则跳出循环,非应答则进行下一次查询
break;
IIC_Stop();
}while(1);
IIC_SendByte(addr); //写入起始地址
IIC_WaitAck();
IIC_Stop();
IIC_Start(); //发送重复启动信号
IIC_SendByte(0xa1);
IIC_WaitAck();
while(len > 1) //连续读取len-1个字节
{
*buf++ = IIC_RecByte(); //最后字节之前为读取操作并且应答
IIC_Ack(1);
len--;
}
*buf = IIC_RecByte(); //最后一个字节为读取操作并且非应答
IIC_Ack(0);
IIC_Stop();
}
/*******************************************************************************
* 函数名 :E2Write_page
* 输入值 :unsigned char *buf, unsigned char addr, unsigned char led
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月25日
* 功能描述:连续写入一页数据
* 备注 :buf为源数据指针,addr为E2PROM中要写入的数据起始地址,len为写入长度
*******************************************************************************/
void E2Write_page(unsigned char *buf, unsigned char addr, unsigned char len)
{
while(len)
{
do{ //用寻址操作查询当前是否可进行读写操作
IIC_Start();
IIC_SendByte(0xa0);
if(IIC_WaitAck() == 1) //应答则跳出循环,非应答则进行下一次查询
break;
IIC_Stop();
}while(1);
IIC_SendByte(addr); //写入起始地址
IIC_WaitAck();
while(len > 0)
{
IIC_SendByte(*buf++); //写入一个字节数据
IIC_WaitAck();
len--; //待写入长度计数递减
addr++; //E2PROM地址递增
if((addr & 0x07) == 0) //检查地址是否到达页边界,24C02每页8字节
break; //到达页边界时,跳出循环,结束本次写操作
}
IIC_Stop();
}
}
/*******************************************************************************
* 函数名 :Read_AIN
* 输入值 :unsigned char chn
* 返回值 :unsigend char dat
* 作者 :小默haa
* 时间 :2019年2月25日
* 功能描述:读取PCF8591AIN采集数据
* 备注 :chn为PCF8591的通道
*******************************************************************************/
unsigned char Read_AIN(unsigned char chn)
{
unsigned char dat;
EA = 0;
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x90); //PCF8591的写设备地址
IIC_WaitAck(); //等待从机应答
IIC_SendByte(chn); //写入PCF8591的控制字节
IIC_WaitAck(); //等待从机应答
IIC_Stop(); //IIC总线停止信号
IIC_Start(); //IIC总线起始信号
IIC_SendByte(0x91); //PCF8591的读设备地址
IIC_WaitAck(); //等待从机应答
dat = IIC_RecByte(); //读取PCF8591通道3的数据
IIC_Ack(0); //产生非应答信号
IIC_Stop(); //IIC总线停止信号
EA = 1;
return dat;
}
/*******************************************************************************
* 函数名 :ValueToString
* 输入值 :unsigned char *str, unsigned char val
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月25日
* 功能描述:将PCF8591AIN采集的数据转换为字符型
* 备注 :注意这里把电压扩大了10倍
*******************************************************************************/
void ValueToString(unsigned char *str, unsigned char val)
{
val = (val * 50) / 255; //电压5V,256个刻度分成255份!
str[0] = val / 10;
str[2] = val % 10;
}
sbit DS18B20_IO = P1^4;
/*******************************************************************************
* 函数名 :Delayus
* 输入值 :unsigned int us
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月17日
* 功能描述:1T单片机延时指定us
* 备注 :最大形参65535,即最大延时65ms
*******************************************************************************/
void Delayus(unsigned int us)
{
do{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}while(--us);
}
/*******************************************************************************
* 函数名 :Get18B20Ack
* 输入值 :none
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:复位总线,获取18B20存在脉冲,以启动一次读写操作
* 备注 :
*******************************************************************************/
bit Get18B20Ack(void)
{
bit ack;
EA = 0; //禁止总中断
DS18B20_IO = 0; //产生500us的复位脉冲
Delayus(500);
DS18B20_IO = 1; //延时60us
Delayus(60);
ack = DS18B20_IO; //读取存在脉冲
while(!DS18B20_IO); //等待存在脉冲结束
EA = 1; //重新使能总中断
return ack;
}
/*******************************************************************************
* 函数名 :DS18B20Write
* 输入值 :unsigned char dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:向18B20写入一个字节
* 备注 :dat为待写入字节
*******************************************************************************/
void DS18B20Write(unsigned char dat)
{
unsigned char mask;
for(mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次移出8个bit
{
EA = 0; //禁止总中断
DS18B20_IO = 0; //产生2us低电平脉冲
Delayus(2);
if(dat & mask) //输出该bit值
DS18B20_IO = 1;
else
DS18B20_IO = 0;
EA = 1; //重新使能总中断
Delayus(60); //延时60us
DS18B20_IO = 1; //拉高通信引脚
}
}
/*******************************************************************************
* 函数名 :DS18B20Read
* 输入值 :none
* 返回值 :unsigend char dat
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:从18B20读取一个字节
* 备注 :返回值为读取到的字节
*******************************************************************************/
unsigned char DS18B20Read(void)
{
unsigned char mask, dat = 0;
for(mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次采集8个bit
{
EA = 0; //禁止总中断
DS18B20_IO = 0; //产生2us低电平脉冲
Delayus(2);
DS18B20_IO = 1; //结束低电平脉冲,等待18B20输出数据
Delayus(2); //延时2us
if(DS18B20_IO) //读取通信引脚上的值
dat |= mask;
EA = 1; //重新使能总中断
Delayus(60); //再延时60us
}
return dat;
}
/*******************************************************************************
* 函数名 :Start18B20
* 输入值 :none
* 返回值 :bit ~ack
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:启动一次18B20温度转换
* 备注 :返回值为是否启动成功
*******************************************************************************/
bit Start18B20()
{
bit ack;
static bit flag = 1;
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则启动一次转换
{
DS18B20Write(0xCC); //跳过ROM操作
if(flag)
{
flag = 0;
DS18B20Write(0x4e); //写暂存器指令4E
DS18B20Write(0x4b); //写高速缓存器TH高温限值75度
DS18B20Write(0x00); //写高速缓存器TL低温限值0度
DS18B20Write(0x1f); //写配置寄存器4
//0x1f : 0.5000°C 转换时间93.75ms
//0x3f : 0.2000°C 转换时间187.5ms
//0x5f : 0.1250°C 转换时间375ms
//0x7f : 0.0625°C 转换时间750ms
}
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则启动一次转换
{
DS18B20Write(0xCC); //跳过ROM操作
DS18B20Write(0x44); //启动一次温度转换
}
}
return ~ack; //ack == 0 表示操作成功,所以返回值对其取反
}
/*******************************************************************************
* 函数名 :Get18B20Temp
* 输入值 :int *temp
* 返回值 :bit ~ack
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:读取18B20转换的温度值
* 备注 :返回值为是否读取成功
*******************************************************************************/
bit Get18B20Temp(int *temp)
{
bit ack;
unsigned char LSB, MSB; //16bit温度值的低字节和高字节
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则读取温度值
{
DS18B20Write(0xCC); //跳过ROM操作
DS18B20Write(0xBE); //发送读命令
LSB = DS18B20Read(); //读温度值的低字节
MSB = DS18B20Read(); //读温度值的高字节
*temp = ((unsigned int) MSB << 8) + LSB; //合成16bit的整数
}
return ~ack; //ack == 0 表示操作应答,所以返回值为1其取反值
}
sbit DS1302_IO = P2^3;
sbit DS1302_CK = P1^7;
sbit DS1302_CE = P1^3;
/*******************************************************************************
* 函数名 :DS1302ByteWrite
* 输入值 :unsigned char dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:发送一个字节到DS1302通信总线上
* 备注 :
*******************************************************************************/
void DS1302ByteWrite(unsigned char dat)
{
unsigned char mask;
DS1302_IO = 1; //拉低IO总线
for(mask = 0x01; mask != 0; mask <<= 1) //低位在前,逐位移出
{
if((dat&mask) != 0) //首先输出该位数据
DS1302_IO = 1;
else
DS1302_IO = 0;
DS1302_CK = 1; //拉高时钟线
DS1302_CK = 0; //拉低时钟线,完成一个位的操作
}
DS1302_IO = 1; //写完之后确保释放IO总线
}
/*******************************************************************************
* 函数名 :DS1302ByteRead
* 输入值 :none
* 返回值 :unsigned char dat
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:由DS1302通信总线上读取一个字节
* 备注 :返回读到的字节数据
*******************************************************************************/
unsigned char DS1302ByteRead(void)
{
unsigned char mask, dat = 0;
for(mask = 0x01; mask != 0; mask <<= 1) //低位在前,逐位读取
{
if(DS1302_IO) //首先读取此时的IO引脚,并设置dat中的对应位
dat |= mask;
DS1302_CK = 1; //拉高时钟
DS1302_CK = 0; //再拉低时钟,完成一个位的操作
}
return dat; //返回读到的字节数据
}
/*******************************************************************************
* 函数名 :DS1302SingleWrite
* 输入值 :unsigned char reg, unsigned char dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:用单次写操作向某一寄存器写入一个字节
* 备注 :reg为寄存器地址,dat为待写入字节
*******************************************************************************/
void DS1302SingleWrite(unsigned char reg, unsigned char dat)
{
DS1302_CE = 1; //使能片选信号
DS1302ByteWrite((reg << 1) | 0x80); //发送写寄存器指令
DS1302ByteWrite(dat); //写入字节数据
DS1302_CE = 0; //除能片选信号
}
/*******************************************************************************
* 函数名 :DS1302SingleRead
* 输入值 :unsigned char reg
* 返回值 :unsigned char dat
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:用单次读操作从某一寄存器读取一个字节
* 备注 :reg为寄存器地址,返回值dat为读到的字节
*******************************************************************************/
unsigned char DS1302SingleRead(unsigned char reg)
{
unsigned char dat;
DS1302_CE = 1; //使能片选信号
DS1302ByteWrite((reg << 1) | 0x81); //发送读寄存器指令
dat = DS1302ByteRead(); //读取字节数据
DS1302_CE = 0; //除能片选信号
DS1302_IO = 0; //单字节读必须加的!
return dat;
}
/*******************************************************************************
* 函数名 :DS1302BurstWrite
* 输入值 :unsigned char *dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:用突发模式连续写入8个寄存器数据
* 备注 :reg为寄存器地址,返回值dat为读到的字节
*******************************************************************************/
void DS1302BurstWrite(unsigned char *dat)
{
unsigned char i;
DS1302_CE = 1;
DS1302ByteWrite(0xBE); //发送突发写寄存器指令
for(i = 0; i < 7; i ++) //连续写入8字节数据
DS1302ByteWrite(*dat++);
DS1302_CE = 0;
}
/*******************************************************************************
* 函数名 :DS1302BurstRead
* 输入值 :unsigned char *dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:用突发模式连续读取8个寄存器的数据
* 备注 :dat为读到的字节
*******************************************************************************/
void DS1302BurstRead (unsigned char *dat)
{
unsigned char i;
DS1302_CE = 1;
DS1302ByteWrite(0xBF); //发送突发读寄存器指令
for(i = 0; i < 7; i++) //连续读取8个字节
dat[i] = DS1302ByteRead();
DS1302_CE = 0;
DS1302_IO = 0; //突发读必须加
}
/*******************************************************************************
* 函数名 :GetRealTime
* 输入值 :struct sTime *time
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:读取DS1302时间
* 备注 :
*******************************************************************************/
void GetRealTime(struct sTime *time)
{
unsigned char buf[8];
DS1302BurstRead(buf);
time -> year = buf[6];
time -> mon = buf[4];
time -> day = buf[3];
time -> hour = buf[2];
time -> min = buf[1];
time -> sec = buf[0];
time -> week = buf[5];
}
/*******************************************************************************
* 函数名 :SetRealTime
* 输入值 :struct sTime *time
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:设置DS1302时间
* 备注 :
*******************************************************************************/
void SetRealTime(struct sTime *time)
{
unsigned char buf[8];
buf[7] = 0;
buf[6] = time -> year;
buf[4] = time -> mon;
buf[3] = time -> day;
buf[2] = time -> hour;
buf[1] = time -> min;
buf[0] = time -> sec;
buf[5] = time -> week;
DS1302BurstWrite(buf);
}
/*******************************************************************************
* 函数名 :InitDS1302
* 输入值 :none
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年3月1日
* 功能描述:DS1302初始化
* 备注 :
*******************************************************************************/
void InitDS1302()
{
struct sTime InitTime[] = { //2019年3月2日 星期六 16:40:00
0x19, 0x03, 0x02, 0x16, 0x40, 0x00, 0x06
};
unsigned char dat;
DS1302_CE = 0; //初始化DS1302通信引脚
DS1302_CK = 0;
dat = DS1302SingleRead(0); //读取秒寄存器
DS1302SingleWrite(7, 0x00); //撤销写保护以允许写入数据
SetRealTime(&InitTime); //设置DS1302为默认时间
}
#define sonic_nop {_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();};
void SendSonic(void)
{
unsigned char i = 8;
while(i --)
{
TX = 1;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
TX = 0;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
}
}
//定时器0初始化
void Time0_Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xcd; //设置定时初值1ms
TH0 = 0xd4; //设置定时初值1ms
TF0 = 0; //清除TF0标志
ET0 = 1; //允许定时器0中断
TR0 = 1; //定时器0开始计时
}
//定时器0中断程序
void Time0(void) interrupt 1
{
static uint t0 = 0;
static uchar index = 0;
t0 ++;
if(t0 == 125)
{
t0 = 0;
flag_125ms = 1;
Led_illume(0xfe << index);
index ++;
index &= 0x07;
}
}
void Timer1Init(void) //0微秒@11.0592MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0; //设置定时初值
TH1 = 0; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0;
}
void main(void)
{
uint t, distance = 0;
All_Init();
Time0_Init();
Timer1Init();
EA = 1;
while(1)
{
if(flag_125ms)
{
flag_125ms = 0;
SendSonic(); //发送50KHz的超声波
TR1 = 1; //开启定时器1计时
while((RX == 1) && (TF1 == 0)); //如果接收到回波或者定时器1溢出
TR1 = 0; //关闭定时器1
if(TF1 == 1)
{
TF1 = 0;
distance = 999; //距离999
}
else
{
t = TH1;
t <<= 8;
t |= TL1;
distance = (uint)(t * 0.017);
}
Deal_distance(distance);
TH1 = 0;
TL1 = 0;
}
}
}