AutoLeaders控制组-51单片机笔记(后期)

目录

一.I/O口介绍

1.I/O口配置

 2.I/O口控制LED数码管

二.中断系统

1.介绍

 2.结构

3.中断寄存器

 1.TCON

 2.SCON

​ 三.定时器

1.寄存器介绍

2.工作模式

3.代码解释

四.串口通信

1.串口相关寄存器

2.相关代码

五.74HC595

1.介绍

2.原理

六.DS1302时钟芯片

1.工作电路

 2.数据传输

3.寄存器地址/定义

 4.代码解释

 5.BCD码

七.I2C总线&AT24C02

1.I2C时序及代码

 2.AT24C02时序及代码

 八.DS18B20

1.介绍

2.使用方法

1.原理图

2.单总线协议

3.DS18B20实例


一.I/O口介绍

1.I/O口配置

·P1/P2/P3/P4上电复位后为准双向口/弱上拉模式

·P0则为开漏输出模式

·P0作为总线扩展用时不用加上拉电阻,作为I/O口使用时需加10K-4.7K上拉电阻

·P0口的灌电流最大为12mA,其他I/O口的灌电流最大为6mA

准双向口输出:

1.当口线输出为1时驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,可吸收相当大的电流。

2.在三个上拉晶体管中分别有“强上拉”、“极弱上拉”、“弱上拉”。

3.此单片机为3V器件,若用户在引脚上加5V电压,将有电流从引脚流向Vcc,导致额外的功率消耗。若要使用,应加限流电阻,或用二极管做输入隔离,或用三极管做输出隔离。

4.准双向口读外部状态前,要先锁存为‘1’,才可读到外部正确的状态。

5.输出图如下:

注:门电路标识符

 开漏输出:

开漏输出就是不输出电压,控制输出低电平时引脚接地,控制输出高电平时引脚既不输出高电平,也不输出低电平,为高阻态。如果外接上拉电阻,则在输出高电平时电压会拉到上拉电阻的电源电压。这种方式适合在连接的外设电压比单片机电压低的时候。

 输出图如下:

 2.I/O口控制LED数码管

1.I/O口动态扫描驱动数码管时,可以一次点亮一个数码管中的8段,但为降低功耗,建议一次只点亮其中的4段或者2段。

2.下图是共阴极的数码管参考图:

 3.下图是共阳极数码管参考图:(注:加了PNP的三极管)

 我们的单片机是共阴极数码管。

数码管原理图与74HC138译码器:

 74HC138译码器逻辑图:

数码管代码:

//在这里,最右边是第一位,如0X3F是0011 1111在位选中的排列是dp g f e d c b a的格式
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,
0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie(unsigned char Location,Number)
{
		switch (Location)
			{
				//在74HC138译码器中P22,P23,P24操控LED的段选,并且给高电平为选中
					case 1 :  P2_4=1;P2_3=1;P2_2=1;break;
					case 2 :  P2_4=1;P2_3=1;P2_2=0;break;
					case 3 :  P2_4=1;P2_3=0;P2_2=1;break;
					case 4 :  P2_4=1;P2_3=0;P2_2=0;break;
					case 5 :  P2_4=0;P2_3=1;P2_2=1;break;
					case 6 :  P2_4=0;P2_3=1;P2_2=0;break;
					case 7 :  P2_4=0;P2_3=0;P2_2=1;break;
					case 8 :  P2_4=0;P2_3=0;P2_2=0;break;
			}
					P0=NixieTable[Number];
									//以下两行代码为了消影
									Delay(1);
									P0=0x00;
}

至于为什么是高电平选中,看不懂逻辑图,看不懂芯片手册,我也不知道。 

二.中断系统

1.介绍

中断系统的目的是为了使CPU具有对外界紧急事件的实时处理能力。当外界发出紧急事件的请求,可要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完成后,再回到原来被中断的地方,继续原来的工作。

1.请示CPU中断的请求源称中断源。一般存在多个中断源,每个中断源有优先级别。因此可以实现中断嵌套

