感应开关盖垃圾桶项目实现.md

news2024/11/15 16:53:54

1.项目接线

接线示意图和实物图

示意图和接线说明:

  • 舵机控制口P1.1(定时器0中断);
  • 超声波Trig接P1.5 ,Echo接P1.4 ;
  • 蜂鸣器接P2.0 口;
  • 震动传感器接P3.2 口(外部中断0)。
image-20230424154750278

实物图(未封装):

image-20230424155200026

信号传输路线

路线1: 单片机P1^5引脚 ——> 超声波模块Trig引脚 ——> 超声波模块Echo引脚 ——> 单片机P1^4引脚 ——> 单片机P1^1引脚 ——> SG90舵机PWM引线

路线2:振动信号 ——> 振动传感器DO引脚 ——> 单片机P3^2引脚 ——> 单片机P1^1引脚 ——> SG90舵机PWM引线

路线3:单片机P2^0引脚 ——> 蜂鸣器I/O引脚


2.项目实现流程

基本控制逻辑

  1. 业务需求
  • 功能1:检测靠近时,垃圾桶自动开盖并伴随蜂鸣器滴一声,2秒后关盖
  • 功能2:发生震动时,垃圾桶自动开盖并伴随蜂鸣器滴一声,2秒后关盖
  • 功能3:按下按键时,垃圾桶自动开盖并伴随蜂鸣器滴一声,2秒后关盖
  1. 控制逻辑: 可以看出本项目包含两三种模式
  • 超声波感应工作模式(配合舵机)
    • 舵机用定时器0
    • 超声波用定时器1
  • 查询的方式添加按键控制(配合舵机)
  • 查询的方式添加震动控制(配合舵机)
    • 使用外部中断0配合震动控制

模式1(超声波控制舵机)——定时器中断

​ 首先对初始化定时器这部分代码进行整合:我们让超声波用定时器1,让舵机用定时器0。根据定时器编程的思路,针对之前的代码修改以下东西,更改完后测试代码:

  1. TMOD寄存器配置定时器0和1的工作模式为16位:回顾51芯片手册第7.1.1小节

    image-20230423131507959
    • 定时器0:

      • 让TMOD寄存器的高4位不变,低4位全部“置0”:TMOD &= 0XF0;
      • 让TMOD寄存器的高4位不变,第0位“置1”:TMOD |= 0X01;
    • 定时器1:

      • 让TMOD寄存器的低4位不变,高4位全部“置0”:TMOD &= 0X0F;
      • 让TMOD寄存器的低4位不变,第4位“置1”:TMOD |= 0X10;
  2. 配置定时器0和1的起始数数位置:回顾51芯片手册第7.1.1小节

    image-20230423132914210
    • 定时器0:舵机定一个0.5ms出来

      • TL0 = 0X33;
      • TH0 = 0XFE;
    • 定时器1:超声波从0开始数数

      • TL1 = 0;
      • TH1 = 0;
  3. TCON寄存器配置定时器0和1的溢出标志位清零

    image-20230418230456964
    • 定时器0:TF0 = 0;
    • 定时器1:TF1 = 0;
  4. IE寄存器配置定时器0和1开启中断:回顾51芯片手册第6.2小节

    image-20230420220024273
    • 定时器0:舵机需要定时器中断来软件模拟PWM
      • EA = 1;
      • ET0 = 1;
    • 定时器1:超声波不需要定时器中断,数数就行了
  5. TCON寄存器配置定时器0和1开始数数

    image-20230418230722881
    • 定时器0:TR0 = 1;
    • 定时器1:TR1 = 1;

