首页天道酬勤,

,

张世龙 05-13 02:01 109次浏览

(指南者)一) 51单片机学习系列文章51什么是单片机(为什么学51单片机)我能做什么)如何用51单片机IO

本系列中的代码是基于STC12C5A60S2型号的芯片编写的,本系列文章的目的是带领lmdxlb们进入51单片机。

51关于单片机

在学习51单片机之前,我们总是需要知道什么是51单片机吗? 你为什么要学那个? 你学到了能做什么吗?

51什么是单片机? 其实我们可以把51单片机视为特别老的电脑。 目前的电脑只有16G内存、1T外部存储器,单片机只有3358www.Sina.sina .

你为什么要学51单片机? 为什么大多数学习电子的人会选择256Byte RAM单片机作为入门呢? 我们可以使用1024KB FLASH51入门。 您可以拥有大量库,只需简单的函数调用即可实现相对复杂的功能,也可以使用ESP32单片机入门。 与3ESP8266单片机相比,具有更强的功能,初学者也熟悉基础,找工作也学习STM32单片机我认为3358www.Sina.com/单片机是电子lmdxlb的最好选择。51单片机操作并不那么困难。 各种概念也不像3358www.Sina.com/单片机那样难以理解,但也不像http://wwwwww.sina.com/单片机那样难以理解

学习了能做什么的51单片机本身其实并不具备很强的功能,但用它做购物车、自动门锁、红灯车等还是令人满意的。

51单片机的使用技巧

图中可以看到51型号为51单片机的针脚图。 每个管脚都有一个称为管脚号的数字。 这与实际芯片上的管脚的顺序相同,但除此之外,还有与各管脚对应的名称,所以实际上

VCC和GND :电源引脚(为芯片供电) RST (复位引脚)重新运行芯片内部的程序,理解为重新启动) XTAL1/2(晶体振动接入引脚P0/P1/P2/P3 )普通用户IO端口可以下面介绍的控制方法可以通过编写程序来控制单片机,但从编写程序到运行单片机都是可行的

首先,我们需要认识到,我们使用像c语言这样的人能理解的编程语言,实现了成为。 但是单片机不能理解编程语言,只能理解由0和1组成的机器语言,所以这个时候很多时候需要把我们写的编程语言转换成机器语言的编译器,可以使用keil等编译器编译器将我们编写的代码打包到hex后缀的文件中,然后通过串行端口将hex文件发送到单片机。 单片机将程序存储在内部内存空间中,开机时运行程序,在内部完成运算,操作IO端口实现具体操作(如点亮或通信)。 控制IO输出的#include 'STC12C5A60S2'//这个我们平时包含的头文件不一样。 平时我们编写c语言程序时,总是需要包含#includestdio.h这样的头文件。 这是因为这个头文件中有我们常用的类似printf的函数。 //51写单片机也一样,不同的是,我们并不经常使用printf这个函数。 51需要操作单片机内部的寄存器。 (什么是寄存器? 寄存器的概率在本系列的报道之后叙述) )。 该寄存器的定义在您刚才看到的STC12C5A60S2.H头文件中,不同于芯片使用的头文件。 //如何控制IO端口的输出? 其实很简单。 直接将值代入IO端口即可。 P01=1; //这样,从P01这个口中输出了很酷的信封。 //其实除了上面的写法以外,还有代入方法。 P0^1=1; P0_1=1; //这三种方法一般通用。 由于不同的头文件限制,某些头文件可能无法单独使用。 为了识别当前使用的单片机头文件支持哪种写法,请尝试三种写法。 //虽然上面是单独操作名为P0^1的IO端口,但实际上也可以看到所有管脚都分为不同的类。 例如,从P0^0到P0^7属于P0,可以直接用一句话操作P0的所有IO端口吗? P0=0x12; 可以看到,如果直接为//P0指定值,则可以直接更改P0的8个IO端口。0x表示十六进制的含义,它将p0的8个IO端口分配给0

0010010,其中最低位代表了P00,最高位代表了P07,这样就很清晰每个IO口的状态了。P0M0 = 0xff;//P0M0是一个寄存器,暂时不用管太多,只需要记住作用就行,这句话的含义是将P0口输出模式变成推挽输出(推挽输出的概念在之后的文章中会讲解),它的作用就是增大P0口的电流。 读取IO口状态 //我们已经可以控制每个IO口的状态了,但是当我们的IO口并不想作为输出,而是由外界传输酷炫的信封或者低电平给单片机IO口,单片机IO口负责读取这个电平应该怎么做呢?//做法其实很简单,我们可以直接读取if (P1^0 == 1){//可以通过if条件语句来判断此时IO口的状态;//语句}if (P0 == 0x01) {}//一次判断P0的8个IO也是可以的//除了用if判断,我们还可以直接读取sbitstate;//sbit在C语言中没有,是51单片机特有的变量类型,代表了定义一个一位宽的变量来存储一个IO口的值state = P0^1;//将P0^1口的状态直接赋值给state变量,就读取到了IO口的状态//也可以读取8个IO的状态charstate;//这时我们就设置一个8位宽的变量来存储IO口的值state = P0;//直接将P0上8个IO口的值存放到变量state上 代码例程