2.此单片机有8个中断,如下图,Int是外部中断,Timer是定时器中断,UART是串口中断

 2.结构

1.结构图:

 2.定时器0和1的中断请求标志位是TF0和TF1。当定时器寄存器THx/TLx(x=0/1)溢出时,溢出标志位TFx(x=0/1)会被置位,定时器中断发生。当执行定时器中断时,TFx(x=0/1)会被硬件清除。

3.串行口接收中断请求的标志位RI和串行口1发送中断请求标志位TI中的任何一个被置为1后,串行口中断都会发生。

3.中断寄存器

单片机中断相关的所有寄存器:

只介绍Timer寄存器TCON和SCON (串行口控制寄存器)

 1.TCON

 

 2.SCON

三.定时器

1.寄存器介绍

 不可位寻址:即此地址只可用十六进制一次性赋值,不可单位单位赋值如P2_1这样。

2.工作模式

模式0

原理图:

描述:TL0低五位溢出则向TH0进位,TH0溢出则置位TCON中的溢出标志TH0

具体看不太懂,就不描述了。

3.代码解释

	void Timer0_Init(void)		//1毫秒@11.0592MHz,
{
	//配置寄存器TMOD
	TMOD &= 0xF0;		//设置定时器模式,保持高位不变
	TMOD |= 0x01;		//设置定时器模式,保持低位其他位不变
	//设置初始值
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	//配置寄存器TCON
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	//中断部分
	ET0=1;		//允许中断
	EA=1;		//允许总中断
	PT0=0;		//中断优先级等于0,低优先级
}

四.串口通信

1.串口相关寄存器

1.全部相关寄存器

 2.SCON寄存器

 

 

 需要软件控制TI RI,在代码中有说明

3.PCON电源控制寄存器

4.SBUF寄存器(数据缓存寄存器)

主机必须在该帧结束前从SBUF缓冲器中读取数据,否则前一帧数据将丢失。SBUF以并行方式送往内部数据总线。

2.相关代码

串口通信代码:

void UartInit()		//4800bps@11.0592MHz定时器1(8位自动重装)
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFA;		//设置定时初始值
	TH1 = 0xFA;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
//以下代码只要在接收时才需要加
	EA=1;				//接口中断
	ES=1;				//使能中断
}

发送字节的代码

void UartSendByte (unsigned char x)
{
	SBUF=x;//SBUF是缓冲区,用来存放将发送的数据
	while(TI==0);//当TI置1时发送完成
	TI=0;//需要软件置0
	//若发送数据有问题,可以试着延时
}

串口接收代码

void URATRoutine() interrupt 4 //串口中断的函数
{
	if(RI==1)
	{
		P2=SBUF//让单片机做出SBUF的相关反应P2可换成别的东西
		RI=0;//RI需要靠软件回零
	}
}

五.74HC595

1.介绍

74HC595是串行输入并行输出的移位寄存器,可用三根线输入串行数据,八根线输出并行数据,多片级联后,可输出十六位,二十四位,三十二位等,常用于IO口扩展。

2.原理

 英文原理图看不懂就不解释了

看代码

void _74HC595_Init()
{
	SCK=0;//初始时SCK是高电平,需要调为低电平
	RCK=0;//初始时RCK是高电平,需要调为低电平
}
void _74HC595_WriteByte(unsigned char Byte)
{
		unsigned char i;
	for(i=0;i<8;i++)
	{
		SER=Byte&(0x80>>i); //给寄存器各位上填数字1或0
		SCK=1;//给高电平,来一个上升沿
		SCK=0;//给低电平,为下一次上升沿做准备
	}
	RCK=1;//给RCK上升沿就能使寄存器中的数输出
	RCK=0;
}

六.DS1302时钟芯片

1.工作电路

 2.数据传输

 一.命令字

 如图所示,位7必须为1,位6逻辑为1则RAM为0则CK(时钟),位5至位1表示输入输出的指定寄存器地址,位0逻辑为1则是读逻辑为0则为写。与数据输入图中相反,所以每次都从最右边开始读。

二.CE

