51单片机的学习
一、单片机的介绍
1.1
1.2 如何使用软件
首先打开Keil 5软件,点击上面的project。
在下拉的菜单中选择New μVision Project…
然后新增文件夹在桌面,例如我这里是my_51project
,然后再新建一个文件名为2_1 light LED
在我们的my_51project
里面,最后可以将名为Project的文件建立在我们的2_1 light LED
中,这是我们要写的第一个工程。
然后建立后点击保存,会出现下面的画面。
我们在Search栏中搜索AT89C52/AT89C51,点击OK,然后出现对话框
可以点击否,然后就可以看到我们的工程了,在工程下面有一个文件Target 1
,在其里面有一个文件夹Source Group 1
,这个就是我们写代码的地方。
来到文件夹Source Group 1
,右键点击,选择Add New Item to Group 'Source Group 1'...
选择C语言文件,将名字设为main
,点击Add添加。
编写代码前,可以修改一下代码的字体大小
选择第二个选项Color & Fonts
在Window
栏中选择C/C++ Editor files
点击右边的Courier New...
在Size
栏中选择自己喜欢的大小就行了,这里推荐16。
写代码前,注意要右键点击代码第一行,选择Insert '#include <REGX52.H>'
然后可以在下面写2.1的代码了,具体代码解析需要在[2.1](###2.1 点亮第一个LED)去看。
1 2 3 4 5 6 7
| #include <REGX52.H>
void main(){ while(1) { P2 = 0xFE; } }
|
写完代码后记得点击编译,就是下图中三个图标里面的中间那个。
为了生成可以下载到单片机里面的hex文件,需要点击Options for Target...
图标
打开该窗口后选择Output
勾选上内容Create HEX File
这个选项
重新编译,可以看到下面提示已经创建好hex文件了
然后用USB连接好51单片机和电脑,打开STC-ISP软件,选择好单片机型号,安装好驱动软件选择好串口号,打开正确的程序文件,点击“下载/编程”,当软件右下半部分显示“正在检测目标单片机…”时,重新关闭并打开单片机的总电源,就可以将程序烧录进去了。
二、LED的学习
LED相关的原理图
2.1 点亮第一个LED
实现代码:
1 2 3 4 5 6 7
| #include <REGX52.H>
void main(){ while(1) { P2 = 0xFE; } }
|
- 如果不设置循环,单片机会在跑完main函数之后重新不断地继续跑main函数,所以为了方便或者其他原因,我们可以在main函数里面设置一个while的死循环。
- 上面代码中,P2的表达方式是用两位十六进制,所以前面要加上
0x
。
- P2代表的是单片机的8个LED灯,用两位十六进制表示,为0时对应的位置亮灯,为1时不亮。
高级代码:
1 2 3 4 5 6 7 8 9 10
| #include <REGX52.H>
sbit LED1 = P2^0;
void mian() { LED1 = 0; while(1) { } }
|
- 在第3行代码中,
sbit
用于特殊功能寄存器中可位寻址的位地址。类似于C语言中的宏定义,对选定位地址进行某特殊功能的命名。 格式为:sbit 命名功能 = 位地址
。
- 与
sbit
使用相似的还有str
,sfr
定义特殊功能寄存器中的字节。类似于C语言中的宏定义,对选定字节地址进行某特殊功能的命名。 格式为:sfr 功能命名 = 地址
(位地址首位)
- 上面的代码对比前面的代码中,一开始就定义了LED1的位置,只需要定义变量一次,然后让程序一直进入死循环即可。可读性高,更加优雅。
2.2 LED闪烁
实现目的:让一个LED以1s为一周期闪烁
首先需要去寻找可用的延时函数,你可以打开STC-ISP软件,在右上部分右划到软件延时计算器
部分,选择合适的系统频率(晶振的频率)以及适合芯片使用的8051指令集,最后选择需要的定时长度,然后点击下面的生成C代码
,得到那一串代码进行复制粘贴就可以使用了。
实现代码:
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 <REX52.H> #include <INTRINS.H>
void Delay500ms() { unsigned char i, j, k; _nop_(); i = 4; j = 129; k = 119; do { do { while (--k); } while (--j); } while (--i); }
void main() { while(1) { P2 = 0xFE; Delay500ms(); P2 = 0xFF; Delay500ms(); }
}
|
- 通过软件复制代码得到延时函数。
- 利用延时函数达到亮灭的效果。
高级代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <REGX52.H>
typedef unsigned int u16; typedef unsigned char u8;
sbit LED1 = P2^0;
void delay_10us(u16 ten_us) { while(ten_us--); }
void main() { while(1){ LED1 = 0; delay_10us(50000); LED1 = 1; delay_10us(50000); } }
|
- 第3行的
typedef unsigned int u16
或者第4行typedef unsigned char u8
,将变量名修改为u16
和u8
,即u16
可以当unsigned int
使用、u8
可以当unsigned char
使用。
- 第6行的
sbit LED1 = P2^0
是将LED1
定义为管脚P2
的0号管脚(第一个管脚,也是第一个led灯)的值,后面就可以使用LED1
,给LED1
定义值相当于给P2的第0位的值定义。
2.3 LED流水灯
实现目的:使得8个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
| #include <REGX52.H> #include <INTRINS.H>
void Delay500ms() { unsigned char i, j, k; _nop_(); i = 4; j = 129; k = 119; do { do { while (--k); } while (--j); } while (--i); }
void main() { while(1) { P2 = 0xFE; Delay500ms(); P2 = 0xFD; Delay500ms(); P2 = 0xFB; Delay500ms(); P2 = 0xF7; Delay500ms(); P2 = 0xEF; Delay500ms(); P2 = 0xDF; Delay500ms(); P2 = 0xBF; Delay500ms(); P2 = 0x7F; Delay500ms(); } }
|
- 通过不断定义P2的值,可以使得8个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
| #include "reg52.h" #include "intrins.h"
typedef unsigned int u16; typedef unsigned char u8;
#define LED_PORT P2
void delay_10us(u16 ten_us) { while(ten_us--); }
void main() { u8 i=0;
LED_PORT=~0x01; delay_10us(50000); while(1) {
for(i=0;i<7;i++) { LED_PORT=_crol_(LED_PORT,1); delay_10us(50000); } for(i=0;i<7;i++) { LED_PORT=_cror_(LED_PORT,1); delay_10us(50000); } } }
|
- 高级代码中使用了文件
intrins.h
(INTRINS.H
),来对流水灯进行移位,其中使用的函数分别为_crol_
与_cror_
,输入参数有两个,第一个为串口地址,第二个为需要左移或者右移的位数,其功能就是实现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 "reg52.h" #include "intrins.h"
typedef unsigned int u16; typedef unsigned char u8;
#define LED_PORT P2
void delay_10us(u16 ten_us) { while(ten_us--); } void main() { u8 i=0; LED_PORT=~0x01; delay_10us(50000); while(1) { for(i=0;i<7;i++) { LED_PORT=_crol_(LED_PORT,1); delay_10us(50000); } for(i=0;i<7;i++) { LED_PORT=_cror_(LED_PORT,1); delay_10us(50000); } } }
|
三、独立按键
与独立按键所相关的原理图
3.1 独立按键控制LED亮灭
实现功能:左边第一个按键控制一个LED灯的亮灭。
1 2 3 4 5 6 7 8 9 10 11
| #include <REGX52.H>
void main() { while (1) { if (P3_1 == 0) { P2_0 = 0; } else { P2_0 = 1; } } }
|
- 当按键按下时,其引脚返回的电平值为0;
- LED灯为低电平亮灯。
高级代码:
实现功能:按下“独立按键”模块中K1键,控制D1指示灯亮灭
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 53 54 55 56 57 58 59 60 61 62 63
| #include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit KEY1=P3^1; sbit KEY2=P3^0; sbit KEY3=P3^2; sbit KEY4=P3^3;
sbit LED1=P2^0;
#define KEY1_PRESS 1 #define KEY2_PRESS 2 #define KEY3_PRESS 3 #define KEY4_PRESS 4 #define KEY_UNPRESS 0
void delay_10us(u16 ten_us) { while(ten_us--); }
u8 key_scan(u8 mode) { static u8 key=1;
if(mode)key=1; if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0)) { delay_10us(1000); key=0; if(KEY1==0) return KEY1_PRESS; else if(KEY2==0) return KEY2_PRESS; else if(KEY3==0) return KEY3_PRESS; else if(KEY4==0) return KEY4_PRESS; } else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) { key=1; } return KEY_UNPRESS; }
void main() { u8 key=0;
while(1) { key=key_scan(0); if(key==KEY1_PRESS) LED1=!LED1; } }
|
- 在前面重定义了默认数据类型,将
unsigned char
定义为u8
,将unsigned int
定义为u16
,更加方便简洁清晰。
- 分别定义了独立按键的控制脚和LED控制脚,注意对比原理图和控制脚的位置,独立按键的四个控制脚上面的管脚数字顺序并不是有顺序的。
- 利用宏定义确定了返回数据值,这样使得代码更加易读。
- 按键扫描函数
key_scan
:检测独立按键是否按下,按下则返回对应键值。只有一个输入参数mode
, mode=0
:单次扫描按键,mode=1
:连续扫描按键。
3.2 独立按键控制LED状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <REGX52.H>
void delay_10us(u16 ten_us) { while(ten_us--); }
void main() { while (1) { if (P3_1 == 0) { delay_10us(2000); while (P3_1 == 0) { P2_0 = 0; } delay_10us(2000); P2_2 = ~P2_2; } } }
|
- 由于LED的引脚输入低电平的时候会亮灯,所以只要按键按下后,经过20ms的消抖,如果按键依旧是按下的状态,那么对应的LED就会亮灯,如果松开,则会在延迟20ms之后灭灯。
3.3 独立按键控制LED显示二进制
实现功能:按键松开会使得所有的LED灯进行二进制变换亮灯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<REGX52.H>
void delay_10us(u16 ten_us) { while(ten_us--); }
void main() { unsigned char LED_num = 0; while (1) { if (P3_1 == 0) { delay_10us(2000); while (P3_1 == 0) ; delay_10us(2000); LED_num++; P2 = ~LED_num; } } }
|
- 与前面不同的是,这里的LED灯会进行二进制的变换。
- 不同的是,在
while
语句里面并没有操作,而是在延迟后才有操作,这样使得在按键抬起才会实现需要的功能。
- 但是这种方法也有弊端,那就是这种代码只要P3_1一旦处于低电平状态,后面功能就会触发。而前面[3.2](###3.2 独立按键控制LED状态)中需要在P3_1在处于低电平的触发状态后20ms依旧还是低电平,这样才会触发功能。
3.4 独立按键控制LED移位
实现功能:松开按键后会对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
| #include<REGX52.H>
void delay_10us(u16 ten_us) { while(ten_us--); }
void main() { unsigned char LED_num = 0; while (1) { if (P3_1 == 0) { delay_10us(2000); while (P3_1 == 0) ; delay_10us(2000); LED_num++; if (LED_num >= 8) { LED_num = 0; } P2 = ~(0x01 << LED_num); } if (P3_0 == 0) { delay_10us(2000); while (P3_1 == 0) ; delay_10us(2000); LED_num++; if (LED_num == 0) { LED_num = 7; } else { LED_num--; } P2 = ~(0x01 << LED_num); } } }
|
- 通过控制LED_num的数字,来确定P2移位的数量。
- 由于P2是低电平亮灯,所以需要进行取反,使得只有一个数字为零,即一个灯亮。
- 通过两个if语句判断来实现两个按键不同的功能,一个进行右移,一个进行左移,而通过控制按键的响应为移位的数字的加减来达到左右移的目的。
四、数码管显示
与七段数码管所相关的原理图
- 上图中,控制8个LED亮灭的是71LS138芯片的引脚P2_2、P2_3、P2_4,按照二进制来控制,即引脚P2_2、P2_3、P2_4组合成为的一个3位二进制数将对需要显示的LED进行选择。例如,如果引脚P2_2、P2_3、P2_4分别为010,则会使得后面的8位二进制数控制LED3。
- 上图中,动态数码管模块的左边P0_1~P0_7八个引脚就是控制LED亮灭的8位二进制数,高电平亮灯,芯片74HC245的功能是管脚对应进行增加驱动。
4.1 静态数码管显示
点亮一个静态数码管LED6,使其显示6
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
| #include <REGX52.H>
unsigned char NixieTable[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
void delay_10us(u16 ten_us) { while(ten_us--); }
void light(unsigned char location, unsigned char number) { switch(location) { case 1: P2_4=0; P2_3=0; P2_2=0; break; case 2: P2_4=0; P2_3=0; P2_2=1; break; case 3: P2_4=0; P2_3=1; P2_2=0; break; case 4: P2_4=0; P2_3=1; P2_2=1; break; case 5: P2_4=1; P2_3=0; P2_2=0; break; case 6: P2_4=1; P2_3=0; P2_2=1; break; case 7: P2_4=1; P2_3=1; P2_2=0; break; case 8: P2_4=1; P2_3=1; P2_2=1; break; } P0 = NixieTable[number]; }
void main() { light(6, 6); while(1) {} }
|
- 通过一个函数进行实现。
- 函数里面的case是选择哪个LED进行亮灯
- 前面定义的数组
NixieTable
是数码管数字显示的阳码,一共十个数字,对应的下标里面的内容如果赋值到P0则会显示对应下标的数字
4.2 动态数码管显示
实现功能:从左往右第一、二、三个数码管动态显示数字456。
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
| #include <REGX52.H>
unsigned char NixieTable[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
void delay_10us(u16 ten_us) { while(ten_us--); }
void light(unsigned char location, unsigned char number) { switch(location) { case 1: P2_4=0; P2_3=0; P2_2=0; break; case 2: P2_4=0; P2_3=0; P2_2=1; break; case 3: P2_4=0; P2_3=1; P2_2=0; break; case 4: P2_4=0; P2_3=1; P2_2=1; break; case 5: P2_4=1; P2_3=0; P2_2=0; break; case 6: P2_4=1; P2_3=0; P2_2=1; break; case 7: P2_4=1; P2_3=1; P2_2=0; break; case 8: P2_4=1; P2_3=1; P2_2=1; break; } P0 = NixieTable[number]; delay_10us(100); P0 = 0x00; }
void main() { while(1) { light(6, 6); light(7, 5); light(8, 4); } }
|
- 与前面相比,只是修改了
light
函数,在后面增加了一下延迟而已。
高级代码:
实现功能:“数码管模块”显示01234567
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 "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
#define SMG_A_DP_PORT P0
sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4;
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay_10us(u16 ten_us) { while(ten_us--); }
void smg_display(void) { u8 i=0;
for(i=0;i<8;i++) { switch(i) { case 0: LSC=1;LSB=1;LSA=1;break; case 1: LSC=1;LSB=1;LSA=0;break; case 2: LSC=1;LSB=0;LSA=1;break; case 3: LSC=1;LSB=0;LSA=0;break; case 4: LSC=0;LSB=1;LSA=1;break; case 5: LSC=0;LSB=1;LSA=0;break; case 6: LSC=0;LSB=0;LSA=1;break; case 7: LSC=0;LSB=0;LSA=0;break; } SMG_A_DP_PORT=gsmg_code[i]; delay_10us(100); SMG_A_DP_PORT=0x00; } }
void main() { while(1) { smg_display(); } }
|
- 实际上与普通代码无异,主要是体现在
smg_display
,必须要经历段选数据的传送、延时以及消音。可以通过增加smg_display
的输入参数,使得函数的适用性更广。
- 相比于普通的代码,这里的高级代码只是在前面定义了更多数据,增加了代码的易读性。
五、模块化编程
5.1自定义模版的固定开头
1 2 3 4
| #ifndef __ _H__ #define
#endif
|
5.2 LCD1602模块代码
LCD1602.c
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
| #include <REGX52.H>
sbit LCD_RS=P2^6; sbit LCD_RW=P2^5; sbit LCD_EN=P2^7; #define LCD_DataPort P0
void LCD_Delay() { unsigned char i, j; i = 2; j = 239; do { while (--j); } while (--i); }
void LCD_WriteCommand(unsigned char Command) { LCD_RS=0; LCD_RW=0; LCD_DataPort=Command; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); }
void LCD_WriteData(unsigned char Data) { LCD_RS=1; LCD_RW=0; LCD_DataPort=Data; LCD_EN=1; LCD_Delay(); LCD_EN=0; LCD_Delay(); }
void LCD_SetCursor(unsigned char Line,unsigned char Column) { if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); } }
void LCD_Init() { LCD_WriteCommand(0x38); LCD_WriteCommand(0x0c); LCD_WriteCommand(0x06); LCD_WriteCommand(0x01); }
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) { LCD_SetCursor(Line,Column); LCD_WriteData(Char); }
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) { unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!='\0';i++) { LCD_WriteData(String[i]); } }
int LCD_Pow(int X,int Y) { unsigned char i; int Result=1; for(i=0;i<Y;i++) { Result*=X; } return Result; }
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0'); } }
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length) { unsigned char i; unsigned int Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0'); } }
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i,SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData(SingleNumber+'0'); } else { LCD_WriteData(SingleNumber-10+'A'); } } }
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) { unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0'); } }
|
LCD1602.h
1 2 3 4 5 6 7 8 9 10 11 12 13
| #ifndef __LCD1602_H__ #define __LCD1602_H__
void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,unsigned char Column,char *String); void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length); void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length); #endif
|
六、矩阵键盘按键
6.1 矩阵键盘
返回矩阵键盘按下后对应的值
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 53 54 55 56 57 58 59 60 61 62 63
| #include <regx51.h> #include <INTRINS.H>
void Delay_1ms(unsigned char times) { do{ unsigned char i, j; _nop_(); i = 2; j = 199; do { while(--j); } while(--i); } while(times--) }
unsigned char MatrixKey() { unsigned char KeyNumber = 0; P1 = 0xFF; P1_3 = 0; if (P1_7 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 1;} if (P1_6 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 5;} if (P1_5 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 9;} if (P1_3 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 13;} P1 = 0xFF; P1_2 = 0; if (P1_7 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 2;} if (P1_6 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 6;} if (P1_5 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 10;} if (P1_3 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 14;} P1 = 0xFF; P1_1 = 0; if (P1_7 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 3;} if (P1_6 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 7;} if (P1_5 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 11;} if (P1_3 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 15;} P1 = 0xFF; P1_0 = 0; if (P1_7 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 4;} if (P1_6 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 8;} if (P1_5 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 12;} if (P1_3 == 0) {Delay_1ms(20); while(P1_7 == 0); Delay_1ms(20); KeyNumber = 16;} return KeyNumber; }
void main() { while(1) { } }
|
高级代码:
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
#define KEY_MATRIX_PORT P1
#define SMG_A_DP_PORT P0
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay_10us(u16 ten_us) { while(ten_us--); }
unsigned char key_matrix_ranks_scan(void) { unsigned char key_value=0;
KEY_MATRIX_PORT=0xf7; if(KEY_MATRIX_PORT!=0xf7) { delay_10us(1000); 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; if(KEY_MATRIX_PORT!=0xfb) { delay_10us(1000); 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; if(KEY_MATRIX_PORT!=0xfd) { delay_10us(1000); 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; if(KEY_MATRIX_PORT!=0xfe) { delay_10us(1000); 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; }
u8 key_matrix_flip_scan(void) { static u8 key_value=0;
KEY_MATRIX_PORT=0x0f; if(KEY_MATRIX_PORT!=0x0f) { delay_10us(1000); if(KEY_MATRIX_PORT!=0x0f) { KEY_MATRIX_PORT=0x0f; switch(KEY_MATRIX_PORT) { 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) { 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; }
void main() { u8 key=0;
while(1) { key=key_matrix_ranks_scan(); if(key!=0) SMG_A_DP_PORT=gsmg_code[key-1]; } }
|
七、定时器
1、定时器0模版代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void Timer0Init(void) { TMOD &= 0xF0; TMOD |= 0x01; TL0 = 0x18; TH0 = 0xFC; TF0 = 0; TR0 = 1; ET0=1; EA=1; PT0=0; }
void Timer0_Routine() interrupt 1 {
}
|
2、定时器1模版代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void Timer1Init(void) { TMOD &= 0x0F; TMOD |= 0x10; TL1 = 0x18; TH1 = 0xFC; TF1 = 0; TR1 = 1; ET1=1; EA=1; PT1=0; }
void Timer1_Routine() interrupt 3 { }
|
八、串口通信
1、串口初始化代码模版
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<REGX51.H>
void UART_Init(void) { PCON |= 0x80; SCON = 0x50; TMOD &= 0x0F; TMOD |= 0x20; TL1 = 0xF4; TH1 = 0xF4; ET1 = 0; TR1 = 1; }
void UART_SendByte(unsigned char byte) { SBUF = byte; while(TI == 0); TI = 0; }
void UART_Routine() interrupt 4 { if (RI == 1) { RI = 0; } }
|
2、串口向电脑发送数据
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
| #include<REGX51.H>
unsigned char Sec;
void UART_Init(void) { PCON |= 0x80; SCON = 0x50; TMOD &= 0x0F; TMOD |= 0x20; TL1 = 0xF4; TH1 = 0xF4; ET1 = 0; TR1 = 1; }
void UART_SendByte(unsigned char byte) { SBUF = byte; while(TI == 0); TI = 0; }
void delay_10us(unsigned int ten_us) { while(ten_us--); }
void main() { UART_Init(); UART_SendByte(0x11); while(1) { delay_10us(10000); UART_SendByte(Sec++);
} }
|
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include<REGX51.H>
unsigned char Sec;
void UART_Init(void) { PCON |= 0x80; SCON = 0x50; TMOD &= 0x0F; TMOD |= 0x20; TL1 = 0xF4; TH1 = 0xF4; ET1 = 0; TR1 = 1; EA = 1; ES = 1; }
void UART_SendByte(unsigned char byte) { SBUF = byte; while(TI == 0); TI = 0; }
void UART_Routine() interrupt 4 { if (RI == 1) { P2 = ~SBUF; UART_SendByte(SBUF); RI = 0; } }
void delay_10us(unsigned int ten_us) { while(ten_us--); }
void main() { UART_Init(); while(1) {
} }
|
九、LED点阵屏
十、DS1302实时时钟
十一、蜂鸣器
十二、AT24C02(IC2总线)EFPROM
十三、DS18B20温度传感器
十四、LCD1602
十五、直流电机驱动(PWM)
十六、AD/DA转换
十七、红外控制