​ 对超声波和舵机测试后的代码进行整合,经过学习,我整理出如下代码(用到的硬件是超声波传感器和舵机),接下来我们对如下代码进行优化,二次开发即可:

  1. 思路

    全局变量:
        sfr指令直接找到AUXR寄存器: sfr AUXR = 0X8E;    //因为AUXR没有在reg52.h中声明
        sbit指令找到P1这个I/O口组的第5位,用作输出口,传递tirg信号给超声波传感器:
            sbit ultrasonicTrig = P1^5;
        sbit指令找到P1这个I/O口组的第4位,用作输入口,从超声波传感器接收echo信号:
            sbit ultrasonicEcho = P1^4;
        sbit指令找到与D5这个led对应的引脚: sbit ledD5 = P3^7;
        sbit指令找到与D6这个led对应的引脚: sbit ledD6 = P3^6;
        sbit指令找到P1这个I/O口组的第1位,用作输出口,传递PWM信号给舵机: sbit sg90_servo = P1^1;
        //sg90_servo的传递路线是:API6 ———> 定时器0中断(中断1)
        定义一个在定时器0的中断服务程序中用于计数的全局变量cnt: int cnt = 0;
        定义一个代表舵机角度的全局变量servoAngle: int servoAngle;   
        //servoAngle的值需要根据舵机的参数确定,传递路线为:API6 ——> 定时器0中断(中断1)
    
    1. 调用API1. 初始化定时器1,用于超声波传感器计时
    2. 调用API5. 初始化定时器0,用于舵机绘制PWM波形图
    3. 调用API6. 初始化舵机到0度转动位置,让垃圾桶处于关盖状态
    4. while死循环,不断用超声波传感器测出距离,达到临界值后转动舵机,同时用led进行测试
        4.1 调用API2. 获取超声波传感器与障碍物的距离,保存在变量distance中:
            distance = get_distance();
        4.2 判断距离是否小于10cm,判据是distance < 10
            4.2.1 如果是,调用API9. 让舵机带动垃圾桶盖处于打开状态:
                    调用API9: openStatus();
            4.2.2 否则,调用API10. 让舵机带动垃圾桶盖处于关闭状态:
                    调用API10:closeStatus();
    
    中断1: 封装定时器0的中断服务程序, void Timer0_Routine()   interrupt 1
    //每当定时器0爆表都会由硬件自动调用该函数,目的是用定时器中断软件模拟PWM波形,输出给SG90舵机
        1.1 修改代表数数次数的循环变量cnt,让其自加1: cnt++;
        1.2 程序清零:令溢出标志位TF0“置0”: TF0 = 0;
        1.3 重新初始化寄存器TL0和TH0,重新确定计数起点:
            TL0 = 0X33;
            TH0 = 0xFE;
        1.4 判断是否数到与角度对应的数值,其中舵机0度位置对应数值1,即高电平0.5ms,...,
            舵机135度位置对应数值4,即高电平2.0ms, 判据是cnt <= servoAngle
        //内在逻辑:根据设置的转动角度servoAngle,实时绘制PWM波形图
        //注意事项: 判据到底有没有等于号要根据你在main函数中初始化的PWM波形图进行选择
            1.4.1 如果是,说明需要把电平拉高: sg90_servo = 1;
            1.4.2 否则,把电平拉低:  sg90_servo = 0;
        1.5 判断是否到达20ms,即是否爆表40次,判据是cnt == 40
        //内在逻辑:利用40次爆表,确定PWM波形的周期是20ms
            1.5.1 如果是,说明需要重置cnt: cnt = 0;
            1.5.2 否则,啥也不干
    
    /* 一级函数:f1 f2 f5 f6 f9 f10 */
    f1. 封装初始化定时器1的API: void initT1();
    //用于超声波传感器测距,所以不着急开始数数,也不需要开启中断
        f1.1 禁用ALE信号,降低单片机时钟对外界的电磁辐射: AUXR &= 0x1F;
        f1.2 通过TMOD寄存器配置定时器16位工作模式:
                TMOD &= 0X0F;
                TMOD |= 0X10;  
        f1.3 通过TL0和TH0寄存器,初始化定时器,从0开始数数:
                TL1 = 0;
    			TH1 = 0;
    f2. 封装利用超声波传感器计算距离的API: double get_distance();
        f2.1 调用API3. 给超声波的trig端口至少10us的高电平: start_ultrasonic();
        f2.2 echo引脚由低电平跳转到高电平代表开始发送超声波,波发出的那一下开始启动定时器
                根据超声波时序图,用空循环体,暂时卡死程序: while(ultrasonicEcho == 0);
                定时器开始计时: TR1 = 1;
        f2.3 echo引脚由高电平跳转到低电平代表波返回来了,停止定时器计数
                根据超声波时序图,用空循环体,暂时卡死程序: while(ultrasonicEcho == 1);
                定时器停止计时: TR1 = 0;
        f2.4 根据定时器数一次用时1.085us的特点,计算超声波发送和返回经历的时间,保存在变量time中:
            time = ((TH1<<8) + TL1)*1.085;
        f2.5 根据公式计算出超声波传感器和障碍物之间的距离,保存在变量distance中:
            distance = time * 0.034 / 2;    //确定量纲: 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
        f2.6 定时器1清零:
                TL1 = 0;
                TH1 = 0;
        f2.7 返回distance
    f5. 封装初始化定时器0的API,在11.0592MHz的晶振频率下定0.5ms出来: void initT0();   
    //用于绘制舵机的PWM波形图,0.5ms是控制舵机的最小时间单位
        f5.1 禁用ALE信号,降低单片机时钟对外界的电磁辐射: AUXR &= 0x1F;
        f5.2 通过TMOD寄存器配置定时器16位工作模式:
                TMOD &= 0XF0;
                TMOD |= 0X01;  
        f5.3 通过TL0和TH0寄存器,初始化定时器,定一个0.5ms出来:
                TL0 = 0x33;
                TH0 = 0xFE;
        f5.4 让溢出标志位清零: TF0 = 0;
        f5.5 打开定时器0的中断开关:
                EA = 1;
                ET0 = 1;
        f5.6 通过TCON寄存器的运行控制位TR0,让定时器开始数数: TR0 = 1;
    f6. 封装初始化舵机位置的API: void initSG90_0degree();
        f6.1 调用API8. 让系统稳定一下,减少软件模拟PWM信号的误差: Delay300ms();
        f6.2 修改全局变量sg90_servo,让PWM波形从低电平开始: sg90_servo = 0;
        f6.3 修改全局变量servoAngle,让舵机初始角度为0度:
            servoAngle = 1;
            cnt = 0;
    f9. 封装舵机带动垃圾桶盖处于打开状态的API: void openStatus();
        f9.1 用LED作为测试:
            ledD5 = 0;
            ledD6 = 1;
        f9.2 修改全局变量servoAngle,让舵机转到135度位置,并保持2s时间
            servoAngle = 4;
            cnt = 0;
            调用API7: Delay2000ms();
    f10. 封装舵机带动垃圾桶盖处于关闭状态的API: void closeStatus();
        f10.1 用LED作为测试:
            ledD5 = 1;
            ledD6 = 0;
        f10.2 修改全局变量servoAngle,让舵机转到0度位置,仅维持0.15s时间
            servoAngle = 1;
            cnt = 0;
            调用API11: Delay150ms();
    
    /* 二级函数: f3 f4 f7 f8 f11 */
    f3. 封装启动超声波传感器的API: void start_ultrasonic();
        f2.1 修改全局变量ultrasonicTrig,让它一开始处于低电平: ultrasonicTrig = 0;
        f2.2 修改全局变量ultrasonicTrig,让它处于高电平,并保持10μs:
            ultrasonicTrig = 1;
            调用API4: Delay10us();
        f2.3 修改全局变量ultrasonicTrig,让它回到低电平:
    f4. 封装软件延时10微秒的API,用于给超声波传感器trig引脚10us的高电平: void Delay10us();
    f7. 封装软件延时2s的API,用于打开垃圾桶盖时,即使感应不到物体也能保持开盖: void Delay2000ms();
    f8. 封装软件延时0.3s的API,用于稳定程序,减少软件模拟PWM信号的误差: void Delay300ms();
    f11. 封装软件延时0.15s的API,用于防止物体快速接近传感器时也会转动舵机的情况(有点像消抖): void Delay150ms();
    
  2. 代码

    #include "reg52.h"
    #include "intrins.h"
     
    sfr AUXR            = 0x8E;
    sbit ultrasonicTrig = P1^5;
    sbit ultrasonicEcho = P1^4;
    sbit ledD5          = P3^7;
    sbit ledD6          = P3^6;
    sbit sg90_servo     = P1^1;
    int cnt = 0;
    int servoAngle;
     
    /* API1: 定时器T1的初始化@11.0592MHz,我们不关心初值,从0开始计算就行,用于超声波传感器 */
    void initT1();
    /* API2. 超声波计算距离 */
    double get_distance();
    /* API3: 启动超声波传感器 */
    void start_ultrasonic();
    /* API4: 软件延时10微秒,用于给超声波传感器trig引脚10us的高电平 */
    void Delay10us();
    /* API5: 定时器T0的初始化,定0.5ms出来@11.0592MHz,用于舵机 */
    void initT0();
    /* API6. 初始化sg90舵机到0度位置 */
    void initSG90_0degree();
    /* API7: 软件延时2s,用于打开垃圾桶盖时,即使感应不到物体也能保持开盖2s */
    void Delay2000ms();
    /* API8: 软件延时0.3s,用于稳定程序,减少软件模拟PWM信号的误差 */
    void Delay300ms();
    /* API9: 测试,代表舵机带动垃圾桶盖打开状态 */
    void openStatus();
    /* API10: 测试,代表舵机带动垃圾桶盖关闭状态 */
    void closeStatus();
    /* API11. 软件延时0.15s,用于在关盖状态进行延时,防止物体快速接近传感器时也会转动舵机 */
    void Delay150ms();
     
    void main(void)
    {
        double distance;
        initT1();               //定时器1用于超声波传感器
        initT0();               //定时器0用于舵机
        initSG90_0degree();     //初始化舵机,让垃圾桶处于关盖状态
        while(1){
            distance = get_distance();
            if(distance < 10){         
                openStatus();
            }else{
                closeStatus();
            }
        }  
    }
     
    void initT1()
    {
        AUXR &= 0x1F;       //禁用ALE信号,降低单片机时钟对外界的电磁辐射
        TMOD &= 0X0F;        
        TMOD |= 0X10;       //配置定时器1为16位工作模式
        TL1 = 0;       
        TH1 = 0;            //初始化定时器,从0开始就行
        //定时器1不着急开始数数
    }
     
    double get_distance()
    {
        double time;
        double distance;
        /* 1.给超声波的trig端口至少10us的高电平 */
        start_ultrasonic();
        /* 2.echo引脚由低电平跳转到高电平代表开始发送超声波,波发出的那一下开始启动定时器 */
        while(ultrasonicEcho == 0); //空循环体,暂时卡死程序
        TR1 = 1;
        /* 3.echo引脚由高电平跳转到低电平代表波返回来了,停止定时器计数 */
        while(ultrasonicEcho == 1); //空循环体,暂时卡死程序
        TR1 = 0;
        /* 4.计算超声波发送和返回经历的时间 */
        time = ((TH1<<8) + TL1)*1.085;  //us为单位
        /* 5.计算出超声波传感器和障碍物之间的距离,先确定量纲: 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us */
        distance = time * 0.034 / 2;    //cm为单位
        /* 6.定时器1清零,重新计时 */
        TL1 = 0;
        TH1 = 1;
        return distance;
    }
     
    void start_ultrasonic()
    {
        ultrasonicTrig = 0;
        ultrasonicTrig = 1;
        Delay10us();
        ultrasonicTrig = 0;
    }
     
    void Delay10us()        //@11.0592MHz
    {
        unsigned char i;
     
        i = 2;
        while (--i);
    }
     
    void initT0()
    {
        AUXR &= 0x1F;       //禁用ALE信号,降低单片机时钟对外界的电磁辐射
        TMOD &= 0XF0;        
        TMOD |= 0X01;       //配置定时器0为16位工作模式
        TL0 = 0x33;    
        TH0 = 0xFE;         //初始化定时器,定一个0.5ms出来
        TF0 = 0;            //让溢出标志位清零
        EA = 1;             //打开总中断EA
        ET0 = 1;            //打开定时器0的中断ET0
        TR0 = 1;            //定时器0开始数数
    }
     
    void initSG90_0degree()
    {
        Delay300ms();           //让系统稳定一下
        sg90_servo = 0;         //初始化PWM波形从低电平开始
        servoAngle = 1;         //初始角度是0度
        cnt = 0;
    }
     
    //定时器0的中断服务程序,目的是用定时器中断软件模拟PWM波形,输出给SG90舵机
    void Timer0_Routine()   interrupt 1   
    {
        cnt ++;
        TF0 = 0;
        TL0 = 0x33;
        TH0 = 0xFE;
        if(cnt <= servoAngle){    //根据设置的转动角度,实时绘制PWM波形图
            sg90_servo = 1;
        }else{
            sg90_servo = 0;
        }
        if(cnt == 40){            //利用40次爆表,确定PWM波形的周期是20ms
            cnt = 0;
        }
    }
     
    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 Delay300ms()       //@11.0592MHz
    {
        unsigned char i, j, k;
     
        _nop_();
        i = 3;
        j = 26;
        k = 223;
        do
        {
            do
            {
                while (--k);
            } while (--j);
        } while (--i);
    }
     
    void openStatus()
    {
        ledD5 = 0;
        ledD6 = 1;
        servoAngle = 4;     //舵机转到135度位置
        cnt = 0;
        Delay2000ms();
    }
     
    void closeStatus()
    {
        ledD5 = 1;
        ledD6 = 0;
        servoAngle = 1;     //舵机转到0度位置
        cnt = 0;
        Delay150ms();
    }
     
    void Delay150ms()       //@11.0592MHz
    {
        unsigned char i, j, k;
     
        _nop_();
        i = 2;
        j = 13;
        k = 237;
        do
        {
            do
            {
                while (--k);
            } while (--j);
        } while (--i);
    }
    

