51单片(更新中)

51单片机

第一章:C51单片机最小系统

1.1 单片机内部硬件结构

AT89C51

在这里插入图片描述

1.2 硬件参数

AT89C51AT89C52
8位微处理器(CPU:运算器,控制器)8位微处理器(CPU:运算器,控制器)
数据存储器(128B RAM)数据存储器(512B RAM)
程序存储器(4KB Flash ROM)程序存储器(8KB Flash ROM)
4个8位可编程并行I/O口(P0、P1、P2和P3)4个8位可编程并行I/O口(P0、P1、P2和P3)
1个全双工异步串行口1个全双工异步串行口
2个可编程的16位定时器/计数器(T0、T1)3个可编程的16位定时器/计数器(T0、T1、T2)
中断系统具有5个中断源、5个中断向量中断系统具有8个中断源、8个中断向量

直插型芯片实物图:在这里插入图片描述

贴片型芯片实物图: 在这里插入图片描述

常见的其他型号:在这里插入图片描述

不同型号的51单片机有不同的资源,后面涉及的资源全部以经典型号AT89C51为准

1.3 单片机各引脚引脚功能

在这里插入图片描述

P0口:P0.0-P0.7引脚

为漏极开路的8位并行I/O口。作为输出口时,每个引脚可驱动8个LS型TTL负载。AT89C52扩展外部存储器及I/O脚芯片时,P0口为分时复用的低8位地址/数据总线。在向P0口写入"1"后就成为高阻态输入口。

当P0为通用I/O口使用时,需外加上拉电阻,这时为准双向口

P1口:P1.0-P1.7引脚

为准双向I/O口,引脚内部有上拉电阻。

P2口:P1.0-P1.7引脚

为准双向I/O口,引脚内部有上拉电阻。

当单片访问外部存储器时,P2作为高8位地址总线使用,输出高8位地址。

P3口:P1.0-P1.7引脚

P3口通用I/O口,内部有上拉电阻。它还具有第二种功能

引脚第二功能
P3.0PXD (串行口输入)
P3.1RTXD (串行口输出)
P3.2INT0 (外部中断0输入)
P3.3INT1 (外部中断1输入)
P3.4T0 (定时器/记数器0的外部输入)
P3.5T1 (定时器/记数器1的外部输入)
P3.6WR (片外数据存储器 “写选通控制” 输出)
P3.7RD (片外数据存储器 “读选通控制” 输出)

1.4 C51单片机最小系统

在这里插入图片描述

电源电路:供电:VCC为+5V电源,VSS接地
时钟电路:XTAL1、XTAL2:接晶振(常用频率:12MHZ、11.0592)和30pf的电容。
复位电路:RST:复位信号输入,在引脚加上持续时间大于2个机器周期的高电平,可使单片机复位。正常工作时,此引脚为低电平。
选择ROM:EA:片内片外程序存储器选择。当EA=1;选择片内程序存储器。EA=0;选择片外程序存储器。

1.5 C51单片机的时钟

时钟周期时钟控制信号的基本时间单位。若单片使用的晶振频率为Fosc,则时钟周期Tosc=1/Fosc。如fosc=12MH,Tosc=1/12us
状态周期每两个时钟周期为一个状态周期。即S=Tosc*2
机器周期CPU完成一个基本操作所需要时间为机器周期。每12个时钟周期为一个机器周期。晶振为12MHZ,则机器周期为 T=12 * 1/fosc =1us
指令周期执行条指令所需的时间。简单的字节指令,只需一个指令周期,而有些复杂的指令(如乘、除指令)需要两个或多个指令周期。

第二章:IO口控制应用

2.1 IO口控制

单片机IO口的状态总是0和1(高电平和低电平)

2.1.1 控制1位IO口

方法1:(推荐)

sbit 引脚名=端口寄存器^位置

/*引脚定义*/ sbit LED=P1^4   //定义P1并行口第5位引脚0名字为LED引脚 
/*输出高电平*/ LED=0;       //为此引脚置位为0
/*输出低电平*/ LED=1;      //为此引脚置位为1

方法2

