单片机 | 51单片机实践【基础篇】

【金善愚】 单片机应用实践——基础篇 笔记整理
课程视频 :https://space.bilibili.com/483942191/channel/collectiondetail?sid=144001

仿真软件:Proteus 8.13
安装链接:https://pan.baidu.com/s/1-1fscykdvulV60xA4Hygaw?pwd=xeob

代码软件:Keil μvision V5.14.2
安装链接:https://pan.baidu.com/s/1MRdG2EkxORr6M6XH-n5ang?pwd=l2rm


一、点亮LED 灯

1.仿真原理图

  内容

电阻 RES
电容 CAP
晶振 crystal
按键 button

2.代码


//包含单片机的头文件,建立软件和硬件的联系
#include<reg51.h>

//sbit LED0 = P1^0;  //位操作,取P1的0位命名为LED
//sbit LED1 = P1^1; 
//sbit LED2 = P1^2; 
//sbit LED3 = P1^3; 

void main()
{
   
	while(1) //保持循环执行
	{
   
		P1 = 0xF0; //P1.7 - P1.0 赋值 1111_0000
		//LED0 = 0;
		//LED1 = 0;
		//LED2 = 0;
		//LED3 = 0;  //P1其他位默认为1
	}
}

2.软硬件关联

(1)生成HEX文件

a.点击图示的快捷图标
在这里插入图片描述

b.生成
在这里插入图片描述

c.编译
在这里插入图片描述

d.文件位置
在这里插入图片描述

(2)仿真中关联代码

a.双击单片机,找到HEX文件位置,关联代码
在这里插入图片描述

(3)开始仿真
在这里插入图片描述

在这里插入图片描述

二、LED 闪烁

1.基本数据类型

在这里插入图片描述

2.代码

(1)用循环语句方式

#include<reg5l.h>

void main ( )
{
   
	unsigned int i;//无符号整形0~65535
	
	while (1)
	{
   
		i =20000;
		P1 = 0xFO;//1111 0000
		while ( i--)
		{
   
		}
		
		i = 20000;
		P1 = 0x0F;//0000 1111
		while ( i--);
		//for(i = 0 ; i<50000;i++) //用for语句
	}
}

(2)用延时函数方式


#include<reg51.h>

void delay();//声明函数

void main()
{
   
	while(1) 
	{
   
		P1 = 0xf0;
		delay();
		P1 = 0x0f;
		delay();	
	}
}

void delay()
{
   
	unsigned int ms = 500000;
	while(ms--)
	{
   		
	}
	
}

(3)用带参数的延时函数

/****************************************
功  能:带有参数的延时函数实现小灯的闪烁
时  间:****/**/**
****************************************/

#include<reg51.h>

//声明引脚
sbit LED = P1^7;

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

/****************************************
函数名: main
功  能: 主函数
参  数: 无
返回值: 无
****************************************/
void main()
{
   
	while(1) 
	{
   
		LED = 0;
		DelayXms(1000);//调用函数
		LED = 1;
		DelayXms(1000);	
	}
}

/****************************************
函数名: DelayXms
功  能: 延时函数
参  数: unsigned int
返回值: 无
****************************************/
void DelayXms(unsigned int xms)
{
   
	unsigned int i,j; // 0 -65535 0000H - FFFFH
	
	for(i = xms;i>0;i--)
	{
   
		for(j = 124;j>0;j--)
		{
   
			
		}
	}
}

2.调试

(1)设置

晶振和仿真
在这里插入图片描述
在这里插入图片描述

(2)进入调试模式
在这里插入图片描述

(3)时间等状态
在这里插入图片描述

(4)分步调试
在这里插入图片描述
①运行到鼠标所在位置
②单步运行
③进入函数
④运行全部(直至断点)
⑤设置断点

二、LED 流水灯

1.用简单顺序语句的方法实现

#include<reg51.h>
 
void DelayXms(unsigned int xms); //函数声明,或者将延迟函数放在main()函数前面,否则会报错

