Windows程序内部运行原理

2023-05-16

本文大部分内容都是摘自孙鑫老师,在下就是一个简单的总结,归纳,希望对大家有用!!!!

Windows操作系统是一种完全不同于传统的dos方式的程序设计方法,是事件驱动的方式(主要是基于消息的,当用户需要完成某种功能时,会调用操作系统的某种支持,然后操作系统将用户的某种需要,包装成消息,并投递到消息队列中去,最后应用程序从消息队列中取走消息,并进行响应。)

Windows应用程序,操作系统,计算机硬件之间的相互关系。
这里写图片描述
1,表示操作系统能操作输出设备,以执行特定的功能:让声卡发出声音,让显卡显示图像
2,表示操作系统能够感知输入设备状态的变化:鼠标移动,键盘按下,并且能够清楚的明白当前移动到了那个位置,键盘按下的是什么字符

(这就是操作系统和计算机硬件之间的交互关系)
应用程序的开发者通常不需要知道具体的实现细节,我们所关心的仅仅是应用程序和操作系统之间的交互

3,表示应用程序可以通知操作系统执行某个具体的动作,操作系统能够控制声卡发出声音,但它并不知道应该何时发出什么样的声音,需要应用程序告诉操作系统该发出什么声音

那么,应用程序是如何通知操作系统执行某个功能的呢???
有过编程经验的读者都应该知道,在应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,,,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(Application Programming Interface),简称为Windows API。
如:CreateWindow就是一个API函数,应用程序中调用这个函数。操作系统就会按照该函数提供的参数信息产生一个相应的窗口。。

4,表示操作系统能够将输入设备的变化上传给应用程序。如:用户在某个程序活动中按下了一个按键,操作系统马上能够感知到这一事件,并且能够知道用户按下的是哪一个键,操作系统并不决定对这一事件如何做出反应,而是将这一事件转交给应用程序,由应用程序决定如何对这一事件做出反应。
蚊子叮了我们一口,我们的神经末梢(操作系统)马上感知到这一事件,并传递给了我们的大脑(应用程序),我们的大脑最终决定如何对这一事件做出反应。将蚊子赶走,或是拍死蚊子。
对事件做出反应的过程就是消息响应。。。。。

操作系统是如何将感知到的事件传递给应用程序的呢???
这是通过消息机制(Message)来实现的。操作系统将每个事件都包装成一个称为消息的结构体MSG来传递给应用进程,
MSG结构定义如下:

typedef struct tagMSG
{
        HWND hwnd;
        UINT    message;
        WPARAM wParam;
        LPARAM lParam;
        DWORD time;
        POINT pt;
}MSG;

句柄(HANDLE),资源的标示(和指针类似)
操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分为图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等到各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄

其实:WPARAM,LPARAM本质上就是int类型,之所以会出现,只是为了更加直观的明白这些参数的意义

WORD:是一个16位的整数
DWORD:是一个32位的整数,表示了这个消息被投递于消息队列中的时间
POINT:是一个点的结构体(当消息被投递时,光标在屏幕上的位置)

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR     lpCmdLine,
    int       nCmdShow
);

//HINSTANCE:当同样的应用程序打开多次的时候,产生多个窗口
//hPrevInstance:标示上一次打开的窗口
//(for a win32-based application,this parameter is always NULL)
//LP:long point(长指针)
//LPSTR:是一个指向字符串首地址的指针
//lpCmdLine:是一个命令行的参数(dos中接收两个参数:argc是参数的个数,argv是一个指针数组,用来存放命令行的参数),
//同样的,windows中也可以接收命令行的参数

//nCmdShow:窗口显示的状态。(最大化,最小化,隐藏显示)

WinMain:是一个入口点函数,其实是由操作系统来调用的,不是由我们去调用的。
当操作系统启动我们的程序的时候,会给我们运行中的程序分配一个实例号,通过这个参数就传递进来了,如果我们传递了一个参数的话,那么操作系统就会将这个参数放在相应的参数中(lpCmdLine)
上面的这些参数,都是由操作系统来赋值呢,,,,

