51单片机学习总结

本文概述了C语言在51单片机中的应用,包括不同数据类型(如int和char)、特殊功能寄存器(SFRs)、位运算、指针、函数、中断处理(特别是中断函数的中断方式和51单片机的组成)以及LED、GPIO、数码管和矩阵键盘的使用。还介绍了定时器中断的基本概念和单片机的时钟管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于C语言的前置知识总结

变量类型

int有别于一般c语言,占两个字节,16位,char占1字节8位

C51扩充数据类型

45efc3c174194b8e8253d39c80ad0c55.png

sfr sbit

用于定义特殊功能寄存器或特殊位。

位运算:

952febf0300b44d49c361792bf4da3a3.png

指针与地址运算符:

025a10f2b5f343f6998f9d7f782022ed.png

函数:

中断函数
在函数形参括号后加修饰符 interrupt m,系统编译时把对应函数转化为中断函数,自动加上程序头段和尾段,并按 51 系 统中断的处理方式自动把它安排在程序存储器中的相应位置。

在该修饰符中,m 的取值为 0~31,对应的中断情况如下:

0——外部中断 0

1——定时/计数器 T0

2——外部中断 1

3——定时/计数器 T1

4——串行口中断

5——定时/计数器 T2

其它值预留。

外部函数
如果要调用的函数不在本文件内,在其他文件内,定义函数时函数开头要加 extern 修饰符。

51单片机的最小组成系统

  • 晶振电路,提供时钟,相当于心脏
  • 复位电路,系统运行不正常时可以重启
  • 电源电路,注意单片机的供电电压要求
  • 下载电路,烧入程序

LED

GPIO(general purpose input output) 即通用输入输出端口,可以通过软件控制其输入和输出.

8639ec02c63f46529152b2327189ee02.png

51单片机默认IO口为高电平,因此在点亮LED灯时只需要将对于的IO口拉为低电平即可以实现电路导通进而实现LED灯点亮。

代码如下:

#include <STC89C5xRC.H>

void main()
{
	P2=0xFE;//11111110
	while(1)
	{
		
	}

}

关于LED闪烁,需要在一定的时间间隔内对指定LED灯的IO口进行反复置高和置低,与LED点亮相比多了一个delay延时函数,delay函数是通过让cup进行空循环而使单片机暂时停在delay函数这块,起到延时的目的,配合IO的置高和制低达到让LED灯闪烁的目的。

delay 500ms为例代码如下:

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

    主函数执行以下代码即可达到目的

        P2=0xFE;
        Delay500ms();
        P2=0xFF;
        Delay500ms();

LED流水灯可采用多个delay的效果,多次赋值为P2寄存器赋值的方法,也可以采用以下方法

    

P2=0x01;	//对P2赋值
		for(i=0;i<8;i++)
		{
			P2=~(P2<<i)  //先移动1的位置再取反等效移动0的位置,继而等效移动灯的位置
			Delay500ms()
		}
			

数码管

f88549e26ecd4144aa42b5bd2e62b7ee.png

e13806d88c6e48adaced86c3e78922db.png

e53f2bd99dc346ab937c3622da3b785a.png

每个数码管都有 abcdefg 七个段
            分为共阴极和共阳极两种,我所使用的STC89C52RC采用的是共阴极数码管,所以我们选中哪一个数码管阴极赋0,就会启动哪一个数码管,传入的 abcdefg 就会点亮该数码管的对应段。

faf156a60f7f41088856628514420982.png

P00~P07 代表控制当前数码管的 a~g 显示形式,接到 74HC245 缓冲器上而不是直接接到数码管上,使得单片机不用直接驱动数码管,Ai 连到 Bi 上。

OE 是使能,接地工作不接地不工作的原理。

DIR 是规定方向,高电平从左边读取数据传输到右边。低电平从右边读数据到左边。开发板上有个 J21 跳线帽,可以调整是 GND 与 LE 相连还是 VCC 与 LE 相连,也就是高电平输入 DIR 还是低电平输入 DIR。

数码管上面的 COM 是公共端,选中哪一个公共端(使得其=0,因为是共阴极)就是调整哪一个数码管的点亮方式。
代码如下:

#include <STC89C25xRC.H>



//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

