初识C51单片机(STC89C52RC开发板)

一、学会创建新工程

(安装Keil 5 教程自行寻找)

选择好保存目录,取好名字

点击Add后即可开始编写第一个程序

二、点亮第一个LED灯

为什么不是高电平?看原理图

因此引脚设置为低电平,才能形成电势差,存在电压才能点亮led

下面讲一下怎么把程序刷入开发板:

首先,用keil5将代码编译成hex文件。

注意:如果在项目目录下的各个文件夹内都没生成hex文件,请看下面的操作步骤

点击ok即可,然后重新编译

再讲解一下将hex文件刷入开发板的方法:

1、使用PZ-ISP软件(打开板子电源开关即可自动下载)

2、使用STC-ISP(官方软件,推荐)需要冷启动

冷启动:板子在掉电状态下点击下载,打开电源后开始下载

三、LED闪烁实验

很简单,点亮,然后循环延时一会再熄灭,重复这个操作就是闪烁了

四、LED流水灯实验

五、蜂鸣器实验

蜂鸣器持续发声,即给蜂鸣器一个脉冲信号,使其不断开关,来持续稳定发声。它不是给一个高电平信号就可以持续响的!

六、数码管(静态/动态)

段码数据计算:

数码管原理图上,让哪根线亮,哪根就是1,按下面的顺序排列,转换成16进制即可,比如

dp g f e d c b a

0 1 1 1 1 1 1 1 -> 0x7F 即亮一个8

所谓动态数码管,本质上是让数码管一位一位点亮,利用人眼的余晖效应,只有30Hz,用高频率刷新,看起来就像同时点亮,在使用上面的nixie()函数时,后面建议加一句P0=0x00;消音以避免会有残影

七、 独立按键实验

我将四个独立按键进行封装,作为函数,便于后续调用。

使用方法:在主函数while(1)里写上if(key() == 1/2/3/4){}即可判断1-4哪个按键被按下

八、 矩阵键盘实验

#include <REGX52.H>
#include "delay.h"

#define KEY_MATRIX_PORT	P1