P1 |=(1<<5) //为P1并行口第5为引脚置位为1 
P1 &=~(1<<5) //为P1并行口第5为引脚置位为0

2.1.2 引脚输入检测

if(LED==1) {执行代码}  //检测引脚是否输入高电平
if(LED==0) {执行代码}  //检测引脚是否输入高电平

2.1.3 延时函数

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

2.2 简易流水灯

各有千秋。

方法1 一位一位去控制

#include <reg51.h>

/***** 端口宏定义 *****/

/***** 引脚定义 *****/
sbit LED0=P1^0;
sbit LED1=P1^1;
sbit LED2=P1^2;
sbit LED3=P1^3;
sbit LED4=P1^4;
sbit LED5=P1^5;
sbit LED6=P1^6;
sbit LED7=P1^7;

/***** 函数声明 *****/
void delay_ms(unsigned int xms);

/***** 变量定义 *****/

/***** 主函数 *****/
void main()
{
	while(1)
	{
		LED0=0;
		delay_ms(200);
		LED0=1;
		delay_ms(200);
		LED1=0;
		delay_ms(200);
		LED1=1;
		delay_ms(200);
		LED2=0;
		delay_ms(200);
		LED2=1;
		delay_ms(200);
		LED3=0;
		delay_ms(200);
		LED3=1;
		delay_ms(200);
		LED4=0;
		delay_ms(200);
		LED4=1;
		delay_ms(200);
		LED5=0;
		delay_ms(200);
		LED5=1;
		delay_ms(200);
		LED6=0;
		delay_ms(200);
		LED6=1;
		delay_ms(200);
		LED7=0;
		delay_ms(200);
		LED7=1;
		delay_ms(200);
	}
}

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

方法2 数组的方式去控制

#include <reg51.h>

/***** 端口宏定义 *****/
#define LED P1

/***** 函数声明 *****/
void delay_ms(unsigned int xms);

/***** 变量定义 *****/ 
char ledDat[8] ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned char i = 0;

/***** 主函数 *****/
void main()
{
	while(1)
	{
		for(i=0;i<8;i++)
		{
			LED=ledDat[i];
			delay_ms(200);
			LED=0xff;
			delay_ms(200);
		}
	}
}

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

方法3 位运算的方式去控制

#include <reg51.h>

/***** 端口宏定义 *****/
#define LED P1

/***** 函数声明 *****/
void delay_ms(unsigned int xms);

/***** 变量定义 *****/ 
unsigned char i = 0;

/***** 主函数 *****/
void main()
{
	while(1)
	{
		unsigned char t = 1;
		for(i=0;i<8;i++)
		{
			LED=~(t);
			delay_ms(200);
			LED=0xff;
			delay_ms(200);
			t=t<<1;
		}
	}
}

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

2.3 独立按键控制LED灯

按键按下后、led亮,按键再次按下,led灭。

#include <reg51.h>

/***** 端口宏定义 *****/

/***** 引脚定义 *****/
sbit KEY1=P2^0; //按键在P2.0引脚
sbit LED1=P1^0; //LED在P1.0引脚

/***** 函数声明 *****/
void delay_ms(unsigned int xms);

/***** 变量定义 *****/
unsigned char ledFlag = 0;

/***** 主函数 *****/
void main()
{
	while(1)
	{
		if(KEY1 == 0)
		{
			delay_ms(10); // 软件消抖
			if(KEY1 == 0) 
			{
				while(KEY1==0); // 等待按键释放
				ledFlag = !ledFlag;
			}
		}
		if(ledFlag)//ledFlag=1,led灯亮
		{
			LED1 = 0;
		} 
		else 
		{
			LED1=1;
		}
	}
}

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

2.4:数码管

2.4.1 单位数码管

八位共阳极数码管:逐渐显示0-f

#include <reg51.h>

/***** 端口宏定义 *****/
#define SEGCA P1

/***** 引脚定义 *****/

/***** 函数声明 *****/
void delay_ms(unsigned int xms);

/***** 变量定义 *****/
/*0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F*/
unsigned char segcaDat[16] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
unsigned char i=0;