//延时子函数
void Delay(unsigned int xms)
{
	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;				//段码清0,消影
}

void main()
{
	while(1)
	{
		Nixie(1,1);		//在数码管的第1位置显示1
//		Delay(20);
		Nixie(2,2);		//在数码管的第2位置显示2
//		Delay(20);
		Nixie(3,3);		//在数码管的第3位置显示3
//		Delay(20);
	}
}

矩阵键盘

为了减少IO口的占用,采用四个IO口代表行,4个IO口代表列的方式

主要存在两种扫描方法:

​ 按行扫描:通过设置 P17 16 15 14 中的一个为低电平来选择扫描哪一行。根据 P10 P11 P12 P13 的输入判断是哪一列。但是 P15 口是蜂鸣器,不断反转会响。所以最好还是用按列扫描

​ 按行扫描:通过设置 P17 16 15 14 中的一个为低电平来选择扫描哪一行。根据 P10 P11 P12 P13 的输入判断是哪一列。但是 P15 口是蜂鸣器,不断反转会响。所以最好还是用按列扫描

相关代码:

#include <STC89C52xRC.H>
#include "Delay.h"

/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
			如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
	P1_2=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
	P1_1=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
	
	P1=0xFF;
	P1_0=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
	
	return KeyNumber;
}


        

定时器中断

中断

使单片机能对外部或者内部随机发生的事件实时处理。

分时操作,实时响应,可靠性高。

中断相应条件:首先我们要确保相关配置都准备好了,CPU 允许中断,中断源允许中断,然后发生中断事件时才会正确触发中断。

中断可能还会被优先级更高的中断打断,支持这种操作的系统叫多级中断系统。

STC89C52 有8个中断,4外部,3定时器,1串口。

定时器中断结构如下:

EA ENABLE ALL:即使能所有中断。

ET:中断允许位。

PT:中断优先级。只有一个 PT 只能决定是高或低两种优先级。更多的中断优先级寄存器可以决定更多中断优先级。

TCON 部分: time controller,不属于 CPU 部分,等到定时器部分展开叙述。

EA=1;//总中断开关:打开
EX0=1;//外部中断0开关:打开。
IT0=0/1;//外部中断触发方式的选择。如下降沿触发,或低电平触发。
//如果要配置外部中断1,则改为EX1和IT1

定时器

CPU时序的相关知识

振荡周期:为单片机提供信号的振荡源的周期(晶振周期)。12MHZ 的晶振振荡周期就是1/12us, 求倒数。

状态周期:两个振荡周期=1状态周期s(时钟周期)。

机器周期:6状态周期=1机器周期。

指令周期:完成一条指令所用的全部时间,以机器周期为单位。
 

左上角支路是时钟功能,左下角支路是计数功能,最终实现中断功能。

TH TL 寄存器最大能存储到65535.每来一次脉冲+1,加到最大值时 flag 申请中断。

SYSCLK 是晶振周期。另一个时钟是 T0 引脚,如果启用 T0 引脚定时器就变成计数器了,每来一个脉冲+1。

默认使用12T 的分频,把 12MHZ 分成12份,每一份就是1us。这个单片机上是没有对应调整的寄存器的,如果想使用 6T 的分频需要在 STC-ISP 中选择使能 6T 模式。

CT 是一位寄存器,赋1为C,即计数器;赋0为T,即时钟(T上面的横线就代表0时)。

每个定时器主要有两种寄存器:TCON TMOD。

TCON 包括:TF, TR, IE, IT。

​ TF 可见上图主路,TH TL 被允许计数后周期性+1计数,加到最大值时 TF=1,并发起中断。处理完中断后恢复为0.

​ TR 可见上图支路,是开启中断的条件之一。

​ IE 是外部中断。

​ IT 是设置中断触发模式,比如设置为0是低电平触发,设置为1是下降沿触发。

TMOD 是不可寻址的寄存器,也就是只能整体赋值,不能像 P2 一样分开给每个变量赋值。包含:GATE, CT, M0, M1.

再上图中gate用于开启定时器,TR=1且INT1/INT0 为高(即打开中断引脚)时定时器开始工作。这一部分内容对应上图电路中的左下角。

M0M1用于选择定时时钟的模式。

#include <XTC89C52xRC.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;			//设置定时初值
	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;
		
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值