CE拉高则开始对移位寄存器进行读写控制逻辑,拉低则中断。

三.数据输入

输入写命令字后的八个SCLK周期的上升沿数据被输入

四.数据输出

输入读命令字后的八个SCLK周期的下降沿,数据被输出

3.寄存器地址/定义

 4.代码解释

void DS1302_Init()
{
	//把CE和SCLK置0实现初始化
	DS1302_CE=0;
	DS1302_SCLK=0;
}
void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;//CE拉高,数据传输开始
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);//字节是从右往左读的,所以每一位需要左移
		DS1302_SCLK=1;//每次拉高则数据输入
		DS1302_SCLK=0;//需要软件拉低		
	}
		for(i=0;i<8;i++)//每次输入完写命令字后开始输入数据
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;		
	}
	DS1302_CE=0;//关闭数据传输
}
unsigned char DS1302_ReadByte(unsigned char Command)
{
	//局部变量十六进制若不初始化,则不一定是0.全局变量则一定是0
	unsigned char i,Data=0x00;
	Command|=0x01;//在写地址的第一位肯定是0,改一下第一位则可以不用多加宏定义
	DS1302_CE=1;
		for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		//先给0再给1目的是避免多出一个SCLK周期
		//在读命令字结束时,那个下降沿就会读出数据而不是上升沿
		DS1302_SCLK=0;
		DS1302_SCLK=1;		
	}
			for(i=0;i<8;i++)
	{
		//后面八个SCLK周期与写命令字一样
		DS1302_SCLK=1;
		DS1302_SCLK=0;	
		if(DS1302_IO) Data|=(0x01<<i);		
	}
	DS1302_CE=0;
	DS1302_IO=0;
		return Data;
}

 5.BCD码

DS1302芯片采用BCD码的形式,写入芯片时需要将数据转化成BCD码,读出时需要转化为十进制

void DS1302_SetTime()
{
	DS1302_WriteByte(DS1302_WP,0X00);//关闭写保护,允许地址数据被修改
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATA,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0X80);//打开写保护,地址数据不允许被修改
}
void DS1302_ReadTime()
{
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_DATA);
	DS1302_Time[2]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
		Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
}

七.I2C总线&AT24C02

1.I2C时序及代码

void I2C_Start()
{
	//保证在start之前SDA和SCL都是高电平
	I2C_SDA=1;
	I2C_SCL=1;
	//SCL为高电平,SDA下降沿是起始条件
	I2C_SDA=0;
	I2C_SCL=0;	
}
void I2C_Stop ()
{
	//保证SDA是低电平
	I2C_SDA=0;
	I2C_SCL=1;	
	//SCL是高电平,SDA上升沿是停止条件
	I2C_SDA=1;
}

void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	//SCL低电平时可写入数据
	I2C_SCL=0;
	for(i=0;i<8;i++)
	{
		//把Byte给SDA
		I2C_SDA=Byte&(0x80>>i);
		//SCL低电平时数据允许被修改,高电平时数据稳定,每个周期读取一个字节
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

unsigned char I2C_ReceiveByte()
{
	unsigned char i, Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA) Byte|=(0x80>>i);
		I2C_SCL=0;		
	}
	return Byte;
}

void I2C_SendAck(bit AckBit)
{
	I2C_SDA=AckBit;//在SCL低电平时发送是否应答
	I2C_SCL=1;
	I2C_SCL=0;
}
unsigned char I2C_ReceiveAck()
{
	bit AckBit;
	I2C_SDA=1;
	I2C_SCL=1;//SCL高电平时读取应答,若SDA是高电平则无应答,若低电平则应答
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}

应答图如下:

 2.AT24C02时序及代码

void AT24C02_WriteByte (unsigned char WordAddress,Data)
{
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);//AT24C02_ADDRESS是0xA0
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Stop();
}

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);//给AT24C02_ADDRESS读地址
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return Data;
}

 八.DS18B20

1.介绍

