蓝桥杯第七届电子类单片机组程序设计

目录

前言

蓝桥杯大赛历届真题

一、第七届比赛题:

二、功能实现:

1.基础/模板部分

2.菜单模式的切换

3.数码管闪烁功能

4.led灯闪烁部分

5.对按键的处理

5.对ds1302的处理

三、代码实现

main.c

onewire.c

 onewire.h

 ds1302.c

 ds1302.h


前言

蓝桥杯的真题可以再官网上查到,链接放下边了,点击即可跳转到官网:

蓝桥杯大赛历届真题

蓝桥杯比赛的题型目前是:客观题: 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

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值