51单片机—电动车报警器

一. 入门
1.1 开发环境的安装
  • 用什么写代码--语言是C,环境是keil
  • Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。
  • Keil安装
  • Keil 破戒
  • 使用
  1. 创建项目工程文件夹,可以当作模板Template
  2. 创建文件,取名main.c (要打开拓展名,在文件夹窗口上找 "查看",勾选"文件拓展名")
  3. 进入keil主页面,工具栏project->new uVision project->选择第一步的工程文件夹位置->输入
    工程名字->选择芯片类型AT89c52->会提示是否拷贝STARTUP.A51,选择是->生成了工程目录-

在工程目录Source Group1上右键鼠标->add Exiting file to Source Group1...->选择代码文

件main.c

  1. 编程,新手如果看不懂以下代码,可以忽略,这次实验只是强调开发流程

  2. 编译,选择输出文件有hex

    #include "reg52.h"
    sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
    sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
    void main()
    {
    led1 = 0;//根据电路图,低电平点亮led
    led2 = 0;
    while(1);
    }

1.2 用什么把代码放进单片机里面

STC-ISP 是一款单片机下载编程烧录软件,是针对STC系列单片机而设计的,可下载STC89系列、12C2052系列和12C5410等系列的STC单片机,使用简便。

  • 单片机通过type-C数据线和电脑连接(如果不识别,安装ch340驱动,在资料包中)
  • 选择单片机型号STC89C52RC
  • 选择生成的执行程序文件template.hex
  • 点击"下载/编程"按钮
  • 单片机开关拨动重新上电
  • 自动检测并下载了程序,看到灯亮。如果失败,仔细对照 以上每一步内容
二、 初识单片机
1.2.1 什么是单片机
  • 单片机(Single-Chip Microcomputer)是一种集成电路芯片,
  • 把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、
  • 多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)
  • 集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。
什么是单片机开发板
  • 基于单片机设计一些外接电路,模块以满足学习,日常调研等工作需求
  • STC89系列单片机
  • 命名规则,封装LQFP44, 特性 定时器,计数器,串口,看门狗,IO
三、 基本IO口控制
1.2.1 关于灯LED的那些事儿

思维发散:

  • 单片机编程是什么:人类要求单片机干具体的活,有点像提前写个小纸条贴冰箱上,告诉你女朋友
    煮鸡蛋不加水
  • 单片机执行程序怎么理解: 女朋友看到纸条后,照做!
  • 单片机能做什么事情: IO口供电,串口数据传输等
  • 肉眼可见的引脚是什么:方便人类对单片机IO口,串口接东西
  • 单片机CPU怎么找到IO口:通过寻址,说白了有一些地址数据,头文件帮你做很多了
  • 怎么写纸条(编程)找到IO口呢:ANSI C

sfr"指令": 用来直接描述硬件地址,小白先理解成"一组IO口"的起始地址中数据 sfr P0 = 0x80; P0 = 0;

  • 怎么找到IO口的具体一个引脚呢:

sbit"指令",对应可位寻址空间的一个位,小白先理解成"一个IO口/针脚"的地址中数据 sbit led2 = P3^6

c语言的一个字节,char型就是8位

注:sfr sbit 非c的标准库 只有在51单片机中使用

上官一号89C52有5组这样的输入输出口,分别为P0,P1,P2,P3每组对应8个针脚,P4是RC系列才有只有7个

针脚

1. sfr 指令

"sfr" 是 Special Function Register 的缩写,用于定义特殊功能寄存器的地址。通常这些寄存器用于控制微控制器的各种外设(例如I/O端口,定时器,中断控制器等)。例如,sfr P0 = 0x80; 这行代码定义了一个名为 P0 的寄存器,并将其地址设置为 0x80

sfr P0 = 0x80;  // 定义特殊功能寄存器 P0,其地址为 0x80
P0 = 0;         // 将 P0 寄存器的值设置为 0

在这个例子中,P0 是微控制器的一个 I/O 端口。通过设置 P0 的值,我们可以控制这个端口上的所有引脚。例如,将 P0 设置为 0 意味着将端口 P0 上的所有引脚都拉低(即设置为 0)。

2. sbit 指令