模式2(查询法按键控制舵机)

  1. 初步思路

    全局变量 | 增加:
    1. sbit指令找到P2这个I/O口组的第1位,用作输入口,代表开发板上的按键SW1: sbit SW1 = P2^1;
    
    main函数 | 修改第4.2步的逻辑:
    ......
    ......
    4. while死循环,不断用超声波传感器测出距离,达到临界值后转动舵机,同时用led进行测试
        4.1 调用API2. 获取超声波传感器与障碍物的距离,保存在变量distance中:
            distance = get_distance();
        4.2 判断距离是否小于10cm或者是否按下SW1按键,判据是distance < 10 || SW1 == 0
            2.2.1 如果是,调用API9. 让舵机带动垃圾桶盖处于打开状态:
                    调用API9: openStatus();
            2.2.2 否则,调用API10. 让舵机带动垃圾桶盖处于关闭状态:
                    调用API10: closeStatus();
    
  2. 这个程序中,是否需要给按键额外一个软件消抖?答:不需要,因为distance > 10是大概率事件,所以一般情况下程序总是在调用closeStatus()函数,我们回顾这个函数中实际上有加上一个150ms的延时,所以模式2中不需要再给按键额外的软件消抖了。

模式3(查询法振动控制舵机)——外部中断

  • ==选用P32口作为振动传感器接线口的原因==:一会儿我们要用外部中断实现该模式,而查阅51单片机开发板原理图,P32口是复用引脚,可以作为外部中断0。