void main()
{
   
	while(1) 
	{
   
		P1 = 0xfe; //1111 1110
		DelayXms(1000); //调用函数
		P1 = 0xfd; //1111 1101
		DelayXms(1000);	
		P1 = 0xfb; //1111 1011
		DelayXms(1000);
		P1 = 0xf7; //1111 0111
		DelayXms(1000);
		P1 = 0xef; //1110 1111
		DelayXms(1000);
		P1 = 0xdf; //1101 1111
		DelayXms(1000);
		P1 = 0xbf; //1011 1111
		DelayXms(1000);
		P1 = 0x7f; //0111 1111
		DelayXms(1000);
	}
}

//延时函数
void DelayXms(unsigned int xms)
{
   
	unsigned int i,j; // 0 -65535 0000H - FFFFH
	
	for(i = xms;i>0;i--)
		for(j = 124;j>0;j--);
}

2.用数组的方法实现(多文件)

1.创建工程目录下新建4个文件夹,并修改设置下的存放路径

Listings  放中间文件
Output   放输出HEX等文件
Project   放工程文件
Source  放 .c、 .h文件

在这里插入图片描述

2.创建模块的 .c文件并创建其对应的.h文件

  • .c文件负责函数的定义及变量的定义
  • .h文件负责函数的声明及变量的声明(不允许赋初值)以及常量和I/O口的宏定义

(1) delay.c

#include"delay.h" //""头文件会在当前目录下查找。< >头文件一般是系统头文件,会在安装目录下寻找

/*************************************
函数名:DelayXms
功  能:毫秒级延时函数
参  数: unsigned int(1 - 65535)
返回值:无
***********************************/

void DelayXms(unsigned int xms)
{
   
	unsigned int i,j; // 0 -65535 0000H - FFFFH
	
	for(i = xms;i>0;i--)
		for(j = 124;j>0;j--);
}


(2) delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void DelayXms(unsigned int xms); //声明加分号

#endif

2.创建main函数的 .c文件,可直接引用模块头文件使用

main.c

#include<reg51.h> 
#include"delay.h"

