51开发学习记录

与天斗其乐无穷,与地斗其乐无穷,与人斗其乐无穷



前言

本人使用的是普中科技51单片机,芯片类型为STC89C52.
开发软件使用的是Keil5.

单片机工作原理如下: 代码在CPU上运行,接着访问寄存器(本单片机为8位寄存器),寄存器再接着通过驱动,对硬件电路实行控制。


一、LED部分

原理图如下:

八个二极管,通过寄存器P2相连,其均采用共阳极解法,输入在阴极,输入高电平则不亮,输入低电平就亮,电阻为限流电阻。

1.1点亮LED灯

通过Keil5新建工程,添加文件,编写如下:要使D1亮,那么我们就得跟寄存器P2 1111 1110的信号,注意从左到右对应(P27-P20,D7-D0).

#include <REGX52.H>//这一头文件内定义了各种寄存器,以及告诉了他们的位置

void main()
{
		P2=0x00;//正常来说是1111 1110,这里从左到右对应P7-P0,注意顺序,但计算机默认会把这种形式看作十进制
						//所以我们需要变为十六进制,注意,0x是十六进制的前缀
} 

1.2LED闪烁

在上一程序的基础上,加入延时函数(由STC-ISP生成),同时需要用到INTRINS.H这个头文件 单片机中INTRINS.H简单介绍

#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 205;
	k = 187;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	while(1)
	{
	P2=0xFE;
	Delay500ms();
	P2=0XFF;
	Delay500ms();
	}
	
	
}

1.3LED流水灯(自定义延时函数)

间隔点亮D1-D7;

#include <REGX52.H>
#include <INTRINS.H>
//普通延时函数,我们只能通过软件生成,且修改起来较麻烦,下面我们以1ms延迟函数为基础,写一个可设置延时时长的延时函数
//注:单片机中int类数据占用16位,计算机中int类数据占用32位
void Delay1ms(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}

void main()
{
	P2=0xFE;//1111 1110
	Delay1ms(100);
	P2=0xFD;//1111 1101
	Delay1ms(100);
	P2=0xFB;//1111 1011
	Delay1ms(100);
	P2=0xF7;//1111 0111
	Delay1ms(100);
	P2=0xEF;//1110 1111
	Delay1ms(100);
	P2=0xDF;//1101 1111
	Delay1ms(100);
	P2=0xBF;//1011 1111
	Delay1ms(100);
	P2=0x7F;//0111 1111
	Delay1ms(100);
}
/*void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 205;
	k = 187;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	P2=0xFE;//1111 1110
	Delay500ms();
	P2=0xFD;//1111 1101
	Delay500ms();
	P2=0xFB;//1111 1011
	Delay500ms();
	P2=0xF7;//1111 0111
	Delay500ms();
	P2=0xEF;//1110 1111
	Delay500ms();
	P2=0xDF;//1101 1111
	Delay500ms();
	P2=0xBF;//1011 1111
	Delay500ms();
	P2=0x7F;//0111 1111
	Delay500ms();
}*/

二、独立按键模块

原理图如下:

初始时默认给寄存器每一位都赋予高电平5V(状态为1),开关按下后,线路接通,对应接口的位电平改变为低电平(状态为0). 即开关未按下时,接口状态为1,开关按下后,接口状态为0.

同时对于机械开关,还有如下必须注意的地方:

在这里插入图片描述

由于开关状态发生改变后,电路并不会立马稳定接通,所以我们需要用到延时函数来过度这两段不稳定的时间:例如开关状态从1到0,并稳定到0,需要一个延时函数来过度,并且我们此时如果不松手,开关状态持续为0,那我们需要一个循环体来限制住,就是说当我们持续按住开关时,程序什么都不做.当我们松开后,开关状态又从0变为1,这时还需要一个延时函数来进行过度。

if(!P3_1)
		{
			Delay(20);//延时,过滤掉开关按下时的信号抖动,使信号直接过渡到稳定状态(中间状态)
			while(!P3_1);//检测是否松手(即开关状态是否发生改变),若没有松手,则一直执行循环体,状态改变后再接着执行下面的代码
			Delay(20);//由于开关状态发生改变后,信号依旧会有一个抖动,故再延时过滤,使信号直接过渡到下一个状态
		}

2.1独立按键控制LED模块:

2.1.1控制LED亮灭

这里我们直接通过改变寄存器下的单独一位来改变对应模块的变化

#include <REGX52.H>
void main()
{
	 while(1)
	 {
		 if(!P3_1)P2_0=0;//P3_1是P3寄存器的第1位,链接P31,也就是K1
				//开关按下为0,松开为1
		 else P2_0=1;
	 }
}

