前言

根据前面对51单片机的了解和基础理论知识的掌握,接下来就正式进入单片机开发——实践。引用最近几天追的电视剧《觉醒年代》里新文化领袖陈独秀、李大钊等革命前辈们一直在说的和在践行的马克思的一句话“实践是检验真理的唯一标准”。“理论基础决定上层建筑”这句话到哪儿都是适用的,同样在这里,在前续知识的了解和掌握就进入了程序编写以及电路调试等工程开展中,真正做到理论与实践结合,这里采用的是C语言来编写的51单片机开发程序,这里通篇可能出现一些不专业的话术和专业名词,这里希望看到文章的朋友仅把此文当作参考,对于存在错误的地方可在下方评论区进行留言或者私信博主允于指导和纠正。那么接下来进入我们的入门之旅。

博主自建博客网站原链接:https://www.little-demon.cn/archives/11/

总体思维脑图

这里我把这单片机入门具体应用分类绘制成了一张简易的思维脑图,可以通过预览这里的思维脑图建立大概的知识框架以及对应的整文目录预览以及后续的入门学习有个整体的学习思想,具体思维脑图如下:

开发工具应用

这里单片机的概念以及最小系统前面两篇文章已经介绍过了,这里就不再过多的赘述,这里在单片机实践开始之前,我们应该先想个事情,我们应该采用什么样的工具来辅助我们进行软件的开发,用上一款得心应手的工具软件对我们开发来说,那一定是事半功倍的。那么我先介绍一下几款要用的开发工具:

  • 编程开发工具——Keil
  • 单片机电路仿真工具——Proteus
  • 单片机电路原理图、PCB绘制工具——Altium Designer

具体软件的安装包以及软件的安装教程这里可以在本博客进行搜索找到,对应的介绍也已经在文章中进行描述,可以自行前往了解,那么对于具体该怎么去操作利用,那么在接下来的时间以及文章篇幅允许下将进行具体的介绍,如果这篇文章没有,那么也不要灰心,对应软件的教程网络上一搜一大把,后期在我有时间的基础上我也将进行博文的描述或者进行录制视频来进行进一步的描述。

IO控制应用

从这里开始正式开始本篇博文的重点以及核心知识点。IO口在经过前面两张文章尤其第51单片机开发入门(2)的介绍已经比较完善,在51单片机里共计有四组单片机IO口,对应的功能、理论知识前面可以进行查阅。我们整篇文章将阐述怎么利用它,以及利用它来实现什么功能。

一位输出:流水灯

电路功能分析

这里首先了解一位是指单片机指利用一组IO口进行操作,那么对应在最小系统基础上完成与8 个发光二极管的驱动电路设计;另外需要编写测试程序,实现循环点亮8 个灯,时间间隔约1 秒。

硬件电路设计

这里将每个LED发光二极管的阴极接到了对应的单片机P1端口上,同时每个LED发光二极管的阳极通过串联一个限流电阻连接到VCC(+5v)电源上。当P1端口输出为低电平时,LED点亮,反之LED熄灭。

软件程序编写

在硬件电路完成的基础上,我们开始软件程序的编写,首先我们先梳理一下单片机是怎么工作的。单片机接通电源后,开始工作,P1端口依次输出低电平并且每次间隔1秒钟,轮流交替。那么程序编写方面该如何实现呢?我们接下来通过三种不同方法的程序来实现。

第一种:位操作

  • 第一步、确定LED的端口,定义单片机IO口
/*******LED位定义*********/
sbit LED0=P1^0;//LED0位定义
sbit LED1=P1^1;//LED1位定义
sbit LED2=P1^2;//LED2位定义
sbit LED3=P1^3;//LED3位定义
sbit LED4=P1^4;//LED4位定义
sbit LED5=P1^5;//LED5位定义
sbit LED6=P1^6;//LED6位定义
sbit LED7=P1^7;//LED7位定义
  • 第二步、根据设计要求,编写延时函数
/******延时函数******/
void delay_ms(unsigned char ms)
{unsigned int i,j;for(i=0;i<ms;i++){for(j=0;j<333;j++);}
}

这里注意程序中编写的函数需要在程序中进行函数声明。

  • 第三步、根据设计要求,编写主函数程序
