51单片机简明笔记(一)
这一系列blog主要用于记录51单片机的软件学习与部分硬件学习思路,保存代码与模版方便速查。
1概述
我的单片机型号是STC89C52RC,具体参数可见下表
推测这个所谓程序空间指的是ROM 单片机简称MCU,是micro
control unit的缩写,意为一个微型的计算机。
中央处理器(CPU):STC89C52RC的CPU是8051体系结构的核心,主要负责执行程序指令、数据处理、中断处理等任务。程序的编写使用C语言或汇编语言,通过编译器生成二进制可执行文件,然后通过下载工具将程序下载到STC89C52RC中。
存储器(FLASH):STC89C52RC具有64KB的Flash存储器,可以用来存储程序代码和数据。在编程时,需要将程序代码和数据存储到Flash中,以便单片机可以读取执行。
存储器(RAM):STC89C52RC具有256字节的RAM存储器,可以用来存储程序中的变量和中间结果。在编程时,需要定义变量并将其存储到RAM中,以便程序可以读写变量的值。
定时器/计数器(Timer):STC89C52RC具有3个定时器/计数器,可以用来产生定时中断、PWM波形输出等功能。在编程时,需要对定时器/计数器进行初始化配置,并编写中断服务程序来处理定时中断。
串口(UART):STC89C52RC具有一个串口,可以用来进行与外部设备的通信。在编程时,需要对串口进行初始化配置,并编写发送和接收函数来进行数据的传输。
IO口:STC89C52RC具有32个IO口,可以用来连接各种外部设备,如LED、LCD、按键、传感器等。在编程时,需要对IO口进行初始化配置,并编写IO口的读写函数来控制外部设备的状态。
中断控制器(INT):STC89C52RC具有中断控制器,可以用来管理各种中断源和中断服务程序。在编程时,需要对中断控制器进行初始化配置,并编写中断服务程序来处理中断事件。
原文链接:https://blog.csdn.net/m0_61107092/article/details/130212554
2 LED灯相关
基本思想 cpu控制寄存器(ram)控制高低电平
点亮一个led
1 2 3 4 5 6
| #include <REGX52.H> void main() { P2=0xFE; }
|
led闪烁(引入延时函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <REGX52.H> #include <INTRINS.H>
void Delay100us() { unsigned char i, j;
_nop_(); _nop_(); i = 2; j = 15; do { while (--j); } while (--i); } void main() { while(1) { P2=0xFE; Delay500ms(); P2=0xFF; Delay500ms(); } }
|
流水灯等等也是同样的道理。在单片机中main函数执行完一遍不会退出,而是会循环,因此想要终止在某一处,可以在main函数中加入一个while死循环。
3 独立按键控制
前置知识 1 控制八位灯中的某一位 采用这种写法P2_i=0/1
i从0取到7 0为低电平,1为高电平。 2 看电路图可知按键接口断开时为1
按下时为2 3
按键按下的抖动导致电位并不是平整的,需要通过软件或硬件实现消抖。
消除抖动是重点研究对象 
控制一个LED
位运算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <REGX52.H> #include <INTRINS.H> void Delay(unsigned int times) { while(times) { unsigned char i, j;
_nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (--j); } while (--i); times--; } } void main() { if(P3_1==0) { Delay(20); while(P3_1==0) Delay(1); P2_0=~P2_0; } }
|
独立按键控制LED移位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <REGX52.H> #include <INTRINS.H> void Delay(unsigned int times) { while(times) { unsigned char i, j;
_nop_(); _nop_(); _nop_(); i = 11; j = 190; do { while (--j); } while (--i); times--; } } unsigned char LEDNum;
void main() { P2=~0x01; while(1) { if(P3_1==0) { Delay(20); while(P3_1==0); Delay(20); LEDNum++; if(LEDNum>=8) LEDNum=0; P2=~(0x01<<LEDNum); } if(P3_0==0) { Delay(20); while(P3_0==0); Delay(20); if(LEDNum==0) LEDNum=7; else LEDNum--; P2=~(0x01<<LEDNum); } } }
|
4 数码管显示
原理:参见 51单片机(三)数码管(超详细、必会!)_数码管abcdefg对应-CSDN博客
静态数码管显示数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
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]; }
void main() { Nixie(2,3); while(1) { } }
|
如若想要动态显示,只需要引入延时函数,在显示不同数字的操作之间加上一段延时即可。
5 模块化编程
几个图

6 矩阵键盘
我们有十六个按键,通过十六个独立通路实现对按键状态的检测是对IO口极大的浪费,因此为了减少I/O口的占用,通常将按键排列成矩阵形式。采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态。矩阵键盘扫(输入扫描)的原理:读取第1行(列)→读取第2行(列)
→读取第3行(列) →
……,然后快速循环这个过程,最终实现所有按键同时检测的效果。这相当于我们读取了键盘的横纵坐标,因为每排(列)按键总是共用同一纵(横)坐标的,所以节省了资源。例如,要判断第一行S1、S2、S3、S4四个按键是否按下,则只需要先将P17接地,之后判断P13是否为0进而判断按键S1是否被按下,因为P17为低电平,若P13为低电平,则说明S1所在的电路导通了,即说明S1被按下,这与独立按键的原理一样。判断S2是否被按下,只需判断P12是否为0即可。要判断第一列S1、S5、S9、S13是否按下,可先将P13接地,然后判断P17、P16、P15、P14是否为0即可。代码实现矩阵按键数值显示
需要用到LCD1602.c文件(驱动程序)同时涉及到了之前独立按键控制LED灯的操作。
返回一个整形的“键盘函数”MatrixKey()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
* @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; }
|