51单片机基础

写在前面:51单片机有一些基础理论概念,大家一般都已经了解或者在百度上能查找到详细说明,博主就会省略,所以以下内容比较精炼,大家看完之后都能上手敲出代码,控制51单片机。但是想要融会贯通,真正精通51单片机,还需要大家私下不断编写代码,烧录程序。
一、LED
LED点亮,闪烁,流水灯见之前的博客。
二、蜂鸣器
蜂鸣器见之前博客。
三、 数码管
见之前博客(上传word文档形式)。
四、键盘
见之前博客(上传word文档形式)。
五、8*8点阵屏
见之前博客(上传word文档形式)。
以上五个板块为51单片机基础中的基础,下面我们来看51单片机中的基础中的中级内容。
六、中断系统
1.什么是中断:
计算机执行某程序时,发生了紧急事件或有特殊请求,CPU暂停某程序的执行,转而去处理上述事件或请求,处理完毕后再重新执行某程序的过程叫做中断。
2.实现外部中断:
言简意赅,需要先进行外部中断1初始化,再编写中断服务函数。中断初始化:a.打开总中断,然后b.开外部中断,c.配置外部中断触发方式。实现代码如下:(以开外部中断1为例)

void int1Init()
{
	EA=1;//开总中断
	EX1=1;//开外部中断1
	IT1=1;//外部中断1下降沿触发
}

之后在主函数中引用此初始化函数即可。
51单片机基础_第1张图片
51单片机基础_第2张图片
51单片机基础_第3张图片
51单片机基础_第4张图片
初始化之后需要编写中断服务函数。

void int1() interrupt 2
{
	P1=~P1;//点亮/熄灭8颗LED灯
}

中断小结:主函数中引用中断初始化函数,之后一旦触发中断,即CPU停下正在处理的事,执行中断服务函数。(关于中断初始化函数中控制位的说明,我会在文章最后附上STC89C52使用手册,控制位记不住在手册中查询即可)

七、定时计数器
1.51单片机上的定时计数器:
51单片机有2个16位定时器/计数器:定时器0(T0为P3.4)和定时器1(T1为P3.5),这里所说的16位是指定时/计数器内部分别有16位的计数寄存器。
当工作在定时模式时,每经过一个机器周期内部的16位计数寄存器的值就会加1,当这个寄存器装满时溢出。我们可以算出工作在定时模式时最高单次定时时间为65535*1.085us=时间(单位us)当工作在计数器模式时,T0(P3.4引脚),T1(P3.5引脚)每来一个脉冲计数寄存器加1。
2.基本步骤
定时器定时
a.定时器初始化:启动定时/计数器(通过TCON控制器),设置定时/计数器工作模式(通过TMOD控制器)
b.查询定时/计数器是否溢出(读TCON内TF位)
定时器初始化

void timer0Init()
{
	TR0=1;//启动定时器0
	TMOD=0x01;//配置工作模式为工作模式1,定时模式
	TH0=0x4b;
	TL0=0xfd;//定时50ms
}

51单片机基础_第5张图片
51单片机基础_第6张图片
51单片机基础_第7张图片
b.在主函数中查询定时计数器是否溢出

if(TF0==1)
{
	TF0=0;//软件清零
	TH0=0x4b;
	TL0=0xfd;//重新赋初值
	mes++;//50ms到
}

定时器计数:这里我们用定时器1做计数器,即使用定时器1的定时功能,然后用定时器0做计数器使用。
初始化函数

void timer0Init()
{
	TR0=1;
	TMOD=0x50;//工作模式1,计数模式
	TH0=0;
	TL0=0;//从0次开始
}

主函数引用
通过计数器每500ms使LED=~LED,产生一次方波,计数器加1,期间不断进行display函数的扫描。

while(1)
{
	if(TF1==1)
	{
		TF=0;
		TH1=0x4b;
		TL1=0xfd;
		mes++;
		if(mes==10)
		{
			mes=0;
			LED=~LED;//之前sbit LED=P1;
		}
	}
	display(TL0);
}

定时器中断:
初始化:需要启动相应中断和启动定时器

void timer0Init()
{
	EA=1;
	ET0=1;
	TR0=1;
	TMOD=0x01;
	TH0=0xed;
	TL0=0xff;
}

根据工作模式,中断服务函数里需要设置初值:

void timer0 () interrupt 1//中断入口
{
	TH0=0xed;
	TL0=0xff;
	dispaly(num);//数码管显示函数
}

PS:以下内容为实现的基础代码及注释,文章最后会上传STC89C52使用手册和开发板原理图,各位浏览资料相应位置结合代码即可理解(STC89C52使用手册,开发板原理图借用“清翔MCS51开发板资料”)
八、串口通信
1.基础步骤:
串口初始化、串口中断函数
串口初始化:

void UARTInit()
{
	EA=1;//打开总中断
	ES=1;//打开串口中断
	REN=1;//串口允许接收
	SM1=1;	SM0=0;//串口工作方式1,8位UART波特率可变
	TR1=1;
	TMOD|=0x20;
	TH1=0xfd;
	TL1=0xfd;//设置波特率为9600
}

波特率=2^SMOD·fosc/32·12·(256-T初)
串口中断函数:

void UART() interrupt 4//触发中断:接收标志位或者发送标志位溢出
{
	uchar temp;//之前宏定义#define uchar unsigned char
	if(RI)//判断接受是否完成
	{
		RI=0;//软件清零RI位
		num=SBUF;
		temp=num;
		SBUF=++temp;
	}
	if(TI)
	TI=0;
}

九、 IIC总线EEPROM
有2个主功能函数,6主功能辅助函数

//起始信号
void I2cStar()
{
	SCL=1;
	SDA=1;
	delay5us();
	SDA=0
	delay5us();
}

//停止信号
void I2cStop()
{
	SCL=0;
	SDA=0;
	SCL=1;
	delay5us();
	SDA=1;
	delay5us();
}

//读应答
bit ReadACK()
{
	SCL=0;
	SCL=1;
	delay5us();
	if(SDA)
	{
		SCL=0;
		return (1);
	}
	else
	{
		SCL=0;
		return (0);
	}
}

//写应答
void SendACK(bit i)
{
	SCL=0;
	if(i)
	SDA=1;
	else
	SDA=0;
	SCL=1;
	delay5us();
	SCL=0;
	SDA=1;
}

//发送一个字节
void I2cSendByte(uchar dat)
{
	uchar i;
	for(i=0;i<8;i++)
	{
		SCL=0;
		if(dat&0x80)//I2c通讯从最高位传输数据
		SDA=1;
		else
		SDA=0;
		SCL=1;
		dat<<=1;
	}
	SCL=0;
	SDA=1;
}

//接收一个字节
uchar I2cReadByte()
{
	uchar i,dat;
	for(i=0;i<8;i++)
	{
		dat=_crol_(dat,1);
		SCL=0;
		SCL=1;
		if(SDA)
		dat|=0x01;
		else
		dat|=0x00;
	}
	return (dat);
}

//写入一个字节
void At24c02WriteByte(uchar ADDR,uchar dat)
{
	I2cStar();
	I2cSendByte(At24c02ADDR+I2cWrite);
	ReadACK();
	I2cSendByte(ADDR);
	ReadACK();
	I2cSendByte(dat);
	ReadACK();
	I2cStop();
}

//读出一个字节
uchar At24c02ReadByte(uchar ADDR)
{	
	uchar dat;
	I2cStar();
	I2cSendByte(At24c02ADDR+I2cWrite);
	ReadACK();
	I2cSendByte(ADDR);
	ReadACK();
	I2cStar();
	I2cSendByte(At24c02ADDR+I2cRead);
	ReadACK();
	dat=I2cReadByte();
	SendACK(1);
	I2cStop();
	return (dat);
}

归结为:PS:()中内容为从机操作
写入一字节步骤:S,器件地址+0,(A),写入首地址,(A),Dat,(A),P
读出一字节步骤:S,器件地址+0,(A),读出首地址,(A),S,器件地址+1,(A),(Dat),NA,P
十、ADDA数模转换
90%类似EEPROM操作。(九中前6个函数一样,后2个函数步骤有细微差异)
写入一字节:S,器件地址+0,(A),发送控制字节,(A),Dat,(A),P
读出一字节:S,器件地址+0,(A),发送控制字节,(A),S,器件地址+1;(A),(Dat),NA,P

十一、数字温度传感器DS18B20
包括:初始化函数,写一字节函数,读一字节函数

bit ds_Init()
{
	bit i;
	DS=1;
	_nop_();
	DS=0;
	delay_us(75);//拉低总线499.45us
	DS=1;
	delay_us(4);
	i=DS;
	delay_us(20);
	DS=1;
	_nop_();
	return (i);
}