DS18B20数字温度计提供9位温度读书,数据经过单线接口从DS18B20送入或送出,因此仅需一条数据线即可完成读写,且由数据线提供电源。一个DS18B20有唯一的序列号,所以可以有多个18B20存在于同一条总线上。这允许在许多不同的地方放置温度灵敏器件。

范围:HVAC环境控制,建筑物、设备或机械内的温度检测,以及过程监视和控制中的温度检测。

特性:单总线。从-55℃至+125℃,增量为0.5℃。在一秒(典型值)内把温度变换为数字

2.使用方法

1.原理图

 由P37引脚控制单总线协议。

2.单总线协议

1.初始化

 主机将总线拉低至少480us,然后释放总线,等待15-60us后,存在的从机会拉低总线60-240us以响应主机,之后从机释放总线。

代码段:

unsigned char OneWire_Init()
{
	unsigned char i,AckBit;
	OneWire_IO=1;//拉高为1,做准备
	OneWire_IO=0;//拉低
	//延迟至少480微秒,接着主机释放此线,并进入接收方式
		i = 230;while (--i);//500微秒
	OneWire_IO=1;
	//等待15~60微秒
		i = 38;while (--i);
	AckBit=OneWire_IO;
		i = 218;while (--i);//延时500微秒,让程序走完
	return AckBit;
}

2.写时间片

 主机把总线拉低60-120us表示发送0,主机将总线拉低后1-15us把总线拉高表示发送1。(尽量贴近15us末尾)

代码段:

void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_IO=0;
			i = 4;while (--i);
	OneWire_IO=Bit;
			i = 25;while (--i);
	OneWire_IO=1;
}

3.读时间片

 主机把总线拉低1-15us,然后主机释放总线,并在此期间读取总线电平。若是低电平则读取为“0”,若为高电平则读取为“1”。注意:总时长至少为60us

 代码段:

unsigned char OneWire_ReceiveBit()
{
	unsigned char Bit,i;
	OneWire_IO=0;
	i=2;while(--i);//延迟五微秒,避免程序还未读出就跳过了
	OneWire_IO=1;
	i=2;while(--i);
	Bit=OneWire_IO;
	i = 30;while (--i);//让总时长超过60us
	return Bit;
}

4.发送和接收一个字节

代码段:

//注意单总线是低位在前
//发送字节
void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}
//接收字节
unsigned char OneWire_ReceiveByte()
{
	unsigned char i,Byte=0x00;
		for(i=0;i<8;i++)
	{
			if(OneWire_ReceiveBit()) Byte|=(0x01<<i);
	}
	return Byte;
}

3.DS18B20实例

命令集:

//ROM命令集
#define READ_ROM 0x33
#define	MATCH_ROM 0x55
#define	SKIP_ROM 0xCC
#define	SEARCH_ROM 0xF0
#define	ALARM_SEARCH_ 0xEC
//
//功能命令集
#define CONVERTT 0x44
#define	RECALLE2 0xB8
#define	READPAD 0xBE
#define	COPYPAD 0x48
#define	READP 0xB4

·通过单总线访问DS18B20的协议

1.初始化

2.ROM操作命令

3.存储器操作命令

4.处理/数据

传递温度值代码段:

void DS18B20_ConvertT()
{
	OneWire_Init();
	OneWire_SendByte(SKIP_ROM);//因为只有一个DS18B20所以直接跳过ROM操作,不需要再搜索ROM
	OneWire_SendByte(CONVERTT);
}

温度存储格式

  

 BIT0~3是存小数,BIT11~15是存符号(+或-)。

读取温度数据代码段: 

float DS18B20_ReadT()
{
	unsigned char Tlsb,Tmsb;
	int Temp;
	float T;
	OneWire_Init();
	OneWire_SendByte(SKIP_ROM);
	OneWire_SendByte(READPAD);//读取数据
	Tlsb=OneWire_ReceiveByte();//低八位
	Tmsb=OneWire_ReceiveByte();//高八位
	Temp=(Tmsb<<8)|Tlsb;
	T=Temp/16.0;//传递的温度值最低位是从1/16开始的
	//而这里是从1开始,所以需要除以16
	return T;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值