篮桥杯总结

一二是必考内容,四五六七是省赛考试会考到的,八是国赛
会考到的(还有串口和频率的测量,相信学过单片机的同学都知
道该怎么编程)
一.数码管显示函数(必考)
void displayseg1(unsigned char i)
{
P2 |= 0xc0; //打开位选锁存信号
P0 = 0x80; //送位码 100 0000
P2 &= ~(0xc0); //关闭位选锁存信号
P0 = 0xff; //消除对段码的影响
P2 |= 0xe0; //打开段选锁存信号
P0 = Seg_Yang_Led_Table[i];
P2 &= ~(0xe0); //关闭段选锁存信号
P0 = 0x00; //消除对位码的影响
delayms(1);
}
二.按键扫描函数(独立建盘,必考)
也可不用这种方法直接用if 语句判断,下面的代码有利于你理解矩阵
键盘。
unsigned char key(void)
{
unsigned char temp,key;//按键消抖
temp = P3;
temp &= 0x0f;
if(temp!=0x0f)
{
delayms(10);
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
switch(temp)
{
case 0x0e: key=0; break;
case 0x0d: key=1; break;
case 0x0b: key=2; break;
case 0x07: key=3; break;
default:break;
}
}
while(temp!=0x0f)
{
temp = P3;
temp = temp&0x0f;
}
}
return key;
}
三.按键扫描函数(矩阵键盘)
uchar key(void)
{
uchar temp,key;
P3 = 0x7f;
P42 = 1;
P44 = 0;
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
delayms(10);
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
temp = P3;
switch(temp)
{
case 0x7e:key=0;break;
case 0x7d:key=4;break;
case 0x7b:key=8;break;
case 0x77:key=12;break;
default:break;
}
}
while(temp!=0x0f)
{
temp = P3;
temp = temp&0x0f;
}
}
P3 = 0xbf;
P42 = 0;
P44 = 1;
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
delayms(10);
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
temp = P3;
switch(temp)
{
case 0xbe:key=1;break;
case 0xbd:key=5;break;
case 0xbb:key=9;break;
case 0xb7:key=13;break;
default:break;
}
}
while(temp!=0x0f)
{
temp = P3;
temp = temp&0x0f;
}
}
P3 = 0xdf;
P42 = 1;
P44 = 1;
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
delayms(10);
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
temp = P3;
switch(temp)
{
case 0xde:key=2;break;
case 0xdd:key=6;break;
case 0xdb:key=10;break;
case 0xd7:key=14;break;
default:break;
}
}
while(temp!=0x0f)
{
temp = P3;
temp = temp&0x0f;
}
}
P3 = 0xef;
P42 = 1;
P44 = 1;
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
delayms(10);
temp = P3;
temp = temp&0x0f;
if(temp!=0x0f)
{
temp = P3;
switch(temp)
{
case 0xee:key=3;break;
case 0xed:key=7;break;
case 0xeb:key=11;break;
case 0xe7:key=15;break;
default:break;
}
}
while(temp!=0x0f)
{
temp = P3;
temp = temp&0x0f;
}
}
return key;
}
此代码是模仿郭天祥的代码,不懂的建议看看郭天祥的视频教程,虽
然有点复杂但讲的很详细,51 里没有P42 和P44 脚,但是15 转接板
没有引出来P36 和P37,而是P42->P36,P44->P37.看看下图的WR 和
RD。
四.AT24C02 读写函数
(9+11)
先发地址再发数据,地址从0x00 开始
//向E2PROM 里写数据(地址,数据)
void WriteByte_AT24C02(unsigned char add,unsigned char date)
{
IIC_Start();
IIC_SendByte(0xa0);//发方式字1010 0000,激活该器件写操作
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(date);
IIC_WaitAck();
IIC_Stop();
Delay10ms();
}
//从E2PROM 里读数据(地址)
uchar ReadByte_AT24C02(uchar add)
{
uchar date;
IIC_Start();
IIC_SendByte(0xa0);//发方式字1010 0000,激活该器件写操作
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);//发方式字1010 0001,激活该器件读操作
IIC_WaitAck();
date = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
return date;
}
驱动函数见资料包,比赛会给出,上面的代码是你自己要编写的,最
好记住。其实你理解透了会发现这些协议有种哲学思想^_^。
五.ADC(PCF8591)
思路:(7+6,两个地址0x90,0x91)
1. 定义要操作的两个脚P21,P20
2. 将IIC 协议里的somenop 全部替换成Dealy5us()
3. 加进所有的协议
4. ADC 初始化和ADC 读取函数
初始化函数的思路:
(1) 启动IIC 函数
(2) 发送地址激活PCF8591:地址为0x90(A2A1A0 已经接地了,最
后一位为0 表示写)
(3) 等待应答函数
(4) 发送通道函数(前面6 位都是0,最后两位选择通道,0x03:滑
动变阻器;0x01:光敏电阻)
(5) 再等待应答
(6) 关闭IIC 函数
(7) 延时10ms 函数
读取ADC 值的函数:
(1) 启动IIC 函数
(2) 发送地址激活PCF8591:地址为0x90(A2A1A0 已经接地了,
最后一位为1 表示读)
(3) 等待应答
(4) IIC 读取函数
(5) 发送应答0(特记)
(6) 关闭IIC
相关的函数:
#define SDA P21
#define SCL P20
#define somenop Delay5us()
/* Delay5us(),Delay10ms()均来自下载器*/
void Delay5us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 11;
while (--i);
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
/*自己写的函数(需要背下来)*/
void ADC_Init(unsigned char chanel)
{
IIC_Start(); //IIC 启动信号
IIC_SendByte(0x90); //1001 000 0;选中该器件(前7 位是地址,
最后一位是R/~W,表示写)
IIC_WaitAck(); //等待应答
IIC_SendByte(chanel);//通过IIC 发送通道
IIC_WaitAck(); //等待应答
IIC_Stop(); //IIC 停止信号
Delay10ms(); //等待10ms
}
unsigned char ADC_Read()
{
unsigned char temp;
IIC_Start(); //IIC 启动信号
IIC_SendByte(0x91); //1001 000 1;选中该器件(前7 位是地址,最
后一位是R/~W,表示读)
IIC_WaitAck(); //等待应答
temp=IIC_RecByte(); //通过IIC 读取采集的值
IIC_Ack(0); //通过IIC 发送应答
IIC_Stop(); //IIC 停止信号
return temp;
}
/*官方给的协议(一个字都没有变)*/
//总线启动条件
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(unsigned char 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;
}
六. DS18B20
思路:(4+5+数据处理指令)先定义输出脚P14,再初始化,再读取
温度
读温度函数:
(1) 初始化DS18B20
(2) 跳过读取ROM 指令(0xcc)
(3) 写转换指令(0x44)
(4) 延时200us
(5) 再初始化DS18B20
(6) 跳过读取ROM 指令(0xcc)
(7) 写读取指令(0xbe)
(8) 先读低八位再读高八位
(9) 数据处理:temp=(Th<<4)|(Tl>>4);(不要小数点)
/*测温函数(自己写的,要背住)*/
unsigned char Temper_Read()
{
unsigned char temp,Tl,Th;
Init_DS18B20(); //DS18B20 初始化
Write_DS18B20(0xcc); //跳过ROM 的字节命令
Write_DS18B20(0x44); //开始转换指令
Delay_OneWire(200); //延时一段时间
Init_DS18B20(); //DS18B20 初始化
Write_DS18B20(0xcc); //跳过ROM 的字节命令
Write_DS18B20(0xbe); //读取指令
Tl=Read_DS18B20(); //读低八位
Th=Read_DS18B20(); //读高八位
temp=(Th<<4)|(Tl>>4);
return temp;
}
/*官方给的驱动函数,一共三个函数*/
//单总线延时函数(要有改动才可以执行)
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--)
{
for(i=0;i<12;i++);//STC15F2K60S2 要加上这条指令才可以
}
}
//DS18B20 芯片初始化
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//通过单总线向DS18B20 写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//从DS18B20 读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
七. DS1302
思路:先定义SCK,RST,SDA 脚;再写初始化函数;再读时间
初始化函数写法:
首先要关闭写保护,再设置寄存器的值,再打开写保护
(一定不能写错)
#define SCK P17
#define RST P13
#define SDA P23
#define SCK_SET SCK = 1;
#define SCK_CLR SCK = 0;
#define RST_SET RST = 1;
#define RST_CLR RST = 0;
#define SDA_SET SDA = 1;
#define SDA_CLR SDA = 0;
/*自己写的程序,必须背住*/
void DS1302_Init()
{
Ds1302_Single_Byte_Write(0x8e,0x00);//关掉写保护
Ds1302_Single_Byte_Write(0x80,0x00);// 秒
Ds1302_Single_Byte_Write(0x82,0x27);// 分
Ds1302_Single_Byte_Write(0x84,0x09);// 时
Ds1302_Single_Byte_Write(0x86,0x25);// 日
Ds1302_Single_Byte_Write(0x88,0x12);// 月
Ds1302_Single_Byte_Write(0x8a,0x06);// 周一
Ds1302_Single_Byte_Write(0x8c,0x10);// 年
Ds1302_Single_Byte_Write(0x8e,0x80);//打开写保护
}
/*官方驱动程序,一个字未改*/
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat)
{
unsigned char i;
SCK = 0;
for (i=0;i<8;i++)
{
if (dat & 0x01) // 等价于if((addr & 0x01) ==1)
{
SDA_SET; //#define SDA_SET SDA=1 /*电平置高*/
}
else
{
SDA_CLR; //#define SDA_CLR SDA=0 /*电平置低*/
}
SCK_SET;
SCK_CLR;
dat = dat >> 1;
}
}
/**********************************************************
**********/
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void)
{
unsigned char i, dat=0;
for (i=0;i<8;i++)
{
dat = dat >> 1;
if (SDA == 1) //等价于if(SDA_R==1) #define SDA_R SDA
/*电平读取*/
{
dat |= 0x80;
}
else
{
dat &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
return dat;
}
/**********************************************************
**********/
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
RST_CLR; /*RST 脚置低,实现DS1302 的初始化*/
SCK_CLR; /*SCK 脚置低,实现DS1302 的初始化*/
RST_SET; /*启动DS1302 总线,RST=1 电平置高 */
addr = addr & 0xFE;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写
之前将最低位置零*/
Write_Ds1302_Byte(dat); /*写入数据:dat*/
RST_CLR; /*停止DS1302 总线*/
SDA_CLR;
}
/**********************************************************
**********/
/*从DS1302 单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
{
unsigned char temp;
RST_CLR; /*RST 脚置低,实现DS1302 的初始化*/
SCK_CLR; /*SCK 脚置低,实现DS1302 的初始化*/
RST_SET; /*启动DS1302 总线,RST=1 电平置高 */
addr = addr | 0x01;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写
之前将最低位置高*/
temp=Read_Ds1302_Byte(); /*从DS1302 中读出一个字节的数据*/
RST_CLR; /*停止DS1302 总线*/
SDA_CLR;
return temp;
}
八. 超声波测距
(1)方法:1、TX(P10)先发送8 个40KHz 的方波(用软件延时
12us)2、初始化计数器,判断RX=0 则接收到返回的超声
波,如TF1=1 则未收到即超出测量范围或者没有东西挡着
(2)相关函数:
//一共四个(定时器1 初始化,12us 延时函数,发8 个方波,计算测
//量距离函数)
//定时器1 初始化
void Timer1Init(void) //19 毫秒@11.0592MHz
{
TMOD |= 0x10;//工作模式1
TH1 = 0;
TL1 = 0;
ET1 = 0;//关闭定时器1 中断,直接当成计数使用
TR1 = 0;//关掉定时器1
EA = 1;
}
//下载器里直接复制的
void Delay12us() //@11.0592MHz
{
unsigned char i;
_nop_();
_nop_();
_nop_();
i = 30;
while (--i);
}
//发送方波的函数
void SendWave(void)
{
unsigned char i;
for(i=0;i<=7;i++)
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
//测量距离的函数
unsigned int GetDistance(void)
{
unsigned int Distance;
SendWave();//发8 个40KHz 的方波
TR1 = 1; //打开计数器一
while((RX==1)&&(TF1==0));//判断何时停止计数
TR1 = 0; //关闭计数器一
if(TF1==1)
{
TF1 = 0;
Distance = 0;
}
else
{
Distance = TH1;
Distance = (Distance << 8) | TL1;
Distance = Distance*17/1000;//放大1000 倍方便显示单位为cm
}
TH1 = TL1 = 0;
return Distance;
}

posted @ 2019-01-24 17:58  流水众生  阅读(290)  评论(0编辑  收藏  举报