/*******************************************************************************
* 函 数 名       : key_matrix_ranks_scan
* 函数功能		 : 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,
				   0:按键未按下
					 
					 ====实现原理====
					 
					 逐列扫描
					 
							    低八位
								————>       1、先拉低某一列
							高|			    2、再检测GPIO 1寄存器中的电平信号来判断某一行
							八|			    3、不断循环这个过程
							位|
							  V
*******************************************************************************/
int scankey()
{
	char key_value=0;

	KEY_MATRIX_PORT=0xf7;//给第一列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下
	{
		delay(10);//消抖
		switch(KEY_MATRIX_PORT)//保存第一列按键按下后的键值	
		{
			case 0x77: key_value=1;break;
			case 0xb7: key_value=5;break;
			case 0xd7: key_value=9;break;
			case 0xe7: key_value=13;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xf7);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfb;//给第二列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下
	{
		delay(10);//消抖
		switch(KEY_MATRIX_PORT)//保存第二列按键按下后的键值	
		{
			case 0x7b: key_value=2;break;
			case 0xbb: key_value=6;break;
			case 0xdb: key_value=10;break;
			case 0xeb: key_value=14;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfb);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfd;//给第三列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下
	{
		delay(10);//消抖
		switch(KEY_MATRIX_PORT)//保存第三列按键按下后的键值	
		{
			case 0x7d: key_value=3;break;
			case 0xbd: key_value=7;break;
			case 0xdd: key_value=11;break;
			case 0xed: key_value=15;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfd);//等待按键松开	
	
	KEY_MATRIX_PORT=0xfe;//给第四列赋值0,其余全为1
	if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下
	{
		delay(10);//消抖
		switch(KEY_MATRIX_PORT)//保存第四列按键按下后的键值	
		{
			case 0x7e: key_value=4;break;
			case 0xbe: key_value=8;break;
			case 0xde: key_value=12;break;
			case 0xee: key_value=16;break;
		}
	}
	while(KEY_MATRIX_PORT!=0xfe);//等待按键松开
	
	return key_value;		
}

/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,
				   0:按键未按下

====原理说明====

先扫出行,再扫出列

依然是分高八位低八位
先扫描列数据,行为高八位,置0,按键按下后就会将列的低八位拉低为0,此时可以检测出哪一列被按下
再扫描行,低八位置0,按键按下后就会将高八位拉低,检测出哪一行被按下,判断哪个按键即可
第一行,直接输出列
第二行,列+4即可
第三行,列+8
依此类推
*******************************************************************************/
char key_matrix_flip_scan()
{
	static char key_value=0;

	KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1
	if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下
	{
		delay(10);//消抖
		if(KEY_MATRIX_PORT!=0x0f)
		{
			//测试列
			KEY_MATRIX_PORT=0x0f;
			switch(KEY_MATRIX_PORT)//保存行为0,按键按下后的列值	
			{
				case 0x07: key_value=1;break;
				case 0x0b: key_value=2;break;
				case 0x0d: key_value=3;break;
				case 0x0e: key_value=4;break;
			}
			//测试行
			KEY_MATRIX_PORT=0xf0;
			switch(KEY_MATRIX_PORT)//保存列为0,按键按下后的键值	
			{
				case 0x70: key_value=key_value;break;
				case 0xb0: key_value=key_value+4;break;
				case 0xd0: key_value=key_value+8;break;
				case 0xe0: key_value=key_value+12;break;
			}
			while(KEY_MATRIX_PORT!=0xf0);//等待按键松开	
		}
	}
	else
		key_value=0;		
	
	return key_value;		
}

代码及原理解释直接给出,方法二效率更高一些,因为扫描次数更少,讲解看不懂的建议去b站看讲解动画。

封装函数使用方法:在主函数while(1)里面写if(scankey() == 1/2/……16){}与独立按键相同

九、点阵屏实验

与数码管类似,但这里多了74HC595芯片(串行传并行,极大减少io使用)

74HC595是一个8位串行输入、并行输出的位移缓存器:并行输出为三态输出。在SCK 的上升沿,串行数据由SDL输入到内部的8位位移缓存器,并由Q7'输出,而并行输出则是在LCK的上升沿将在8位位移缓存器的数据存入到8位并行输出缓存器。当串行数据输入端OE的控制信号为低使能时,并行输出端的输出值等于并行输出缓存器所存储的值。

看不懂b站上有动画说明

根据74HC595芯片的工作原理,我们知道,最关键的引脚其实只有三个,分别是串行数据输入引脚DS、移位寄存器时钟输入引脚SHCP、储存寄存器时钟输入引脚STCP;所以代码怎么写,无非就是配置这几个引脚,定义串行数据输入的子函数,以及运行所需要的主函数

下面直接给出代码

/**************************************************************************************
实验名称:LED点阵实验(显示图像)
实验现象:下载程序后,8*8LED点阵显示心形
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端																				  
***************************************************************************************/
#include "reg51.h"

//定义74HC595控制管脚
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit RCLK=P3^5;		//存储寄存器时钟输入
sbit SER=P3^4; 		//串行数据输入

#define LEDDZ_COL_PORT	P0	//点阵列控制端口

char gled_row[8]={0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};//LED点阵显示图像的行数据
char gled_col[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//LED点阵显示图像的列数据

/*******************************************************************************
* 函 数 名         : hc595_write_data(char dat)
* 函数功能		   : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
void hc595_write_data(char dat)
{
	char i=0;
	
	for(i=0;i<8;i++)//循环8次即可将一个字节写入寄存器中
	{
		SER=dat>>7;//优先传输一个字节中的高位
		dat<<=1;//将低位移动到高位
		SRCLK=0;
		delay(1);
		SRCLK=1;
		delay(1);//移位寄存器时钟上升沿将端口数据送入寄存器中	
	}
	RCLK=1;
	delay(1);
	RCLK=0;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出	
}

void main()
{	
	char i=0;

	while(1)
	{			
		for(i=0;i<8;i++)//循环8次扫描8行、列
		{
			LEDDZ_COL_PORT=gled_col[i];//传送列选数据
			hc595_write_data(gled_row[i]);//传送行选数据
			delay(1);//延时一段时间,等待显示稳定
			hc595_write_data(0x00);//消影	
		}								
	}		
}

 十、定时器

        1.CPU时序

                 1) 震荡周期:为单片机提供定时信号的震荡源的周期(晶振周期或外加震荡周期)。

                 2) 状态周期:2个震荡周期为1个状态周期,用S表示。震荡周期又称S周期或时钟周期。

                 3) 机器周期:1个机器周期含6个状态周期,12个震荡周期

                 4) 指令周期:完成1条指令所占用的全部时间,他以机器周期为单位。

  • 例如:外界晶振为12MHz时,51单片机相关周期的具体值为:
  • 震荡周期=1/12us
  • 状态周期=1/6us
  • 机器周期=1us
  • 指令周期=1~4us

        2.定时器初步认识

                ① 51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器/计数器   

                ② 定时器/计数器和单片机的CPU是相互独立的。定时器/计数器工作的过程自动完成的,不需要CPU的参与。

                ③ 51单片机中的定时器/计数器是根据机器内部的时钟或者外部的脉冲信号对寄存器中的数据加1

        3.定时器原理

                STC89C5X单片机内有两个可编程的定时/计数器 T0,T1 和一个特殊功能定时器T2。定时/计数的是指是加 1 计数器(16位),由高 8 位到低 8 位两个寄存器 THx 和 TLx 组成。它随着计数器的输入脉冲进行自加 1 ,也就是每来一个脉冲,计数器就自动加 1 ,当加到计数器为全 1 时,再输入一个脉冲就使计数器回零,且计数器的益出相应的中断标志位置 1 ,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。可见,由溢出时计算器的值减去计数初值才是加 1 计数器的计算值。

        4.定时器/计数器控制寄存器TCON

可位寻址:可以对寄存器的某一位进行修改操作,而其它位数据保持不变

上图中常用的几个数据位为:

TF0 / TF1  ——  定时器/计数器 T1溢出标志。 当最高位产生溢出时由硬件置“1”,向CPU请求中断。 一直保持到 CPU 响应中断时,才由硬件清 “0 ”。
TR0 / TR1 ——   定时器 T0的运行控制位。 TRX=1 时就允许TX 开始计数。

        5.定时器/计数器工作模式寄存器TMOD

不可位寻址 : 必须对整个寄存器的每一位数据进行覆盖。此处可以利用“TMOD &= 0xF0”来保持高位不变,低位清0,也可以利用“TMOD |= 0xXX”来实现更多的修改操作

这里用定时器0的16位模式演示

按照手册,TMOD = 0x01;

#include <REGX52.H>

sbit LED1 = P2^0;//将P2寄存器按位寻址第一位赋给LED1

void t0_init(void)
{
	TMOD=0x10; //设置定时器0模式为16位 
	TF0=0; // 溢出位 置零
	TH0=0xFC; // 高位  1111 1100
	TL0=0x18; // 低位  0001 1000
	//1ms  FC18(16) -> 64536(10) 距离65536差1000(us) 即1ms后中断一次
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//定时器开始计时
}

void main()
{
	t0_init();//初始化
	while(1)
	{
		
	}
}

void t0() interrupt 1 //定时器0中断函数  interrupt 中断次序号 越小优先级越高
{
	static int i;//定义静态变量i
	//重新赋初值,为下次计时准备
	TH0=0XFC;
	TL0=0X18;
	i++;
	if(i==1000)//1000ms = 1s
	{
		LED1=!LED1;	//电平反转
		i=0;
	}						
}

实验效果:第一个LED灯先暗1s然后亮1s,依次循环 

注意:上面代码中的注释“次序号越小优先级越高”有误,手册中说的是相同优先级情况下,次序号越小优先级越高,中断优先级是可以通过寄存器控制的,具体解释看十一节

十一、外部中断

        STC89C51RC/RD+系列单片机提供了8个中断请求源,它们分别是:外部中断0(INT0)、
定时器0中断、外部中断1(INT1)、定时器1中断、串口(UART)中断、定时器2中断、外部中断
2(INT2)、外部中断3(INT3)。所有的中断都具有4个中断优先级。

此处对上一节做出解释:中断优先级控制寄存器相同情况下(即同一中断优先级下),优先级取决于中断查询次序。

具体外部中断的寄存器的基本操作步骤为:

1、打开中断允许控制寄存器(总中断开关EA=1,子中断开关比如EX0=1)

2、调整ITx寄存器来控制中断触发方式(比如低电平触发IT0=0,下降沿触发IT0=1)

3、配置中断执行函数 void func(void) interrupt 次序号 { //要执行的内容 }

4、其他高级操作比如修改中断优先级请自行研究手册

#include "reg52.h"

//定义LED1管脚
sbit LED1=P2^0;
//定义独立按键K2控制脚
sbit KEY2=P3^0;

void exti1_init(void)
{
	IT0=1;//跳变沿触发方式(下降沿)
	EX0=1;//打开INT0的中断允许
	EA=1;//打开总中断
}

void main()
{	
	exti1_init();//外部中断0配置
	while(1)
	{			
		
	}		
}

void exti1() interrupt 1 //外部中断0中断函数
{
	if(KEY2==0)//判断K3键是否按下
		LED1=!LED1;//LED1状态翻转					
}

实验现象:下载程序后,当按下K3键可控制D1指示灯亮灭

  • 14
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STC89C52RC开发板是一种基于STC89C52RC单片机的开发工具。该单片机STC公司生产的一款高性能、低功耗的8位单片机。该开发板具有丰富的资源和功能,是学习和开发嵌入式系统的理想选择。 STC89C52RC单片机具有51系列常用的特性和功能,并且在性能上有所提升。它内置了8KB的FLASH程序存储器,可用于程序存储。同时,它具有256字节的RAM,用于数据存储。STC89C52RC还具有强大的外设接口,包括定时器、串行通信接口等。这些功能使得STC89C52RC在物联网、家电控制、工业控制等领域有着广泛的应用。 STC89C52RC开发板是针对STC89C52RC单片机开发的一款硬件平台,具有丰富的接口和扩展能力。它通常包括主控模块、显示模块、输入输出模块、通信模块等。通过这些模块的组合,开发者可以方便地实现各种功能需求,如LED灯控制、液晶显示、按键输入等。 使用STC89C52RC开发板进行开发,首先需要编写程序代码,然后通过编程工具将代码下载到STC89C52RC单片机中。开发板上通常提供了下载接口和调试接口,可以通过USB接口或者串口与电脑连接,方便下载程序和进行调试。开发者可以使用C语言或者汇编语言来进行编程。 总之,STC89C52RC开发板是一种方便、易用的开发工具,适用于嵌入式系统的学习和开发。它提供了丰富的资源和功能,支持多种接口和扩展模块,帮助开发者快速实现各种功能需求。无论是初学者还是专业开发者,都可以通过STC89C52RC开发板轻松实现自己的创意和想法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值