"sbit" 是用于定义单个位的地址。例如,可以用它来定义某个 I/O 端口的特定引脚。下面的代码定义了 P3 端口的第 6 位(引脚)。

sbit led2 = P3^6;  // 定义 led2 位,表示 P3 端口的第 6 引脚

在这个例子中,P3 是一个 I/O 端口,而 P3^6 表示这个端口的第 6 位。通过操作 led2,可以单独控制 P3 端口的第 6 引脚。例如:

led2 = 1;  // 将 P3 端口的第 6 引脚设置为高电平
led2 = 0;  // 将 P3 端口的第 6 引脚设置为低电平
总结
  • sfr****指令 :用于定义整个 I/O 端口或特殊功能寄存器。例如:sfr P0 = 0x80; 定义了地址为 0x80 的寄存器 P0
  • sbit****指令 :用于定义特定 I/O 端口的某个位。例如:sbit led2 = P3^6; 定义了 P3 端口的第 6 引脚。
四、 输入&&输出

是对单片机来讲的,IO口的 输入(把外面东西拿回来)/输出(给东西给外面)

89C52比较简单粗暴,关于引脚输入还是输出的功能不需要配置

  • 比如

    sbit IFfire = P1^0;
    int main()
    {
    int io_data;
    //什么情况叫做输入
    io_data = IFfire; // 给变量赋值,就是输入 ------ 或者理解为,这个针脚有数据啦,拿个变量来
    保存
    if(io_data == 0){
    }
    //什么情况叫做输出
    IFfire = 1; // 被给予一个数值,引起IO口电压变化(一般1输出高电平,0输出低电平),此时为输
    出,来影响外接的电路
    return 0;
    }

如何使用 sbit 指令来定义和操作一个单独的 I/O 引脚。以下是逐行的中文解释:

sbit IFfire = P1^0;  // 定义一个名为 IFfire 的位变量,它代表 P1 端口的第 0 引脚
  • sbit IFfire = P1^0;:这行代码使用 sbit 指令定义了一个位变量 IFfire,它表示 P1 端口的第 0 位(即第 0 引脚)。

    int main() // 主函数入口
    {
    int io_data; // 定义一个整型变量 io_data

  • int io_data;:定义一个整型变量 io_data,用于存储 I/O 引脚的数据。

    io_data = IFfire; // 读取 P1 端口第 0 引脚的值,并赋值给变量 io_data

  • io_data = IFfire;:这行代码将 P1 端口第 0 引脚的电平状态(高或低)读入到变量 io_data 中。这就是所谓的"输入"操作,因为它是从引脚读取数据。

    if(io_data == 0){
    // 如果 io_data 的值为 0,则执行这里的代码
    }

  • if(io_data == 0){}:检查 io_data 的值是否为 0。如果是 0,则表示 P1 端口第 0 引脚当前为低电平。

    IFfire = 1; // 将 P1 端口第 0 引脚的电平设置为高电平(输出)

  • IFfire = 1;:这行代码将 P1 端口第 0 引脚的电平设置为高电平。这是"输出"操作,因为它改变了引脚的电平,从而影响外部电路。

    return 0; // 返回 0,表示程序正常结束
    }

  • return 0;:主函数返回 0,表示程序正常结束。

总结
  • sbit IFfire = P1^0;:定义了 P1 端口第 0 引脚为 IFfire
  • io_data = IFfire;:读取 P1 端口第 0 引脚的电平状态到变量 io_data 中(输入操作)。
  • if(io_data == 0){}:检查 P1 端口第 0 引脚的电平状态是否为低电平。
  • IFfire = 1;:将 P1 端口第 0 引脚的电平设置为高电平(输出操作)。
五、52开发板入门
5.1 为什么灯会亮

得看电路图,但是不要怕,初中电路知识而已!也叫单片机原理图,是硬件设计者设计的

记住:原理图中标号一样代表是同一根"电线"

简单的串联电路,D4,D5,D6板子上有标记, D5一端通过电阻接5v,另外一端接着"LED1标志的线",我

们发现在89C52RC的电路图中也有LED1的标志,是在P3的IO口组中,在P3.7引脚,所以编程让P3.7出