窗口的创建:

创建一个完整的窗口需要经过下面四个操作步骤:
1,设计一个窗口类
2,注册窗口类
3,创建窗口
4,显示及更新窗口

设计一个窗口类???

因为一个窗口具有很多特征,光标(形状(十字,箭头)),图标,背景
也就是说:windows已经为我们定义了一个窗口所需要的因素,我们只需要向里面填写相应的值即可

这里写图片描述

style:
可能会出现:CS_HREDRAW, CS_VREDRAW
CS:表示的是class style
程序中:我们可能会这么写

wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE
//中间用的是(|)运算符,表示两者特性兼而有之
//水平重画,垂直重画,当我们窗口应用程序的水平,垂直坐标发生变化的时候,窗口此刻需要重画

窗口类的类型

在我们的程序中经常要用到一类变量,这个变量里的每一位(bit)都对应某一种特性。当该变量的某位为1时,表示有该位对应的那种特性,当该位为0时,即没有该位所对应的特性。当变量中的某几位同时为1时,就表示同时具有几种特性的组合。一个变量中的哪一位代表那种意义,不容易记忆,所以我们经常根据特征的英语拼写的大写去定义一些宏,该宏所对应的数值中仅有与该特征相对应的那一位(bit)为1,其余的bit都为0.
CS_VREDRAW = 0X0001
CS_HREDRAW = 0X0002
CS_DBLCLKS = 0X0008
CS_NOCLOSE = 0X0200
全部都是只有一位为1,其余全是0,如果我们希望某一变量的数值既有CS_VREDRAW的特性,又有CS_HREDRAW,我们只需要使用二进制OR(|)运算符,将其进行组合,如上
如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反(~)之后再进行与(&)运算,就可以实现,如在刚才的style基础上去掉CS_NOCLOSE特征,可以用style & ~CS_NOCLOSE

WNDPROC:    lpfnWndProc
/*
窗口过程的一个类型,(long point function,接收一个函数指针),

指定了这一类型窗口的过程函数,也称为回调函数(当应用程序收到某一个

窗口的消息时,就应该调用某一函数来处理这条消息(消息通常都是与窗口

相关的)。这一调用不是应用程

序自己来实施,而是由操作系统来完成的,但是,回调函数本身的代码必须

由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的那个

函数(回调函数)来处理呢???操作系统调用的就是接受消息的窗口所属

的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自

己专用的回调函数,该函数就是通过lpfnWndProc成员指定的)
*/
HINSTANCE:hInstance
//代表当前应用程序的实例号
HICON:    hIcon
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
HICON LoadIcon(
    HINSTANCE hInstance,
    LPCTSTR   lpIconName
);
//hInstance:handle to application instance
//this parameter must be NULL when a standard icon is being loaded.
//lpIconName: name string or resource identifier
//图标的句柄
HCURSOR:hCursor
//光标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
HCURSOR LoadCursor(
    HINSTANCE hInstance,
    LPCTRSTR  lpCursorName
);
//解释同上
HBRUSH:hbrBackground
//画刷的句柄
wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
//the GetStockObject function retrieves a handle to one of the stock pens , brushes, fonts, or palettes(获取一个句柄,笔,画刷,字体,调色板)
HGDIOBJ GetStockObject(
    int fnObject;
);
可以为:BLACK_BRUSH, DKGRAY_BRUSH, DC_BRUSH, WHITE_BRUSH, BLACK_PEN, DC_PEN, ANSI_FIXED_FONT
LPCSTR:lpszMenuName
//LPC: long point const
//菜单的名字
wndclass.lpszMenuName = NULL;//表面当前这个程序没有菜单
LPCTSTR:lpszClassName
//一个窗口类的名字

同样的,汽车的生产必须上交国家有关部门的批准。我们才能够生产汽车;类似的,当我们设计完一款新的窗口之后,需要对这个窗口进行注册,向操作系统进行注册,那么我们只有注册成功之后,我们才能创建基于当前类型的窗口

