单片机学习笔记---红外遥控红外遥控电机调速(完结篇)
目录
低电平触发中断和下降沿触发中断的区别
红外遥控
Int0.c
Int.h
Timer0.c
Timer0.h
IR.c
IR.h
main.c
红外遥控电机调速
Timer1.c
Timer.h
Motor.c
Motor.h
main.c
上一节讲了红外发送和接收的工作原理,这一节开始代码演示!
提前说明,本节代码演示中会涉及定时器和中断系统!
如果不懂定时器和中断系统的话,建议去看看我之前已经详细写过的中断系统和定时器的博客,也写的比较全面的了,看过后肯定能让你明白中断系统和定时器的工作原理!
单片机学习笔记---中断系统(含外部中断)-CSDN博客
单片机学习笔记---定时器/计数器(简述版!)_定时计数器ea-CSDN博客
单片机学习笔记---定时器和中断系统如何连起来工作-CSDN博客
低电平触发中断和下降沿触发中断的区别
在正式演示红外遥控的代码之前我们先来看看配置外部中断时,选择低电平触发和下降沿触发有什么区别?
我们用外部中断INT0来举个例子:
我们单片机的原理图上,INT0接的是单片机的P32口,
而独立按键K3正好也是P32口。
那么我们按下K3的时候就相当于给单片机的P32口一个下降沿
那么我们现在来写一个程序验证一下选择低电平触发和下降沿触发有什么区别:
先创建一个工程文件,把我之前的博客中讲过的LCD1602的程序文件添加进来
然后在主程序main.c中调用这个函数来显示中断触发的现象
首先是选择下降沿触发:
#include <REGX52.H>
#include "LCD1602.h"unsigned char Num;void main()
{LCD_Init();//初始化液晶屏//配置中断系统IT0=1;//选择下降沿触发方式IE0=0;//中断标志位清零EX0=1;//打开中断EA=1;//打开总中断PX0=1;//一般都选择高优先级中断//跳转到中断函数//中断函数执行完进入while循环while(1){LCD_ShowNum(1,1,Num,3);}
}//中断函数
void Init0_Routine(void) interrupt 0
{Num++;
}
下降沿触发的话,你按下的时候加一次,松开再按下的时候才再加一次。“松开状态再按下”这一个过程就是给一个下降沿的过程。
效果请看视频:
选择下降沿触发中断的结果现象
再来看看选择低电平触发:
#include <REGX52.H>
#include "LCD1602.h"unsigned char Num;void main()
{LCD_Init();//初始化液晶屏//配置中断系统IT0=0;//选择低电平触发方式IE0=0;//中断标志位清零EX0=1;//打开中断EA=1;//打开总中断PX0=1;//一般都选择高优先级中断//跳转到中断函数//中断函数执行完进入while循环while(1){LCD_ShowNum(1,1,Num,3);}
}//中断函数
void Init0_Routine(void) interrupt 0
{Num++;
}
而如果是低电平触发的话,只要按键按下这个中断会一直处于触发状态,当中断函数结束之后它会再次进入,直到变成高电平为止。那它的现象就是按下不松的时候,这个数值是一直加的,直到松手,数值才停止加。
效果请看视频:
选择低电平触发中断的结果现象
以上就是低电平触发中断和下降沿触发中断的区别
而本节红外遥控的示例代码要用的是下降沿触发中断的这种方式!
红外遥控
现在开始正式演示代码:
新创建一个工程文件:红外遥控
将我之前的博客讲过的程序模块直接添加进来
然后先创建Int0.c,Int.h,IR.c,IR.h和main.c文件
开始代码讲解:
首先写一个初始化中断系统的函数
Int0.c
#include <REGX52.H>void Int0_Init(void)
{IT0=1;//选择下降沿触发中断IE0=0;//中断标志位清零EX0=1;//把中断打开EA=1;//打开总中断PX0=1;//选择高优先级中断
}
声明一下这个函数
Int.h
#ifndef __INT0_H__
#define __INT0_H__void Int0_Init(void);#endif
Timer0.c
接下来我们把Timer0.c文件的程序改造一下
将计时器初始化函数中的中断系统配置部分删掉,将初值清零,并且关闭计时
#include <REGX52.H>
//定时器0初始化
void Timer0_Init(void)
{TMOD &= 0xF0; //设置定时器模式TMOD |= 0x01; //设置定时器模式TL0 = 0; //设置定时初值TH0 = 0; //设置定时初值TF0 = 0; //清除TF0标志TR0 = 0; //定时器0不计时
}
单独写一个给定时器0设置初值的函数
//定时器0设置计数器值
void Timer0_SetCounter(unsigned int Value)
{TH0=Value/256;//取出高八位赋值给TH0TL0=Value%256;//取出低八位赋值给TH0
}
//Value,要设置的计数器值,范围:0~65535
定时器0设置好初值后,再写一个获取定时器0当时的计数器值的函数
//定时器0获取计数器值,范围:0~65535
unsigned int Timer0_GetCounter(void)
{return (TH0<<8)|TL0;//将TH0的8位数据左移8位,然后和TL0的8位数据组合成16位数据作为返回值
}
然后再写一个函数用来控制定时器的开始和结束
//定时器0启动停止控制
//Flag 启动停止标志,
//在TMOD寄存器中的GATE位等于0的情况下,TR0是定时器0在方式1的工作模式下的启停控制位
//1为启动,0为停止void Timer0_Run(unsigned char Flag)
{TR0=Flag;
}
将这几个函数声明一下
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);#endif
接下来写一下红外解码的程序函数
IR.c
先定义好一些变量,后面会用到
#include <REGX52.H>
#include "Timer0.h"
#include "Int0.h"unsigned int IR_Time;//上一次中断到此次中断的时间
unsigned char IR_State;//接收的状态unsigned char IR_Data[4];//数据,4个字节,32位
unsigned char IR_pData;//告知当前是在第几位,每次进来pData++,告诉告知现在收到第几位了,收满32位之后就结束了unsigned char IR_DataFlag;//收到连发帧标志位
unsigned char IR_RepeatFlag;//重发标志
unsigned char IR_Address;//存的是地址
unsigned char IR_Command;//存的是命令码(就是遥控上的键码)
然后写一个红外遥控初始化函数
void IR_Init(void)
{Timer0_Init();//初始化定时器0Int0_Init();//初始化外部中断0
}
红外遥控获取收到数据帧标志位
返回值:是否收到数据帧,1为收到,0为未收到
unsigned char IR_GetDataFlag(void)
{if(IR_DataFlag){IR_DataFlag=0;//将收到连发帧标志位置0,方便下一次进行return 1;//代表已经收到了}return 0;//如果IR_DataFlag=0,直接return 0
}
红外遥控获取收到连发帧标志位
返回值:是否收到连发帧,1为收到,0为未收到
unsigned char IR_GetRepeatFlag(void)
{if(IR_RepeatFlag){IR_RepeatFlag=0;return 1;}return 0;
}
红外遥控获取收到的地址数据
返回值: 收到的地址数据
unsigned char IR_GetAddress(void)
{return IR_Address;
}
红外遥控获取收到的命令数据
返回值:收到的命令数据
unsigned char IR_GetCommand(void)
{return IR_Command;
}
外部中断0中断函数,下降沿触发执行
这部分主要是根据这张图定义的函数
void Int0_Routine(void) interrupt 0
{//第一次进入中断函数时if(IR_State==0) //状态0,空闲状态{Timer0_SetCounter(0); //定时计数器清0Timer0_Run(1); //定时器启动IR_State=1; //置状态为1}//下一次进入中断函数时else if(IR_State==1) //状态1,等待Start信号或Repeat信号{IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0,方便下次计时//计数器每加1就是1微秒,1000us=1ms//如果计时为13.5ms即13500us,则接收到了Start信号(判定值在12MHz晶振下为13500,在11.0592MHz晶振下为12442)//因为有一些误差,所以有可能不是13500us整,需允许波动的范围//13500-11250=2250,允许波动的范围不能超过2250,可以给上下500的范围,上下500即1000的波动范围//所以给个上下500波动的范围即13500-500~13500+500合理if(IR_Time>13500-500 && IR_Time<13500+500){IR_State=2; //置状态为2,下次再来中断就要开始解码数据}//如果计时为11.25ms,则接收到了Repeat信号(判定值在12MHz晶振下为11250,在11.0592MHz晶振下为10368)else if(IR_Time>11250-500 && IR_Time<11250+500){//如果接收到这个信号就说明一帧已经结束了,后面就不用数据了IR_RepeatFlag=1; //置收到连发帧标志位为1Timer0_Run(0); //定时器停止IR_State=0; //置状态为0}else //接收出错{IR_State=1; //置状态为1,继续收Start信号或者repeat信号}}//以上情况执行完就接收完了起始信号//那再次进入中断函数来就要开始解码else if(IR_State==2) //状态2,接收数据{IR_Time=Timer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0,方便下次计时//如果计时为1120us,则接收到了数据0(判定值在12MHz晶振下为1120,在11.0592MHz晶振下为1032)if(IR_Time>1120-500 && IR_Time<1120+500){//收到0之后就要把数据写进去IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); //数据对应位清0//假设pData的范围是0~7,即一个字节长度//那么如果要将第一个字节的8位对应位清零//可以写成IR_Data[0]&=~(0x01<<IR_pData);//但是我们是要4个字节,把pData定义为告知32位数据中的哪一位数据,变化范围是0~31//要将pData的范围0~31拆成4个字节,也就是4个数组元素,一个字节8位//那么每8位就是一个数组元素,所以左移的范围要限制在一个字节中//因此左移的范围要限制在0~7,则IR_pData%8//4个数组元素范围是IR_Data[0]~IR_Data[3],则IR_pData/8,//这样程序就可以自动跳到下一个元素的第0位IR_pData++; //数据位置指针自增}//如果计时为2250us,则接收到了数据1(判定值在12MHz晶振下为2250,在11.0592MHz晶振下为2074)else if(IR_Time>2250-500 && IR_Time<2250+500){IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); //数据对应位置1IR_pData++; //数据位置指针自增}else //接收出错{IR_pData=0; //数据位置指针清0IR_State=1; //置状态为1}//32位数据解码完成后,开始验证if(IR_pData>=32) //如果接收到了32位数据{IR_pData=0; //数据位置指针清0if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3])) //数据验证{IR_Address=IR_Data[0]; //转存数据IR_Command=IR_Data[2];IR_DataFlag=1; //置收到连发帧标志位为1}Timer0_Run(0); //定时器停止IR_State=0; //置状态为0}}
}
IR.h
声明一下这些函数,并且把键码重定义,方便主程序调用,不用每次都查找对应的键码
#ifndef __IR_H__
#define __IR_H__#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4Avoid IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);#endif
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "IR.h"unsigned char Num;
unsigned char Address;
unsigned char Command;void main()
{LCD_Init();LCD_ShowString(1,1,"ADDR CMD NUM");LCD_ShowString(2,1,"00 00 000");IR_Init();while(1){if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧{Address=IR_GetAddress(); //获取遥控器地址码Command=IR_GetCommand(); //获取遥控器命令码LCD_ShowHexNum(2,1,Address,2); //显示遥控器地址码LCD_ShowHexNum(2,7,Command,2); //显示遥控器命令码,即键码if(Command==IR_VOL_MINUS) //如果遥控器VOL-按键按下{Num--; //Num自减}if(Command==IR_VOL_ADD) //如果遥控器VOL+按键按下{Num++; //Num自增}LCD_ShowNum(2,12,Num,3); //显示Num}}
}
效果请看视频:
红外遥控显示键码值
注意:如果程序没有出凑,但是没有结果反应的话,请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz,这两种晶振的机器周期是不一样的,要在IR.c文件中的程序对应修改,要修改的地方在IR.c文件程序中已经给出了注释,请认真查看并修改!
红外遥控电机调速
新创建一个工程:红外遥控电机调速
这个程序是建立在之前写的直流电机调速的那个程序的基础上改造的,之前是用独立按键用控制电机的运转的速度,这次改为用红外遥控来控制电机的运转速度。
复用到的程序:
Delay函数
数码管
中断系统配置,定时器0配置,红外解码
Timer1.c
由于红外解码部分用了定时器0,所以我们要加一个定时器1程序,即将Timer0.c复制一份并且对应的地方改成定时器
#include <REGX52.H>void Timer1_Init(void)
{TMOD &= 0x0F; //设置定时器模式TMOD |= 0x10; //设置定时器模式TL1 = 0x9C; //设置定时初值TH1 = 0xFF; //设置定时初值TF1 = 0; //清除TF1标志TR1 = 1; //定时器1开始计时ET1=1;EA=1;PT1=0;
}
Timer.h
#ifndef __TIMER1_H__
#define __TIMER1_H__void Timer1_Init(void);#endif
Motor.c
写一个驱动电机的模块
#include <REGX52.H>
#include "Timer1.h"//引脚定义
sbit Motor=P1^0;unsigned char Counter,Compare;//电机初始化
void Motor_Init(void)
{Timer1_Init();
}//电机设置速度
//Speed 要设置的速度,范围0~100
void Motor_SetSpeed(unsigned char Speed)
{Compare=Speed;
}//定时器1中断函数
void Timer1_Routine() interrupt 3
{TL1 = 0x9C; //设置定时初值TH1 = 0xFF; //设置定时初值Counter++;Counter%=100; //计数值变化范围限制在0~99if(Counter<Compare) //计数值小于比较值{Motor=1; //输出1}else //计数值大于比较值{Motor=0; //输出0}
}
Motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);#endif
main.c
#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Motor.h"
#include "IR.h"unsigned char Command,Speed;void main()
{Motor_Init();//初始化电机(定时器1初始化)IR_Init();//红外遥控初始化(定时器0和中断系统初始化)while(1){if(IR_GetDataFlag()) //如果收到数据帧{Command=IR_GetCommand(); //获取遥控器命令码//将命令码/键码和遥控上的数字对应起来if(Command==IR_0){Speed=0;} //根据遥控器命令码设置速度if(Command==IR_1){Speed=1;}if(Command==IR_2){Speed=2;}if(Command==IR_3){Speed=3;}//Motor_SetSpeed相当于PWM输出中用到的比较值if(Speed==0){Motor_SetSpeed(0);} //速度输出if(Speed==1){Motor_SetSpeed(50);}if(Speed==2){Motor_SetSpeed(75);}if(Speed==3){Motor_SetSpeed(100);}}Nixie(1,Speed); //数码管显示速度}
}
效果请看视频:
红外摇控调档速的小风扇
注意:如果程序没有出凑,但是没有结果反应的话,请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz,这两种晶振的机器周期是不一样的,要在IR.c文件中的程序对应修改,要修改的地方在IR.c文件程序中已经给出了注释,请认真查看并修改!
以上就是本篇的内容,源码会放在评论区(含12MHz和11.0592MHz两种源码),如有问题可评论区留言!
相关文章:

单片机学习笔记---红外遥控红外遥控电机调速(完结篇)
目录 低电平触发中断和下降沿触发中断的区别 红外遥控 Int0.c Int.h Timer0.c Timer0.h IR.c IR.h main.c 红外遥控电机调速 Timer1.c Timer.h Motor.c Motor.h main.c 上一节讲了红外发送和接收的工作原理,这一节开始代码演示! 提前说…...

Linux第62步_备份移植好的所有的文件和文件夹
1、备份“my-tfa”目录下所有的文件和文件夹 1)、打开终端 输入“ls回车”,列出当前目录下所有的文件和文件夹 输入“cd linux回车”,切换“linux”目录下 输入“ls回车”,列出当前目录下所有的文件和文件夹 输入“cd atk-mp1/回车”&am…...
【xss跨站漏洞】xss漏洞前置知识点整理
xss漏洞成因 xss漏洞是一种前端javascript产生的漏洞。 我们网站基本都是会用到javascript编写一些东西,浏览器也能直接识别javascript。 如果有一个地方能够输入文字,但是他又没有过滤你的输入,那么自己或者他人看到你输入的javascript代…...
mac下mysql 常用命令
mysql启动命令 在Mac OS X启动和停止MySQL服务的命令, 启动MySQL服务 sudo /usr/local/mysql/support-files/mysql.server start 停止MySQL服务 sudo /usr/local/mysql/support-files/mysql.server stop 重启MySQL服务 sudo /usr/local/mysql/support-files/mys…...
2.21号qt
1.QMainWindow中常用的类 继承于QMainWindow类,原因该类提供了QWidget没有提供的成员函数。 菜单栏、工具栏、状态栏、浮动窗口(铆接部件)、核心部件 1.1 菜单栏 QMenuBar //创建菜单栏 QMenuBar 最多只能有一个 QMenuBar *mbar menu…...
什么是MVVM?MVC、MVP与MVVM模式的区别?
MVVM(Model-View-ViewModel)是一种软件架构模式,用于将用户界面(View)与业务逻辑(Model)分离,并通过ViewModel来连接两者。MVVM的目标是实现可测试性、可维护性和可复用性。 MVC&am…...

ElementUI组件的安装和使用
Element UI 是一款基于 Vue 2.0 的桌面端组件库,主要用于快速构建网站的前端部分。它提供了丰富的组件,如按钮、输入框、表格、标签页等,以及一些布局元素,如布局容器、分割线等。Element UI 的设计风格简洁,易于上手&…...

Laravel01 课程介绍以及Laravel环境搭建
Laravel01 课程介绍 1. Laravel2. mac开发环境搭建(通过Homebrew)3. 创建一个项目 1. Laravel 公司中面临着PHP项目与Java项目并行,所以需要我写PHP的项目,公司用的框架就是Laravel,所以在B站上找了一门课学习。 Laravel中文文档地址 https…...

面试redis篇-03缓存击穿
原理 缓存击穿:给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮 解决方案一:互斥锁 解决方案二:逻辑过期 提问与回答 面试官 :什么是缓存击穿 ? 怎么解决 ? 回答: 缓存击穿的意思…...
k8s容器以及基础设施优化
1.硬件系统选型:宿主机通用配置16c/32GB/4网卡队列 2.os优化:单机支持百万tcp并发,/etc/sysctl.conf,/etc/security/limits.conf 3.k8s&容器层优化:性能优化initContainer 4.kube-dns优化:增大--cache-size,设置…...

蓝桥杯备赛系列——倒计时50天!
蓝桥杯备赛系列 倒计时50天! 前缀和和差分 知识点 **前缀和数组:**假设原数组用a[i]表示,前缀和数组用sum[i]表示,那么sum[i]表示的是原数组前i项之和,注意一般用前缀和数组时,原数组a[i]的有效下标是从…...

jenkins配置ssh的时候测试连接出现Algorithm negotiation fail
背景:当jenkins升级后,同时ssh插件也升级,测试ssh连接的时候 出现的问题: com.jcraft.jsch.JSchAlgoNegoFailException: Algorithm negotiation fail: algorithmName"server_host_key" jschProposal"ecdsa-sha2-n…...

思维模型整合
思维模型整合 4P--- 4C思考模型能力圈模型 4P— 4C思考模型 在竞争激烈的今天,每个赛道都有众多可以为客户提供相同价值的对手,而赛道中的佼佼者之所以能打败大部分人,可能并不是他们能比别人更能讨好大众,而是因为在这个赛道它有…...

代理模式笔记
代理模式 代理模式代理模式的应用场景先理解什么是代理,再理解动静态举例举例所用代码 动静态的区别静态代理动态代理 动态代理的优点代理模式与装饰者模式的区别 代理模式 代理模式在设计模式中是7种结构型模式中的一种,而代理模式有分动态代理&#x…...
手机中有哪些逆向进化的功能
手机中有哪些逆向进化的功能?逆向进化是指明明很优秀的很方便的功能,却因为成本或者其他工业原因莫名其妙地给取消了。 逆向进化1:可拆卸电池-变为不可拆卸电池。 智能手机为了追求轻薄等原因,所以移除了可拆卸电池功能。将电池…...
LeetCode24.两两交换链表中的节点
参考链接:代码随想录:LeetCode24.两两交换链表中的节点 我这里使用了3个变量进行暴力交换,简单快捷!但是有一点想不明白,return这里只能写dh->next,写返回head就结果不对了!但是后面又想明白了ÿ…...

Eureka注册中心(黑马学习笔记)
Eureka注册中心 假如我们的服务提供者user-service部署了多个实例,如图: 大家思考几个问题: order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口? 有多个user-service实例地址,…...

unity-firebase-Analytics分析库对接后数据不显示原因,及最终解决方法
自己记录一下unity对接了 FirebaseAnalytics.unitypackage(基于 firebase_unity_sdk_10.3.0 版本) 库后,数据不显示的原因及最终显示解决方法: 1. 代码问题(有可能是代码写的问题,正确的代码如下ÿ…...
JWT(JSON Web Token)原理、应用与安全性分析
随着互联网的快速发展,Web应用的安全性越来越受到重视。在众多的安全认证技术中,JSON Web Token(JWT)凭借其简洁、自包含和传输安全的特点,被广泛应用于Web应用的用户身份验证和信息交换。 一、JWT的原理 JWT是一个开…...

Redis 缓存(Cache)
什么是缓存 缓存(cache)是计算机中的一个经典的概念在很多场景中都会涉及到。 核心思路就是把一些常用的数据放到触手可及(访问速度更快)的地方,方便随时读取。 这里所说的“触手可及”是个相对的概念 我们知道,对于硬件的访问速度来说,通常…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...