unsigned char code LEDBUF[] = {
   0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; 
//创建数组,常量可存放在ROM中,添加关键词code。变量可存放在RAM中
	
void main()
{
   
	unsigned char cnt;//unsigned char 类型范围是0 -255
	while(1) 
	{
   
		for (cnt = 0; cnt<8;cnt++)
		{
   
			P1 = LEDBUF[cnt];
			DelayXms(1000);
		}
	}
}


3.用库函数的方法实现

1._crol_函数

_crol_函数功能:将 c 进行b位左位移,并将值以unsigned char类型返回

//文档定义
#include <intrins.h>

unsigned char _crol_ (
unsigned char c,        /* character to rotate left */
unsigned char b);       /* bit positions to rotate */

函数返回类型为unsigned char,函数的两个形参也是unsigned char类型。
c 为要被进行 位左移 的形式参数
b 为要进行的 位移数

注释:向左循环移位时,从左边出去会从右边重新补入

2._cror_函数

与_crol_函数类似,区别只是进行的是右位移

注释:向右循环移位时,从右边出去会从左边重新补入

3.main.c 代码

#include<reg51.h> 
#include <intrins.h>
#include"delay.h"

void main()
{
   
	unsigned char temp = 0xfe; //1111 1110
	while(1)
	{
   
		P1 = temp;
		temp = _crol_(temp,1);
		DelayXms(1000);
	}
}

4.用移位运算符的方法实现

1.位运算符 及 位表达式

在这里插入图片描述⚠️注意:位表达式c<<1的值是0011 1100B,而c的值并未改变,仍是1001 1110B。移出补0。

2.代码

(1)main.c 用移位+补位方法

#include<reg51.h> 
#include <intrins.h>
#include"delay.h"

void main()
{
   
	unsigned char temp = 0xfe; //1111 1110
	while(1)
	{
   
		P1 = temp;			// 输出
		DelayXms(1000);		// 延时
		
		if (temp & 0x80)	// 判断temp最高位是否为1
		{
   
			temp = temp<<1;	// 左移
			temp = temp|1; 	// 如果左移之前temp最高位为1,则在temp的最低位补1
		}
		else
		{
   
			temp<<=1;		// 左移
		}
	}
}

(2)main.c 用反向方法

#include<reg51.h> 
#include <intrins.h>
#include"delay.h"

void main()
{
   
	unsigned char temp = 0x1; //0000 0001
	unsigned char i;
	
	while(1)
	{
   
		P1 = ~(temp<<i++);			
		DelayXms(1000);		
		
		if (8 == i)	i=0;	
	}
}

三、蜂鸣器

1.蜂鸣器工作电路

在这里插入图片描述
图中 D4为 续流二极管:
一种配合电感性负载使用的二极管,当电感性负载的电流有突然的变化或减少时,电感二端会产生突变电压,可能会破坏其他元件。配合续流二极管时,其电流可以较平缓地变化,避免突波电压的发生。

2.仿真原理图

在这里插入图片描述

3.代码

#include<reg51.h> 

#include"delay.h"

sbit Sound = P3^7;
void main()
{
   
	unsigned int i;
	while(1)
	{
   
		for(i = 0;i<100;i++)
		{
   
			Sound = ~Sound;
			DelayXms(1);
		}
		for(i = 0;i<100;i++)
		{
   
			Sound = ~Sound;
			DelayXms(5);
		}
	}
}

四、数码管

1.静态显示

(1)仿真原理图
在这里插入图片描述

数码管seg
CC-共阴
CA-共阳

(2)代码

#include<reg51.h> 

void main()
{
   	
	while(1)
	{
   
		P2 = 0xc0;
	}
}

2.动态显示

(1)仿真原理图
在这里插入图片描述

(2)代码

#include<reg51.h> 
#include"delay.h" 

void DelayXms();

unsigned char code leddata[] = {
   	//数码管的段码表
														0x3F,	//0
														0x06,	//1
														0x5B,	//2
														0x4F,	//3
														0x66,	//4
														0x6D,	//5
														0x7D,	//6
														0x07,	//7
														0x7F,	//8
														0x6F	//9
	};


unsigned char LEDBuf[] = {
   0,3,0,5};//数据缓存区

void main()
{
   	
	while(1)
	{
   
		P2 = 0xfe;//1111 1110 第一个数码管的位选打开,其他的关掉,打开第一个
		P0 = leddata[LEDBuf[0]];
		DelayXms(10);
		
		P2 = 0xfd;//1111 1101 第一个数码管的位选关掉,同时打开第二个数码管的位选
		P0 = leddata[LEDBuf[1]];
		DelayXms(10);
		
		P2 = 0xfb;//1111 1011 第二个数码管的位选关掉,同时打开第三个数码管的位选
		P0 = leddata[LEDBuf[2]];
		DelayXms(10);
		
		P2 = 0xf7;//1111 0111 第三个数码管的位选关掉,同时打开第四个数码管的位选
		P0 = leddata[LEDBuf[3]];
		DelayXms(10);
		
	}
}

(3)模块化

display.h

#ifndef __DISPLAY_H__
#define __DISPLAY_H__

#include <reg51.h> 
#include "delay.h"

//宏定义
#define GPIO_DIG	P0			//段码IO
#define GPIO_PLACE	P2			//位选IO
#define N			4			//数码管的个数


//变量声明
unsigned char code leddata[];
extern unsigned char LEDBuf[];	//定义成外部变量

//函数声明
void Display(); 								

#endif

display.c (if语句实现)

#include "display.h"  
#include "delay.h"


unsigned char LEDBuf[] = {
   0,6,2,3};//数据缓存区
unsigned char code PLACE_CODE[] = {
   0xfe,0xfd,0xfb,0xf7};//数码管位选信号


//数码管的段码表
unsigned char code leddata[] = {
   	
														0x3F,	//0
														0x06,	//1
														0x5B,	//2
														0x4F,	//3
														0x66,	//4
														0x6D,	//5
														0x7D,	//6
														0x07,	//7
														0x7F,	//8
														0x6F,	//9
	
														0x77,	//A 10
														0x7C,	//B 11
														0x39,	//C 12
														0x5E,	//D 13
														0x79,	//E 14
														0x71,	//F 15
	
														0x76,	//H 16
														0x38,	//L 17
														0x37,	//N 18
														0x3E,	//U 19
														0x73,	//P 20
														0x5C,	//O 21
														0x40,	//- 22
														
														0x00,	//熄灭 23
	};



void Display()
{
   
	//static unsigned char i = 0;	//静态变量,只在第一次初始化有效
	unsigned char i;
	
	//1.送位选
	GPIO_PLACE = PLACE_CODE[i];	
	//2.送段码
	GPIO_DIG = leddata[LEDBuf[i]];	
	//3.延时 1ms <10ms 
	DelayXms(10);	
	//4.消隐
	GPIO_DIG = 0x00;
	
	i++;
	if (N == i)
		i = 0;
}

display.c (switch case 语句实现)

void Display()
{
   
	//static unsigned char i = 0;	//静态变量,只在第一次初始化有效
	unsigned char i;
	
	//1.送位选		
	//2.送段码	
	//3.延时 1ms <10ms 
	//4.消隐
	switch(i)
	{
   
		case 0: 
				GPIO_PLACE = leddata[LEDBuf[0]];	
				GPIO_PLACE = PLACE_CODE[0];	
				DelayXms(10);
				GPIO_DIG = 0x00;
				i++;
				break;
		case 1: 
				GPIO_PLACE = leddata[LEDBuf[1]];	
				GPIO_PLACE = PLACE_CODE[1];	
				DelayXms(10);
				GPIO_DIG = 0x00;
				i++;
				break;
		case 2: 
				GPIO_PLACE = leddata[LEDBuf[2]];	
				GPIO_PLACE = PLACE_CODE[2];	
				DelayXms(10);
				GPIO_DIG = 0x00;
				i++;
				break;		
		case 3: 
				GPIO_PLACE = leddata[LEDBuf[3]];	
				GPIO_PLACE = PLACE_CODE[3];	
				DelayXms(10);
				GPIO_DIG = 0x00;
				i = 0;
				break;		
		default:break;
	}	

}

main.c

#include <reg51.h> 
#include "display.h"  
#include "delay.h"


void main()
{
   	
	while(1)
	{
   
		Display();
	}
}

3.应用层程序开发

项目1:数码管开机初始显示 - - - -,正常运行时显示4567

main.c

#include <reg51.h> 
#include "display.h"  
#include "delay.h"


void main()
{
   	
	unsigned int i;
	
	for(i = 0;i<500;i++)
	{
   
		Display();
	}
	
	while(1)
	{
   
		LEDBuf[0] = 4; //调用前修改底层参数值
		LEDBuf[1] = 5;
		LEDBuf[2] = 6;
		LEDBuf[3] = 7;
		Display();
	}
}


项目2:显示任意4位十进制数

main.c

#include <reg51.h> 
#include "display.h"  
#include "delay.h"


void main()
{
   	
	unsigned int i;   //0 - 65535
	unsigned int num = 1995; //十进制数
		
	for(i = 0;i<500;i++)
	{
   
		Display();
	}
	
	while(1)
	{
   
		LEDBuf[0] = num/1000;   
		LEDBuf[1] = num/100%10;
		LEDBuf[2] = num/10%10;
		LEDBuf[3] = num%10;
		Display();
	}
}


项目3:逐渐加1

#include <reg51.h> 
#include "display.h"  
#include "delay.h"


void main()
{
   	
	unsigned int i;   //0 - 65535
	unsigned int num = 1995; //十进制数
		
	for(i = 0;i<500;i++)
	{
   
		Display();
	}
	
	while(1)
	{
   
		LEDBuf[0] = num/1000;   
		LEDBuf[1] = num/100%10;
		LEDBuf[2] = num/10%10;
		LEDBuf[3] = num%10;
		for(i = 0;i<50;i++) //延时
		{
   
			Display();
		}
		
		num++;
		if (num >2000)
			num = 1994;
		
	}
}


项目4:
1、开机时显示闪烁的8888
2、正常工作时,需要分时显示2个参数,大概每隔2S切换显示一个参数
3、 参数1的范围是0-3
  参数2的范围是0-99
  中间用 - 隔开
  在这里插入图片描述

main.c

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值