RegisterClass(&wndclass);
//注册一个窗口类
ATOM RegisterClass(
    CONST WNDCLASS * lpWndClass;
);
//创建一个窗口,首先需要一个句柄:
HWND hwnd;
//我们利用这个句柄来作为新创建窗口的标示

这里写图片描述

//窗口创建完成之后,就应该将我们的这个窗口显示出来
ShowWindow(hwnd, SW_SHOWNORMAL);

BOOL ShowWind(
    HWND hWnd,   //句柄
    int nCmdShow //窗口显示的状态(最大化,最小化)
);

//当然,我们还是需要更新的
UpdateWindow(hwnd);
//接下来,就到了我们程序当中关键的部分,消息循环
MSG msg;
while(GetMessage(&msg, NULL , 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
//GetMessage:从消息队列中取出一条消息
the GetMessage function retrieves a message from the calling thread's message queue.

BOOL GetMessage(
        LPMSG lpMsg,
        HWND  hWnd,
        UINT  wMsgFilterMin,
        UINT  wMsgFilterMax
);
//每一个应用程序,操作系统就会给其建立一个消息队列,当我们的一个窗口有消息的时候,操作系统会将这个消息放到消息队列当中。我们的程序就会通过GetMessage从消息队列中取出一条一条具体的消息
lpMsg: [out](out表明,在传参的过程中,不需要对这个结构体内部的成员进行初始化,我们只需要定义一个结构体变量,将地址放在这个位置就可以了,通过这个函数调用,会帮我们自动的填充消息结构体内部的变量,这就是out的含义,当我们调用getmessage的时候,这个函数就会从消息队列中取出一条消息,然后利用消息结构体的变量返回)

hWnd:是一个句柄(我们要获取的是哪一个窗口的消息),如果我们将其设置为NULL,则说明,我们需要获取属于这个调用线程的任何窗口的消息,如上,我们将其设置为NULL


wMsgFilterMin:可以指示这个消息的最小的消息值,在我们的消息队列当中,有很多的消息。那么我们可以对这个消息进行一些选择(有的消息可能感兴趣,有的消息可能不感兴趣),那么我们还可以指定一些消息的范围。就可以利用当前的这个参数来设定消息的最小值。(use WM_KEYFIRST to specify the first keyboard message or WM_MOUSEFIRST to specify the first mouse message.)

wMsgFilterMax:指示这个消息的最大值(use WM_KEYLAST to specify the last keyboard message or WM_MOUSELAST to specify the last mouse message.)

如果我们将我们上面两个消息设置为NULL的话,那么getmessage可以返回所有可以利用的消息,没有范围的过滤。
当然,我们也可以用这两个参数做一个消息的过滤,在这个范围当中的我们进行获取,不在这个范围当中的,我们过滤

GetMessage(&msg, NULL , 0, 0);


此刻GetMessage的返回值为bool类型的,当getmessage从消息队列中取出一条消息的时候,返回为真,如果我们能够保证这个消息队列当中始终都有消息的话,那么返回值应该永远为真
//下面我们紧接着用到了TranslateMessage(&msg)
上面提到了,while(getmessage(&msg, NULL00))
while1)的话,那么上面就是一个死循环,这样也就能够保证程序不断的运行,那么什么时候为假呢,也就是什么时候退出呢???
当我们取出一条消息的时候,我们才用到了translatemessage函数,转换消息,翻译消息,这个函数到底什么意思呢???
是对取到的消息对进行转换(当我们按下键盘上的一个按键,系统将发出一个WM_KEYDOWN和WM_KEYUP这样的两个消息,并且参数当中提供了键盘上的,刚才按键中的虚拟的扫描码,但是有时候用户按下某个键,我们想要得到的是用户输入某一个字符的消息,也就是键盘上对应的某一个字母,那么在消息补充的附加参数当中提供我们按键字母的一个ascii码),这个translatemessage函数能够将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且将转换后的消息投递到消息队列当中,(这个转换过程不会影响原来的消息只会产生一个新的消息,)也就是说,我们如果不用这样的消息的话,我们是不会受到WM_CHAR消息的。

当我们采用translatemessage消息的话,一旦我们按键,就能够将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且将转换后的消息投递到消息队列当中,也就是这样的话,就能捕获到WM_CHAR
这样的消息了。
dispatchmessage函数呢??
是将我们收到的消息传到窗口的回调函数中去,也就是窗口过程函数当中去处理,也可以理解为:将消息给了操作系统,然后操作系统调用我们的窗口过程函数,
所以,windows系统消息循环的整个机制:
当一个应用程序建立的时候,操作系统会为这个应用程序分配一个消息队列,凡是跟这个应用程序相关的消息,都会被放入到这个消息队列当中,然后,我们的应用程序利用这个getmessage从消息队列当中取出具体的消息,利用translatemessage将WM_KEYDOWN和WM_KEYUP这样的两个消息转换为WM_CHAR消息,并且投放的消息队列当中,利用dispatchmessage将这个消息投递出去,分发出去(操作系统,操作系统利用我们设计窗口类的时候所指定的窗口回调函数(winsunproc),在这个函数里面,对不同的消息做了不同的处理 )

LRESULT CALLBACK WindowProc(
    HWND hwnd,  //handle to window
    UINT uMsg,  //message identifier
    WPARAM wParam, //first message parameter
    LPARAM lParam  //second message parameter
);
函数名字可以改,参数的类型不能改,名字可以改。
四个参数和消息的四个参数很像。(也就是说:利用dispatchmessage的时候,操作系统会去调用这样的windowproc窗口过程函数,将这个消息参数结构体中的前四个参数传递给我们这个函数,对于消息的参数(有两个我们暂时不需要,一个是消息投递时的时间,另一个是光标在屏幕上的位置。))一旦有一个消息产生的时候,都会调用我们的窗口过程函数。因此,我们需要判断到底是哪一个消息。
MessageBox:
如下:我们的用法:
MessageBox(hwnd, szChar, "weixin", MB_OK);

int MessageBox(
    HWND    hWnd,      //handle to owner window
    LPCTSTR lpText,    //text in message box
    LPCTSTR lpCaption, //message box title
    UINT    uType      //message box style
);

程序简单代码:

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WinSunProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
)
{
    WNDCLASS wndcls;
    wndcls.cbClsExtra=0;
    wndcls.cbWndExtra=0;
    wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
    wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
    wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
    wndcls.hInstance=hInstance;
    wndcls.lpfnWndProc=WinSunProc;
    wndcls.lpszClassName="2016 3+1";
    wndcls.lpszMenuName=NULL;
    wndcls.style=CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&wndcls);

    HWND hwnd;
    hwnd=CreateWindow("2016 3+1","wince3+1",WS_OVERLAPPEDWINDOW,
        0,0,600,400,NULL,NULL,hInstance,NULL);

    ShowWindow(hwnd,SW_SHOWNORMAL);
    UpdateWindow(hwnd);

    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