低电平(0)就让D5灯完成一个串联电路,所以亮

led 表示二极管,key表示按键。

D4是完整的串联电路,通过电源5v->电阻->二极管,然后接地(GND)即可点亮。

GND 就是低电平 0;

D4不是完整的串联电路,通过电源5v->电阻->二极管,然后将P3^7口等于0,即接地(GND)可点亮。

D4不是完整的串联电路,通过电源5v->电阻->二极管,然后将P3^6口等于0,即接地(GND)可点亮。

D5为P3^7口,将P3^7口等于0就会亮。

D6为P3^6口,将P3^6口等于0就会亮。

  • 下面看一下代码:

    #include "reg52.h"

    sbit ledOne = P3^7; // i|o口赋值给变量
    sbit ledtwo = P3^6; // i|o口赋值给变量

    void main()
    {
    // D5为P3^7口,将P3^7口给个低电平,就会亮。
    // D6为P3^6口,将P3^6口给个低电平,就会亮。
    ledOne = 0;
    ledtwo = 0;
    }

5.2 怎么做,D5D6,才会闪烁
  • 使用STC-ISP自带延时函数

    #include "reg52.h"
    sbit ledOne = P3^7;
    sbit ledTwo = P3^6;
    void Delay500ms() //@11.0592MHz //使用STC工具中的延迟生成器自动生成延时函数
    {
    unsigned char i, j, k;
    i = 4;
    j = 129;
    k = 119;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }
    void main() //重复执行
    {
    //灯灭,给一个高电平
    //重复执行
    while(1){
    //灯亮,给一个P3.7低电平
    ledOne = 0 ;
    ledTwo = 0 ;
    //数数,数的期间,维持低电平,灯亮,延迟
    Delay500ms();
    //灯灭,给一个高电平
    ledOne = 1;
    ledTwo = 1 ;
    //数数,数的期间,维持高电平,灯灭,延迟
    Delay500ms();
    }
    }

5.2.1打开STC-ISP软件---找到软件延时计算器,按照以下我给参数进行修改。

一步使代码变万能

软件所生成的函数是延时 500ms,就是说单片机执行这个函数的程序体时用时为 500ms,那么首先我们用 while 循环把程序体框住,然后每执行一次让控制 while 循环结束的变量减一,这个变量我们通过形参传递到函数中。

注意:当使用 nop() 函数(可理解为软件延时)时,必须在开头添加头文件 #include <intrins.h>。不然回报错。

  • 优化后的代码如下:

    void Delay500ms() //@11.0592MHz //使用STC工具中的延迟生成器自动生成延时函数
    {
    unsigned char i, j, k;
    i = 4;
    j = 129;
    k = 119;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }

至此,51 单片机的延时函数就编写完成啦, 快去试着生成一个延时函数,将它应用到你的项目当中吧。

1.2.2 按键控制灯

原理:按键和灯不是我们传统理解的思维,传统按键和灯是在同一个电路中的。而我们单片机编程按键

和灯是分开的两个电路,通过单片机作为媒介来处理数据,通过逻辑来实现按键控制灯

查询法按键控制灯

  • 怎么知道sw1按键被按下

KEY1位置和GND接通,表现为低电平,值为0

  • 怎么知道sw1按键没有被按下

KEY1位置通过上拉电阻到5V,表现为高电平,值为1

通过图a2得知

同理LED的分析,

KEY1接到STC89C52RC的P2.1口,我们只要不断检测P2.1口的值(0-按下,1-松开)就知道按键是

