蓝桥杯——根据手册写底层

一、 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(0x90);
	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(0x90);
	I2CWaitAck();
//word
	I2CSendByte(0x43); //选择需要写入器件的地址 0x41与0x43,写入的时候为
	I2CWaitAck();


//dat
	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;
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ssm入门

文章目录1.介绍ssm2.Spring篇基础内容&#x1fa85;什么是IOC&#xff08;控制反转&#xff09;Spring和IOC之间的关系IOC容器的作用以及内部存放IoC入门案例&#x1f4ec;DI&#xff08;Dependency Injection&#xff09;依赖注入依赖注入的概念IOC容器中哪些bean之间要建立依…

函数微分和导数的定义

1.我们先来看可导的定义&#xff1a; 相信这个大家都看的懂。 2.接下来我们看可微的定义&#xff1a; 你们有没用想过为什么会有可微&#xff0c;他是用来干什么的&#xff0c;我们接下来看下面这张图&#xff0c;特别是结合图2-11来说&#xff0c; 我们可以看到书上说可微是在…

【day2】Android Jetpack Compose环境搭建

【day2】Android Jetpack Compose环境搭建 以下是适用于 Jetpack Compose 的环境要求&#xff1a; Android Studio 版本&#xff1a;4.2 Canary 15 或更高版本Gradle 版本&#xff1a;7.0.0-beta02 或更高版本Android 插件版本&#xff1a;4.2.0-beta15 或更高版本Kotlin 版本…

MySQL 幻读问题

承接上文MySQL多版本并发控制MVCC实现原理 幻读现象 因为在RR&#xff08;可重复读&#xff09;隔离级别里&#xff0c;事务1的第二次查询没有生成新的readview&#xff0c;而是用的第一次查询时生成的readview&#xff0c;所以第二次查询返回2条数据&#xff0c;而不是3条数据…

看过来,这里有JavaScript技术干货?

今天是一篇正经的技术分享&#xff0c;针对JavaScript技能的十来个专业小技巧&#xff0c;如果你想提升一下JS方面的能力成为一个更好的前端开发人员&#xff0c;那么就可以接着看下去哦。 1、使用逻辑运算符进行短路评估 您可以使用逻辑运算符进行短路评估&#xff0c;方法是…

云边协同与人工智能AI的深度融合(云端训练、边端推理)

在面向物联网、大流量等场景下&#xff0c;为了满足更广连接、更低时延、更好控制等需求&#xff0c;云计算在向一种更加全局化的分布式节点组合形态进阶&#xff0c;边缘计算是其向边缘侧分布式拓展的新触角。 以物联网场景举例&#xff0c;设备产生大量数据&#xff0c;上传到…

都2023了,学习自动化测试还有必要么?会不会浪费我时间

最近收到不少小伙伴私信提问&#xff0c;其中问得比较多的就是“学习自动化测试有那么重要吗&#xff1f;”。 我的回答是肯定的——很重要。 相信不少同学都有诸如此类的疑问&#xff0c;例如&#xff1a;“日常工作中好像用不上自动化&#xff1f;”、“手工点点点好像也可…

【从零开始学习 UVM】9.1、UVM Config DB —— UVM Resource database 资源库详解

文章目录 resource 是一个参数化的容器,可以保存任意数据。资源可用于配置组件、为序列提供数据或在TestBench不同部分之间启用信息共享。它们使用作用域信息(scope)存储,因此其可见性可以限制在TestBench的某些部分中。您可以将任何数据类型放入资源数据库中,并使另一个组…

若依后端管理系统学习日志

文章目录遇到的问题1. 自定义模块404解决方案1. 自定义后台异常返回2. 添加导入按钮3. 树形列表搜索遇到的问题 1. 自定义模块404 idea没有报错&#xff0c;但是点击进去页面显示404。 F12查看错误信息&#xff0c;原来是访问后端controller接口没有成功&#xff0c;找不到导…

上传文件—ajax

