目录
· 初识单片机
单片机(Micro Controller Unit, 简称MCU),内部集成了RAM、ROM、CPU、定时器、中断系统、通讯接口等一系列常用硬件外设,常用于信息采集、处理和设备控制。
换句话说,单片机相当于一台迷你计算机,体积小,结构简单。
而此次学习的51单片机:兼容最早的MCS51指令集的一类单片机。
· 单片机的外设
此次使用的STC89C52RC单片机,有非常丰富的外接硬件。
· 单片机控制硬件
单片机控制设备的方式
MCU集成有CPU,书写的代码在CPU中执行。
MCU 中还有寄存器(一种存储器),寄存器以8个为一组,每一位寄存器后面的导线上,有一个驱动器(用于增大电流),导线最终连接到 IO 口(1为高电平,0为低电平)
简而言之:CPU通过控制寄存器来控制硬件
另外,单片机不会自动停止一个程序,需要在程序中写入死循环使它不断被执行,从而停止在主函数中不断的执行。
while ( 1 ) {
//执行代码;
}
编写程序
需要用到软件 Keil 5
建立工程:
Project -> New uVision Project -> 选择路径 -> 保存(S)-> 否 -> 打开左侧Source Group1 ->
-> 右键新建 Add New Item To... -> 选择C File -> 文件名 -> Add -> 界面上方Option For Target...->
-> Output -> 勾选Create HEX File -> OK
烧录程序
需要用到软件STC-ISP
具体方法:选择单片机型号(这里选STC89C52RC/LE52RC)-> 串口号在接入电脑后选择USB->
-> 打开程序文件 -> 下载/编程 -> 重启单片机
此时程序会烧录至芯片中。
· LED模块
LED:发光二极管
接口:P2
8个LED( D1 ~ D8 )分别对应 P2_0 ~ P2_7 。
根据表中的进制转换,赋值给P2 口达到控制LED亮灭目的。
1、点亮一个LED
点亮一个LED,控制P2口输出的0和1。
在告诉P2口输出时使用16进制(更为方便)。
#include <REGX52.H>
void main () {
P2 = 0xFE ; //1111 1110
}
这行语句相当于让P2口输出一个 1111 1110 的电平,此时会点亮D1。
2、LED的闪烁
控制LED的闪烁,即让P2口不断输出“ 1111 1110 ” “ 1111 1111 ” 两种电平。
其中间隔为500ms,就可以达到LED以1秒为周期闪烁。
而我们可以通过烧录程序的软件获取延时的函数。
通过STC-ISP 软件中带的 “软件延时计算器” 插件,调整参数,生成C代码,并将其复制到程序中,就得到了延时500ms的函数。(系统频率时晶振管的频率,指令集选Y1)
最后在头文件中加入 #include <INTRINS.H> 以运行函数中的 _nop_() ; 语句。
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@11.0592MHz
{
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();
}
}
3、 LED流水灯
流水灯即让P2口以一定的间隔让D1~D8依次亮起。
即以此输出“ 1111 1110 ” “ 1111 1101 ” “ 1111 1011 ” “ 1111 0111 ”......
#include <REGX52.H>
void Delay1ms(unsigned int xms)
unsigned char i, j;
while (xms){
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;}
}
void main(){
while(1){
P2=0xFE;
Delay1ms(100);
P2=0xFD;
Delay1ms(100);
P2=0xFB;
Delay1ms(100);
P2=0xF7;
Delay1ms(100);
P2=0xEF;
Delay1ms(100);
P2=0xDF;
Delay1ms(100);
P2=0xBF;
Delay1ms(100);
P2=0x7F;
Delay1ms(100);
}
}
在该代码中 ,我们修改了一下延时函数,使其可以被修改延时时长。
具体方法是:(1)添加函数形参,使其可以被修改
(2)写while函数循环,每执行一次,对应时间减一,直到变为0,离开while
· 独立按键模块
1、按键控制LED亮灭
按键对应端口为P3 口,从左到右K1到K4四个按键分别对应:
P3_1 ; P3_0 ; P3_3 ; P3_4
用按键控制 LED,即通过判断语句,当 P3 为 0 或者 1(分别对应按下和松开)。
#include <REGX52.H>
void main(){
while(1){
if(P3_1==0){
P2_0=0;
}else{
P2_0=1;
}
}
}
代码满足当K1被按下时,P3_1输出低电平,此时对第一个LED D1输出低电平,使其亮起
反之松开后 P3_1输出高电平,此时对第一个LED D1输出高电平,使其熄灭。
2、按键控制LED状态
与上一个类似,不同点在于,此时在判断后加入循环,使LED一直处于点亮状态,直到再次按下按键。
特殊的,机械按键在触发时不可避免的有波动,可能造成误判,因此需要在判断后加入延迟,以抵消机械按键的波动。
#include <REGX52.H>
void Delay1ms(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms){
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main(){
while(1){
if(P3_1==0){
Delay1ms(20);
while(P3_1==0);
Delay1ms(20);
P2_0=~P2_0;
}
}
}
3、按键控制LED表示二进制
与上类似,只需要将对P2_0 一个LED的控制转变为对 P2 所有LED的控制,并每次按动按键都使P2 对应的值++,即可表示二进制。
#include <REGX52.H>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--){
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void main(){
unsigned char LEDNum=0;
while(1){
if(P3_1==0){
Delay(20);
while(P3_1==0);
Delay(20);
LEDNum++;
P2=~LEDNum;
}
}
}
4、按键控制LED移位
这次需要两个按键K1 与 K2 , 即控制P3_1 与 P3_0。
当K1 被按动时,让LED灯向左位移,K2向右。
即:当 P3_1 ==0 时,P2向左移位(使用移位符<<); 反之,P3_0==0 时,P2>>;
#include <REGX52.H>
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--){
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void main(){
unsigned char LEDNum=0;
P2=~0x01;
while(1){
if(P3_0==0){
Delay(20);
while(P3_0==0);
Delay(20);
LEDNum++;
if(LEDNum>=8){
LEDNum=0;
}
P2=~(0x01<<LEDNum);
}
if(P3_1==0){
Delay(20);
while(P3_1==0);
Delay(20);
if(LEDNum==0){
LEDNum=7;
}else{
LEDNum--;
}
P2=~(0x01<<LEDNum);
}
}
}
先定义了一个变量 LEDNum ,向左--,向右++,P2只需要在初始状态 0000 0001 做出对应移位
· 数码管模块
1、数码管的结构
数码管的断码表(可以理解为对应符号的 “编码” )
2、静态数码管显示
数码管对应P0 口,将数字的断码赋给 P0 口,即可显示对应的数字。
显示位置有1~8位,由 P2_4 , P2_3 , P2_4 ,控制P0 显示的位置。
#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(){
while(1){
Nixie(7,2);
}
}
3、动态数码管显示
与上非常类似,显示后加入一段很短的延时显示下一个数字,如此循环
在while死循环中一直执行,数字会不断以极小间隔闪烁,看上去像同时亮起。
#include <REGX52.H>
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay3ms() //@11.0592MHz
{
unsigned char i, j;
i = 6;
j = 93;
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];
}
void main(){
while(1){
Nixie(5,2);
Delay3ms();
Nixie(6,0);
Delay3ms();
Nixie(4,5);
Delay3ms();
}
}