@说明: 以下是大学期间参加蓝桥杯的远古代码,常见模块代码分享,因为是远古代码水平有限
下文模块有DS1302、AT24C02、双目超声波测距、PCF8591、继电器和蜂鸣器。
按键 -> 按键消抖处理思路-CSDN博客
数码管 -> 51单片机_动态数码管_带小数点处理-CSDN博客
流水灯 -> 51单片机_3种方法_流水灯-CSDN博客
一. DS1302时钟
//=====================================================
#include "MAIN.H"
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3;
u8 data SetNum[] = {0,0,0,0,0,0,0}; //时间数组
//=====================================================
//@role :存放写地址和读地址的合集
typedef data enum
{
Seconds_W = 0X80,Seconds_R ,Minutes_W , Minutes_R ,Hour_W , Hour_R ,Data_W ,Data_R ,Month_W , Month_R ,Day_W , Day_R,Year_W , Year_R ,WP_W , WP_R ,
} Office;
//=====================================================
//@role :设定时间
//十进制转BCD存入
void DS1302_SetTime()
{
Write_Ds1302_Byte( WP_W ,0X00); // close write protect
Write_Ds1302_Byte( Year_W,SetNum[0]/10*16+SetNum[0]%10); // years
Write_Ds1302_Byte( Month_W,SetNum[1]/10*16+SetNum[1]%10); // months
Write_Ds1302_Byte( Data_W,SetNum[2]/10*16+SetNum[2]%10); // data
Write_Ds1302_Byte( Hour_W,SetNum[3]/10*16+SetNum[3]%10); // hours
Write_Ds1302_Byte( Minutes_W,SetNum[4]/10*16+SetNum[4]%10); // Minutes
Write_Ds1302_Byte( Seconds_W,SetNum[5]/10*16+SetNum[5]%10); // Senconds
Write_Ds1302_Byte( Day_W ,SetNum[6]/10*16+SetNum[5]%10); // week (1-7)
Write_Ds1302_Byte( WP_W,0X80); // up write protect
}
//=====================================================
//@role : 读取时间数组中的时间
//BCD转10进制读出
void DS1302_ReadTime()
{
SetNum[0] = Read_Ds1302_Byte(Year_R)/16*10+Read_Ds1302_Byte(Year_R)%16;
SetNum[1] = Read_Ds1302_Byte(Month_R)/16*10+Read_Ds1302_Byte(Month_R)%16;
SetNum[2] = Read_Ds1302_Byte(Data_R)/16*10+Read_Ds1302_Byte(Data_R)%16;
SetNum[3] = Read_Ds1302_Byte(Hour_R)/16*10+Read_Ds1302_Byte(Hour_R)%16;
SetNum[4] = Read_Ds1302_Byte(Minutes_R)/16*10+Read_Ds1302_Byte(Minutes_R)%16;
SetNum[5] = Read_Ds1302_Byte(Seconds_R)/16*10+Read_Ds1302_Byte(Seconds_R)%16;
SetNum[6] = Read_Ds1302_Byte(Day_R)/16*10+Read_Ds1302_Byte(Day_R)%16;
}
//=====================================================
二. AT2402存储,这个器件有写周期和写保护
//===============================================
#include "MAIN.H"
#define AT24C02_Address 0XA0
//===============================================
//@role : 写入一字节
//@detail : Address can be 0-255
void AT2C02_WriteByte(uchar Address,Data )
{
IIC_Start(); //开始
IIC_SendByte(AT24C02_Address);//发送设备地址 ——写
if(!IIC_WaitAck()){IIC_Stop();} //如果没有寻址成功,停止
IIC_SendByte(Address); //发送写入的地址
IIC_WaitAck(); //等待应答
IIC_SendByte(Data); //发送写入的数据
IIC_WaitAck(); //等待应答
IIC_Stop(); //停止
}
//===============================================
//@role : 读出一字节数据
//@detail : address can be 0-255;
uchar AT24C02_ReadByte(uchar Address)
{
unsigned char Data;
IIC_Start(); //开始
IIC_SendByte(AT24C02_Address);
if(!IIC_WaitAck()){IIC_Stop();}
IIC_SendByte(Address);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(AT24C02_Address|0X01); //发送设备地址——读
IIC_WaitAck();
Data=IIC_RecByte();
IIC_Ack(1);
IIC_Stop();
return Data;
}
//===============================================
三. 双目超声波测距
//============================================================
#include "MAIN.H"
sbit TD = P1^0; //发射端
sbit RD = P1^1; //接收端
u16 data DISTANCE; //测量距离变量
//============================================================
//@role :定时器1初始化
void T1_INIT()
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TH1=0; TL1=0;
TF1 = 0; //清除TF1标志
}
//============================================================
//@role : 每隔12us翻转一次IO口,RD口发送8个周期频率约为K40HZ的信号
//@detail: f = 1/T ,T = 24us,f =1/24 = 0.04MHZ
void RELAY_SEND()
{
u8 i = 0;
for(i=0;i<8;i++){ TD =! TD; DELAY_12US(); }
}
//============================================================
//@role :超声波模块初始化
void RELAY_INIT()
{
T1_INIT(); //定时器1初始化
RELAY_SEND(); //RD口发送8个周期频率约为K40HZ的信号
TR1 = 1; //定时器1开始计时
while(RD==1 && TF1==0); //等待接收口接收完整信号
TR1 = 0; //定时器1停止计时
if(TF1==1) //若超出测量范围,即溢出,溢出标志位TF1=1
{
//超出测量范围
}
else //若没超出测量范围
{
DISTANCE = TH1*255+TL1;
DISTANCE = (uint)(DISTANCE*0.017);
}
}
//============================================================
四. PCF8591AD&DA转换器,转换有时间间隔。遇到的比较坑的一点是读取多个通道时数据会乱,采取的办法是读两遍,只取第二遍的数据为有效数据
//========================================================================
#include "MAIN.H"
uchar Data = 0;
//========================================================================
//@role:显示AD单通道读取的数值
void PCF8591_SHOW()
{
NIXIE_SET(1, Data/100);
NIXIE_SET(2, Data%100/10);
NIXIE_SET(3, Data%10);
}
//========================================================================
//@role :PCF8591,AD初始化函数
//@detail : PCF8591_INIT(选择通道,选择模式); AINX can be( 0X01 、0X02、0X03、0X04)
void PCF8591_AD_INIT(uchar AINX)
{
IIC_Start(); //开始信号
IIC_SendByte(PCF8591_Address); //发送IIC设备地址,(写)
if(!IIC_WaitAck()){IIC_Stop();} //0为应答,1为不应答,if no ACK即没有寻址成功,end
IIC_SendByte(AINX); //发送控制字节
IIC_WaitAck(); //等待应答
IIC_Stop(); //停止信号
}
//========================================================================
//@role : 单通道AD读取
uchar PCF8591_AD_READ(void)
{
IIC_Start();
IIC_SendByte(PCF8591_Address | 0X01); //发送IIC设备地址(读)
if(!IIC_WaitAck()) {IIC_Stop(); return 0;} //if没有寻址成功,返回0;
IIC_RecByte(); //接收两遍数据并舍弃第一遍数据
IIC_Ack(1); //不应答
Data = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
return Data;
}
//========================================================================
//@role :PCF8591,DA初始化函数
void PCF8591_DA_INIT(float Data) //0X40
{
IIC_Start(); //开始信号
IIC_SendByte(PCF8591_Address); //发送IIC设备地址,(写)
if(!IIC_WaitAck()){IIC_Stop();} //0为应答,1为不应答,if no ACK即没有寻址成功,end
IIC_SendByte(0X40); //发送控制字节
IIC_WaitAck(); //等待应答
IIC_SendByte(255*(Data/5));
IIC_WaitAck();
IIC_Stop();
}
五、 要求上电关闭蜂鸣器和继电器,两种方法
//=================================================================
#include <STC15F2K60S2.H>
//=================================================================
//@role :锁存开关
//@detail :4——LED、5——蜂鸣器继电器、6——数码管段选、7——数码管位选
void switch_138(unsigned char location)
{
P27 = location/2/2%2;
P26 = location/2%2;
P25 = location%2;
}
//=================================================================
void main()
{
switch_138(5);P0 &= 0XAF;switch_138(0);//上电默认关闭蜂鸣器和继电器
while(1);
}
//=================================================================
//=================================================================
#include <STC15F2K60S2.H>
//=================================================================
//@role :锁存开关
//@detail :4——LED、5——蜂鸣器继电器、6——数码管段选、7——数码管位选
void switch_138(unsigned char location)//锁存器通道选择函数
{
switch(location)
{
case 0:{P2&=0X1F;}break;//无
case 4:{P2&=0X1F;P2|=0X80;}break;//LED*8通道
case 5:{P2&=0X1F;P2|=0XA0;}break;//蜂鸣器继电器通道
case 6:{P2&=0X1F;P2|=0XC0;}break;//数码管位选端通道
case 7:{P2&=0X1F;P2|=0XE0;}break;//数码管段选端通道
}
}
//=================================================================
void main()
{
switch_138(5);P0 &= 0XAF;//上电默认关闭蜂鸣器和继电器
while(1);
}
//=================================================================