本文主要是介绍初识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,其余全为1if(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,其余全为1if(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,其余全为1if(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,其余全为1if(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,列全为1if(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);//等待按键松开 }}elsekey_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
可位寻址:可以对寄存器的某一位进行修改操作,而其它位数据保持不变
上图中常用的几个数据位为:
5.定时器/计数器工作模式寄存器TMOD
不可位寻址 : 必须对整个寄存器的每一位数据进行覆盖。此处可以利用“TMOD &= 0xF0”来保持高位不变,低位清0,也可以利用“TMOD |= 0xXX”来实现更多的修改操作
这里用定时器0的16位模式演示
按照手册,TMOD = 0x01;
#include <REGX52.H>sbit LED1 = P2^0;//将P2寄存器按位寻址第一位赋给LED1void t0_init(void)
{TMOD=0x10; //设置定时器0模式为16位 TF0=0; // 溢出位 置零TH0=0xFC; // 高位 1111 1100TL0=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,依次循环
十一、外部中断
等待更新……
这篇关于初识C51单片机(STC89C52RC开发板)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!