目录 一、上传图片文件 1.写基本html 完成页面主框架 2.script部分 2-0 主框架 上传文件按钮被点击触发事件 2-1验证使得否选择文件 2-2 介绍 FormData 2-3 监听onreadystatechange事件 小结 二、实现上传文件进度条 1. 在bootstrap找进度条组件 2.script 完成进度条算法…

Java锁深入理解2——ReentrantLock

前言 本篇博客是《Java锁深入理解》系列博客的第二篇&#xff0c;建议依次阅读。 各篇博客链接如下&#xff1a; Java锁深入理解1——概述及总结 Java锁深入理解2——ReentrantLock Java锁深入理解3——synchronized Java锁深入理解4——ReentrantLock VS synchronized Java锁…

QT Qwidget 事件处理机制

qlineEdit Qt事件处理是指在Qt应用程序中处理各种事件的过程。事件是指在应用程序中发生的各种操作&#xff0c;例如按键、鼠标点击、窗口移动等。Qt提供了一个事件处理机制&#xff0c;使得开发者可以对这些事件进行处理&#xff0c;以实现应用程序的各种功能。 Qt中的事件处…

CMake设置Visual Studio工程的调试环境变量和工作目录cwd的方法

1、设置在Visual Studio中调试的环境变量&#xff0c;此设置仅仅在VS中点击那个绿色三角运行时有效&#xff0c;与你直接双击打开exe文件运行无关&#xff0c;有效避免多版本动态库全部写入系统环境变量的污染问题&#xff1b; # Visual Studio中调试依赖的独立环境变量 set_p…

代码随想录算法训练营第五十天| ● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费 ●总结

309.最佳买卖股票时机含冷冻期 看完题后的思路 dp[i][] 0: 第i天不持有股票的最大利润 1: 持有 递推公式 dp[i][0]max(第i-1天不持有,第i-1天持有,在第i天卖了) dp[i][1]max(第i-1天持有, 第i-2天不持有,第i天持有) 初始化 dp[0][0]0; dp[0][1]-price[i]; dp[1][0]max(x,x) d…

PCB模块化设计23——LDO线性稳压电源模块PCB布局布线设计规范

目录PCB模块化设计23——LDO线性稳压电源模块PCB布局布线设计规范一、LDO线性稳压电源组成与概念二、LDO的电路的主干道布局要点PCB模块化设计23——LDO线性稳压电源模块PCB布局布线设计规范 一、LDO线性稳压电源组成与概念 LDO线性稳压器是最基本的稳压电源变换&#xff0c;…

STM32时钟与定时器

目录 一、STM32的时钟系统 二、SysTick定时器 三、HAL_Delay的实现 四、通用定时器 一、STM32的时钟系统 概念时钟系统是由振荡器&#xff08;信号源&#xff09;、定时唤醒器、分频器等组成的电路。常用的信号源有晶体振荡器和RC振荡器。 意义时钟是嵌入式系统的脉搏&…

自然语言处理中的数据预处理:理论与实践

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

2020-2022年美赛C题信件汇总

2020-2022年美赛O奖C题写信汇总(机翻) 2020 <1> Dear Marketing Director of Sunshine Company , According to your requirements, we analyze the ratings and reviews of competitive products on Amazon for baby pacifier, microwave and hair dryer to be intro…

C++ 模板、函数模板、类模板

函数模板、类模板 文章目录函数模板、类模板前言1.模板1.1 模板的概念1.2 模板的特点2. 函数模板2.1 函数模板语法2.2 函数模板注意事项2.3 普通函数与函数模板的区别2.4 普通函数与函数模板的调用规则2.5 模板的局限性2.6 函数模板案例3. 类模板3.1 类模板语法3.2 类模板与函数…

2023年Java程序员生存指南,8个中肯建议度过寒潮!

最近小源看到一个2023Java程序员生存指南&#xff0c;觉得挺有意思的&#xff0c;今天分享给大家&#xff01; 第一&#xff0c;不要在互联网公司基于低代码做开发。 第二&#xff0c;保证一定强度的刷题&#xff0c;原因嘛你懂的~ 第三&#xff0c;凡是要求名校的岗位&#xf…
最新文章