image-20230423225652220
  1. 初步思路

    全局变量 | 增加:
    1. sbit指令找到P3这个I/O口组的第2位,用作输入口,获取振动传感器信号: sbit vibrate = P3^2;
    
    main函数 | 继续修改第4.2步的逻辑:
    ......
    ......
    4. while死循环,不断用超声波传感器测出距离,达到临界值后转动舵机,同时用led进行测试
        4.1 调用API2. 获取超声波传感器与障碍物的距离,保存在变量distance中:
            distance = get_distance();
        4.2 判断距离是否小于10cm,或者是否按下SW1按键,或者受到振动,判据是:
            distance < 10 || SW1 == 0 || vibrate == 0
            4.2.1 如果是,调用API9. 让舵机带动垃圾桶盖处于打开状态:
                    调用API9: openStatus();
            4.2.2 否则,调用API10. 让舵机带动垃圾桶盖处于关闭状态:
                    调用API10: closeStatus();
    
  2. 出现的BUG:有时候受到振动了,但是振动传感器上的指示灯短暂亮了一下就又灭掉了,直接表现为舵机没有转动,也就是说在高精度的场合振动传感器工作好像出现了问题。

  3. BUG分析:这种情况和我们第一个项目《电动车报警器》出现的bug很像(在报警状态下强制解除报警模式)

    • 振动传感器的电平信号维持的时间很短,而按键的低电平信号是个持续的信号,也就是说振动信号没有按键信号稳定和持久,这是一方面。
    • 另一方面,因为distance > 10是大概率事件,所以一般情况下程序总是在调用closeStatus()函数,我们回顾这个函数中实际上有加上一150ms的延时,所以振动传感器的信号很有可能在这150ms以内被丢失掉了,没有及时被捕获到。
  4. 解决方法外部中断

  1. **外部中断0的中断号是什么?**查阅51芯片手册的6.1小节:
image-20230424100057755

解释

  • 外部中断的中断号是0。
  • 中断开关有两个,分别是EX0和EA。
  • 暂时不用考虑IE0,图中可以看出,它类似于定时器的溢出标志位TF0。

  1. 外部中断0的中断开关是什么?查阅51芯片手册的6.2小节:
image-20230424101351957

解释

  • 在IE这个寄存器的第0位,也就是EX0,是外部中断0的中断开关,高电平代表中断开启。可以把EX0理解为:enable extern 0

  1. 外部中断0什么时候触发?查阅中断触发行为:
image-20230424101743826
image-20230424104043504

解释

  • 外部中断有两种触发方式可以配置,一种是下降沿触发,一种是低电平触发。
  • 下降沿触发由TCON寄存器的第0位,也就是IT0 进行配置,高电平代表下降沿触发。
  • 低电平触发也由TCON寄存器的第0位,也就是IT0 进行配置,低电平代表低电平触发。

  1. 最终思路

    全局变量 | 增加
    1. 代表是否受到振动的状态标志位,默认是0: char vibrate_falg = 0;	//1表示受到振动
    
    main函数 | 继续修改第4步开始的逻辑:
    ......
    ......
    4. 调用API12. 初始化外部中断0,用于振动传感器控制舵机
    5. while死循环,不断用超声波传感器测出距离,达到临界值后转动舵机,同时用led进行测试
        5.1 调用API2. 获取超声波传感器与障碍物的距离,保存在变量distance中:
            distance = get_distance();
        5.2 判断距离是否小于10cm,或者是否按下SW1按键,或者受到振动,判据是:
            distance < 10 || SW1 == 0 || vibrate_flag == 0
            5.2.1 如果是:
                    调用API9,让舵机带动垃圾桶盖处于打开状态: openStatus();
    				将状态标志位vibrate_flag程序“置0”:vibrate_flag = 0;
            5.2.2 否则,调用API10. 让舵机带动垃圾桶盖处于关闭状态:
                    调用API10: closeStatus();
    
    中断 | 增加
    中断0: 封装外部中断0的中断服务程序, void INT0_Routine()   interrupt 0
    //每当检测到P3^2引脚出现低电平,都会由硬件自动调用该函数,目的是检测到振动传感器的低电平后,挂起closeStatus()函数,立马记住低电平状态
        0.1 修改状态标志位vibrate_flag: vibrate_flag = 1;
    
    /* 一级函数:f1 f2 f5 f6 f9 f10 */ | 增加
    f12. 封装初始化外部中断0的API,用于振动传感器控制舵机
        f12.1 通过TCON寄存器的ITO位,令外部中断0的触发方式为低电平触发,匹配振动传感器: IT0 = 0;
    	f12.2 通过总中断EA和IE寄存器的EX0位,开启外部中断0:
            EA = 1;
            EX0 = 1;
    

Debug成功,完事

  • 最后加入蜂鸣器,我将它的I/O口接在了单片机的P2^0口。程序中简单修改openStatus()函数即可,另外,对于超声波传感器一直感应到distance<10时蜂鸣器还在那响,甚至垃圾桶出现了“抽抽”的情况(因为cnt在开盖状态下又被赋值为0了),我们的解决方法是定义一个记录上一次舵机角度的全局变量lastAngle。思路如下:

    全局变量 | 增加
    1. sbit指令找到P2这个I/O口组的第0位,用作输出口,控制蜂鸣器: sbit buzzer = P2^0;
    2. 定义记录上一次舵机角度的全局变量lastAngle: char lastAngle;
    //lastAngle的传递路线为:initSG90_0degree() ——> openStatus(); 或 closeStatus();
    
    /* 一级函数:f1 f2 f5 f6 f9 f10 */ | 修改
    f6. 封装初始化舵机位置的API: void initSG90_0degree();
    	f6.1 调用API8. 让系统稳定一下,减少软件模拟PWM信号的误差: Delay300ms();
    	f6.2 修改全局变量sg90_servo,让PWM波形从低电平开始: sg90_servo = 0;
    	f6.3 修改全局变量servoAngle,让舵机初始角度为0度: 
    		servoAngle = 1;
    		cnt = 0;
    f9. 封装舵机带动垃圾桶盖处于打开状态的API: void openStatus();
    	f9.1 修改全局变量servoAngle,让舵机转到135度位置,不着急令cnt=0
        	servoAngle = 4;
    	f9.2 判断这次的角度是否和上次的角度不一样,判据是: servoAngle != lastAngle
            f9.2.1 如果是,说明需要做出动作
            	f9.2.1.1 程序清零cnt: cnt = 0;
    			f9.2.1.2 用LED作为测试: 
    					ledD5 = 0;
    					ledD6 = 1;
    			f9.2.1.3 利用已有的延时函数,让蜂鸣器响0.3s:
    				buzzer = 0;
    				调用API8: Delay300ms();
    				buzzer = 1;
    		f9.2.2 否则,啥也不干
        f9.3 不管上一次角度是否等于这次角度,总是要更新最后一次角度值,并延时2s
    		lastAngle = servoAngle;
    		调用API7: Delay2000ms();
    f10. 封装舵机带动垃圾桶盖处于关闭状态的API: void closeStatus();
    	f10.1 用LED作为测试: 
    		ledD5 = 1;
    		ledD6 = 0;
    	f10.2 修改全局变量servoAngle和lasrAngle,让舵机转到0度位置,仅维持0.15s时间
        	servoAngle = 1;
    		cnt = 0;
    		修改全局变量lastAngle: lastAngle = servoAngle;
    		调用API11: Delay150ms();f9. 
    