/***** 主函数 *****/
void main()
{
	while(1)
	{
		for(i=0;i<16;i++)
		{
			SEGCA=segcaDat[i];
			delay_ms(200);
			SEGCA=0xff;
			delay_ms(200);
		}
	}
}

void delay_ms(unsigned int xms)
{
	unsigned char i,j;
	for(i=0;i<xms;i++)
		for(j=0;j<110;j++);
}

2.4.2多位数码管动态显示

四位共阳极PNP驱动数码管

头文件

#ifndef __SEG_H__
#define __SEG_H__

#include <reg51.h>

#define Duan_PORT P1 /*段码线端口宏定义*/

/***** 引脚的定义 *****/
sbit WEI1=P2^0; /*控制第一位数码管的引脚*/
sbit WEI2=P2^1; /*控制第二位数码管的引脚*/
sbit WEI3=P2^2; /*控制第三位数码管的引脚*/
sbit WEI4=P2^3; /*控制第四位数码管的引脚*/

/*显示四位整数         显示数据                 延时时间*/
void display_four(int displayNum, unsigned char delay_ms); 

/*显示四位小数         显示数据                  小数点位置                  延时时间*/
void display_float(int displayNum, unsigned char float_position,unsigned char delay_ms); 

/*独位显示整数         显示数据                  显示位置                  延时时间*/
void display_data(int displayNum, unsigned char display_position,unsigned char delay_ms); 

#endif


c文件

#include "seg.h"
#include "delay.h"

/***** 变量定义 *****/
unsigned char seg_dat[] = {0xC0,0xF9,0xA4,0xB0,0x99,
/*0,1,2,3,4,5,6,7,8,9,*/	0x92,0x82,0xF8,0x80,0x90};


void display_four(int displayNum,unsigned char delay_ms) /* 数码管显示四位整数 */
{
	WEI1=0;
	Duan_PORT=seg_dat[displayNum/1000%10];
	delay_xms(delay_ms);
	WEI1=1;
	Duan_PORT=0xff;
	
	WEI2=0;
	Duan_PORT=seg_dat[displayNum/100%10];
	delay_xms(delay_ms);
	WEI2=1;
	Duan_PORT=0xff;
	
	WEI3=0;
	Duan_PORT=seg_dat[displayNum/10%10]; 
	delay_xms(delay_ms);
	WEI3=1;
	Duan_PORT=0xff;
	
	WEI4=0;
	Duan_PORT=seg_dat[displayNum%10];
	delay_xms(delay_ms);
	WEI4=1;
	Duan_PORT=0xff;
}

void display_float(int displayNum, unsigned char float_position,unsigned char delay_ms) 
{
	WEI1=0;
	if(float_position == 1) {Duan_PORT=seg_dat[displayNum/1000]&0x7f;} 
	else {Duan_PORT=seg_dat[displayNum/1000];}
	delay_xms(delay_ms);
	WEI1=1;
	Duan_PORT=0xff;
	
	WEI2=0;
	if(float_position == 2) {Duan_PORT=seg_dat[displayNum/100%10]&0x7f;}
	else {Duan_PORT=seg_dat[displayNum/100%10];}
	delay_xms(delay_ms);
	WEI2=1;
	Duan_PORT=0xff;
	
	WEI3=0;
	if(float_position == 3) {Duan_PORT=seg_dat[displayNum/10%10]&0x7f;}
	else {Duan_PORT=seg_dat[displayNum/10%10]; }
	delay_xms(delay_ms);
	WEI3=1;
	Duan_PORT=0xff;
	
	WEI4=0;
	Duan_PORT=seg_dat[displayNum%10];
	delay_xms(delay_ms);
	WEI4=1;
	Duan_PORT=0xff;
	
}

