目录
前言
蓝桥杯的真题可以再官网上查到,链接放下边了,点击即可跳转到官网:
蓝桥杯大赛历届真题
蓝桥杯比赛的题型目前是:客观题: 15%基于硬件平台的程序设计与调试: 85%。客观题是数电模电+单片机基础知识的选择题,这里包括往后开元代码时,就不再带着大家看了,大家可以去上边发的那个链接里找。
根据经验,省赛程序设计是大头,如果你程序设计写的很好,但是客观题写的一塌糊涂,省一也是绝对没问题的,当然参加国赛想拿好名次的话,客观题就也得重视起来了。
程序设计题这几年都是只需要设计程序即可,早些年(比如第七届比赛时)还有电路设计呀之类的奇奇怪怪的东西,我们在准备蓝桥杯时,除了程序设计之外的内容可以忽略不看了。
一、第七届比赛题:
二、功能实现:
1.基础/模板部分
我们在基础篇已经完成了按键,led灯,温度传感器的实时时钟的相关内容。
之前介绍的是矩阵按键,这里使用了独立按键,我们只需把扫描其他三列的代码删去,在对源代码稍加修整即可(注意要改跳线帽的位置)。
2.菜单模式的切换
我们定义一个变量mod记为菜单模式,从题目可以看出,总共有三个模式,分别是模式0(显示时间间隔):
模式1,显示时间:
模式2,显示温度采集
当然也就对应要求中的这三张图,定义show_menu函数,根据mod的值不同,显示各个菜单
void show_menu(void)//控制数码管显示
{
if(mod==0)//模式0显示采样间隔
{
Nixie_num[0]=10;//从开头的Seg_Table可以查出,10 对应全灭,11对用“-”,这俩要自己会写
Nixie_num[1]=10;
Nixie_num[2]=10;
Nixie_num[3]=10;
Nixie_num[4]=10;
Nixie_num[5]=11;
Nixie_num[6]=Time_jiange/10%10;
Nixie_num[7]=Time_jiange/1%10;
}
else if(mod==1)//模式1显示时钟
{
Nixie_num[0]=Time[2]/10%10;
Nixie_num[1]=Time[2]/1%10;
Nixie_num[3]=Time[1]/10%10;
Nixie_num[4]=Time[1]/1%10;Nixie_num[6]=Time[0]/10%10;
Nixie_num[7]=Time[0]/1%10;
//每过1s翻转一次提示符的灭亮状态,以达到闪烁的目的
if(TiShiFu_is_on==1&&count_Nixie==1)//过了1s,并且提示符目前处于点亮状态
{
TiShiFu_is_on=0;
count_Nixie=0;
Nixie_num[2]=10;//那就熄灭提示符
Nixie_num[5]=10;
}
else if(TiShiFu_is_on==0&&count_Nixie==1)//过了1s,并且提示符目前处于熄灭状态
{
TiShiFu_is_on=1;
count_Nixie=0;
Nixie_num[2]=11;//那就点亮提示符
Nixie_num[5]=11;
}
}
else if(mod==2)//模式2 显示回调温度数据,
{
Nixie_num[0]=11;
Nixie_num[1]=times/10%10;
Nixie_num[2]=times/1%10;
Nixie_num[3]=10;
Nixie_num[4]=10;
Nixie_num[5]=11;
Nixie_num[6]=temp_times[times]/10%10;//显示第times位,time的值会在其他地方被更新
Nixie_num[7]=temp_times[times]/1%10;
}
}
函数中出现了一些变量,以及其他功能的代码,这里先不介绍,反正大体思路就是专门写一个函数根据mod的值不同,让数码管显示不同的数据。
这样,我们只需要切换mod就可以切换数码管显示了。
3.数码管闪烁功能
题目说在菜单1,要求两个提示符以1s为间隔闪烁,常规的闪烁我们都是用定时器来实现的(比如下边要介绍的LED灯的闪烁),但是它是在时间显示的界面......,又刚好是1s为时间间隔闪烁,如果按照常规的定时器控制其闪烁的话,多少有点误差,而这点误差放在每秒钟跳动一次的时间显示界面,显得特别明显,所以选择用RTC控制标志符闪烁。
要控制数码管闪烁,需要以下三部(LED也一样):
Step1:定义一个时间标志位count_Nixie,时间标志位为0时,1秒后将时间标志位置为1,;标志位为1时则不处理
Step2:在数码管显示函数中,每当检测到标志位被置为1,就将标志位置为0,同时进行Step3
Step3:定义一个状态标志位TiShiFu_is_on,记录当前数码管处于亮的状态还是灭的状态,如果时间标志位为1,并且数码管处于亮(状态标志位为1),就熄灭数码管并将状态标志位置为0,反之依然,以达到“翻转数码管状态的功能”。
我们接下来按照这个思路逐步实现,对于Step1,我们只需要当标志位被置为0时,一秒之后将其置为1,而且我们又是要在RTC中实现这一步,我们只需判断当前读取到的秒Time[0]的值,与上一次读取到的秒count_1s_Nixie的值是否一致即可,如果不一致说明“过了1s”了,就把时间标志位count_Nixie置为1.
/*控制符号提示位没过1s闪烁一次的if判断*/
//如果过了1s(当前的秒值与上一次读到的秒值不一样,说明过来1s)
//并且count_Nixie被置为0了,就把count_Nixie置为1
if(Time[0]!=count_1s_Nixie&&count_Nixie==0)
{
count_1s_Nixie=Time[0];
count_Nixie=1;
}
对于Step2和Step3:如果提示符状态标志位TiShiFu_is_on=1,也就是提示符处于显示的状态,并且时间标志位count_Nixie为1,说明“亮够1s了,接下来要熄灭了”,那么就熄灭状态提示符,反之依然。这里的Nixie_num[5]=10就是熄灭数码管,因为Seg_Table[10]=0xFF,对应全部熄灭,这个Seg_Table数组除了前十位,后边的一般派不上用场,往往需要自己手动修改。
//每过1s翻转一次提示符的灭亮状态,以达到闪烁的目的
if(TiShiFu_is_on==1&&count_Nixie==1)//过了1s,并且提示符目前处于点亮状态
{
TiShiFu_is_on=0;
count_Nixie=0;
Nixie_num[2]=10;//那就熄灭提示符
Nixie_num[5]=10;
}
else if(TiShiFu_is_on==0&&count_Nixie==1)//过了1s,并且提示符目前处于熄灭状态
{
TiShiFu_is_on=1;
count_Nixie=0;
Nixie_num[2]=11;//那就点亮提示符
Nixie_num[5]=11;
}
4.led灯闪烁部分
与上边数码管显示的三个步骤类似:
Step1:定义一个时间标志位count_led,时间标志位为0时,1秒后将时间标志位置为1,;标志位为1时则不处理
Step2:在LED显示函数中,每当检测到标志位被置为1,就将标志位置为0,同时进行Step3
Step3:定义一个状态标志位L1_is_on,记录当前led处于亮的状态还是灭的状态。如果时间标志位为1,并且数码管处于亮(状态标志位为1),就熄灭数码管并将状态标志位置为0,反之依然,以达到“翻转led亮灭状态的功能”。
对于第一步,我们就不在使用RTC了,而是我们用的最多的定时器来进行置位。我们扫描数码管用的定时器是1ms的,刚好可以直接拿来用。我们先设置一个预设值count_250_led,当时间标志位count_led为0,并且进入了250次定时器之后,也就是过了250ms之后(当然,这个不是十分的准),我们就把时间标志位count_led置为1。注意,我们这里设置的预设值count_250_led可能会很大,如果它的值大于255之后,我们就不能用unsigned char了,就得用unsigned int了。刚上手时,经常会有人犯这个错
//如果检测到count_led被置为0,250*1ms=250ms之后,count_led会重新置为1,用于控制led灯闪烁
//当然,这个250ms不是十分精准
if(count_led==0)
{
//这个预设值可以随便改,主要是控制LED灯闪烁的频率的,题目也没规定要闪多快
if(++count_250_led>250)//达到预设值.
{
count_250_led=0;
count_led=1;
}
}
对于Step2和Step3就跟数码管类似,这里就不再赘述了,直接看代码。
void led(void)//控制LED灯
{
if(L1_is_shanshuo==1&&count_led==1)//如果过了预定的时间(就是上文提到的250ms)并且现在需要led闪烁
{
count_led=0;
/*反转led亮灭状态*/
if(L1_is_on==0)//如果当前是熄灭状态
{
LED_ON(0);//那就点亮lED灯
L1_is_on=1;
}
else if(L1_is_on==1)//如果当前是点亮状态
{
LED_OFF(0);//那就熄灭LED灯
L1_is_on=0;
}
}
}
5.对按键的处理
这里的按键并没有什么难点,大概就是在模式0按下s4切换采样间隔,按下s5进入模式1呀之类的,进入模式1之后刚才写的菜单模式切换的函数已经把相关功能实现了,所以按键功能这一块都比较一般,这里不再详细介绍,一定要注意好细节,尤其是切换时的细节:
void get_key(void)
{
unsigned char key_P3=P3;//这里用到了独立按键,只需要把扫描其他三列的代码删除,改一改板子上的跳线帽即可
//这里在while(P30==0)里,加了run函数,其目的是为了在长按按键时,也不影响main的正常运行
P3=0xFF;
if(P30==0){Delay5ms();while(P30==0){run();}Delay5ms();key_value=7;}
else if(P31==0){Delay5ms();while(P31==0){run();}Delay5ms();key_value=6;}
else if(P32==0){Delay5ms();while(P32==0){run();}Delay5ms();key_value=5;}
else if(P33==0){Delay5ms();while(P33==0){run();}Delay5ms();key_value=4;}
/*对按键S4的处理*/
//s4
if(key_value==4&&mod==0)//在模式0(显示采集间隔)按下S4
{
//切换采集时间间隔,分别为1s 5s 30s和60s
if(Time_jiange==1)
Time_jiange=5;
else if(Time_jiange==5)
Time_jiange=30;
else if(Time_jiange==30)
Time_jiange=60;
else if(Time_jiange==60)
Time_jiange=1;
}
/*对按键S5的处理*/
//s5
else if(key_value==5&&mod==0)//在模式0(显示采集间隔)按下S5
{
mod=1;//进入模式1(显示时钟)
}
//模式1会在其他地方处理
/*对按键S6的处理*/
//s6
else if(key_value==6&&mod==2)//在模式2(显示回调温度数据)按下S6
{if(L1_is_shanshuo==1)//如果当前led灯正处在闪烁的状态(在led函数中处理)
{
L1_is_shanshuo=0;//则停止led灯闪烁,
LED_OFF(0);//并关闭LED灯
L1_is_on=0;
}
if(++times==10)//show_menu函数会依次显示第times条温度数据。
{
times=0;//times取值:00到09
}
}
/*对按键S7的处理*/
//s7
else if(key_value==7&&mod==2)//在模式2(显示回调温度数据)按下S7
{
mod=0;//跳转回模式0(显示采样间隔)
times=0;
}
key_value=0;
P3=key_P3;
}
6.对ds1302的处理
题目要求每过采样间隔的时间之后,就读取一次温度传感器的值并记录。我们采取跟数码管闪闪烁Step1一样的思路,在mod1状态下只要上一次记录的秒值Last_S和这次读取到的秒值Time[0]不一致,说明过了1s了,那么就更新Lasts,并且从上一次读取温度传感器到现在的时间count_times就加一,当count_times加到跟采样间隔相同之后,就记录一次温度传感器的值,当记录够十次温度传感器的值之后,就进入mod2
if(Time[0]!=Last_S&&mod==1)//与上边相同,当前秒值与上一次读取到的秒不一致,说明过了1s
{
Last_S=Time[0];//更新上一次的秒值
if(++count_times==Time_jiange)//如果从上一次读取的时间到现在,累计达到了预设的采样间隔(采样间隔就是1s 5s 30s 60s那个)
{
temp_times[times]=read_18b20();//就记录当前的温度值
if(++times==10)//记录够十次之后,
{
times=0;
mod=2;//跳出模式1(显示时钟),进入模式2(显示回调温度采集数据)
Last_S=60;//重置lasts
L1_is_shanshuo=1;//led灯开始闪烁
}
count_times=0;
}
}
逻辑判断有点多,但代码并不复杂,自己第一次遇到时需要一定时间的思考。
三、代码实现
到这里我们几乎已经实现了全部的功能,下边是完整的代码:
基础部分的代码没有写注释,不懂得可以参考前几篇文章,里面有带注释的代码
main.c
#include <stc15.h>
#include <intrins.h>
#include "onewire.h"
#include "ds1302.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xFF,//熄灭
0xBF
};
unsigned char Led_Num=0xFF;
#define LED_ON(x) Led_Num&=~(0x01<<x); P0=Led_Num;P2|=0x80;P2&=0x9F;P2&=0x1F;
#define LED_OFF(x) Led_Num|=0x01<<x; P0=Led_Num;P2|=0x80;P2&=0x9F;P2&=0x1F;
#define LED_OFF_ALL() Led_Num=0xFF; P0=0xFF;P2|=0x80;P2&=0x9F;P2&=0x1F;
#define NIXIE_CHECK() P2|=0xC0;P2&=0xDF;P2&=0x1F;
#define NIXIE_ON() P2|=0xE0;P2&=0xFF;P2&=0x1F;
void Delay100ms(void); //@11.0592MHz
void Timer0_Init(void); //1毫秒@11.0592MHz
void get_key(void);//读取按键
void show_menu(void);//数码管显示
void led(void);//控制LED灯
void ds1302_run(void);//由于这个题目涉及到的温度读取的逻辑有点复杂,这里单独写了一个函数来处理
void run();//
unsigned char Nixie_num[]={1,2,3,4,5,6,7,8};//数码管要显示的数据
unsigned char location=0;//中间变量,数码管当前显示的位置
unsigned char key_value=0;//读取到的按键的键值,中间变量,在get_key()函数之外,key_value的值恒为0
extern unsigned char Time[3];//记录读取到的时间,数组定义在ds1302.c
unsigned char mod=0;//菜单的模式,0:菜单0,显示采样间隔。1:菜单1,显示时钟。2:菜单2显示回调读取到的温度信息
unsigned char Time_jiange=1;//读取的时间间隔,默认为0
unsigned char temp_times[10]={0,0,0,0,0,0,0,0,0,0};//读取到的十次温度的数据,用数组存储
unsigned char times=0;//读取到的温度值的索引。取值00到09
bit L1_is_shanshuo=0;//led1是否闪烁,1:闪烁。0:不闪烁
bit L1_is_on=0;//当前led1是出于亮还是处于灭。0:灭,1:亮。。中间变量
bit count_Nixie=0;//每隔1s这个值就会被置为1,(前提是其它代码能及时将其置为0)用于控制数码管每隔1s的闪烁功能,由RTC控制
void main()
{
LED_OFF_ALL();//关闭所以LED灯
read_18b20();//上电先读取一次温度传感器
init_ds();//上电先初始化一次RTC
show_menu();//上电先调用一次显示菜单,避免刚上电显示数据异常
Timer0_Init();//数据初始化好之后,初始化定时器
EA=1;//开总中断
Delay100ms();
while(1)
{
get_key();
//temp=read_18b20();
run();
Delay100ms();
}
}
void run()
{
read_18b20();
ds1302_run();
show_menu();
led();
}
bit count_led=0;//记录是否达到预设值,当其他代码将count_led重新0时,预设值之后count_led会重新变为1(用于LED闪烁)
unsigned int count_250_led=0;//中间变量,就是刚才提到的预设值,单位250*1ms=250ms,1ms是定时器中断的时间
void Timer0_Isr(void) interrupt 1
{
/*s数码管扫描*/
P0=0x01<<location;NIXIE_CHECK();
P0=Seg_Table[Nixie_num[location]];NIXIE_ON();
if(++location==8)
location=0;
//如果检测到count_led被置为0,250*1ms=250ms之后,count_led会重新置为1,用于控制led灯闪烁
//当然,这个250ms不是十分精准
if(count_led==0)
{
//这个预设值可以随便改,主要是控制LED灯闪烁的频率的,题目也没规定要闪多快
if(++count_250_led>250)//达到预设值.
{
count_250_led=0;
count_led=1;
}
}
}
void Timer0_Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初始值
TH0 = 0xD4; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
void Delay100ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 5;
j = 52;
k = 195;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay5ms(void) //@11.0592MHz
{
unsigned char data i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void get_key(void)
{
unsigned char key_P3=P3;
//这里用到了独立按键,只需要把扫描其他三列的代码删除,改一改板子上的跳线帽即可
//这里在while(P30==0)里,加了run函数,其目的是为了在长按按键时,也不影响main的正常运行
P3=0xFF;
if(P30==0){Delay5ms();while(P30==0){run();}Delay5ms();key_value=7;}
else if(P31==0){Delay5ms();while(P31==0){run();}Delay5ms();key_value=6;}
else if(P32==0){Delay5ms();while(P32==0){run();}Delay5ms();key_value=5;}
else if(P33==0){Delay5ms();while(P33==0){run();}Delay5ms();key_value=4;}
/*对按键S4的处理*/
//s4
if(key_value==4&&mod==0)//在模式0(显示采集间隔)按下S4
{
//切换采集时间间隔,分别为1s 5s 30s和60s
if(Time_jiange==1)
Time_jiange=5;
else if(Time_jiange==5)
Time_jiange=30;
else if(Time_jiange==30)
Time_jiange=60;
else if(Time_jiange==60)
Time_jiange=1;
}
/*对按键S5的处理*/
//s5
else if(key_value==5&&mod==0)//在模式0(显示采集间隔)按下S5
{
mod=1;//进入模式1(显示时钟)
}
//模式1会在其他地方处理
/*对按键S6的处理*/
//s6
else if(key_value==6&&mod==2)//在模式2(显示回调温度数据)按下S6
{
if(L1_is_shanshuo==1)//如果当前led灯正处在闪烁的状态(在led函数中处理)
{
L1_is_shanshuo=0;//则停止led灯闪烁,
LED_OFF(0);//并关闭LED灯
L1_is_on=0;
}
if(++times==10)//show_menu函数会依次显示第times条温度数据。
{
times=0;//times取值:00到09
}
}
/*对按键S7的处理*/
//s7
else if(key_value==7&&mod==2)//在模式2(显示回调温度数据)按下S7
{
mod=0;//跳转回模式0(显示采样间隔)
times=0;
}
key_value=0;
P3=key_P3;
}
bit TiShiFu_is_on=0;//记录提示符的状态,因为在模式1要求提示符闪烁。1:提示符亮起,0:熄灭。中间变量
void show_menu(void)//控制数码管显示
{
if(mod==0)//模式0显示采样间隔
{
Nixie_num[0]=10;//从开头的Seg_Table可以查出,10 对应全灭,11对用“-”,这俩要自己会写
Nixie_num[1]=10;
Nixie_num[2]=10;
Nixie_num[3]=10;
Nixie_num[4]=10;
Nixie_num[5]=11;
Nixie_num[6]=Time_jiange/10%10;
Nixie_num[7]=Time_jiange/1%10;
}
else if(mod==1)//模式1显示时钟
{
Nixie_num[0]=Time[2]/10%10;
Nixie_num[1]=Time[2]/1%10;
Nixie_num[3]=Time[1]/10%10;
Nixie_num[4]=Time[1]/1%10;
Nixie_num[6]=Time[0]/10%10;
Nixie_num[7]=Time[0]/1%10;
//每过1s翻转一次提示符的灭亮状态,以达到闪烁的目的
if(TiShiFu_is_on==1&&count_Nixie==1)//过了1s,并且提示符目前处于点亮状态
{
TiShiFu_is_on=0;
count_Nixie=0;
Nixie_num[2]=10;//那就熄灭提示符
Nixie_num[5]=10;
}
else if(TiShiFu_is_on==0&&count_Nixie==1)//过了1s,并且提示符目前处于熄灭状态
{
TiShiFu_is_on=1;
count_Nixie=0;
Nixie_num[2]=11;//那就点亮提示符
Nixie_num[5]=11;
}
}
else if(mod==2)//模式2 显示回调温度数据,
{
Nixie_num[0]=11;
Nixie_num[1]=times/10%10;
Nixie_num[2]=times/1%10;
Nixie_num[3]=10;
Nixie_num[4]=10;
Nixie_num[5]=11;
Nixie_num[6]=temp_times[times]/10%10;//显示第times位,time的值会在其他地方被更新
Nixie_num[7]=temp_times[times]/1%10;
}
}
void led(void)//控制LED灯
{
if(L1_is_shanshuo==1&&count_led==1)//如果过了预定的时间(就是上文提到的250ms)并且现在需要led闪烁
{
count_led=0;
/*反转led亮灭状态*/
if(L1_is_on==0)//如果当前是熄灭状态
{
LED_ON(0);//那就点亮lED灯
L1_is_on=1;
}
else if(L1_is_on==1)//如果当前是点亮状态
{
LED_OFF(0);//那就熄灭LED灯
L1_is_on=0;
}
}
}
unsigned char count_1s_Nixie=0;//中间变量,没过1s会被置为一次1,前提是被置为1之后及时被置为0
unsigned char Last_S=60;//记录上一次读取到的秒值,设置为60是使得可以尽快更新lasts
unsigned char count_times=0;//中间变量,记录从上一次读取到现在过来多少秒
void ds1302_run(void)
{
read_ds1302();
/*控制符号提示位每过1s闪烁一次的if判断*/
//如果过了1s(当前的秒值与上一次读到的秒值不一样,说明过了1s)
//并且count_Nixie被置为0了,就把count_Nixie置为1
if(Time[0]!=count_1s_Nixie&&count_Nixie==0)
{
count_1s_Nixie=Time[0];
count_Nixie=1;
}
if(Time[0]!=Last_S&&mod==1)//与上边相同,当前秒值与上一次读取到的秒不一致,说明过了1s
{
Last_S=Time[0];//更新上一次的秒值
if(++count_times==Time_jiange)//如果从上一次读取的时间到现在,累计达到了预设的采样间隔(采样间隔就是1s 5s 30s 60s那个)
{
temp_times[times]=read_18b20();//就记录当前的温度值
if(++times==10)//记录够十次之后,
{
times=0;
mod=2;//跳出模式1(显示时钟),进入模式2(显示回调温度采集数据)
Last_S=60;//重置lasts
L1_is_shanshuo=1;//led灯开始闪烁
}
count_times=0;
}
}
}
onewire.c
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <stc15.h>
#include <intrins.h>
#include "onewire.h"
sbit DQ=P1^4;
//
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;
}
unsigned int read_18b20(void)
{
unsigned int temp=0;
unsigned char low=0;
unsigned char high=0;
init_ds18b20();
Write_DS18B20(0xCC);//跳过ROM检测
Write_DS18B20(0x44);//开始温度转化
Delay_OneWire(200);
init_ds18b20();
Write_DS18B20(0xCC);//跳过ROM检查
Write_DS18B20(0xBE);//读取温度信息
low=Read_DS18B20();
high=Read_DS18B20();
temp=high;
temp&=0x0F;//舍弃符号位
temp<<=8;
temp|=low;
temp>>=4;//舍弃小数位
return temp;
}
onewire.h
#ifndef _ONEWIRE_H_
#define _ONEWIRE_H_
unsigned int read_18b20(void);
#endif
ds1302.c
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <stc15.h>
#include <intrins.h>
#include "ds1302.h"
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;
unsigned char Time[3]={50,59,23};//存读到的数据
//
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);
}
void init_ds(void)
{
unsigned char add=0;
unsigned char i=0;
add=0x80;
Write_Ds1302_Byte(0x8E,0x00);
for(i=0;i<3;i++)
{
Write_Ds1302_Byte(add,(Time[i]/10<<4)|(Time[i]%10));
add+=2;
}
Write_Ds1302_Byte(0x8E,0x80);
}
void read_ds1302(void)
{
unsigned char add=0;
unsigned char dat=0;
unsigned char i=0;
add=0x81;
for(i=0;i<3;i++)
{
dat=Read_Ds1302_Byte(add);
Time[i]=dat/16*10+dat%16;
add+=2;
}
}
ds1302.h
#ifndef _DS1302_H_
#define _DS1302_H_
void init_ds(void);
void read_ds1302(void);
#endif