void write_byte(uchar dat)
{
 uchar i;
 for(i=0;i<8;i++)
 {
  DS = 0;
  _nop_();//产生写时序
  DS = dat & 0x01;
  Delay_us(10);//76.95us
  DS = 1; //释放总线准备下一次数据写入
  _nop_();
  dat >>= 1;
 }
}

uchar read_byte()
{
 uchar i, j, dat;
 for(i=0;i<8;i++)
 {
  DS = 0;
  _nop_();//产生读时序
  DS = 1;
  _nop_();//释放总线
  j = DS;
  Delay_us(10);//76.95us
  DS = 1;
  _nop_();
  dat = (j<<7)|(dat>>1); 
 }
 return (dat);
}

void main()
{
 uint i;
 uchar L, M;
/* ds_init();//初始化DS18B20
 write_byte(0xcc);//发送跳跃ROM指令
 write_byte(0x4e);//写暂存器指令
 write_byte(0x7f);
 write_byte(0xf7);
 write_byte(0x1f);//配置工作在9位模式下
 ds_init();//初始化DS18B20
 write_byte(0xcc);//发送跳跃ROM指令 
 write_byte(0x48);*/
 while(1)
 {
  ds_init();//初始化DS18B20
  write_byte(0xcc);//发送跳跃ROM指令
  write_byte(0x44);//发送温度转换指令
  ds_init();//初始化DS18B20
  write_byte(0xcc);//发送跳跃ROM指令
  write_byte(0xbe);//读取DS18B20暂存器值
  L = read_byte();
  M = read_byte();
  i = M;
  i <<= 8;
  i |= L;      
  i = i * 0.0625 * 10 + 0.5;
  Display(i);
 }
}

注意,主机和DS18B20做任何通讯之前都需要对其初始化
操作一般步骤:初始化,ROM指令,操作指令

十二、红外通讯

//初始化函数
void init()
{
	TMOD = 0x22; 
	TH0 = 0x00;  
	TL0 = 0x00;
	EA = 1;      
	ET0 = 1;    	
 	TR0 = 1;     
	IT0 = 1;    
 	EX0 = 1;
 	TH1 = 0xfd; 
	TL1 = 0xfd;
	TR1 = 1;     
	SM1 = 1; 
	ES=1;    
}

void time0() interrupt 1   //定时器0中断服务函数
{
 IRtime++;       
}

void int0() interrupt 0     
{
 static uchar i;   
 static bit startflag;  
 if(startflag)     
 {
  if( (IRtime < 53) && (IRtime >= 32) )   i = 0;    
  IRdata[i] = IRtime;     
  IRtime = 0;     
  i++;      
  if(i == 33)      
  {
    IRok = 1;     
   i = 0;      
  }
 }
 else    
 {
  IRtime = 0;      
  startflag = 1;    
 }
}

void IRcordpro()        //解码
{
 uchar i, j, k, cord, value; 
  k = 1;       
 for(i = 0; i < 4; i++)
 {
  for(j = 0; j < 8; j++)
  {
   cord = IRdata[k];     
   if(cord > 5)    
   value = value | 0x80; 
     if(j < 7)
   {
    value = value >> 1; 
   }
   k++;    
  }
  IRcord[i] = value;   
  value = 0;      
 }
 IRpro_ok = 1;      
}

void main()
{
 uchar i;
 init(); 
 while(1) 
 {
  if(IRok)                      
  {   
   IRcordpro();
   IRok = 0;
   if(IRpro_ok) 
   {
    for(i = 0; i < 4; i++)  
    {  
     SBUF = IRcord[i];
     while(!TI);
     TI = 0;
    }
    IRpro_ok = 0;
   }
  } 
 }
}

红外通讯:脉宽检测,解码,传输数据

十三、实时时钟DS1302