否被按下

  • 按键控制灯

    #include "reg52.h"
    sbit key1 = P2^1;
    sbit ledOne = P3^7;
    void main()
    {
    while(1){
    //注意:用"=="两个等于号表示判断,新手容易犯错
    if(key1 == 0){ //KEY1位置和GND接通,表现为低电平,值为0
    //灯亮,给一个P3.7低电平
    ledOne = 0;
    }
    }
    }

  • 按键控制灯,SW1开,SW2关, 软件消除抖动

    #include "reg52.h"
    #include <intrins.h>
    sbit key1 = P2^1;
    sbit key2 = P2^0;
    sbit ledOne = P3^7;
    void Delay50ms() //@11.0592MHz
    {
    unsigned char i, j, k;
    nop();
    nop();
    i = 3;
    j = 26;
    k = 223;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }
    void main()
    {
    //查询法检测,是否被按下
    while(1){
    if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
    {
    //感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
    //软件消除抖动
    Delay50ms();
    if(key1 == 0){
    //灯亮,给一个P3.7低电平
    ledOne = 0;
    }
    }
    if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
    Delay50ms();
    if(key2 == 0){
    //灯亮,给一个P3.7低电平
    ledOne = 1;//灭
    }
    }
    }

  • 按键按下一次,灯状态改变

    #include "reg52.h"
    #include <intrins.h>
    sbit key1 = P2^1;
    sbit key2 = P2^0;
    sbit ledOne = P3^7;
    void Delay50ms() //@11.0592MHz
    {
    unsigned char i, j, k;
    nop();
    nop();
    i = 3;
    j = 26;
    k = 223;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }
    void main()
    {

      ledOne = 1;  //初始灯是灭的状态
      //查询法检测,是否被按下
      while(1){
          if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
          {
          //感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
          //软件消除抖动
          Delay50ms();
              if(key1 == 0){
              //记住,key1被按下,记住,在其他地方点灯
                   ledOne = !ledOne; 
                  }
              }	
              if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
                   ledOne = 1;  
              }
      }
    

    }

  • 状态位来控制LED

    #include "reg52.h"
    #include <intrins.h>

    #define ON_STATUS 1
    #define OFF_STATUS 0
    sbit key1 = P2^1;
    sbit key2 = P2^0;
    sbit ledOne = P3^7;
    void Delay10ms() //@11.0592MHz
    {
    unsigned char i, j;

      	i = 18;
      	j = 235;
      	do
      	{
      		while (--j);
      	} while (--i);
      }
    

    void main()
    {
    int ledMark = OFF_STATUS;
    ledOne = 1; //初始灯是灭的状态
    //查询法检测,是否被按下
    while(1){
    if(key1 == 0)//KEY1位置和GND接通,表现为低电平,值为0
    {
    //感觉被按下,不知道是抖动还是人为,延迟50ms再判断一次
    //软件消除抖动
    Delay10ms();
    if(key1 == 0){
    //记住,key1被按下,记住,在其他地方点灯
    ledMark = ON_STATUS;
    }
    }
    Delay10ms();
    if(key2 == 0){//KEY2位置和GND接通,表现为低电平,值为0
    ledMark = OFF_STATUS;
    }
    if(ledMark == OFF_STATUS){
    ledOne = 1;
    }
    else{
    ledOne = 0;
    }
    }
    }

六、入门项目电动车报警器

1.3.1 硬件清单列表

振动传感器模块,继电器模块,433M无线模块,反应出来的代码都是高低电平,跟以上学习按键,LED

并没有区别

但是!做出来有乐趣,好玩刺激。

1.3.2 振动传感器控制灯

通过我们已经掌握的LED来了解下振动传感器是怎么回事

  • 如何知道是否发生振动

振动传感器检测是否有振动产生。

  • 振动后的信号表现又是什么