对于单片机的控制已经了解了,我们可以做一些简单的玩意儿了。

这是之后讲解代码的原理图。

流水灯

首先,我们使用的是 led 灯,也叫发光二极管,它具有单向导通的特性,图中我将 led 的负极接在了 GND 上,所以,当我的 P0IO 口输出酷炫的信封的时候,相应的 led 灯就会被点亮。
怎么让 led 出现流水的效果呢?我们让 P00 先变成酷炫的信封,其他变成低电平,就可以让第一个灯亮,然后将 P01 变为酷炫的信封,其他变成低电平,循环下来,就是一个流水灯了。

#include "STC12C5A60S2"//首先包含一个51单片机的头文件#include <intrins.h>//这个头文件里面包含了后面使用到的_nop_()函数,具体作用后面会说unsigned int k = 0;//定义一个全局变量void Delay_ms(unsigned int time) {//定义一个延时函数,用于后面的延时,具体作用后面会说unsigned char i, j;//定义一个局部变量,此变量只在当前函数有用while (time--) {//有外部传入参数决定循环次数//在51单片机的引脚有两个接入晶振的引脚,晶振在电路中充当了心脏在人体中的作用,他会自动给出一定频率的震动,单片机靠着这个频率完成内部复杂的功能_nop_();//等待一个时钟周期,就是晶振震动一个周期的时间,单片机不做任何事_nop_();_nop_();i = 11;j = 190;do {//两层循环,在这儿只是单纯的空循环,不做任何事情,因为单片机运行一条程序需要时间,这儿就是使时间白白浪费掉,起到延时的作用while (j--);} while (i--);}}void main(void) {P0M0 = 0xff;//将P0设置成推挽输出while (1) {//死循环,让程序一直运行for (k = 0; k < 8; k++) {P0 = 0x01 << k;//利用for循环,k的值每次就只能在0到7中顺序改变,利用0x01左移k位,就可以实现流水灯了Delay_ms(500);//每次点亮一个灯后都延时500ms,如果不加延时,流水灯的速度就会非常的快,人的眼睛反应不过来,最后你就会看到所有灯都亮的情况,所以为了适应人眼,就主动的延时一段时间,让人眼可以清晰的看清流水灯}}} 按键控制

图中可以看出,我们将 IO 口连到了按键上,并将按键的另一端接到了 GND ,在 51 单片机中, IO 口默认是输出酷炫的信封,当按键按下, IO 连通到 GND 此时 IO 口的状态变成低电平,我们就可以通过判断 IO 口是否是低电平来进行判断按键是否按下。
我们理想的情况下,按键一按下就立马变成低电平,按键松开就立马恢复成酷炫的信封:

而实际情况下,按键是一个机械结构,按下的瞬间和松开的瞬间会有数次的抖动:

由于抖动的存在,单片机的 IO 口又只能读取酷炫的信封和低电平两种状态,所以最终的波形是:

实际生活中,按键大概率会由于磕磕碰碰产生一些抖动,可能在你没有按下的情况下,按键也会发生抖动而出现低电平的情况,所以我们不能检测到低电平就判断按键已经按下,一般情况我们需要判断到低电平后再等待一段时间,再次判断按键是否为低电平,如果此时按键为低电平,我们才确定按键按下。
当然,有些情况我们希望长按按键可以连续操作,例如长按音量 + 让音量一直增加,有些情况下我们只希望按键按一次只触发一次。
这儿我们就要用到松键检测,如果连续操作就不使用松键检测,如果按键按一下只生效一次,我们就要使用松键检测。

#include "STC12C5A60S2.H"#include <intrins.h>sbit key = P2^1;//将按键连的引脚定义成key这个名字,方便后面查看void Delay_ms(unsigned int time) {unsigned char i, j;while (time--) {_nop_();_nop_();_nop_();i = 11;j = 190;do {while (j--);} while (i--);}}void main(void) {P0 = 0x00;//将P0所有IO口输出低电平while (1) {if (key == 0) {//判断按键是否有按下的趋势Delay_ms(10);//延时10ms等待抖动消失,按键消抖if (key == 0) P00 = !P00;//再次判断按键是否真的按下,如果按下,就让P00口连接的led亮灭翻转while (!key);//松手检测,当按键按下时,key值为0,!key值为1,所以wsdxmy在这儿//当松手后,按键恢复成1,!key为0,跳出循环}}} 逻辑运算

我们可以使用 IO 口输出不同的波形。

#include "STC12C5A60S2"unsigned char time = 0;void main(void) {while (1) {P30 = !P30;//让P30不断翻转,最终P30不断呈现方波的样子if (time++ == 9) {time = 0;//time用于计时,让每次进入这儿的时间相等,所以对time赋初值,或者称为清零(赋初值和清零是两个概念,这儿初值正好是0,不要混了)P31 = !P31;//让P31以P30翻转速度的十分之一速度翻转time从0到9是十次}P32 = !(P30 & P31);//将P30和P31的电平做逻运算后的结果让P32显示P33 = !P30 | !P31;}}
, ,