2.1.2控制LED状态

#include <REGX52.H>
#include <INTRINS.H>
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
	
}

void main()
{
	while(1)
	{
		if(!P3_1)
		{
			Delay(20);//延时,过滤掉开关按下时的信号抖动,使信号直接过渡到稳定状态(中间状态)
			while(!P3_1);//检测是否松手(即开关状态是否发生改变),若没有松手,则一直执行循环体,状态改变后再接着执行下面的代码
			Delay(20);//由于开关状态发生改变后,信号依旧会有一个抖动,故再延时过滤,使信号直接过渡到下一个状态
			
			P2_0=~P2_0;
		}
	}
}

2.1.3 控制LED显示二进制

#include <REGX52.H>
#include <INTRINS.H>
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
	
}

void main()
{
	unsigned char LEDNum=0;// LEDNum= 0000 0000
	while(1)
	{
		
		if(!P3_1)
		{
			Delay(20);
			while(!P3_1);
			Delay(20);
			LEDNum++;//第一次:LEDNum= 0000 0001 第二次:LEDNum= 0000 0010,依次类推
			P2=~LEDNum;//第一次:P2=~LEDNum = 1111 1110; 第二次:P2=~LEDNum = 1111 1101
		}
	}
}

2.1.4 控制LED移位

这里需要用到移位运算符<<.

#include <REGX52.H>
#include <INTRINS.H>

void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
	
}

void main()
{
	unsigned char LEDNum=0;//unsigned char LEDNum=0,把定义放在P2=0xFE之后,就会出现语法错误,为啥?;
	P2=0xFE;
	while(1)
	{
		if(!P3_1)
		{
			Delay(20);
			while(!P3_1);
			Delay(20);
			
			LEDNum++;
			if(LEDNum>=8)LEDNum=0;
			P2=~(0x01<<LEDNum);
			
		}
		
		if(!P3_0)
		{
			Delay(20);
			while(!P3_0);
			Delay(20);
			
			//如果是这样定义,由于LEDNum为无符号类型,0之后再减一就会溢出.
			/*LEDNum--;
			if(LEDNum<0)LEDNum=LEDNum+8;*/
			
			//所以我们按照下面这种方式来判断
			if(LEDNum==0)LEDNum=7;//当LEDNum为0的时候,不再自减,而是直接赋最大值
			else LEDNum--;
			P2=~(0x01<<LEDNum);
		
		if(!P3_2)
		{
			Delay(20);
			while(!P3_2);
			Delay(20);
			
			P2=0xFE;//1111 1110
			Delay(100);
			P2=0xFD;//1111 1101
			Delay(100);
			P2=0xFB;//1111 1011
			Delay(100);
			P2=0xF7;//1111 0111
			Delay(100);
			P2=0xEF;//1110 1111
			Delay(100);
			P2=0xDF;//1101 1111
			Delay(100);
			P2=0xBF;//1011 1111
			Delay(100);
			P2=0x7F;//0111 1111
			Delay(100);
		}
			
		}
	}
}

三、数码管部分

原理图如下:

板子上一共有8个数码管,对于单个的数码管,其原理图如下:

每个数码管上有8个"-“,每个”-"都由一个二极管控制,51开发板上8个二极管采用共阴接法,即其公共端为低电平时,端口才有效,这一点后面会再次提到。

看上面的图不难发现,8只管子的各个输入口都是公共的,这就导致我们不能通过控制输入来单独控制一个管子,但是我们可以通过控制一个管子公共端的有效性来决定这个管子是否亮

那么我们怎么来控制一个管子的公关端的有效性呢?前面说了,51单片机的情况下,公共端为低电平称之为有效,这里我们需要用到译码器74HC138,原理图如下:


通过在P22-P24端口进行输出来控制LED1-LED8公共端的有效性

输入从高到低为P24,P23,P22,并将输入结果转化为十进制数,对应不同的Yn,Yn对应的LED公共端就为有效公共端。

现在我们就能控制不同数码管公共端的有效性了,我们接下来就只需给P0输入特定的值,就能让数码管显示出我们想要的数字了。

3.1 静态数码管显示

#include <REGX52.H>

unsigned char Nixietable[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//这个数组指的是,显示数字x时,对应的阳码(51中数码管部分的LED灯采用共阴解法),即并排接口P0的值。
void Nixie(unsigned char Location,Number)//Location指的是单片机上从左到右第几个数码管显示数字,Number指的是显示什么数字
{
	switch(Location)
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;//这里的数字1指的是单片机上从左到右第一个数码管,在原理图中实际对应LED8,故需要Y7接通。
		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];
}
void main()
{
	 
	 Nixie(7,2);//在这里就可以直接输入需要显示的LED的位置和所要显示的数字了。
	 while(1)
	 {
		 
	 }
}