void display_data(int displayNum, unsigned char display_position,unsigned char delay_ms)
{
	if(display_position == 1) 
	{
		WEI1=0;
		Duan_PORT=seg_dat[displayNum];
		delay_xms(delay_ms);
		WEI1=1;
	} else if(display_position == 2) {
		WEI2=0;
		Duan_PORT=seg_dat[displayNum];
		delay_xms(delay_ms);
		WEI2=1;
	}else if(display_position == 3) {
		WEI3=0;
		Duan_PORT=seg_dat[displayNum];
		delay_xms(delay_ms);
		WEI3=1;
	} else if(display_position == 4) {
		WEI4=0;
		Duan_PORT=seg_dat[displayNum];
		delay_xms(delay_ms);
		WEI4=1;
	}
	Duan_PORT=0xff;
	
}

2.5:LCD1602液晶屏

h文件

#ifndef __LCD1602_H__
#define __LCD1602_H__
#include <reg51.h>

/***** 端口宏定义 *****/
#define LCD_PORT P0

/***** 引脚定义 *****/
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;

/***** 函数声明 *****/

/********** 底层驱动函数 **********/
void init_1602();                   /* 初始化函数 */
void write_cmd(unsigned char dat);  /* 写命令 */
void read_cmd(unsigned char dat);   /* 读命令 */
void write_dat(unsigned char dat);  /* 写数据 */
void read_dat(unsigned char dat);   /* 读命令 */

/********** 基本应用函数 **********/
// 显示单个字符			显示数据               行位置(0-1)        列位置(0-15)
void display_char(unsigned char dat, unsigned char row, unsigned char column);
// 显示字符串				显示数据(长度:1-16)  行位置(0-1)       列位置(0-15)
void display_string(unsigned char *p_str, unsigned char row, unsigned char column);
// 显示两位整数     显示数据(0-99)       行位置(0-1)       列位置(0-15)
void display_2Digit(unsigned int digit, unsigned char row,unsigned char column);

/********** 用户函数 **********/
// 双行滚动显示字符串       显示数据       行位置(0-1)         列位置(0-1)       间隔时间(ms)
void roll_string(unsigned char *p_str, unsigned char row, unsigned char column, unsigned int spt_ms);

#endif



c文件

#include "lcd1602.h"

void lcd_delay_ms(unsigned int xms)
{
	unsigned int i,j;
	for(i=0;i<xms;i++) 
	{
		for(j=0;j<110;j++);
	}
}

void init_1602()
{
	write_cmd(0x38); /* 16*2显示,5*7点阵,8位数据接口 */
	write_cmd(0x08); /* 显示关闭*/
	write_cmd(0x01); /* 清屏 */
	write_cmd(0x06); /* 文字不动,地址自动+1 */
	write_cmd(0x0c); /* 显示器开,光标关闭 */
	//write_cmd(0x0f); /* 显示器开,光标显示 闪烁 */
}

void write_cmd(unsigned char dat)
{
	RS=0;
	RW=0;
	LCD_PORT = dat;
	E=0;
	lcd_delay_ms(1);//延时
	E=1;
	lcd_delay_ms(1);//延时
	E=0;
}

void read_cmd(unsigned char dat)
{
	RS=0;
	RW=1;
	LCD_PORT=dat;
	E=0;
	lcd_delay_ms(1);//延时
	E=1;
	lcd_delay_ms(1);//延时
	E=0;
}

void write_dat(unsigned char dat)
{
	RS=1;
	RW=0;
	LCD_PORT = dat;
	E=0;
	lcd_delay_ms(1);//延时
	E=1;
	lcd_delay_ms(1);//延时
	E=0;
}

void read_dat(unsigned char dat)
{
	RS=1;
	RW=1;
	LCD_PORT=dat;
	E=0;
	lcd_delay_ms(1);//延时
	E=1;
	lcd_delay_ms(1);//延时
	E=0;
}

void display_char(unsigned char dat, unsigned char row, unsigned char column)
{
	if(row ==0)write_cmd(0x80+column);
	else if(row ==1)write_cmd(0xc0+column);
	write_dat(dat);
}

void display_string(unsigned char *p_str, unsigned char row, unsigned char column)
{
	unsigned char temp_cmd = 0x00;
	
	if(row ==0) temp_cmd = 0x80;
	else if(row ==1) temp_cmd =0xc0;
	while(*p_str!='\0')
	{
		write_cmd(temp_cmd+(column++));
		write_dat((*p_str++));
	}
}