LRESULT CALLBACK WinSunProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
    switch(uMsg)
    {
    case WM_CHAR:
        char szChar[20];
        sprintf(szChar,"char is %d",wParam);
        MessageBox(hwnd,szChar,"weixin",0);
        break;
    case WM_LBUTTONDOWN:
        MessageBox(hwnd,"mouse clicked","wince3+1",0);
        HDC hdc;
        hdc=GetDC(hwnd);
        TextOut(hdc,0,50,"hello, world",strlen("hello, world"));
        ReleaseDC(hwnd,hdc);
        break;
    case WM_PAINT:
        HDC hDC;
        PAINTSTRUCT ps;
        hDC=BeginPaint(hwnd,&ps);
        TextOut(hDC,0,0,"3+1",strlen("3+1"));
        EndPaint(hwnd,&ps);
        break;
  case WM_CLOSE:
        if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))
        {
            DestroyWindow(hwnd);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd,uMsg,wParam,lParam);
    }
    return 0;
}

运行结果:
(点击左键)
这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windows程序内部运行原理 的相关文章

  • Python-面向对象之多态

    当子类和父类都存在相同的run 方法时 xff0c 我们说 xff0c 子类的run 覆盖了父类的run xff0c 在代码运行的时候 xff0c 总是会调用子类的run 这样 xff0c 我们就获得了继承的另一个好处 xff1a 多态 c
  • 使用Ubuntu帐户创建SFTP

    提供sftp服务的有vsftpd和internal sftp xff0c 这里用的是系统自带的internal sftp xff0c 操作步骤如下 xff1a 1 创建用户 testenv xff0c 并禁止ssh登录 xff0c 不创建家
  • flask数据分页paginate的使用(flask学习)

    Flask的数据分页示例 1 xff0c 首先写数据获取的视图函数 xff0c 就像这样 xff1a 64 app route 39 39 64 login required def index page 61 request args g
  • Python __dict__属性详解

    我们都知道Python一切皆对象 xff0c 那么Python究竟是怎么管理对象的呢 xff1f 1 无处不在的 dict 首先看一下类的 dict 属性和类对象的 dict 属性 coding utf 8 class A object 3
  • Flask-SQLAlchemy 中的 relationship & backref

    今天重看 Flask 时 xff0c 发现对backref仍然没有理解透彻 查阅文档后发现 xff0c 以前试图孤立地理解backref是问题之源 xff0c backref是与relationship配合使用的 一对多关系 db rela
  • Django HttpResponse与JsonResponse

    我们编写一些接口函数的时候 xff0c 经常需要给调用者返回json格式的数据 xff0c 那么如何返回可直接解析的json格式的数据呢 xff1f 首先先来第一种方式 xff1a from django shortcuts import
  • Ubuntu安装mysql

    首先执行下面三条命令 xff1a sudo apt get install mysql server sudo apt install mysql client sudo apt install libmysqlclient dev 安装成
  • 10种动态进度条用css3实现

    用css做的10种动态进度条 xff0c 喜欢可以直接去用话不多说先看效果图 xff1a 实现上图的 xff0c 最主要的就是应用了css动画属性 64 keyframes和animation属性结合应用 下面看看语法 xff1a 64 k
  • Yolo训练数据标注工具-Yolo_mark 使用教程

    一 安装与测试 环境 xff1a Ubuntu16 04 43 Opnecv 43 Cmake 项目地址 xff1a https github com AlexeyAB Yolo mark 下载 打开终端 xff0c 键入 xff1a gi
  • x86、ARM分属大小端

    小端模式 xff1a 一个数据的高位在大的地址端 xff0c 低位在小的地址端 xff0c x86也就是pc机就是小端的 xff1a include 34 stdio h 34 include 34 stdlib h 34 int main
  • 二叉树(C语言实现)——链式存储结构

    include lt stdio h gt include lt stdlib h gt include lt stdbool h gt define QueueSize 200 typedef char DataType typedef
  • 栈,堆,常量区都放什么

    1 寄存器 xff1a 最快的存储区 由编译器根据需求进行分配 我们在程序中无法控制 xff1b 1 栈 xff1a 存放基本类型的变量数据和对象的引用 xff0c 但对象本身不存放在栈中 xff0c 而是存放在堆 xff08 new 出来
  • Windows10安装Docker并创建本地Ubuntu环境

    安装Docker参考文章 xff1a https www cnblogs com Can daydayup p 15468591 html label0 安装本地Ubuntu环境 xff1a windows10下安装docker xff0c
  • 机器人操作系统ROS是什么?

    目录 1 什么是ROS 2 ROS的许可协议 3 ROS的主要发行版本 4 ROS的主要功能 5 ROS的应用 6 ROS开发的常用工具 7 ROS的优点 8 ROS的缺点 1 什么是ROS ROS是机器人操作系统 xff08 Robot
  • 【教程】如何移植FPGA关于HDMI例程

    教程 如何移植FPGA关于HDMI例程 时钟IP核约束条件 在完成EDA作业后 xff0c 抽空分享一下如何移植FPGA的例程 我EDA作业用的板子型号是Zybo Z7 xff0c 然后移植的是原子哥的HDMI实现方块移动例程 故本教程是基
  • 【MATLAB UAV Toolbox】使用指南(三)

    可视化自定义飞行日志 通过配置flightLogSignalMapping可从自定义的飞行日志中可视化数据 加载自定义的飞行日志 在本例中 xff0c 假设飞行数据已经被解析到MATLAB 中 xff0c 并存储为M文件 本示例重点介绍如何
  • matplotlib学习笔记

    matplotlib第一章 matplotlib通常有两种绘图接口 xff1a 显示创建figure和axes 依赖pyplot自动创建figure和axes 并绘图 matplotlib环境 本文是在jupyter notebook下运行
  • OPNET 修改节点图标大小

    老是记不住在哪修改图标 xff0c 有一天看急眼了 xff0c 经过半小时的斗争 xff0c 终于找到了 xff0c 这次一定要把它记下来 View gt Layout gt Scale Node icons Interactively
  • 自定义msg使用C++

    在之前创建talker的src文件夹中创建person cpp并编写如下 include 34 ros ros h 34 include 34 learning communication Person h 34 include lt ss
  • GPIO的八种模式分析

    GPIO是general purpose input output 即通用输入输出端口 xff0c 作用是负责外部器件的信息和控制外部器件工作 GPIO有如下几个特点 xff1a 1 不同型号的IO口数量不同 xff1b 2 xff0c 反