/******位操作方式******/
/******主函数******/
void main(void)
{while(1){LED0=0;delay_ms(1000);LED0=1;//LED0点亮,其余熄灭LED1=0;delay_ms(1000);LED1=1;//LED1点亮,其余熄灭LED2=0;delay_ms(1000);LED2=1;//LED2点亮,其余熄灭LED3=0;delay_ms(1000);LED3=1;//LED3点亮,其余熄灭LED4=0;delay_ms(1000);LED4=1;//LED4点亮,其余熄灭LED5=0;delay_ms(1000);LED5=1;//LED5点亮,其余熄灭LED6=0;delay_ms(1000);LED6=1;//LED6点亮,其余熄灭LED7=0;delay_ms(1000);LED7=1;//LED7点亮,其余熄灭}
}

通过while(1){}死循环操作,使得单片机在一位一位的点亮和熄灭,但这里发现需要编写的变量比较多,虽然能够实现对应设计要求,但是看起来也比较复杂,可读性不强,程序在编写过程中也十分容易出错,所以我们在程序设计过程也要追求程序的简化,增强可读性,那么开始第二种方法。

第二种:移位操作

  • 第一步、确定LED的端口,宏定义单片机的IO口
#define  LED P1;//单片机LEDIO口宏定义

这里也可以不用宏定义,直接在程序中写对应的IO号,但是最好养成习惯,在单片机程序编写过程中最好用宏定义,那么后期在更换IO口时只需要,在这里更改就可以了,而不用整个程序中去搜索更改对应的IO标号。

  • 第二步、根据设计要求,编写延时函数

这里延时程序和上面第一种方法的函数一致,这里就不再重复,具体可以参考上面第一种方法的延时函数程序。

  • 第三步、根据设计要求,编写主函数程序
/******移位操作方式******/
/******主函数******/
void main(void)
{while(1){unsigned char temp=0xfe,i;temp=0xfe;    // 1111 1110for(i=0;i<8;i++){LED=temp;temp=(temp<<1)+1; //1111 1101delay_ms(1000); //延时1s    }}
}

这里通过设定P0初始值为0xfe(1111 1110)通过每间隔1秒循环8次左移,完成程序设计要求。

第三种:数组方式

  • 第一步、确定LED的端口,宏定义单片机的IO口
#define  LED P1;//单片机LEDIO口宏定义

这里也可以不用宏定义,直接在程序中写对应的IO号,但是最好养成习惯,在单片机程序编写过程中最好用宏定义,那么后期在更换IO口时只需要,在这里更改就可以了,而不用整个程序中去搜索更改对应的IO标号。

  • 第二步、变量定义
/*****变量定义*****/
unsigned char LED_DAT[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

通过数组将8种状态所对应的字节归纳定义为数组变量。

  • 第三步、根据设计要求,编写延时函数

这里延时程序和上面第一种方法的函数一致,这里就不再重复,具体可以参考上面第一种方法的延时函数程序。

  • 第四步、根据设计,要求编写主函数
void main(void)
{while(1){unsigned char i;for(i=0;i<8;i++){LED=LED_DAT[I];delay_ms(1000); }  }
}

通过数组种对应元素的变化,改变P1端口对应输出的字节,控制LED灯进行流水灯操作。

烧录程序,仿真调试

这里通过Proteus仿真工具根据电路原理图进行绘制对应的单片机最小系统以及所需要的外围电路,将前面编写的单片机程序编译生成的HEX文件烧录进单片机里,查看具体效果。

整体程序整理:

#include <reg51.h>/*****引脚定义*****/
sbit LED0=P1^0;
sbit LED1=P1^1;
sbit LED2=P1^2;
sbit LED3=P1^3;
sbit LED4=P1^4;
sbit LED5=P1^5;
sbit LED6=P1^6;
sbit LED7=P1^7;/*****变量定义*****/
unsigned char LED_DAT[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};/*****函数声明*****/
void delay_ms(unsigned char ms) ;
void shagua();//傻瓜方式
void shuzu();//数组方式
void yiwei();//移位方式/*****主函数*****/
void main(void)
{while(1){shagua();yiwei();shuzu(); }
}void shagua()//傻瓜方式
{LED0=0;delay_ms(1000);LED0=1;//LED0点亮,其余熄灭LED1=0;delay_ms(1000);LED1=1;//LED1点亮,其余熄灭LED2=0;delay_ms(1000);LED2=1;//LED2点亮,其余熄灭LED3=0;delay_ms(1000);LED3=1;//LED3点亮,其余熄灭LED4=0;delay_ms(1000);LED4=1;//LED4点亮,其余熄灭LED5=0;delay_ms(1000);LED5=1;//LED5点亮,其余熄灭LED6=0;delay_ms(1000);LED6=1;//LED6点亮,其余熄灭LED7=0;delay_ms(1000);LED7=1;//LED7点亮,其余熄灭
}void shuzu()//数组方式
{   unsigned char i;for(i=0;i<8;i++){P1=LED_DAT[i];delay_ms(1000;}
}void yiwei()//移位方式
{unsigned char temp=0xfe,i;temp=0xfe;    // 1111 1110for(i=0;i<8;i++){P1=temp;temp=(temp<<1)+1; //1111 1101delay_ms(100);}
}/******延时函数******/
void delay_ms(unsigned char ms)
{unsigned int i,j;for(i=0;i<ms;i++){for(j=0;j<333;j++);}
}

一位输入:独立按键

电路功能分析

这里首先了解一位是指单片机指利用一组IO口进行操作,那么对应在最小系统基础上完成2个独立按键与8 个发光二极管的驱动电路设计;另外需要编写测试程序,实现实现按键控制循环点亮8 个灯,时间间隔约1 秒。

硬件电路设计

通过上图发现:这里将每个LED发光二极管的阴极接到了对应的单片机P1端口上,同时每个LED发光二极管的阳极通过串联一个限流电阻连接到VCC(+5v)电源上。当P1端口输出为低电平时,LED点亮,反之LED熄灭。

在上面LED流水灯的基础之上,引入添加了独立按键模块,根据电路设计要求,具体添加的按键模块,根据按键开关(非自锁开关)原理。当按键没有按下的时候,VCC(+5v)经过470欧姆限流电阻 输入进单片机的IO口,按键所对应的单片机IO口输入信号为高电平;当按键按下的时候,输入信号对地,这样子按键输入信号对地,即输入信号为低电平,单片机输入信号为低电平。通过高低电平检测,判断按键是否按下。

单独按键主要功能简化:

按键K1按键时,P3.0输入为“0“;

按键K1松下时,P3.0输入为“1“。

图中,按键和电阻可以交换位置,交换后输入逻辑刚好相反。

按键抖动问题

  • 按键抖动问题分析

这里认识了解了按键单个按键的工作原理后,我们还需要了解按键抖动的影响 :当用手按下一个按键时,往往所按按键在闭合位置和断开位置之间弹跳几下才会稳定到闭合状态;在释放一个按键时,也会出现类似的情况。这就是按键抖动。这是由机械结构的固有特性决定的,不可避免。

按键抖动的持续时间大小不一,一般在10ms 左右。

  • 按键抖动问题举例

    当存在按键抖动时,下面程序将**对抖动时的每一个下降沿进行计数**,从而出错。因此应当采取一定的措施消除抖动的影响

# include <reg51.h>
# define  uchar  unsigned char
sbit  KEY = P2^0;void main( )
{uchar ucCounter;uchar ucPreKey;ucCounter = 0x00;   //计数初值KEY = 1;     //准双向口ucPreKey = 1;while(1){if ((KEY==0) && (ucPreKey==1)){ucCounter++;  //计数值加一}    ucPreKey = KEY;    //存储前一状态}
}
  • 按键抖动问题消除方法

要求消除按键抖动的影响,实现一次按键计数值只增加一次。

实现方法:

软件:延迟再扫描

硬件:外接额外电路 (触发器、滤波电路)

# include <reg51.h>
# define  uchar  unsigned char
sbit  KEY = P2^0;void main( )
{uchar ucCounter, ucPreKey ;ucCounter = 0x00;   //计数初值KEY = 1;     //准双向口ucPreKey = 1;while(1){if ((KEY==0) && (ucPreKey==1)){delay(2);   //延时20msif(KEY == 0){ucCounter++;   //计数值加一} }  ucPreKey = KEY;    //存储前一状态}
}

软件程序编写

在硬件电路完成的基础上,我们开始软件程序的编写,首先我们先梳理一下单片机是怎么工作的。单片机接通电源后,开始工作,两个独立按键在这里,一个按键按下时控制P1口所接的LED灯进行左移,另一个按键按下时控制P1口所接的LED灯右移,那么程序编写方面该如何实现呢?

  • 第一步、确定LED的端口,宏定义单片机的IO口以及确定两个独立按键的端口,位定义两个按键
//独立按键管脚IO口定义
sbit KEY1=P3^0;
sbit KEY2=P3^1;
//8个LED灯端口宏定义
#define LED P1
  • 第二步、变量定义
/*****变量定义*****/
unsigned char LED_DAT[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

通过数组将8种状态所对应的字节归纳定义为数组变量。

  • 第三步、根据设计要求,编写延时函数
void delay_ms(unsigned char ms)
{unsigned int i,j;for(i=0;i<ms;i++){for(j=0;j<333;j++);}
}
  • 第四步、根据设计要求,编写按键扫描函数
unsigned char key_scan()    //按键扫描函数
{unsigned char keynum;keynum=0;if(KEY1==0)                       //按键1按下{delay_ms(10);     //软件消除按键抖动if(KEY1==0){while(KEY1==1);keynum=1;             //按键1按下输出变量为1}}if(KEY2==0){delay_ms(10);            //软件消除按键抖动if(KEY2==0)             //按键2按下{while(KEY2==1);keynum=2;           //按键2按下输出变量为2}}return(keynum);
}

通过按键扫描函数,当没有按键按下时,输出按键变量keynum=0;当按键1按下时,输出按键变量keynum=1;当按键2按下时,输出按键变量keynum=2;这里按键进行延时消抖。

  • 第五步、根据设计要求,编写数组左移以及右移函数
//******数组操作******//
void shuzu_you()//数组方式_右移
{char i=0;     for(i=0;i<8;i++)  //循环右移{P1=LED_DAT[i];delay_ms(1000);   }
}void shuzu_zuo()//数组方式_左移
{char n;for(n=7;n>=0;n--)  //循环左移{P1=LED_DAT[n];delay_ms(1000);}
}

这里先将数组的左移以及右移函数提前写好,到时候在主函数种可以进行调用,但是同时也可以在主函数中进行左移、右移操作,同时也可以进行添加相关头文件,直接调用函数进行左移、右移。

  • 第六步、根据设计要求,编写主函数
void main()
{while(1){if(key_scan()==1)  //按键1按下{shuzu_you();      //执行右移函数}if(key_scan()==2)    //按键2按下{shuzu_zuo();        //执行左移函数}}
}

在上面已经梳理清楚了独立按键控制8个LED左移流水灯以及右移流水灯,那么通过while(1){}死循环将单片机一开始就先进行按键扫描,当按键没有任何操作的时候,按键值没有任何变化为0;当按键发生变化的时候,对应的按键值返回到键盘扫描函数,再根据if()的判断函数或者可以利用Switch()选择函数来进行编写后来实现具体的功能。

烧录程序,仿真调试

这里通过Proteus仿真工具根据电路原理图进行绘制对应的单片机最小系统以及所需要的外围电路,将前面编写的单片机程序编译生成的HEX文件烧录进单片机里,查看具体效果。

整体程序梳理;

#include <reg51.h>//独立按键管脚IO口定义
sbit KEY1=P3^0;
sbit KEY2=P3^1;
//8个LED灯端口宏定义
#define LED P1/*****函数声明*****/
void shuzu_zuo();
void shuzu_you();
unsigned char key_scan();
void delay_ms(unsigned char ms);/*****变量定义*****/
unsigned char LED_DAT[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};/*****延时函数*****/
void delay_ms(unsigned char ms)
{unsigned int i,j;for(i=0;i<ms;i++){for(j=0;j<333;j++);}
}   //******数组操作******//
void shuzu_you()//数组方式_右移
{char i=0;     for(i=0;i<8;i++)  //循环右移{P1=LED_DAT[i];delay_ms(1000);   }
}
void shuzu_zuo()//数组方式_左移
{char n;for(n=7;n>=0;n--)  //循环左移{P1=LED_DAT[n];delay_ms(1000);}
}unsigned char key_scan()    //按键扫描函数
{unsigned char keynum;keynum=0;if(KEY1==0)                       //按键1按下{delay_ms(10);     //软件消除按键抖动if(KEY1==0){while(KEY1==1);keynum=1;             //按键1按下输出变量为1}}if(KEY2==0){delay_ms(10);            //软件消除按键抖动if(KEY2==0)             //按键2按下{while(KEY2==1);keynum=2;           //按键2按下输出变量为2}}return(keynum);
}void main()
{while(1){if(key_scan()==1)  //按键1按下{shuzu_you();      //执行右移函数}if(key_scan()==2)    //按键2按下{shuzu_zuo();        //执行左移函数}}
}

多位输出:数码管

数码管:由发光二极管阵列构成。用于显示数字和简单英文字符。

数码管的工作原理

  • 数码管的结构

共阳极数码管

共阴极数码管

  • 数码管的显示

段码,数码管显示的内容:

位码,(即com端)数码管是否点亮

  • 数码管的段码分析(以共阴极数码管为例)

上方图片即为共阴极数码管的段选表,通过不同段位的电平情况,显示不同的字符。dp为小数点位

  • 多个数码管的控制

静态显示,每个数码管单独控制,所有数码管同时点亮

51单片机开发入门(3)-IO口应用相关推荐

  1. 第一章 51单片机开发入门知识介绍

    第一章 单片机开发入门知识介绍 1.1 51单片机介绍 51单片机是对所有兼容Intel 8031指令系统的单片机的统称. 该系列单片机的始祖是Intel的8004单片机,后来随着Flash rom技 ...

  2. 51单片机开发入门(5)-定时器/计数器

    定时器/计数器阐述 AT89S51单片机有**两个16位**内部定时/计数器,记作T0.T1. (AT89S52有3个定时/计数器,比AT89S51多了个T2.) 本质上,定时/计数器就是一个可以通过 ...

  3. 51单片机8255扩展c语言,参阅:基于51单片机的实时时钟的设计与开发8255扩展io口1V0.1...

    <基于51单片机的实时时钟的设计与开发(8255扩展io口) (1).doc>由会员分享,可免费在线阅读全文,更多与<基于51单片机的实时时钟的设计与开发(8255扩展io口) (1 ...

  4. 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

    目录 硬知识 IO 扩展芯片 TCA6416A TAC6416A 的寄存器 IO 输入寄存器 IO 输出寄存器 IO 反相寄存器 IO 方向寄存器 TCA6416A 的操作 TCA6416A 写数据 ...

  5. 【51单片机快速入门指南】2.3:GPIO读取矩阵键盘 8个IO读16键

    目录 硬知识 矩阵键盘介绍 测试程序 Key_Board.c Key_Board.h main.c 实验现象 普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK ...

  6. 51单片机开发系列一-51单片机开发环境搭建以及入门汇编代码

    51单片机开发系列一 51单片机开发环境搭建以及入门汇编代码 象棋小子    1048272975 1. 51单片机概述 51单片机是对所有兼容Intel 8031指令系统的单片机的统称.目前教科书基 ...

  7. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  8. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

  9. 【51单片机快速入门指南】4.3: I2C读取MPU6050陀螺仪的原始数据

    目录 硬知识 特性参数 MPU6050 简介 模块重要寄存器简介 电源管理寄存器 1 陀螺仪配置寄存器 加速度传感器配置寄存器 FIFO 使能寄存器 陀螺仪采样率分频寄存器 配置寄存器 电源管理寄存器 ...

最新文章

  1. Oracle Study之--ORA-12537(TNS:connection closed) 错误案例
  2. 辗转相除法求最大公约数,非goto
  3. oracle to_char函数的使用
  4. Windows下更改MySQL数据库的存储位置
  5. MySQL使用CREATE INDEX创建索引
  6. make -j32 21 | tee show.log
  7. wireshark、tcpdump、dsniff、Ettercap、NetStumbler、netsniff-ng
  8. 认识 UML 类关系——依赖、关联、聚合、组合、泛化
  9. spring数据持久化
  10. Android Gallery组件实现循环显示图像
  11. Android View的绘制机制流程深入详解(一)
  12. mui框架下监听返回按钮
  13. 【转载】程序员历史之一
  14. OPPO Find X5系列上架预约:全球首款天玑9000旗舰
  15. Jmeter(四十八)_动态线程分析HTML测试报告
  16. php是属于什么软件,.php是什么软件?
  17. RedHat Enterprise Linux 4的新安全机制-SELinux
  18. 制冷与空调设备运行操作作业题库(含答案)
  19. (20)雅思屠鸭第二十天:雅思听力part1中各种场景词的总结
  20. 流量焦虑意外带来契机,“福禄控股们”赚钱容易做大难?

热门文章

  1. 电子商务系统的设计与实现:数据库设计
  2. 在Kali 2022.2上成功编译驱动TP-LINK TL-WN726免驱版无线USB网卡 8188GU
  3. “火星人”马斯克推论:世界很大可能性是被编程的,上帝可能是个程序员!
  4. bugku Simple_SSTI_1and 2(SSTI模板注入)
  5. MySQL之学生成绩表查询语句解析
  6. 方差分析 可汗学院统计学 笔记
  7. EXCEL VB简单使用
  8. Unity程序化地形教程集合
  9. 11-VulnHub-SkyTower 1
  10. 多玩我的世界盒子电脑版 免费官方版