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

news2024/11/27 4:31:55

目录

前言

蓝桥杯大赛历届真题

一、第七届比赛题:

二、功能实现:

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1448688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Chainlit, Langchain 及 Elasticsearch 轻松实现对 PDF 文件的查询

在我之前的文章 “Elasticsearch&#xff1a;与多个 PDF 聊天 | LangChain Python 应用教程&#xff08;免费 LLMs 和嵌入&#xff09;” 里&#xff0c;我详述如何使用 Streamlit&#xff0c;Langchain, Elasticsearch 及 OpenAI 来针对 PDF 进行聊天。在今天的文章中&#xf…

PWR电源控制

PWR电源 PWR简介 PWR&#xff08;Power Control&#xff09;电源控制 PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能 可编程电压监测器&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上…

【安装指南】图床神器之Picgo下载、安装详细教程

&#x1f33c;一、概述 PicGo是一款开源的图片上传、管理工具&#xff0c;旨在帮助用户快速上传图片到云存储或图床&#xff0c;并提供链接方便在网页或其他应用中使用。它支持各种常见的图床服务商&#xff0c;如GitHub、七牛云、腾讯云等&#xff0c;并提供了简洁易用的界面和…

收藏:关于块存储,文件存储和对象存储

在B站上看到”【IT老齐465】“这个系列相当不错&#xff0c;每次的视频15分钟左右&#xff0c;出了400多个了&#xff0c;今天偶然看到&#xff0c;地址是&#xff1a;【IT老齐465】块存储、文件存储、对象存储的关系与区别_哔哩哔哩_bilibili 精彩摘录如下&#xff1a;

金庆培:世界需要有一个国际易货贸易协定

2024年2月4日&#xff0c;我拜访了中国金融与证券行业的著名专家徐士敏教授。 首先开言&#xff0c;他就告诉我&#xff1a;“你金老师&#xff0c;是研究中国自由贸易区创新发展和世界自由贸易区创新发展的专家&#xff0c;我认为&#xff0c;在当前世界经济形势下&#xff0c…

C语言每日一题(57)二叉树的最小深度

题目链接 力扣网111 二叉树的最小深度 题目描述 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,…

四、案例 - Oracle数据迁移至MySQL

Oracle数据迁移至MySQL 一、生成测试数据表和数据1.在Oracle创建数据表和数据2.在MySQL创建数据表 二、生成模板文件1.模板文件内容2.模板文件参数详解2.1 全局设置2.2 数据读取&#xff08;Reader&#xff09;2.3 数据写入&#xff08;Writer&#xff09;2.4 性能设置 三、案例…

C++:priority_queue模拟实现

C&#xff1a;priority_queue模拟实现 什么是priority_queue模拟实现向上调整算法向下调整算法插入与删除 仿函数 什么是priority_queue priority_queue称为优先级队列。优先级队列是一种特殊的队列&#xff0c;其中每个元素都有一个相关的优先级。元素的优先级决定了它们在队…

Vue2中v-for 与 v-if 的优先级

在Vue2中&#xff0c;v-for 和 v-if 是常用的指令&#xff0c;它们在前端开发中非常有用。但是&#xff0c;当我们在同一个元素上同时使用这两个指令时&#xff0c;就需要注意它们的优先级关系了。 首先&#xff0c;让我们了解一下v-for和v-if的基本用法。 v-for 是Vue的内置…

基于JAVA的课程案例资源库系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员需求分析2.2 用户需求分析 三、系统设计3.1 业务流程设计3.1.1 管理员业务流程设计3.1.2 用户业务流程设计3.1.3 首页功能模块及业务流程分析3.1.4 案例资源中心功能模块及业务流程分析3.1.5 用户信息中心功能模块…

爱快使用VPN

文章目录 一、VPN服务器1. 各种VPN比较2. PPTP服务端配置3. 创建登录账号4. 创建端口映射5. 设置动态域名 二、Windows客户端1. 连接配置2. 不能连接 Internet 配置 一、VPN服务器 1. 各种VPN比较 PPTPIPSECOpenVPN简介微软推出的VPN协议&#xff0c;占用资源少更高级的VPN协…

再利用系统盘时,如何删除恢复分区(Recovery Partition)

系统盘有一个Recovery Partition&#xff0c;记录了重要的系统信息&#xff0c;不能删除。 Windows 10的 Disk Managment 不提供用户删除这个Partition的选项。 近日我插入一块原系统盘&#xff0c;Format后作为DataDisk&#xff0c;此时需要删除这块硬盘上的RecoveryPartition…

matplotlib画简单的论文图像

由于最近论文里需要插入绘图&#xff0c;因此写一篇博客记录一下 折曲线图 基本绘图 在matplotlib中折线和曲线图是最常用和最简单的图。只需要直接使用方法plot即可。 import matplotlib.pyplot as plt plt.plot(x,y) plt.show()其中上述的代码中x&#xff0c;y分别是横坐…

langchain==win11搭建使用GPU

annaconda安装Python 3.11.7 下载代码&#xff1a; GitHub - chatchat-space/Langchain-Chatchat: Langchain-Chatchat&#xff08;原Langchain-ChatGLM&#xff09;基于 Langchain 与 ChatGLM 等语言模型的本地知识库问答 | Langchain-Chatchat (formerly langchain-ChatGLM)…

【Tomcat】:One or more listeners failed to start.报错解决方案

报错信息:One or more listeners failed to start. Full details will be found in the appropriate container log file. 具体就是web.xml此配置报错: 服务器启动错误Tomcat:One or more listeners failed to start.报错解决方案 IDEA:在使用IDEA运行SSM项目的时候 , Tomcat运…

基于SSM的教材管理系统

文章目录 教材管理系统一、项目演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;&#xff09; 教材管理系统 一、项目演示 基于SSM的教材管理系统 二、项目介绍 有三个角色 1、管理员 功能模块&#xff1a;用户管理、教…

【数据结构】链表OJ面试题3《判断是否有环》(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 后三题在这http://t.csdnimg.cn/gbohQ 记录每天的刷题&#xff0c;继续坚持&#xff01; 2.OJ题目训练 9. 给定一个链表&#xff0c;判断链表中是否有环。 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成…

幻兽帕鲁Palworld服务器设置参数(汉化)

创建幻兽帕鲁服务器配置参数说明&#xff0c;Palworld服务器配置参数与解释&#xff0c;阿腾云atengyun.com分享&#xff1a; 自建幻兽帕鲁服务器教程&#xff1a; 阿里云教程 https://t.aliyun.com/U/bLynLC腾讯云教程 https://curl.qcloud.com/oRMoSucP 幻兽帕鲁服务器 幻…

《数字图像处理-OpenCV/Python》连载:形态学图像处理

《数字图像处理-OpenCV/Python》连载&#xff1a;形态学图像处理 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第 12 章 形态学图像处理 形态学图像处理是基于形状的图像处理&…

《Git 简易速速上手小册》第9章:Git 工作流程定制(2024 最新版)

文章目录 9.1 选择合适的工作流9.1.1 基础知识讲解9.1.2 重点案例&#xff1a;为中等规模的 Python 项目选择 Feature Branch 工作流9.1.3 拓展案例 1&#xff1a;适应 Gitflow 工作流的大型项目9.1.4 拓展案例 2&#xff1a;使用 Forking 工作流的开源 Python 项目 9.2 定制化…