3.2 动态数码管显示

只让一个管子亮起来是远远不够的,我们肯定想能让多个管子同时亮起来,显示不同的数字。如果在上一节代码的基础上,我们直接通过不断改变位选和段选,也能让多个管子同时亮起来,但是,我们会在一个管子上看到其他管子所显示数字的影子,所以我们需要进行消影操作

消影其实就是在两次位选和段选之间,流出一段时间空隙,并且把段选值清零,那我们就能保证在下一次位选和段选前,上一次的值不会转移过来,且即使转移过来,也是初始零状态

在这里插入图片描述

#include <REGX52.H>

unsigned char Nixietable[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
	
}

void Nixie(unsigned char Location,Number)
{
	switch(Location)
	{
		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;
}
void main()
{	 	 
	 while(1)
	 {
		 Nixie(1,1);
		// Delay(200);
		 Nixie(2,2);
		// Delay(200);
		 Nixie(3,3);
		 // Delay(200);
	 }
}

四、模块化编程以及LCD调试

LCD部分原理图如下:
在这里插入图片描述
在这里插入图片描述
由于其和数码管部分共用P0端,所以接上LCD后会与数码管部分产生冲突

4.1将动态数码管部分代码模块化处理

在这里插入图片描述
模块化的思想在大一写C++课设时已经用到了,就是将需要在主函数中调用的函数在外部 .c文件中编译,并在 .h文件中声明,我们要想在主函数中调用时就只许引入其对应的 .h文件即可

其中 .h文件内涉及到c语言中的预编译部分的知识

在这里插入图片描述

//Delay.c文件部分:
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
//Delay.h文件部分:
#ifndef __DELAY__H
#define __DELAY__h


void Delay(unsigned int xms);




#endif

//Nixie.c文件部分:
#include <REGX52.H>
#include "Delay.h"

unsigned char Nixietable[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void Nixie(unsigned char Location,Number)
{
	switch(Location)
	{
		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;
}
//Nixie.h文件部分:
#ifndef __NIXIE__
#define __NIXIE__

void Nixie(unsigned char Location,Number);

#endif

//main.c文件部分:
#include <REGX52.H>
#include "Delay.h"
#include "Nixie.h"
void main()
{
	while(1)
	{
		 Nixie(1,1);		
		 Nixie(2,2);		
		 Nixie(3,3);
	}
}

4.2调用各种函数来测试LCD部分

测试所用到的所有函数均来源于江科大自协老师.
LCD.c具体内容如下:

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}


LCD.h文件内容如下:

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif


五、定时器和中断

定时器简介

STC89C52中一共有T0,T1,T2三个定时器,定时器是单片机内部自带的资源,不是板子上的外设。

每一个定时器都有四种工作模式,常用的是模式1(用作普通定时器)和模式2(用于串口中)

在这里插入图片描述
定时器的工作原理如下:
在这里插入图片描述

这里的时钟就是单片机上所带的晶振,此型号板子上的晶振是12MHZ,也就是它的计数频率为12MHZ,它走一次相当于过了1/12M秒。


模式1介绍

这里以定时器0为样例
在这里插入图片描述

先看左上角,这一部分就是时钟模块,SYSclk就是系统时钟,也就是晶振,本系统板是12MHZ;在之后经过分频,走上就是12分频,最后得到的就是1MHZ,计数单元就是1/1M=1us。然后就是C/T,这里的意思是说,给0就是T一横有效,就是执行Timer时钟的功能;给1就是C有效,就是执行Counter计数器的功能,计数器是通过外部输入来计数的,很少用到。

之后是中间部分,中间下面的部分是执行Counter计数器时才会用到,后面TL0和TH0就是16位定时器,它们最高可以记到65535 ‘秒’(这里的秒实际上是1us).

最后,当定时器溢出后,它的存储单元TH0和TL0就会置零,同时标志位TF0置1,表示满足进入中断的条件,中断电路还请往下看。

中断介绍

STC89C52中一共有8个中断源,分别是:外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3。

中断源优先级一共有4个。

在这里插入图片描述

在这里插入图片描述

定时器初始化

这里以初始化Timer0为例子

void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值,要记得设置初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

六、串口通信

简介

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通信。
不严谨的说UART就是串口。

下面这些术语及含义已经非常熟悉了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值