• 51单片机学习笔记(郭天祥版)(2)——第一课作业、流水灯、蜂鸣器


    免费样片申请(暂时无用,不说了,很简单)


    作业讲解

    1-5点亮灯过简单,不说了

    6:尝试让第一个发光管闪烁

    闪烁,就是亮,灭,再亮,再灭这样一个循环的过程,就是写程序控制某一个IO口先输出低电平,再输出高电平,再输出低电平,如此循环,没变化一个状态要持续一个时间(即为延时)。简单的延时就用一个while或者for循环就可以。

     1 #include<reg52.h>
     2 sbit p1_1=P1^0;
     3 unsigned int a;
     4 void main()
     5 {
     6     a=50000;
     7     p1_1=0;
     8     while(a--);
     9     a=50000;
    10     p1_1=1;
    11     while(a--);
    12 }

    定义一个unsigned int(无符号整型)类型的变量a,其范围为0-65535,若超出这个值,就会取余,例如70000,那么就会取70000-65535后的值。

    这里选中这两个,这样如果一直插着单片机,然后更改代码并编译的话,会自动下载进单片机。

    你可能会按照上面的方法,但这样是不对的,不标准。因为正常执行c语言代码时,从进入main函数开始,执行完main内部的代码就结束了,但这里却又重新再执行了,因为单片机会一直重复执行main函数,但有时会出错。

    正确的写法

     1 #include<reg52.h>
     2 sbit p1_1=P1^0;
     3 unsigned int a;
     4 void main()
     5 {
     6     while(1)
     7     {
     8         a=50000;
     9         p1_1=0;
    10         while(a--);
    11         a=50000;
    12         p1_1=1;
    13         while(a--);
    14     }
    15 }

    在main函数内部再写一个while(1),将需要循环执行的代码放入while(1)的花括号内,这样单片机就会一直循环while(1)内部的内容而不出错了。


    要学会软件调试

     

    点击这个放大镜一样的东西就是打开调试了,调试前要先编译。再次点击就关闭。

    黄色箭头指着的就是下一条要执行的语句

    这个是复位,点击后让调试重头开始。

    全速执行。

    停止全速执行,只有在开启全速执行后它才会变成红色,才能使用。

    进入函数内部。

    执行下一调语句。

     

    点击Peripheral(硬件)

    Interrupt:中断

    I/O-Ports:IO口

    Serial:串行端口

    Timer:定时器

    这里选择我们现在用到的IO口的P1口Port 1

    可以看到P1上电后为oxFF,即上电后所有IO口为高电平(IO口上电后为1,其余寄存器上电后为0,上电后会自动复位,所以这里软件的复位就可以当做上电),对应的后面8位都打了√,如果√没了,对应的一位就变成了0。操作单片机就是对内部的寄存器(P1)进行操作。

    点击View,选上call stack window

     

    看到,执行过的语句变成绿色,没执行的是灰色,这里while(a--)要想执行完需要单步执行(即一次执行一句)50000次,要点50000次,很慢,所以我们可以设置断点。

    断点就是前面出现了红色,有的版本是红色的圆,设置断点的方法就是在需要的语句前方灰色处用鼠标单击。

    现在我们说一下上面的全速执行,全速执行就是一直执行,而且执行的很快,不需要你一下一下的点,但是你不知道执行到哪里了,所以我们要用到断点,这里我们不想点击50000次,所以我们在while(a--)后面那条语句设置断点,再开启全速执行,那么程序就会全速执行到断点的位置然后停止,不会执行断点那条语句。

    这里执行完全速后,a变为了65535(也是满,unsigned int类型的最大值,满和空是一个概念),意思是减空了,从原本的50000,减到0后再减一次就是65535了。


     硬件调试(在线调试)(仿真芯片)     你没买,先不用看

    仿真芯片有利于你领悟程序具体是怎么执行的

    点开设置

    点到debug这一栏。

    原本是use Simulator,现在我们点击右边的Use,选择keil Monitor-51 Driver,再点击Settings设置

    选择com口,下载程序用的com几,这里就选com几,然后点击ok。

    之后这里全部打钩,再确定。

    仿真时必须先接通电源

    然后点击debug调试

    下方会显示连接到了(Connected to Monitor-51)

    然后就按刚才方法调试即可,不同的是这里调试时,单片机也会跟着一步一步走。

    这种调试你可以知道每一条指令什么时候执行,每一种变量如何变化的。

    结束调制时先按下单片机上的复位按钮,再点debug结束


    接下来学习如何设置比较准确的延时时间

    首先,要知道,实验板的晶振频率是11.0592MHz,计算机单片机的运行速度是由其决定的

    下面的内容只需要知道一个机器周期是12个时钟周期,一个时钟周期是震荡源的周期。

     

     在调节时间的时候,需要把keil中的晶振频率改为和单片机的晶振频率相同

    下面打开调试状态

    会看到当程序运行到这里时是0.00042209s,先运行到灯亮

    0.00042752s,然后我们运行到它灭之前看看中间有多少时间,这就是我们要的延时时间,这里要设置断点,不然while(a--)我们要手动50000次....

    时间变为了0.48893555s,离500ms近了,我们微调下,把a变为51000再运行到这里就差不多了。下面的也改。

     

    下面我们看看如果不设置11.0592MHz晶振频率,用默认的24MHz会怎么样

    频率24大约是11的2倍,那么时间也差不多是1/2。

    但是这里只是模拟,对单片机没有影响,单片机还是用它本身的11.0592来计算的,不过这样你就算不准了。


    接下来学习子函数(以后写程序都是写在函数里,然后main全是调用)

    首先介绍一下宏定义define,就相当于起一个新的名字,用法#define new_name old_name

     1 #include<reg51.h>
     2 #define uint unsigned int//宏定义
     3 #define uchar unsigned char
     4 
     5 void delay();//声明函数
     6 sbit D1=P1^0;
     7 void main()
     8 {
     9     while(1)
    10     {
    11         D1=0;
    12         delay();
    13         D1=1;
    14         delay();
    15     }
    16 }
    17 
    18 void delay()//定义函数,大约是500ms的延时,
    19 {
    20     uint x,y;
    21     for(x=100;x>0;x--)
    22     {
    23         for(y=600;y>0;y--)
    24         {
    25             
    26         }
    27     }
    28 }

    这里for循环还有上面出现的while循环,当没有内部语句时,可以省略{},直接写分号

    1 void delay(uint n)
    2 {
    3     uint x,y;
    4     for(x=n;x>0;x--)
    5     {
    6         for(y=600;y>0;y--);
    7     }
    8 }

    其它自己看懂,不再赘述了

    带参数的子函数

     1 #include<reg51.h>
     2 #define uint unsigned int
     3 #define uchar unsigned char
     4 
     5 void delay(uint n);
     6 //void delay(uint );这里声明也可以写成这样(不写n),但建议写上面那种,方便,上面那种只需要在函数定义那里复制过来就可以了,不会出错。
     7 sbit D1=P1^0;
     8 void main()
     9 {
    10     while(1)
    11     {
    12         D1=0;
    13         delay(100);
    14         D1=1;
    15         delay(100);
    16     }
    17 }
    18 
    19 void delay(uint n)
    20 {
    21     uint x,y;
    22     for(x=n;x>0;x--)
    23     {
    24         for(y=600;y>0;y--)
    25         {
    26             
    27         }
    28     }
    29 }

    函数定义和函数声明的参数叫做形参(形式参数),函数调用时给的数值是实参(实际参数),因为函数定义时函数是不执行的,而只有调用时,函数才执行,其中的参数会使用你传的参数,也就是实参。


    接下来我们用stc-isp来生成延时函数

    打开后点击红框内的三角箭头,找到软件延时计算器

    先选择晶振频率,再设置延时的时间,再选择指令集STC-Y1,然后生成c代码,最后复制就可以了

     1 #include<reg51.h>
     2 #define uint unsigned int
     3 #define uchar unsigned char
     4     
     5 void Delay1ms();
     6 void delay(uint n);
     7 sbit D1=P1^0;
     8 void main()
     9 {
    10     while(1)
    11     {
    12         D1=0;
    13         delay(200);
    14         D1=1;
    15         delay(200);
    16     }
    17 }
    18 
    19 void delay(uint n)
    20 {
    21     while(n--)
    22     {
    23         Delay1ms();
    24     }
    25 }
    26 void Delay1ms()        //@12.000MHz
    27 {
    28     unsigned char i, j;
    29 
    30     i = 2;
    31     j = 239;
    32     do
    33     {
    34         while (--j);
    35     } while (--i);
    36 }

    定义一个延时1ms的函数,然后再定义一个带参数的函数,调用延时1ms的函数n次,就产生了延时n ms的函数了


    接下来是流水灯

    找到C51文件夹中Hlp文件夹下的c51帮助文档,在Reference里能看到库函数,都是写好的可以直接调用的函数

    这里我们要用到_crol_

    点开后可以看到介绍和例子,需要用到头文件intrins.h,将变量c循环左移b位,返回移动后的结果。a=0xA5(1010 0101),循环左移一位变成(0100 1011),循环左移第二位(1001 0110),循环左移第三位(0010 1101)即0x2D,循环左移一次就是整体左移一次,把最高位的放到最低位。

     1 #include<reg51.h>
     2 #include<intrins.h>
     3 
     4 #define uint unsigned int
     5 #define uchar unsigned char
     6 
     7 uchar temp;//为什么用uchar而不用uint?
     8 
     9 void Delay1ms();
    10 void delay(uint n);
    11 
    12 void main()
    13 {
    14     temp=0xfe;
    15     P1=temp;//因为uchar有8位,而uint有16位,每组IO口也是8位,所以如果我们要用uchar
    16     while(1)//先让P1=0xfe(1111 1110)
    17     {
    18         delay(300);//延时300ms
    19         temp=_crol_(temp,1);//改变temp的值
    20         P1=temp;//改变P1的值
    21     }
    22 }
    23 
    24 void delay(uint n)
    25 {
    26     while(n--)
    27     {
    28         Delay1ms();
    29     }
    30 }
    31 void Delay1ms()        //@12.000MHz
    32 {
    33     unsigned char i, j;
    34 
    35     i = 2;
    36     j = 239;
    37     do
    38     {
    39         while (--j);
    40     } while (--i);
    41 }

    其实temp这里多余,只是想让你知道定义变量要注意的地方,比如为什么不用unsigned int而用unsigned char

     1 void main()
     2 {
     3     P1=0xfe;
     4     while(1)//先让P1=0xfe(1111 1110)
     5     {
     6         delay(300);//延时300ms
     7         P1=_crol_(temp,1);//改变P1的值
     8 
     9     }
    10 }

    main可以直接改成这样


    课后作业


    补充一下蜂鸣器

    蜂鸣器原理图

       

    (我的板子是第二种)(继电器也挺重要,但暂时不说了)

    FM就是P2^3口,然后接一个电阻,这里用了一个三极管,用了它的开关作用(它还有放大作用),(蜂鸣器内阻很小(忽略)),当给P2^3低电平时,ce就导通了,就有从VCC流经蜂鸣器然后经过ce的电流。

    因此蜂鸣器的使用也很简单,0就响,1就停止。

     1 #include<reg51.h>
     2 
     3 sbit beep=P2^3;
     4 
     5 void main()
     6 {
     7 
     8     while(1)
     9     {
    10             beep=0;
    11     }
    12 }

    这样就响了

    接下里是响、停循环进行

     1 #include<reg51.h>
     2 
     3 #define uint unsigned int
     4 #define uchar unsigned char
     5 
     6 sbit beep=P2^3;
     7 
     8 void Delay1ms();
     9 void delay(uint n);
    10 
    11 void main()
    12 {
    13 
    14     while(1)
    15     {
    16             beep=0;
    17             delay(300);
    18             beep=1;
    19             delay(300);
    20     }
    21 }
    22 
    23 void delay(uint n)
    24 {
    25     while(n--)
    26     {
    27         Delay1ms();
    28     }
    29 }
    30 void Delay1ms()        //@12.000MHz
    31 {
    32     unsigned char i, j;
    33 
    34     i = 2;
    35     j = 239;
    36     do
    37     {
    38         while (--j);
    39     } while (--i);
    40 }

    这里在提一下前面说到的~(取反),原本是0,取反就是1,原本是1,取反就是0,用这个会很简单。

     1 #include<reg51.h>
     2 
     3 #define uint unsigned int
     4 #define uchar unsigned char
     5 
     6 sbit beep=P2^3;
     7 
     8 void Delay1ms();
     9 void delay(uint n);
    10 
    11 void main()
    12 {
    13 
    14     while(1)
    15     {
    16             beep=~beep;
    17             delay(300);
    18     }
    19 }
    20 
    21 void delay(uint n)
    22 {
    23     while(n--)
    24     {
    25         Delay1ms();
    26     }
    27 }
    28 void Delay1ms()        //@12.000MHz
    29 {
    30     unsigned char i, j;
    31 
    32     i = 2;
    33     j = 239;
    34     do
    35     {
    36         while (--j);
    37     } while (--i);
    38 }
  • 相关阅读:
    ElEmentUI选择器弹出框定位错乱问题解决(弹出框出现在左上角)
    Element中(Notification)通知组件字体修改(Vue项目中Element的Notification修改字体)
    解决谷歌浏览器设置font-family属性不起作用,(css中设置了font-family:没有用)css字体属性没用
    开发环境Vue访问后端接口教程(前后端分离开发,端口不同下跨域访问)
    nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.报错解决
    ssm项目中中文字符乱码
    idea使用PlantUML画类图教程
    org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3报错解决
    安装anaconda python时只能安装到默认文件夹&& 安装提示文件夹以存在问题
    生产者消费者代码学习,Producer_Consuner
  • 原文地址:https://www.cnblogs.com/IceHowe/p/10573963.html
Copyright © 2020-2023  润新知