单片机学习笔记---红外遥控红外遥控电机调速(完结篇)

目录

低电平触发中断和下降沿触发中断的区别

红外遥控

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;//取出高八位赋值给TH0
	TL0=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();//初始化定时器0
	Int0_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);	//定时计数器清0
		Timer0_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;	//置收到连发帧标志位为1
			Timer0_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));	//数据对应位置1
			IR_pData++;			//数据位置指针自增
		}
		else					//接收出错
		{
			IR_pData=0;			//数据位置指针清0
			IR_State=1;			//置状态为1
		}
		
		//32位数据解码完成后,开始验证
		if(IR_pData>=32)		//如果接收到了32位数据
		{
			IR_pData=0;			//数据位置指针清0
			if((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			0x4A

void 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~99
	if(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两种源码),如有问题可评论区留言!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件安装遇到bug、报错不知道怎么解决?赶紧收藏起来!

前言 本文举例了几个常见的软件工具使用问题&#xff0c;文末会提供一些我自己整理和使用的工具资料 。 "在追逐零 Bug 的路上&#xff0c;我们不断学习、改进&#xff0c;更加坚定自己的技术信念。让我们相信&#xff0c;每一个 Bug 都是我们成长的机会。" 一、VM…

Microsoft Visio 摄像机图标

Microsoft Visio 摄像机图标 1. 更多形状 -> 搜索形状2. 摄像机References 1. 更多形状 -> 搜索形状 2. 摄像机 ​​​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

2024云服务器ECS新老用户优惠价格表,收费更新

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

h5页面实现图片局部热区跳转

之前没有了解过图片局部热区跳转这种样式&#xff0c;百度搜索实现方法发现两种方法。所谓图片热区跳转就是用户点击图片中的某些区域可以跳转到不同的页面&#xff0c;如下图&#xff0c;点击“舞动人生馆”可以跳转到舞动人生对应的活动页面&#xff0c;点击展望美好馆可以跳…

【嵌入式学习】QT-Day1-Qt基础

笔记 https://lingjun.life/wiki/EmbeddedNote/20QT 毛玻璃登录界面实现&#xff1a;

Android的Compose

Jetpack Compose 是用于构建原生 Android 界面的新工具包&#xff0c;无需修改任何 XML 布局&#xff0c;也不需要使用布局编辑器。相反&#xff0c;只需调用可组合函数来定义所需的元素&#xff0c;Compose 编译器即会完成后面的所有工作。 简而言之&#xff0c;使用Compose&…

【论文精读】ESViT

摘要 基于transformer的SSL方法在ImageNet线性检测任务上取得了最先进的性能&#xff0c;其关键原因在于使用了基于对比学习方法训练单尺度Transformer架构。尽管其简单有效&#xff0c;但现有的基于transformer的SSL&#xff08;自监督学习&#xff09;方法需要大量的计算资源…

Laravel02 路由基本概念和用法 给视图传递请求参数

Laravel02 路由基本概念和用法 1. 路由的基本概念2. 给视图传递请求参数 1. 路由的基本概念 routes文件夹下的web.php是用来定义路由规则的。 自己定义一个路径 2. 给视图传递请求参数 在laravel里使用一个辅助函数request来快速获取请求参数

[ansible] playbook角色

一、roles Roles又称为角色&#xff0c;playbook被称为剧本。Roles角色是自1.2版本之后引入的新特性&#xff0c;用于层次性、结构化的组织剧本 roles能够根据层次型结构自动装载变量文件、任务集、以及触发的动作等&#xff0c;要使用roles只需要在剧本中使用include命令引入…

五种多目标优化算法(MOAHA、MOGWO、NSWOA、MOPSO、NSGA2)性能对比,包含6种评价指标,9个测试函数(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOAHA 1.2MOGWO 1.3NSWOA 1.4MOPSO 1.5NSGA2 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数&#xff08;zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3&#xff09;&#xff…

计算机网络看这里就够了!!!

入门概念 参考视频链接&#xff1a; 1.2 因特网概述_哔哩哔哩_bilibili 一些基础概念 因特网发展阶段&#xff1a; 三个大标题&#xff1a; 从单个ARPANET-----逐步建成三级结构的因特网----逐步形成多层次ISP结构(互联网服务提供商&#xff08;Internet Service Provider…

MAC端Terminus 绿色版下载【一键安装,即可使用】

Termius Mac 是一款非常好用而且漂亮的SSH客户端&#xff0c;能快速远程控制服务器 现在呢&#xff0c;很多小伙伴&#xff0c;都开始使用这个软件啦 但是对于mac系统来说&#xff1a; 这个软件不要在苹果app store下载&#xff0c;不能实现传输功能这个软件目前有7天适用期&a…

【Linux权限】 Linux权限管理 | 粘滞位

文章目录 Linux权限管理什么是权限 ❓&#x1f4a6; 文件访问者的分类(人)&#x1f4a6; 文件类型和访问权限(事物属性) &#x1f4a6; 文件访问权限的相关设置方法目录的权限 粘滞位 Linux权限管理 什么是权限 ❓ 权限本质上是决定某件事情&#xff0c;某人能否做。 Linux下…

【Linux】主机搭建 Linux服务器环境 笔记

目录 前言选择系统软件1. 用U盘装系统2. 安装 Centos7.93. 网络套件 应用软件1. ngnix2. 防火墙配置3. nodejs 后记 前言 过年买了个 mini 主机当玩具玩一下&#xff0c;这里记录下。 选择 已有主力机 (windows) 的情况下&#xff0c;使用过如下四种 Linux宿主环境。这里总…

猫头虎分享已解决Bug || Python AI错误处理:IndexError

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

基于情感分析的网上图书推荐系统

项目&#xff1a;基于情感分析的网上图书推荐系统 摘 要 基于网络爬虫的数据可视化服务系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取网上商品评论信息实现商品评论的情感分析系统功能。对于…

IO进程-day3

1>多线程实现文件拷问 代码&#xff1a; #define MAXSIZE 1024 #include<myhead.h>int main(int argc, char const *argv[]) {FILE *srcfpNULL;FILE *destfpNULL;if((srcfp fopen("./pm.bmp", "r")) NULL){perror("fopen error");re…

【PCIE709-F】基于复旦微JFM7VX690T80 FPGA的全国产化8通道光纤双FMC接口数据处理平台

板卡概述 PCIE709-F是一款基于上海复旦微电子的28nm 7系列FPGA JFM7VX690T80的全国产化8通道光纤双FMC接口数据预处理平台&#xff0c;该板卡采用复旦微的高性能7系列FPGA作为实时处理器&#xff0c;实现4路10G SFP光纤以及1路QSFP通信接口、实现1路X8 PCIE数据传输的功能。板载…

MySQL 锁的内存结构

目录 1.摘要 2. 加锁的本质 3. 锁结构详解 3.1 锁所在的事务信息 3.2 索引信息 3.3 表锁/行锁信息 3.4 type_mode 3.5 其他信息 3.6 一堆比特位 1.摘要 在 MySQL 中&#xff0c;有很多种锁&#xff0c;例如行锁&#xff0c;表锁&#xff0c;页锁&#xff0c;全局锁&a…

0207-2-计算机组成

Principle-of-Computer-Composition 计算机组成原理思维导图 计算机组成 第一章 计算机系统概论 冯诺依曼型计算机特点 1.计算机由运算器&#xff0c;控制器&#xff0c;存储器&#xff0c;输入和输出设备5部分组成2.采用存储程序的方式&#xff0c;程序和数据放在同一个存…