//写DS1302数据
void Write_DS1302_DAT(uchar cmd, uchar dat)
{
	uchar i;
 	TRST = 0; 
	TSCLK = 0;
	TRST = 1; 
	for(i = 0; i < 8; i++)
 	{
  	TSCLK = 0;    
  	TIO = cmd & 0x01; 
  	TSCLK = 1;    
  	cmd >>=1;   
 	}
 	for(i = 0; i < 8; i++)
 	{
  	TSCLK = 0;    
  	TIO = dat & 0x01; 
  	TSCLK = 1;    
  	dat >>= 1;    
 	}
}
//读DS1302数据
uchar Read_DS1302_DAT(uchar cmd)
{
 uchar i, dat;
 TRST = 0;  
 TSCLK = 0; 
 TRST = 1;  
 for(i = 0; i < 8; i++)
 {
  TSCLK = 0;   
  TIO = cmd & 0x01;
  TSCLK = 1;  
  cmd >>=1;  
 }
 for(i = 0; i < 8; i++)
 {
  TSCLK = 0;    
  dat >>= 1;    
  if(TIO) dat |= 0x80;
  TSCLK = 1;   
 }
 return dat; 
}
//数据转BCD码
uchar Dat_Chg_BCD(uchar dat)
{
 uchar dat1, dat2;
 dat1 = dat / 10;
 dat2 = dat % 10;
 dat2 = dat2 + dat1 * 16;
 return dat2;
}
//BCD码转换为数据
uchar BCD_Chg_Dat(uchar dat)
{
 uchar dat1, dat2;
 dat1 = dat / 16;
 dat2 = dat % 16;
 dat2 = dat2 + dat1 * 10;
 return dat2;
}
void main()
{
uchar i;
 uchar Sec, Min, Hour;
 Write_DS1302_DAT(0x8e, 0);
 Write_DS1302_DAT(0x80, Dat_Chg_BCD(30));
 Write_DS1302_DAT(0x82, Dat_Chg_BCD(15));
 Write_DS1302_DAT(0x84, Dat_Chg_BCD(19));
 Write_DS1302_DAT(0x8e, 0x80);
 while(1)
 {	
Write_DS1302_DAT(0x8e, 0); 
  Sec = BCD_Chg_Dat(Read_DS1302_DAT(0x81));
  Min = BCD_Chg_Dat(Read_DS1302_DAT(0x83));
  Hour = BCD_Chg_Dat(Read_DS1302_DAT(0x85));
  Write_DS1302_DAT(0x8e, 0x80);
  for(i = 0; i < 50; i++) 
   Display(Hour, Min, Sec);
}
}

十四、LCD1602液晶

//判断液晶忙
void Read_Busy()
{
 uchar busy;
 P0 = 0xff;
 RS = 0;
 RW = 1;
 do
 {
  EN = 1;
  busy = P0;
  EN = 0;
 }while(busy & 0x80);
}
//写LCD1602命令一个字节
void Write_Cmd(uchar cmd)
{
 Read_Busy();//判断忙
 RS = 0;
 RW = 0;
 P0 = cmd;
 EN = 1;
 EN = 0;
}
//写一个字节数据
void Write_Dat(uchar dat)
{
 Read_Busy();
 RS = 1;
 RW = 0;
 P0 = dat;
 EN = 1;
 EN = 0;
}
void main()
{
Write_Cmd(0x38);
 Write_Cmd(0x0f);
 Write_Cmd(0x01);
 Write_Cmd(0x06);
 Write_Cmd(0x80 | 0x06);
 Write_Dat(1 + '0');
 Write_Dat(2 + '0');
 Write_Dat(3 + '0');
 Write_Dat(4 + '0');
 Write_Dat(5 + '0');
 while(1);
}

十五、手机蓝牙控制51最小系统

void UART_INIT()
{
 SM0 = 0;
 SM1 = 1;
 REN = 1;
 EA = 1;
 ES = 1;
 TMOD = 0x20;
 TH1 = 0xfd;
 TL1 = 0xfd;
 TR1 = 1;
}
//串口中断
void UART_SER() interrupt 4
{
 if(RI)
 {
  RI = 0;
  switch(SBUF)
  {
   case 0x01: LED1 = 0; break;
   case 0x02: LED1 = 1; break;
  }
 }
}
void main()
{
 UART_INIT();
 while(1); 
}

以上就是51单片机的基础内容(湿度传感器,电机驱动,蓝牙,WiFi四个板块博主也会在近期写出相应博客),后面一些章节因为时间匆忙,只有代码,各位可以结合以下博主上传的开发板原理图资料自己消化理解,结合实际,相信大家一定可以学好51单片机,共勉!

PS:开发板原理图是借用的此清翔MCS51开发板资料。
STC89C52使用手册大家可以在网络上找以下资源,里面内容也是非常重要的。

你可能感兴趣的:(嵌入式)