void roll_string(unsigned char *p_str, unsigned char row, unsigned char column, unsigned int spt_ms)
{
	unsigned char temp_cmd = 0x00;
	
	//write_cmd(0x0f); //显示器开,光标显示 闪烁
	if(row ==0) temp_cmd = 0x80;
	else if(row ==1) temp_cmd =0xc0;
	while(*p_str!='\0')
	{
		write_cmd(temp_cmd+(column++));
		write_dat((*p_str++));
		
		if(column>=16 && temp_cmd == 0x80) 
		{
			column=0;
			temp_cmd = 0xc0;
			lcd_delay_ms(spt_ms); //滚动的延时 
			display_string("                ",1,0);
		}
		else if (column>=16 && temp_cmd == 0xc0) 
		{
			column=0;
			temp_cmd=0x80;
			lcd_delay_ms(spt_ms); //滚动的延时 
			display_string("                ",0,0);
		}
	}
	lcd_delay_ms(spt_ms); //滚动的延时 
	write_cmd(0x01);/*清屏*/
	write_cmd(0x0c); //显示器开,光标关闭
}

void display_2Digit(unsigned int digit,unsigned char row,unsigned char column)
{
	display_char((digit/10%10)+0x30,row,column);
	display_char((digit%10)+0x30,row,column+1);
}


2.6:矩阵键盘

h文件

#ifndef __MATRIX4X4_H__
#define __MATRIX4X4_H__
#include <reg51.h>

/***** 端口宏定义 *****/
#define KEY_PORT P2

/***** 函数声明 *****/
//键盘哪个按键被按下返回按键 【序号(1-16)】,没有按键按下返回0
unsigned char key_scan(); 
//读键盘功能 重新定义按键返回值 没有按键按下,返回255
unsigned char read_key();

#endif



c文件

#include "matrix4X4.h"

void matrix_delay_ms(unsigned int xms)
{
	unsigned int i,j;
	for(i=0;i<xms;i++)
	{
		for(j=0;j<110;j++);
	}
}

unsigned char key_scan() 
{
	unsigned char temp=0,row=0,column=0,i=0;
	
	KEY_PORT = 0x0f;
	matrix_delay_ms(1);
	temp=KEY_PORT;
	if(temp!=0x0f)
	{
		switch (temp)
    {
    	case 0x0e: //0000 1110
				row=1; break;
    	case 0x0d: //0000 1101
				row=2; break;
        case 0x0b: //0000 1011
				row=3; break;
		case 0x07: //0000 0111
				row=4; break;
    	default:break;
    }
		KEY_PORT=0xf0;
		matrix_delay_ms(1);
		temp=KEY_PORT;
		if(temp!=0xf0)
		{
			switch (temp)
			{
				case 0xe0: //1110 0000 
					column=1; break;
				case 0xd0: //1101 0000
					column=2; break;
				case 0xb0: //1011 0000 
					column=3; break;
				case 0x70: //0111 0000 
					column=4; break;
				default:break;
			}
		}
		while(KEY_PORT!=0xf0 && i<255){matrix_delay_ms(1);i++;}
	}
	if(row!=0&&column!=0){ return ( (row-1)*4+column ) ;}
	else {return 0;}
}

unsigned char read_key()
{
	unsigned char temp=0,key_char=255;
	temp=key_scan();
	if(temp!=0)
	{
		switch(temp)
		{
			case 1:key_char=1;break;
			case 2:key_char=2;break;
			case 3:key_char=3;break;
			case 4:key_char='A';break;
			
			case 5:key_char=4;break;
			case 6:key_char=5;break;
			case 7:key_char=6;break;
			case 8:key_char='B';break;
			
			case 9:key_char=7;break;
			case 10:key_char=8;break;
			case 11:key_char=9;break;
			case 12:key_char='C';break;

			case 13:key_char='R';break;
			case 14:key_char=0;break;
			case 15:key_char='Y';break;
			case 16:key_char='D';break;
		}
	}
	else
	{
		key_char=255;
	}
	return key_char;
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值