传感器监测到振动之后,向I|0输出低电压。绿灯会亮。如果没有监测到振动时,就输出高电压

  • 振动传感器控制灯

    #include "reg52.h"
    sbit led1 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
    sbit vibrate = P3^3;//Do接到了P3.3口 振动传感器
    void Delay2000ms() //@11.0592MHz
    {
    unsigned char i, j, k;
    // nop();
    i = 15;
    j = 2;
    k = 235;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }
    void main()
    {
    //查询方式判断是否发生震动
    while(1){
    if(vibrate == 0)//模块说明告诉我们,震动的话,D0输出低电平
    {
    led1 = 0;//亮灯
    Delay2000ms(); // 延迟2秒
    led1 = 1;
    }
    else{
    led1 = 1;//灭灯
    }
    }

1.3.3 继电器工作逻辑

其实就是电子开关,怎么开怎么关弄清楚就可以了

  • 怎么控制"闭合"开关呢
    • 传感器监测到振动之后,向I|0输出低电压。继电器开关闭合。
  • 怎么控制"断开"开关呢
    • 默认是闭合状态,如果没有监测到振动时,就输出高电压,继电器开关闭合。

通过继电器来控制电路,比如智能插座,比如220V的灯,比如我们项目不带开关的傻瓜式报警器

当设置继电器为低电平处罚时,STC89C52RC的IO输出低电平,就会导致COM口和NO口闭合,也

就是完成报警器的串联电路,开始响

现在我们就可以来写程序,完成振动控制警报的功能

#include "reg52.h"
sbit vibrate = P3^3;//Do接到了P3.3口
sbit switcher = P1^1;  //继电器
void Delay2000ms() //@11.0592MHz
{
    unsigned char i, j, k;
    // _nop_();
        i = 15;
        j = 2;
        k = 235;
    do
        {
            do
            {
                while (--k);
        } while (--j);
    } while (--i);
}
void main()
{
    //查询方式判断是否发生震动
    while(1){
        if(vibrate == 0)//模块说明告诉我们,震动的话,D0输出低电平
        {
        //当发生震动适合,导通继电器,给继电器IN一个低电平
            switcher = 0;
            Delay2000ms(); //闭合两秒之后,继电器断开
            switcher = 1;//高电平,继电器N0和COM不通
        }
        else{
            switcher = 1;
        }
    }
}
1.3.4 遥控发送接收433M

https://wenku.baidu.com/view/8fe8f444bed5b9f3f80f1c33.html

  • 遥控按下后信号怎么被接收
  • 接收后的信号表现又是什么
    • 默认低电平,按键之后是高电平。
  • 遥控控制LED

    #include "reg52.h"
    sbit D0_ON = P1^2; //遥控传感器 A键
    sbit D1_OFF = P1^3; //遥控传感器 B键
    sbit switcher = P1^1; // 继电器
    void main()
    {
    //查询方式哪个按键被按下
    while(1)
    {
    if(D0_ON == 1)//收到遥控信号A,D0表现为高电平
    {
    //A被按下,我们导通继电器,给继电器IN一个低电平
    switcher = 0; //喇叭报警
    }
    if(D1_OFF == 1)//收到遥控信号C,D1表现为高电平
    {
    //B被按下,我们不导通继电器,给继电器IN一个高电平
    switcher = 1; //喇叭关闭
    }
    }
    }

1.3.4 项目开发

接线

  • 开发流程代码

    #include "reg52.h"
    #include<intrins.h>
    #define J_ON 1
    #define J_OFF 0
    sbit switcher = P1^0; // 继电器
    sbit D0_ON = P1^1; // A 键
    sbit D1_OFF = P1^2; // B 键
    sbit vibrate = P1^3; // 振动传感器
    void Delay2000ms() //@11.0592MHz
    {
    unsigned char i, j, k;
    nop();
    i = 15;
    j = 2;
    k = 235;
    do
    {
    do
    {
    while (--k);
    } while (--j);
    } while (--i);
    }
    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()
    {
    int mark = J_OFF;
    while(1)
    {
    //1. 如果a按键被按下,设定为开启警报模式
    if(D0_ON == 1){
    //长响,表示进入警报模式
    switcher = 0;
    Delay2000ms();
    switcher = 1;
    //设定警报模式标记
    mark = J_ON ;
    }
    //2. 如果b按键被按按下,设定为关闭警报模式
    if(D1_OFF == 1){
    //短响,表示进入解除警报模式
    switcher = 0;
    Delay500ms();
    switcher = 1;
    //设定警报解除模式标记
    mark = J_OFF ;
    }
    //3. 如果标记是在警报模式下
    if(mark == J_ON){
    //3.1 如果发生了震动
    if(vibrate == 0){
    //喇叭响,给继电器低电平,导通
    switcher = 0;
    Delay2000ms();//闭合2秒之后,继电器断开
    switcher = 1;//高电平,继电器N0和COM不通
    }//3.2 如果不发生震动
    else{
    //喇叭不响,给继电器高电平,不导通
    switcher = 1;
    }
    }
    }
    }

相关推荐
老猿讲编程20 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk1 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*1 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue1 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man1 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸3 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农3 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
秋の花3 小时前
【JAVA基础】Java集合基础
java·开发语言·windows