蓝桥杯——根据手册写底层
Posted _Li.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯——根据手册写底层相关的知识,希望对你有一定的参考价值。
一、 DS18B20温度传感器
1.官方所给源码
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
void Write_Ds1302(unsigned char temp)
unsigned char i;
for (i=0;i<8;i++)
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
过程:
1. 初始化 ——> 2.ROM跳过指令 ——> 3.功能指令
功能指令:
温度转化参数
读取寄存器
由上面总结的流程:
1. 初始化
2. ROM(0xcc命令)
3. 读取温度转化函数(0x44)
4. 初始化
5. ROM
6. 读取寄存器
7. 先读低八位
8. 再读高八位
10. 精度处理
原理引脚图:
根据引脚图的到我们所需要设置的引脚和头文件
#include <reg52.h>
#include <intrins.h>
#include "ds1302.h"
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3;
同时,得到代码:
float rd_temperature(void) //浮点数
unsigned float temp;
unsigned char low,high; //高八位与低八位
init_ds18b20() //第一部初始化 1.Initialization
Write_DS18B20(0xcc); //2.ROM 跳过指令
Write_DS18B20(0x44); //3.功能指令
/* 题目说每次上电都需要初始化一次 */
init_ds18b20() //第一部初始化 1.Initialization
Write_DS18B20(0xcc); //2.ROM 跳过指令
Write_DS18B20(0xbe); //3.功能指令
/* 接下来就可以读 */
low = Read_DS18B20();
high = Read_DS19B20();
/* 返回一个值 */
temp = ((high << 8)|low)/16.0; // 可以选择 *0.0625
return temp;
二、AT24C02_EEPROM储存器
官方所给源码(IIC)
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
/* 根据引脚*/
#include <STC15F2K602K.H>
#include "intrins.h"
sbit sda = P21;
sbit scl = P20;
#define DELAY_TIME 5
//
static void I2C_Delay(unsigned char n)
do
_nop_();
while(n--);
//
void I2CStart(void)
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
//
void I2CStop(void)
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
//
void I2CSendByte(unsigned char byt)
unsigned char i;
for(i=0; i<8; i++)
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80)
sda = 1;
else
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
scl = 0;
//
unsigned char I2CReceiveByte(void)
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
return da;
//
unsigned char I2CWaitAck(void)
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
//
void I2CSendAck(unsigned char ackbit)
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
2. 器件地址
3. 字节写入流程
我们根据图八就可以明白整个流程
开始 -> 发送(写)器件地址 -> 等待 -> 发送字节地址 -> 等待 -> 写数据 -> 等待 -> 停止
其中 写器件地址为(0xa0),读器件地址为(0xa1)
4. EEPROM代码
void EEPROM_Write(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
I2CStart(); //1.开始
I2CSendByte(0xa0); //2.写入器件地址
I2CWaitAck(); //3.等待
I2CSendByte(addr); //3.写入字节地址 ,这个地方使用的时候一般为0
I2CWaitAck();//4 等待
/* I2CSendByte(dat); // 5.数据发送
I2CWaitAck(); */
// 上面是发送单个,我们可以改为发送整个数组长度,用num计数,一个个发
while(num--)
I2CSendByte(EEPROM_String);
I2CWaitAck();
I2C_Delay(200); //补充数据
I2CStop();
5. 随机读流程
我们就可以得到整个流程
开始 -> 发送(写)器件地址 -> 等待 -> 发送字节地址 -> 等待 -> 开始 -> 发送(读)器件地址 -> 等待 -> 读数据 -> 停止
6. 随机读Read代码
void EEPROM_Read(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
I2CStart(); //1.开始
I2CSendByte(0xa0); //2.写入器件地址
I2CWaitAck(); //3.等待
I2CSendByte(addr); //3.写入字节地址
I2CWaitAck();//4 等待
I2CStart();
I2CSendByte(0xa1); //修改这个地址
I2CWaitAck();
/* I2CSendByte(dat); // 5.数据发送
I2CWaitAck(); */
// 上面是发送单个,我们可以改为发送整个数组长度,用num计数,一个个发
/* 下面这个读数据可以实现整个字符全部读取,是需要记住的 */
while(num--)
*EEPROM_String++=I2CReceiveByte();
if(num) I2CSendAck(0); //是1,说明有消息,发送应答
else I2CSendAck(1); /是0.说明没消息,不应答
I2CStop();
三、PCF8591模块
1. 原理图及引脚
两个模块都是IIC模块里的,所以我们的引脚都是一样的
代码如下:
#include "reg52.h"
#include "intrins.h"
sbit sda = P2^1;
sbit scl = P2^0;
上面说过两者都是在IIC里面的,所以通信协议是相同的,我们就可以使用同样的流程来进行读写操作,同时,我们不需要对写内容进行修改(同时读取后,我们使用比例对参数进行修改,让其符合我们的要求)
代码如下:
Ad_Read 读取函数
unsigned char Ad_Read(unsigned char addr)
unsigned char temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
temp = I2CReceiveByte(); //接收消息
I2CSendAck(1); //答应
I2CStop(); //停止
return temp; //返回AD值
Da_Write 写入函数
void Da_Write(unsigned char dat)
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(0x43); //选择需要写入器件的地址 0x41与0x43,写入的时候为
I2CSendByte(dat); //发送数据
I2CWaitAck();
I2CStop();
四、DS1302时钟模块
他的协议是SPI协议,我们的头文件是使用的是onewrie.h,单总线
1. 官方所给底层
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
void Delay_OneWire(unsigned int t)
unsigned char i;
while(t--)
for(i=0;i<12;i++);
//
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);
//
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;
//
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;
2. 原理图及引脚
由上面的原理图,我们就可以得到其头文件与引脚
#include "ds1302.h"
#include <reg52.h>
#include <intrins.h>
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
3. 手册重要地点:
通过上面的,我们就知道如何写入和读取时间数据
4. 如何读写数据
我们根据表格上的 WRITE,与READ一列,其之后对应了各个时间
很多时候我们不需要到 日月周年,我们接着把需要的时间设置到一个数组里:ucRtc[]
所以我们得到一个流程:
code unsigned char write_addr[]=0x80,0x82,0x84,0x86,0x88,0x8a,0x8c;
code unsigned char read_addr[]=0x81,0x83,0x85,0x87,0x89,0x8b,0x8d;
code unsigned char ucRtc[]=0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;
void Set_Rtc()
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);// 关闭写保护
for(i = 0;i<7;i++)
Write_Ds1302_Byte(write_addr[i],ucRtc[i]); //每位时间地址写入需要时间
Write_Ds1302_Byte(0x8e,0x80);// 开启保护
void Read_Rtc()
unsigned char i;
for(i=0;i<7;i++)
ucRtc[i] = Read_Ds1302_Byte(read_addr[i]);
这是在我们设置好数组的需要填的时间参数后进行的,如果我们需要把时间放在主函数设置,我们可以把ucRtc的位置不设置,而使用指针代替
unsigned char* ucRtc
我们也可以和上面一样直接在onewire里面写入即可,我们也可以不写,只需要在定义里面添加,在主函数写即可
修改如下:
void Set_Rtc(unsigned char* ucRtc)
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);// 关闭写保护
for(i = 0;i<7;i++)
Write_Ds1302_Byte(write_addr[i],ucRtc[i]); //每位时间地址写入需要时间
Write_Ds1302_Byte(0x8e,0x00);// 开启保护
void Read_Rtc(unsigned char* ucRtc)
unsigned char i;
for(i=0;i<7;i++)
ucRtc[i] = Read_Ds1302_Byte(read_addr[i]);
六、NE555
通过滑动变阻器来改变输出频率
我们就需要选择定时器的计数功能,但是因为定时和计数只能选一个,所以我们使用两个中断,一个计时(定时器1)一个计数(定时器0)
我们直接来看他的代码:
定时器 与下多一个 0x05,且不需要打开中断使能
void Timer0Init(void) //1毫秒@12.000MHz
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x05; //设置计数模式
TL0 = 0; //设置定时初始值
TH0 = 0; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
然后在计时下算频率
void Timer1Init(void) //1毫秒@12.000MHz
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x18; //设置定时初始值
TH1 = 0xFC; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //定时器中断1打开
EA = 1; //总中断打开
/* 定时器1中断服务函数 */
void Timer1Server() interrupt 3
if(++Timer_1000Ms == 1000) //实时读取频率值
Timer_1000Ms = 0;
Freq = TH0 << 8 | TL0; //和时间函数很相似
TH0 = TL0 = 0;
2016年 蓝桥杯决赛体验
本来想搜决赛题解的...
结果搜到了“如何评价16年蓝桥杯......”看到一众人说自己只会第一题....刚觉得安慰了许多...
然后就搜到了决赛成绩...优秀奖...完美打铁...
.........看到同行的一等...二等...三等...怀疑自己的水平已经.....
说多了都是泪....已经不能理解只提交了第一题我了...
比赛的时候就感觉不想写不想写...看上去都是可以暴力过30%~50%的数据...然后暴力每每写的太丑...放弃找bug...填空题又太笨没有想出来...
就这样思考完了每个题...敲敲删删...蓝桥杯就这样结束了...
第一场个人参加的大比赛...惨淡收场...虽然断断续续也算准备了许久...
悲伤的心情...
以上是关于蓝桥杯——根据手册写底层的主要内容,如果未能解决你的问题,请参考以下文章