随机推荐

  • 关于STM32_IWDG独立看门狗的一些笔记

    独立看门狗 IWDG xff0c Independent watchdog xff0c 本质是一个可以定时产生系统复位信号 并且可以通过 喂狗 复位的计时器 它由独立的RC振荡器 低速时钟 LSI 驱动 xff0c 即使主时钟发生故障它也仍
  • 关于MPU的笔记

    MPU xff08 memory protection unit xff09 内存保护单元 这些系统必须提供一种机制来保证正在运行的任务不破坏其他任务的操作 即要防止系统资源和其他一些任务不受非法访问 嵌入式系统有专门的硬件来检测和限制系统
  • 关于OLED屏的笔记

    OLED即有机发光管 Organic Light Emitting Diode OLED OLED显示技术具有自发光 广视角 几乎无穷高的对比度 较低功耗 极高反应速度 可用于绕曲性面板 使用温度范围广 构造及制程简单等有点 xff0c 被
  • Ubuntu 上 Let‘s Encrypt 生成泛域名证书

    安装生成工具certbot xff1a apt install certbot 查看安装在哪 xff1a which certbot 使用certbot xff08 位置在 usr bin certbot xff09 生成证书 xff1a
  • DMA的补充笔记

    DMA有两个总线 xff1a 1 DMA存储器总线 xff1a DMA通过该总线来执行存储器数据的传入和传出 2 DMA外设总线 xff1a DMA通过该总线访问AHB外设 xff08 AHB主要是针对高效率 高频宽以及快速系统模块所设计的
  • 关于ADC的笔记1

    ADC xff0c 全称Anlog to Digital Converter xff0c 模拟 数字转换器 是指将连续变量的模拟信号转换为离散的数字信号的器件 xff0c 我们能通过ADC将外界的电压值读入我们的单片机中 常见的ADC有两种
  • STM32-ADC单通道采集实验

    实验要求 xff1a 通过ADC1通道 xff08 PA1 xff09 采集电位器的电压 xff0c 并显示ADC转换的数字量及换算后的电压值 首先要确定最小刻度 Vref 61 3 3V xff0c 所以输入电压有效范围在0V lt 61
  • jetson xavier nx安装ROS Melodic

    1 前期准备 打开系统设置 软件和更新 xff0c 确保图示的选项已选中 点击close xff0c 选择reload 在不同的教程里搜到的这一步都不同 xff0c 似乎没什么影响 xff0c 就很迷 2 设置你的源文件列表 设置计算机以接
  • sylixos标准工程移植到Lite版本

    1 概述 针对低端处理器 xff08 如ARM M系列处理器 xff09 的开发工作 xff0c 翼辉信息推出了SylixOS Lite工程版本 SylixOS Lite版本工程属于SylixOS轻量级工程 xff0c 与标准的SylixO
  • Linux下TCP/IP网络编程示例——实现服务器/客户端通信(一)

    一 说明 最近梳理网络编程的一些知识点时 xff0c 整理了一些笔记 xff0c 写了一些demo例程 xff0c 主要包含下面几部分 xff0c 后面会陆续完成 1 Linux下TCP IP网络编程示例 实现服务器 客户端通信 xff08
  • OpenMV色块寻找

    OpenMV入门 xff0c 从入门到入坟 gt lt 此文章大部分内容取自OpenMV官方中文参考文档 详情看OpenMV官方中文参考文档 文章目录 一 sensor snapshot 拍一张照片二 image find blogs 查找
  • 四轴 PID 调试

    四轴 PID 用到了串级 PID xff0c 即两个闭环 xff0c 分别为 角速度环 xff08 内环 xff09 和角度环 xff08 外环 xff09 调试时 xff0c 先整定内环PID xff0c 再整定外环 P 内环 P xff
  • bind:address already in use的深刻教训以及解决办法

    今天在linux下 xff0c 编写了一个简单的回射客户 服务器 xff08 就是客户机从控制台标准输入并发送数据 xff0c 服务端接受数据 xff0c 但是不对数据进行处理 xff0c 然后将数据返回 xff0c 交由客户机标准输出 x
  • stm32简说步进电机(有代码)!!!

    步进电机 xff08 也称脉冲电机 xff09 xff08 将电脉冲转换为相应的角位移或线位移的电磁机械装置 xff0c 具有快速启动 xff0c 停能力 xff0c 在电机的负荷不超过它能提供的动态转矩时 xff0c 可以通过输入脉冲来控
  • 阿里云Linux Ubentu16.04 安装 Nginx 并配置 https,后续升级openssl和Nginx

    一 准备工作 进入安装目录 cd usr local 下载nginx xff08 官网选择版本稳定版即可 xff1a http nginx org en download html xff09 wget http nginx org dow
  • C++多线程面向对象封装

    相信很多人都读过 C 43 43 沉思录 这本经典著作 xff0c 在我艰难地读完整本书后 xff0c 留给我印象最深的只有一句话 xff1a 用类表示概念 xff0c 用类解决问题 关 于多线程编程 xff0c 如果不是特别需要 xff0
  • stm32(寄存器)超声波程序

    我们是基于stm32f103系列 xff0c 超声波模块用的是 xff1a HC SR04 寄存器版的代码 编译器用的是 xff1a keil5 在此 xff1a 输入捕获用的是TIM2 CH1 用的是PA0 xff0c 可以从开发板原理图
  • 127.0.0.1和localhost和本机IP三者的区别!!!

    1 xff0c 什么是环回地址 xff1f xff1f 与127 0 0 1的区别呢 xff1f xff1f 环回地址是主机用于向自身发送通信的一个特殊地址 xff08 也就是一个特殊的目的地址 xff09 可以这么说 xff1a 同一台主
  • malloc函数,大大的详解

    很多学过C的人对malloc都不是很了解 xff0c 知道使用malloc要加头文件 知道malloc是分配一块连续的内存 xff0c 知道和free函数是一起用的 但是但是 xff1a 一部分人还是将 xff1a malloc当作系统所提
  • Windows程序内部运行原理

    本文大部分内容都是摘自孙鑫老师 xff0c 在下就是一个简单的总结 xff0c 归纳 xff0c 希望对大家有用 xff01 xff01 xff01 xff01 Windows操作系统是一种完全不同于传统的dos方式的程序设计方法 xff0