代码心得:

  • 基于之前的代码做二次开发时,我们先将之前的代码烧录到单片机中进行验证:确保接线没问题、确保代码能正常运行来完成所需功能。

可以优化的地方:

  • BUG:超声波传感器没有被供电时,按键和振动传感器是无效的,无法驱动舵机转动。原因:在我们main函数第4.1点中有这么一条语句:distance = get_distance();。再回顾我在get_distance()函数中写的一条暂停程序的语句:while(ultraSonicEcho == 0);。所以,如果程序不给超声波传感器上电,那么get_distance()函数永远会卡死在那里,因为无法发送超声波,也无法接收回超声波。
  1. 总体思路:将上面的三种模式的思路组合在一起就行了,最后确认一全局变量的传递路线

    全局变量:
    1.sfr指令直接找到AUXR寄存器: sfr AUXR = 0X8E;    //因为AUXR没有在reg52.h中声明
    2.sbit指令找到P1这个I/O口组的第5位,用作输出口,传递tirg信号给超声波传感器:
        sbit ultrasonicTrig = P1^5;
    3.sbit指令找到P1这个I/O口组的第4位,用作输入口,从超声波传感器接收echo信号:
        sbit ultrasonicEcho = P1^4;
    4.sbit指令找到与D5这个led对应的引脚: sbit ledD5 = P3^7;
    5.sbit指令找到与D6这个led对应的引脚: sbit ledD6 = P3^6;
    6.sbit指令找到P1这个I/O口组的第1位,用作输出口,绘制PWM信号给舵机: sbit sg90_servo = P1^1;
    //sg90_servo的传递路线是:initSG90_0degree() ———> 定时器0中断(中断1)
    7.定义一个在定时器0的中断服务程序中用于计数的全局变量cnt: int cnt = 0;
    8.定义一个代表舵机角度的全局变量servoAngle: int servoAngle;   
    //servoAngle的值需要根据舵机的参数确定,传递路线为:
    //路线1. initSG90_0degree() ——> 定时器0中断(中断1)
    //路线2. openStatus() ——> lastAngle ——> 定时器0中断(中断1)
    //路线3. closeStatus ——> lastAngle ——> 定时器0中断(中断1)
    9.sbit指令找到P2这个I/O口组的第1位,用作输入口,代表开发板上的按键SW1: sbit SW1 = P2^1;
    10. 定义代表是否受到振动的状态标志位,默认是0: char vibrate_falg = 0;	
    //vibrate_flag的传递路线是:外部中断0(中断0) ——> main函数
    11.sbit指令找到P2这个I/O口组的第0位,用作输出口,控制蜂鸣器: sbit buzzer = P2^0;
    12.定义记录上一次舵机角度的全局变量lastAngle: char lastAngle;
    //lastAngle的传递路线为:initSG90_0degree() ——> openStatus(); 或 closeStatus();
    
    1. 调用API1. 初始化定时器1,用于超声波传感器计时
    2. 调用API5. 初始化定时器0,用于舵机绘制PWM波形图
    3. 调用API6. 初始化舵机到0度转动位置,让垃圾桶处于关盖状态
    4. 调用API12. 初始化外部中断0,用于振动传感器控制舵机
    5. while死循环,不断用超声波传感器测出距离,达到临界值后转动舵机,同时用led进行测试
        5.1 调用API2. 获取超声波传感器与障碍物的距离,保存在变量distance中:
            distance = get_distance();
        5.2 判断距离是否小于10cm,或者是否按下SW1按键,或者受到振动,判据是:
            distance < 10 || SW1 == 0 || vibrate_flag == 0
            5.2.1 如果是:
                    调用API9,让舵机带动垃圾桶盖处于打开状态: openStatus();
    				将状态标志位vibrate_flag程序“置0”:vibrate_flag = 0;
            5.2.2 否则,调用API10. 让舵机带动垃圾桶盖处于关闭状态:
                    调用API10: closeStatus();
    
    中断0: 封装外部中断0的中断服务程序, void INT0_Routine()   interrupt 0
    //每当检测到P3^2引脚出现低电平,都会由硬件自动调用该函数,目的是检测到振动传感器的低电平后,挂起closeStatus()函数,立马记住低电平状态
        0.1 修改状态标志位vibrate_flag: vibrate_flag = 1;
    中断1: 封装定时器0的中断服务程序, void Timer0_Routine()   interrupt 1
    //每当定时器0爆表都会由硬件自动调用该函数,目的是用定时器中断软件模拟PWM波形,输出给SG90舵机
        1.1 修改代表数数次数的循环变量cnt,让其自加1: cnt++;
        1.2 程序清零:令溢出标志位TF0“置0”: TF0 = 0;
        1.3 重新初始化寄存器TL0和TH0,重新确定计数起点:
            TL0 = 0X33;
            TH0 = 0xFE;
        1.4 判断是否数到与角度对应的数值,其中舵机0度位置对应数值1,即高电平0.5ms,...,
            舵机135度位置对应数值4,即高电平2.0ms, 判据是cnt <= servoAngle
        //内在逻辑:根据设置的转动角度servoAngle,实时绘制PWM波形图
        //注意事项: 判据到底有没有等于号要根据你在main函数中初始化的PWM波形图进行选择
            1.4.1 如果是,说明需要把电平拉高: sg90_servo = 1;
            1.4.2 否则,把电平拉低:  sg90_servo = 0;
        1.5 判断是否到达20ms,即是否爆表40次,判据是cnt == 40
        //内在逻辑:利用40次爆表,确定PWM波形的周期是20ms
            1.5.1 如果是,说明需要重置cnt: cnt = 0;
            1.5.2 否则,啥也不干
    
    /* 一级函数:f1 f2 f5 f6 f9 f10 f12*/
    f1. 封装初始化定时器1的API: void initT1();
    //用于超声波传感器,所以不着急开始数数,也不需要开启中断
        f1.1 禁用ALE信号,降低单片机时钟对外界的电磁辐射: AUXR &= 0x1F;
        f1.2 通过TMOD寄存器配置定时器16位工作模式:
                TMOD &= 0X0F;
                TMOD |= 0X10;  
        f1.3 通过TL0和TH0寄存器,初始化定时器,从0开始数数:
                TL1 = 0;
    			TH1 = 0;
    f2. 封装利用超声波传感器计算距离的API: double get_distance();
        f2.1 调用API3. 给超声波的trig端口至少10us的高电平: start_ultrasonic();
        f2.2 echo引脚由低电平跳转到高电平代表开始发送超声波,波发出的那一下开始启动定时器
                根据超声波时序图,用空循环体,暂时卡死程序: while(ultrasonicEcho == 0);
                定时器开始计时: TR1 = 1;
        f2.3 echo引脚由高电平跳转到低电平代表波返回来了,停止定时器计数
                根据超声波时序图,用空循环体,暂时卡死程序: while(ultrasonicEcho == 1);
                定时器停止计时: TR1 = 0;
        f2.4 根据定时器数一次用时1.085us的特点,计算超声波发送和返回经历的时间,保存在变量time中:
            time = ((TH1<<8) + TL1)*1.085;
        f2.5 根据公式计算出超声波传感器和障碍物之间的距离,保存在变量distance中:
            distance = time * 0.034 / 2;    //确定量纲: 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
        f2.6 定时器1清零:
                TL1 = 0;
                TH1 = 0;
        f2.7 返回distance
    f5. 封装初始化定时器0的API,在11.0592MHz的晶振频率下定0.5ms出来: void initT0();   
    //用于绘制舵机的PWM波形图,0.5ms是控制舵机的最小时间单位
        f5.1 禁用ALE信号,降低单片机时钟对外界的电磁辐射: AUXR &= 0x1F;
        f5.2 通过TMOD寄存器配置定时器16位工作模式:
                TMOD &= 0XF0;
                TMOD |= 0X01;  
        f5.3 通过TL0和TH0寄存器,初始化定时器,定一个0.5ms出来:
                TL0 = 0x33;
                TH0 = 0xFE;
        f5.4 让溢出标志位清零: TF0 = 0;
        f5.5 打开定时器0的中断开关:
                EA = 1;
                ET0 = 1;
        f5.6 通过TCON寄存器的运行控制位TR0,让定时器开始数数: TR0 = 1;
    f6. 封装初始化舵机位置的API: void initSG90_0degree();
        f6.1 调用API8. 让系统稳定一下,减少软件模拟PWM信号的误差: Delay300ms();
        f6.2 修改全局变量sg90_servo,让PWM波形从低电平开始: sg90_servo = 0;
        f6.3 修改全局变量servoAngle,让舵机初始角度为0度:
            servoAngle = 1;
            cnt = 0;
    f9. 封装舵机带动垃圾桶盖处于打开状态的API: void openStatus();
        f9.1 用LED作为测试:
            ledD5 = 0;
            ledD6 = 1;
        f9.2 修改全局变量servoAngle,让舵机转到135度位置,并保持2s时间
            servoAngle = 4;
            cnt = 0;
            调用API7: Delay2000ms();
    f10. 封装舵机带动垃圾桶盖处于关闭状态的API: void closeStatus();
        f10.1 用LED作为测试:
            ledD5 = 1;
            ledD6 = 0;
        f10.2 修改全局变量servoAngle,让舵机转到0度位置,仅维持0.15s时间
            servoAngle = 1;
            cnt = 0;
            调用API11: Delay150ms();
    f12. 封装初始化外部中断0的API,用于振动传感器控制舵机
        f12.1 通过TCON寄存器的ITO位,令外部中断0的触发方式为低电平触发,匹配振动传感器: IT0 = 0;
    	f12.2 通过总中断EA和IE寄存器的EX0位,开启外部中断0:
            EA = 1;
            EX0 = 1;
    
    /* 二级函数: f3 f4 f7 f8 f11 */
    f3. 封装启动超声波传感器的API: void start_ultrasonic();
        f2.1 修改全局变量ultrasonicTrig,让它一开始处于低电平: ultrasonicTrig = 0;
        f2.2 修改全局变量ultrasonicTrig,让它处于高电平,并保持10μs:
            ultrasonicTrig = 1;
            调用API4: Delay10us();
        f2.3 修改全局变量ultrasonicTrig,让它回到低电平:
    f4. 封装软件延时10微秒的API,用于给超声波传感器trig引脚10us的高电平: void Delay10us();
    f7. 封装软件延时2s的API,用于打开垃圾桶盖时,即使感应不到物体也能保持开盖: void Delay2000ms();
    f8. 封装软件延时0.3s的API,用于稳定程序,减少软件模拟PWM信号的误差: void Delay300ms();
    f11. 封装软件延时0.15s的API,用于防止物体快速接近传感器时也会转动舵机的情况(有点像消抖): void Delay150ms();
    
  2. 代码

    #include "reg52.h"
    #include "intrins.h"
    
    sfr AUXR            = 0x8E;
    sbit ultrasonicTrig = P1^5;
    sbit ultrasonicEcho = P1^4;
    sbit ledD5          = P3^7;
    sbit ledD6          = P3^6;
    sbit sg90_servo     = P1^1;
    sbit SW1 			= P2^1;
    sbit vibrate		= P3^2;	//外部中断0口
    sbit buzzer			= P2^0;
    int cnt = 0;
    char servoAngle;
    char vibrate_flag = 0;
    char lastAngle;
    
    /* API1: 定时器T1的初始化@11.0592MHz,我们不关心初值,从0开始计算就行,用于超声波传感器 */
    void initT1();
    /* API2. 超声波计算距离 */
    double get_distance();
    /* API3: 启动超声波传感器 */
    void start_ultrasonic();
    /* API4: 软件延时10微秒,用于给超声波传感器trig引脚10us的高电平 */ 
    void Delay10us();
    /* API5: 定时器T0的初始化,定0.5ms出来@11.0592MHz,用于舵机 */
    void initT0();
    /* API6. 初始化sg90舵机到0度位置 */
    void initSG90_0degree();
    /* API7: 软件延时2s,用于打开垃圾桶盖时,即使感应不到物体也能保持开盖2s */
    void Delay2000ms();
    /* API8: 软件延时0.3s,用于稳定程序,减少软件模拟PWM信号的误差 */
    void Delay300ms();
    /* API9: 测试,代表舵机带动垃圾桶盖打开状态 */
    void openStatus();
    /* API10: 测试,代表舵机带动垃圾桶盖关闭状态 */
    void closeStatus();
    /* API11. 软件延时0.15s,用于在关盖状态进行延时,防止物体快速接近传感器时也会转动舵机 */
    void Delay150ms();
    /* API12. 外部中断0的初始化,用于振动传感器控制舵机 */
    void initINT0();
    
    void main(void)
    {
    	double distance;
    	initT1();               //定时器1用于超声波传感器
        initT0();               //定时器0用于舵机
    	initINT0();				//外部中断0用于振动传感器
        initSG90_0degree();     //初始化舵机,让垃圾桶处于关盖状态
    	while(1){
            distance = get_distance();
    		if(distance < 10 || SW1 == 0 || vibrate_flag == 1){		
    			openStatus();
    			vibrate_flag = 0;
    		}else{
    			closeStatus();
    		}
    	}	
    }
    
    void initT1()
    {
    	AUXR &= 0x1F;		//禁用ALE信号,降低单片机时钟对外界的电磁辐射
    	TMOD &= 0X0F;		  
    	TMOD |= 0X10;		//配置定时器1为16位工作模式
    	TL1 = 0;		
    	TH1 = 0;			//初始化定时器,从0开始就行
    	//定时器1不着急开始数数
    }
    
    double get_distance()
    {
        double time;
        double distance;
        /* 1.给超声波的trig端口至少10us的高电平 */
        start_ultrasonic();
        /* 2.echo引脚由低电平跳转到高电平代表开始发送超声波,波发出的那一下开始启动定时器 */
        while(ultrasonicEcho == 0);	//空循环体,暂时卡死程序
        TR1 = 1; 
        /* 3.echo引脚由高电平跳转到低电平代表波返回来了,停止定时器计数 */
        while(ultrasonicEcho == 1);	//空循环体,暂时卡死程序
        TR1 = 0;
        /* 4.计算超声波发送和返回经历的时间 */
        time = ((TH1<<8) + TL1)*1.085;	//us为单位
        /* 5.计算出超声波传感器和障碍物之间的距离,先确定量纲: 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us */
        distance = time * 0.034 / 2;	//cm为单位
        /* 6.定时器1清零,重新计时 */
        TL1 = 0;
        TH1 = 1;
        return distance;
    }
    
    void start_ultrasonic()
    {
    	ultrasonicTrig = 0;
    	ultrasonicTrig = 1;
    	Delay10us();
    	ultrasonicTrig = 0;
    }
    
    void Delay10us()		//@11.0592MHz
    {
    	unsigned char i;
    
    	i = 2;
    	while (--i);
    }
    
    void initT0()
    {
    	AUXR &= 0x1F;		//禁用ALE信号,降低单片机时钟对外界的电磁辐射
    	TMOD &= 0XF0;		  
    	TMOD |= 0X01;		//配置定时器0为16位工作模式
    	TL0 = 0x33;		
    	TH0 = 0xFE;			//初始化定时器,定一个0.5ms出来
    	TF0 = 0;			//让溢出标志位清零
        EA = 1;             //打开总中断EA
        ET0 = 1;            //打开定时器0的中断ET0 
    	TR0 = 1;			//定时器0开始数数
    }
    
    void initSG90_0degree()
    {
        Delay300ms();			//让系统稳定一下
    	sg90_servo = 0;			//初始化PWM波形从低电平开始
    	servoAngle = 1; 		//初始角度是0度
    	cnt = 0;
    	lastAngle = 1;
    }
    
    //定时器0的中断服务程序,目的是用定时器中断软件模拟PWM波形,输出给SG90舵机
    void Timer0_Routine()    interrupt 1    
    {
        cnt ++;
        TF0 = 0;
        TL0 = 0x33;
        TH0 = 0xFE;
    	if(cnt <= servoAngle){	  //根据设置的转动角度,实时绘制PWM波形图
    		sg90_servo = 1;
    	}else{
    		sg90_servo = 0;
    	}
        if(cnt == 40){     		  //利用40次爆表,确定PWM波形的周期是20ms
            cnt = 0;
        }
    }
    
    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 Delay300ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 3;
    	j = 26;
    	k = 223;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void openStatus()
    {
        servoAngle = 4;		//舵机转到135度位置
    	if(servoAngle != lastAngle){
    		cnt = 0;
    		ledD5 = 0;
    		ledD6 = 1;
    		buzzer = 0;
    		Delay300ms();
    		buzzer = 1;
    	}
    	lastAngle = servoAngle;	//不管上一次角度是否等于这次角度,总是要更新最后一次角度值
    	Delay2000ms();
    }
    
    void closeStatus()
    {
        ledD5 = 1;
        ledD6 = 0;
        servoAngle = 1;		//舵机转到0度位置
        cnt = 0;
    	lastAngle = servoAngle;
    	Delay150ms();
    }
    
    void Delay150ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 2;
    	j = 13;
    	k = 237;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void initINT0()	
    {
    	IT0 = 0;	//外部中断0的触发方式为低电平触发,匹配振动传感器
    	EA = 1;
    	EX0 = 1;	//开启外部中断0
    }
    
    //外部中断0的中断服务程序,目的是检测到振动传感器的低电平后,挂起closeStatus()函数,立马记住低电平状态
    void INT0_Routine()	   interrupt 0
    {
    	vibrate_flag = 1;
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/456362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

室内人员定位,硬件部署方案多场景技术分析

室内外定位技术在工业、矿业、医疗养老、能源电力、展览展会、公检法司、工地等众多领域具有丰富的应用场景。定位能力作为“物联网”的核心能力之一&#xff0c;其定位精度和稳定性不仅需要强大的算法支撑&#xff0c;也有赖于好的室内定位设备的落地部署。 基于蓝牙LoRa定位…

MySQL按照,库的操作,表的约束 --- MySQL总结(一)

MySQL 文章目录 MySQLMySQL的安装MySQL组成架构连接池软件层引擎层储存层 库的操作创建库修改数据库删除数据库备份数据库还原数据库查看链接情况 表操作创建表查看表结构修改表结构添加字段修改字段类型长度更改表名修改属性删除表 数据类型表的约束空属性&#xff08;not nul…

typescript全局安装卸载以及npm相关问题

全局安装 npm install -g typescript 全局安装之后&#xff0c;如果想要卸载要使用 npm uninstall -g typescript 全局安装之后可以在终端使用 tsc xxx 编译ts文件 本地安装&#xff0c;也就是在项目目录下安装 npm install typescript 本地卸载 npm uninstall type…

【LeetCode】刷题数据结构(1)[反转链表]

【LeetCode】刷题数据结构&#xff08;1&#xff09; 1.题目来源2.题目描述3.解题思路4.代码展示 所属专栏&#xff1a;玩转数据结构题型 博主首页&#xff1a;初阳785 代码托管&#xff1a;chuyang785 感谢大家的支持&#xff0c;您的点赞和关注是对我最大的支持&#xff01;&…

Elasticsearch ILM DSL 索引生命周期管理

1、冷热集群架构 冷热架构也叫冷暖架构&#xff0c;是“Hot-Warm” Architecture的中文翻译。 冷热架构本质是给节点设置不同的属性&#xff0c;让每个节点具备了不同的属性。为演示 ILM&#xff0c;需要首先配置冷热架构&#xff0c;三个节点在 elasticsearch.yml 分别设置的…

4月21号软件更新资讯合集.....

PlayEdu v1.0-beta.3 发布&#xff0c;视频培训解决方案 PlayEdu 是基于 SpringBoot3 Java17 React18 开发的企业内部培训系统。它专注于提供私有化部署方案&#xff0c;包括视频&#xff0c;图片等资源的内网部署。目前主要支持有本地视频上传播放、学员邮箱登录、无限级部门…

如何使用JMeter和Ant生成高效测试报告?

Jmeter接口自动化测试项目实战视频教程地址&#xff1a;https://www.bilibili.com/video/BV1e44y1X78S/? 目录&#xff1a;导读 引言 一、安装ant 二、ant关联jmeter工具 三、执行 结语 引言 你曾经在进行软件测试时遇到过测试结果难以分析&#xff0c;甚至花费大量时间…

机器学习基础知识之相关性分析

文章目录 相关性分析定义1、图表相关性分析2、协方差分析3、相关系数分析4、回归分析 相关性分析定义 相关性分析一般是指通过对两种或两种以上的变量数据进行数学分析来确定两种或两种以上的变量数据之间的相关密切程度。由此定义我们可以得知相关性分析的目的在于衡量变量数…

算法leetcode|48. 旋转图像(rust重拳出击)

文章目录 48. 旋转图像&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 48. 旋转图像&#xff1a; 给定一个 n n 的二维矩…

我国风电叶片行业分析:行业技术创新白热化竞争来临 后续回收再利用是行业可持续发展的关键

1、风电叶片行业定义及产业链 风电叶片是一个复合材料制成的薄壳结构&#xff0c;一般由外壳、腹板和主梁三部分组成&#xff0c;复合材料在整个风电叶片中的重量一般占到90%以上。风电叶片是风力发电机将风能转化为机械能的重要部件之一&#xff0c;其设计、制造及运行状态直…

易点易动设备管理系统帮助钢铁厂实现智能设备巡检

随着工业自动化和智能化的不断推进&#xff0c;越来越多的企业开始采用智能设备来提高生产效率和质量。然而&#xff0c;随之而来的是设备管理的复杂性和挑战性的增加。为了解决这一问题&#xff0c;易点易动设备管理系统应运而生&#xff0c;该系统可以帮助钢铁厂实现智能设备…

从C出发 28 --- 指针与数组

int a[ ] {1, 2, 3, 4, 0}; //定义了一个数组&#xff0c;这个数组有5个元素&#xff0c;每个元素是一个 int 类型变量 这里的地址是相同的&#xff0c;是相同的意味着数组的地址和 0 号元素的地址是一样的 结论: 数值上相同但是意义上不同&#xff0c;一个是数组整体…

有仰拍相机和俯拍相机时,俯拍相机中心和吸嘴中心的标定

俯拍相机中心和吸嘴中心的标定 文章目录 俯拍相机中心和吸嘴中心的标定 前言适用模型如下&#xff1a;一、使用一个标定片进行标定1.关键注意&#xff1a;2.标定步骤&#xff1a; 二、使用一个L型的工件1.关键注意&#xff1a;2.标定步骤&#xff1a; 总结 前言 在自动化设备领…

centos7查看磁盘io

1.查看所使用到的命令为iostat&#xff0c;centos7没有自带iostat&#xff0c;需要安装一下 2.安装iostat命令 yum -y install sysstat 3.使用iostat命令 iostat %user&#xff1a;表示用户空间进程使用 CPU 时间的百分比 %nice&#xff1a;表示用户空间进程以降低优先级的…

索引失效了?看看这几个常见的原因

索引是 MySQL 数据库中优化查询性能的重要工具&#xff0c;通过对查询条件和表数据的索引&#xff0c;MySQL可以快速定位数据&#xff0c;提高查询效率。但是&#xff0c;在实际的数据库开发和维护中&#xff0c;我们经常会遇到一些情况&#xff0c;导致索引失效&#xff0c;从…

Vue安装

Vue安装 一、安装二、使用步骤1.在项目中使用vue2.使用命令创建vue项目 一、安装 安装vue之前需要安装nodeJS 1.需要安装Node.js。可以从官方网站进行下载并安装。 2.这篇博客有详细的步骤 Node.js安装详解 3.或者在官网安装最新版本的不用配置Node.js下载官网 安装完成Nod…

Python每日一练(20230424)

目录 1. 滑动窗口最大值 &#x1f31f;&#x1f31f;&#x1f31f; 2. 用栈实现队列 &#x1f31f; 3. 直线上最多的点数 &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一…

准确率,精确率,召回率,F1,AUC

以西瓜数据集为例&#xff0c;我们来详细解释一下什么是TP、TN、FP以及FN。 一、基础概念 TP&#xff1a;被模型预测为正类的正样本 TN&#xff1a;被模型预测为负类的负样本 FP&#xff1a;被模型预测为正类的负样本 FN&#xff1a;被模型预测为负类的正样本 二、通俗理解&am…

如何在 Linux 中查找文件所有者?

在 Linux 系统中&#xff0c;每个文件和目录都有一个所有者&#xff08;owner&#xff09;和一个所属组&#xff08;group&#xff09;。所有者通常是创建该文件或目录的用户&#xff0c;而所属组通常是文件或目录所属的组。在某些情况下&#xff0c;您可能需要查找特定文件或目…

前端学习--Ajax(5) Http

一、Http简介 1.1 通信 信息的传递和交换 通信三要素&#xff1a;主体&#xff08;双方&#xff09;、内容、方式 1.2 通信协议 通信双方通信遵守的规则 http--超文本传输协议&#xff1a;客户端与服务器之间进行网页内容传输时必须遵守的传输格式 1.3 HTTP 交互模型&a…