STM32_9(USART串口)

一、串口通信

  • 串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信
  • 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力

1. 硬件电路

  • 简单双向串口通信有两根通信线(发送端TX和接收端RX)
  • TX与RX要交叉连接
  • 当只需单向的数据传输时,可以只接一根通信线
  • 当电平标准不一致时,需要加电平转换芯片

        一个设备使用TX发送高低电平,另一个设备使用RX接收高低电平。

        因为STM32是3.3V,所以线路对地是3.3V,就代表发送了逻辑1,线路对地为0V,就代表了发送逻辑0。

2. 串口参数及时序

  • 波特率:串口通信的速率(串口一般使用异步通信,需要双方约定一个通信速率)
  • 起始位:标志一个数据帧的开始,固定为低电平
  • 数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
  • 校验位:用于数据验证,根据数据位计算得来(奇校验:加入需要传输的字节为0000 1111,则在最后一位补一个1为 5个1为奇数,如果传输的字节为0000 0111,则最后一位补一个0,3个1为奇数,最后在接收放验证个数是不是奇数。偶校验同理,但奇偶校验只能保证一定程度上的数据校验)
  • 停止位:用于数据帧间隔,固定为高电平

        串口中每一个字节都装载在一个数据帧里,每个数据帧都由起始位,数据位,停止位组成。左图数据位有8位,代表一个字节8位,右图数据位有9位,最后一个为奇偶校验位。

        没用工作的时候都是空闲为高电位,开始工作的时候有一个起始位为低电平,产生下降沿,来告诉接收设备,我要发数据了。同理,一个字节数据发送完成后,必须要有一个停止位。

二、USART

  • USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器
  • USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里
  • 自带波特率发生器,最高达4.5Mbits/s
  • 可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)
  • 可选校验位(无校验/奇校验/偶校验)
  • 支持同步模式、硬件流控制(在硬件电路上会多出一根线,如果B没准备好接收,就置高电平,如果准备好了就置低电平,A会根据电平来发送数据)、DMA、智能卡、IrDA、LIN
  • STM32F103C8T6 USART资源: USART1、 USART2、 USART3

1. USART框图

        发送数据寄存器:排队等待打饭;发送移位寄存器:正在打饭;

        接收移位寄存器:拿到了饭;接收数据寄存器:开始吃饭。

2. USART基本结构

        当数据由数据寄存器转到移位寄存器时,会置一个TXE的标志位,判断这个标志位就可以知道是否可以写入下一个数据;

        同理,移位寄存器转到数据寄存器的时,会置一个RXNE的标志位,检查这个标志位就可以知道是否收到数据了。

3. 数据帧

        停止位就是停止的位数,一般常用于一位停止位。

4. 起始位侦测

        当输入电路侦测到一个数据帧的起始位后,就会以波特率的帧率,连续采样一帧数据。同时,从起始位开始,采样位置就要对其到位的正中间,只要第一位对齐了,后面就肯定对齐。

        首先输入的部分电路对采样时钟进行了细分,它会以波特率16倍频率进行采样,也就是一位的时间里,进行16次采样。

        最开始,空闲状态高电平采样一直为1,在某个位置突然采样到0,那么说明在这两次采样之间出现了下降沿,如果没有任何噪声,就应该是起始位。在起始位进行连续16次采样。

5. 数据采样

        从1到16是一个数据位的时间长度,在一个数据位,有16个采样时钟,由于起始位侦测到已经对齐了采样的时钟,所有就在8、9、10次开始采样,为了保证数据准确性性,是连续采样3次。由于噪声的影响,它是由2:1规则来,2次为1则为1,两次为0则为0。这种情况下,噪声标志位NE也会置1,告诉我,虽然我收到数据了,但有噪声,需要考虑使用。

6. 波特率发生器(寄存器)

  • 发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
  • 计算公式:波特率 = fPCLK2/1 / (16 * DIV)    (为什么有16,因为一个数据位,有16个采样时钟)
  • 如果是使用库函数,库函数自动帮我们算好BRR

7. HEX数据包

        数据包作用:把一个个单独的数据打包起来,方便进行多字节的数据通信。

        比如:陀螺仪传感器需要用串口发送数据STM32。

        固定包长,含包头包尾。

        这里定义0xFF为包头,0xFE为包尾。

        可变包长,含包头包尾。

        如果载荷会出现包头包尾重复的情况,最好选择固定包长,避免接收错误;如果载荷不会和包头包尾重复,可以选择可变包长。

8. 文本数据包

        固定包长,含包头包尾。

        这里以@作为包头,以\r\n作为包尾。

        可变包长,含包头包尾。

9. HEX数据包流程图

        这里可以利用状态机。先定义3个状态,第一个状态是等待包头,第二个状态是接收数据,第三个状态时等待包尾。

        最开始S=0,收到一个数据进入中断,根据S=0进入第一个状态的程序,判断数据是不是包头FF,如果时FF,则代表收到包头,之后置S=1,退出中断结束。这样下次进中断,就可以根据S=1进行接收数据程序。那在第一个状态,如果收到的不是FF,证明数据包没有对齐, 所以包头仍为0。下次进中断还是进入包头,直到出现FF,才进入下一状态。如果出现了FF,就可以转移到接收数据状态,这时再收到数据,就直接把它存在数组中,另外再用一个变量,记录收了多少个数据,如果没有收够4个数据,就一直是接收状态,如果收够了,就置S=2,下次中断时,就可以进去下一个状态。最后一个等待包尾,判断是不是FE,如果是则置S=0,回到最初的状态开始下一次轮回,如果不是就一直等待FE。

10. 文本数据包流程图

        这个与上面数据包流程图类似,但这个是可变包长,需要在S=1时接收数据并且等待包尾,需要时刻监视是不是该收包尾。

建议

        一般情况下,HEX数据包一般多用于传输各种传感器的每个独立数据,比如陀螺仪的X,Y,Z轴数据,温湿度数据等。那文本数据包一般可以利用发送文字到串口,实现相应功能。

二、代码部分

1. 串口发送和接收

#include "Bsp_Serial.h"

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init(void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);          // 1.时钟配置
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;                            // 2.配置GPIO
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 // 在手册中推荐使用复用推挽
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                          

    USART_InitTypeDef USART_InitStructure;                          // 3.配置USART      
    USART_InitStructure.USART_BaudRate = 9600;                      // 波特率
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;     // 硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 同时开启发送和接收
    USART_InitStructure.USART_Parity = USART_Parity_No;             // 奇偶校验位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;          // 停止位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 传输位长
    USART_Init(USART1, &USART_InitStructure);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  // 开启串口中断

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 // 设置中断组
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART1, ENABLE);                                      // 4.开启串口1

}

/* 发送一个字节 */
void Serial_SendByte(uint8_t Byte)                                  // 这里只传8位,用uint_8可以。要传9位的话就得是uint_16的类型了
{
    USART_SendData(USART1, Byte);
    while ((USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET));
}

/* 发送一个数组 */
void Serial_SendArray(uint8_t *Array, uint32_t Length)
{
    for (uint16_t i = 0; i < Length; i++)
    {
        Serial_SendByte(Array[i]);
    }
}

/* 发送字符串 */
void Serial_SentString(char *String)
{
    for (uint8_t i = 0; String[i] != '\0'; i++)
    {
        Serial_SendByte(String[i]);
    }
}

/* 次方 */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
    uint32_t Result = 1;
    while (Y --)
    {
        Result *= X;
    }
    return Result;
}

/* 发送十进制数字 */
void Serial_SentNumer(uint32_t Number, uint8_t Length)
{
    for (uint8_t i = 0; i < Length; i++)
    {
        Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    }
    
}

/* 移植printf到串口 fputc是printf的底层函数,利用这个函数重定位到串口 */
int fputc(int ch, FILE *f)
{
    Serial_SendByte(ch);
    return ch;
}

/* 封装sprintf */
void Serial_Printf(char *format, ...)
{
    char String[100];
    va_list arg;                    // va_list是一个类型名,arg是变量名
    va_start(arg, format);          // va_start是从format位置开始接收参数表,放在arg里
    vsprintf(String, format, arg);  // 打印位置是String,格式化字符串是format,参数表是arg
    va_end(arg);                    // 释放参数表 
    Serial_SentString(String);
}

/* 检测RXNE标志位 */
/*
void Serial_RXNE_Flag(uint8_t RxData)
{
    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
    {
        RxData = USART_ReceiveData(USART1);
        OLED_ShowHexNum(1, 1, RxData, 2);
    }
}
*/

/* 中断接收封装 */
uint8_t Serial_GetRxFlag(void)
{
    if (Serial_RxFlag == 1)
    {
        Serial_RxFlag = 0;
        return 1;
    }
    return 0;
}

/* 中断变量封装 */
uint8_t Serial_GetRxData(void)
{
    return Serial_RxData;
}

/* USART1中断函数 */
void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USART1, USART_IT_RXNE) == 1)
    {
        Serial_RxData = USART_ReceiveData(USART1);
        Serial_RxFlag = 1;
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

2. 串口发送HEX数据包

#include "Bsp_Serial.h"

// uint8_t Serial_RxData;
uint8_t Serial_RxPacket[4];
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxFlag = 0;

void Serial_Init(void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);          // 1.时钟配置
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;                            // 2.配置GPIO
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 // 在手册中推荐使用复用推挽
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                          

    USART_InitTypeDef USART_InitStructure;                          // 3.配置USART      
    USART_InitStructure.USART_BaudRate = 9600;                      // 波特率
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;     // 硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 同时开启发送和接收
    USART_InitStructure.USART_Parity = USART_Parity_No;             // 奇偶校验位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;          // 停止位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 传输位长
    USART_Init(USART1, &USART_InitStructure);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  // 开启串口中断

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 // 设置中断组
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART1, ENABLE);                                      // 4.开启串口1

}


/* 中断接收封装 */
uint8_t Serial_GetRxFlag(void)
{
    if (Serial_RxFlag == 1)
    {
        Serial_RxFlag = 0;
        return 1;
    }
    return 0;
}

/* 每次发送HEX数据包加上包首和包尾 */
void Serial_SendPacket(void)
{
    Serial_SendByte(0xFF);
    Serial_SendArray(Serial_TxPacket, 4);
    Serial_SendByte(0xFE);
}

/* 中断变量封装 */
/* 
uint8_t Serial_GetRxData(void)
{
    return Serial_RxData;
}
*/

/* USART1中断函数 */
void USART1_IRQHandler(void)
{
    static uint8_t RxState = 0;                             // static类似于全局变量,只初始化一次,但与全局变量不同的是,静态变量只在本函数使用         
    static uint8_t pRxPacket = 0;                           // 指示接收到第几个了

    if (USART_GetITStatus(USART1, USART_IT_RXNE) == 1)
    {
        uint8_t RxData = USART_ReceiveData(USART1);
        switch (RxState)                                    // 这里使用了状态机
        {
            case 0:
            {
                if (RxData == 0xFF)
                {
                    RxState = 1;
                    pRxPacket = 0;
                }
            }
            break;

            case 1:
            {
                Serial_RxPacket[pRxPacket] = RxData;
                pRxPacket ++;
                
                if (pRxPacket >= 4)
                {
                    RxState = 2;
                }
            }
            case 2:
            {
                if (RxData == 0xFE)
                {
                    RxState = 0;
                    Serial_RxFlag = 1;
                }   
            }
        }
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);             
    }
}

3. 串口发送文本数据包

#include "Bsp_Serial.h"

// uint8_t Serial_RxData;
char Serial_RxPacket_Char[100];                                     // 接收文本数据包变量
uint8_t Serial_RxPacket[4];                                         // 接收HEX数据包变量
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxFlag = 0;

void Serial_Init(void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);          // 1.时钟配置
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;                            // 2.配置GPIO
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 // 在手册中推荐使用复用推挽
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                          

    USART_InitTypeDef USART_InitStructure;                          // 3.配置USART      
    USART_InitStructure.USART_BaudRate = 9600;                      // 波特率
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;     // 硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 同时开启发送和接收
    USART_InitStructure.USART_Parity = USART_Parity_No;             // 奇偶校验位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;          // 停止位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 传输位长
    USART_Init(USART1, &USART_InitStructure);

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  // 开启串口中断

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 // 设置中断组
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART1, ENABLE);                                      // 4.开启串口1

}

/* 文字数据包状态机 */
void USART1_IRQHandler(void)
{
    static uint8_t RxState = 0;                             // static类似于全局变量,只初始化一次,但与全局变量不同的是,静态变量只在本函数使用         
    static uint8_t pRxPacket = 0;                           // 指示接收到第几个了

    if (USART_GetITStatus(USART1, USART_IT_RXNE) == 1)
    {
        uint8_t RxData = USART_ReceiveData(USART1);
        
        switch (RxState)
        {
            case 0:
            {
                if (RxData == '@' && Serial_RxFlag == 0)        // 如果两个条件满足才接受,如果没有Serial_RxFlag,就怕到时候传输数据太快,错位。
                {
                    RxState = 1;
                    pRxPacket = 0;
                }
            }
            break;

            case 1:
            {
                if (RxData == '\r')
                {
                    RxState = 2;
                }
                else
                {
                    Serial_RxPacket_Char[pRxPacket] = RxData;
                    pRxPacket ++;
                }
            }
            break;
            case 2:
            {
                if (RxData == '\n')
                {
                    RxState = 0;
                    Serial_RxPacket_Char[pRxPacket] = '\0';
                    Serial_RxFlag = 1;
                }   
            }
            break;
        }

        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

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

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

相关文章

西南科技大学(数据结构A)期末自测练习一

一、填空题(每空0.5分,共5分) 1、数据结构是指( A )。 A、数据元素的组织形式 B、数据类型 C、数据存储结构 D、数据定义 2、数据结构被形式地定义为(D,R),其中D是( B )的有限集合,R是D上( D )的有限集合。 (1)A.算法B.数据元素C.数据操作D.逻辑结构 (2)A.操作B.…

滴滴昨晚崩了,看这波还敢不敢降本增效?

起因 截至 2023 年 11 月 27 日晚&#xff0c;中国最大的网约车服务平台滴滴打车遭遇系统崩溃&#xff0c;继阿里云控制台故障之后&#xff0c;再次引发热议。这一事件迅速攀升至热搜榜首&#xff0c;引起广泛关注。 今晚约 10 点&#xff0c;滴滴打车遭遇大范围技术故障。用户…

小程序----使用图表显示数据--canvas

需求&#xff1a;在小程序上实现数据可视化 思路&#xff1a;本来想用的是echarts或者相关的可视化插件&#xff0c;但因为用的是vue3&#xff0c;大多数插件不支持&#xff0c;所以用了echarts&#xff0c;但最后打包的时候说包太大超过2M无法上传&#xff0c;百度了一下&…

[Linux] 正则表达式及grep和awk

一、正则表达式 1.1 什么是正则表达式 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本模式。 正则表达式可以在文本中查找、替换、提取和验证特定的模式。 正则表达式和通配符的区别 正则…

继承JsonSerializer+注解实现自定义数据脱敏方案

1、数据脱敏 数据脱敏是一种保护隐私数据的技术&#xff0c;通过将敏感信息转化为非敏感信息来实现对数据的保护&#xff0c;以保护敏感隐私数据的可靠性和安全性。 数据脱敏可以分为可恢复和不可恢复两类: 可恢复类可以通过一定的方式恢复成原来的敏感数据。不可恢复类则无…

计算机基础知识59

MySQL的卸载流程 1、先停止MySQL服务&#xff1a;右键“此电脑”&#xff0c;选择“管理”&#xff0c;之后选择“服务和应用程序”--“服务”&#xff0c;在服务中找到“MySQL”&#xff0c;右键选择“停止”。 2、找到“控制面板”--“程序和功能”&#xff0c;找到MySQL&…

C++二分查找视频教程:两数之和

作者推荐 利用广度优先或模拟解决米诺骨牌 本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 n…

Find My键盘|苹果Find My技术与键盘结合,智能防丢,全球定位

键盘是最常用也是最主要的输入设备&#xff0c;通过键盘可以将英文字母、汉字、数字、标点符号等输入到计算机中&#xff0c;从而向计算机发出命令、输入数据等。还有一些带有各种快捷键的键盘。随着时间的推移&#xff0c;渐渐的市场上也出现独立的具有各种快捷功能的产品单独…

STK Components 二次开发- StarLink

1.星链数据下载 CelesTrak: Current GP Element Sets 下载二根数就可以。 2.处理数据 下载下来的数据是这样&#xff0c;要将字符串转为 二根数对象 TwoLineElementSet tle new TwoLineElementSet(tleString); Sgp4Propagator propagator new Sgp4Propagator(tle); 3.批量…

linux task_struct中进程调度相关的变量记录

参考文章&#xff1a; Linux进程调度分析记录&#xff0c;进程优先级&#xff0c;隔离处理器&#xff0c;isolcpus - 知乎

js的数组去重方法

目录 es6数组中对象去重 1. filter()用法 2. findIndex()用法 3. 去重 其他方法&#xff1a; 方法二&#xff1a;reduce()去重 1. reduce()用法 1.1 找出字符长度最长的数组成员。 1.2 扁平化二维数组 1.3 扁平化多维数组 三、总结方案&#xff1a; 使用Set&#xf…

AT89S52单片机------中断系统

目录 单片机的内部结构 中断请求标志寄存器 (1)TCON寄存器 (2)SCON寄存器 (3)定时器2的控制寄存器T2CON 中断允许与中断优先级的控制寄存器 中断允许寄存器IE 中断优先级寄存器IP 响应中断请求的条件 外部中断响应时间 外部中断的触发方式选择 中断请求的撤销 1.定…

[极客大挑战2023] Crypto/PWN/Reverse

这个网站真辛苦&#xff0c;每次都要回到all&#xff0c;屏幕随时卡。界面有待进步老远。也不提示结束&#xff0c;结果现在才听说结束了&#xff0c;才开始记录一下。 还跟往常一样&#xff0c;WM不作&#xff0c;其它也AK不了&#xff0c;总是差点。 Crypto SignIn 53594…

AI - Steering behaviors(转向系统)

游戏AI角色的转向系统&#xff08;Steering behaviors&#xff09;实现 一些向量的接口是cocos2dx的。但从名字上应该能理解做了什么向量操作 Seek&#xff1a; 获取当前位置指向目标点的向量&#xff0c;转化为单位向量后再乘以速度值&#xff0c;即为所需速度desired velo…

Centos 如何判断分区是mbr还是gpt格式

1 介绍 MBR 自20世纪80年代初以来的标准分区表格式每个驱动器最多支持四个主分区最多可以划分2TB的磁盘 GPT GPT是MBR分区表格式的后续每个驱动器最多支持128个分区可以将一个磁盘分区到最大到18艾字节 对小于2TB的磁盘使用MBR对大于2TB的磁盘使用GTP 2 查询方式 2.1 fdis…

uniapp页面使用多个echarts出现数据渲染错乱问题解决

首先&#xff0c;uniapp当中使用echarts是在通过使用renderjs的script模板的前提下实现的&#xff0c;在官方提供的案例当中&#xff0c;核心代码是这一部分&#xff1a; 但如果将其封装为组件&#xff0c;并在一个页面当中引用多次来生成多个charts图标&#xff0c;那么这个时…

化学仿制药参比制剂目录-参比制剂查询网站

2015年以前&#xff0c;参比制剂对于仿制药的研究无关紧要&#xff0c;但推出了’仿制药一致性评价’后&#xff0c;参比制剂的选择成为了决定仿制药成功与否的关键因素&#xff0c;如今在进行仿制药研究时&#xff0c;首要任务就是确定仿制目标&#xff0c;也就是参比制剂。 …

C++之算术生成算法

C之算术生成算法 accumulate #include<iostream> using namespace std; #include<vector> #include<numeric>void test() {vector<int> v;for (int i 0; i < 10; i){v.push_back(i);}int total accumulate(v.begin(), v.end(),0);cout << t…

TIME_WAIT状态套接字重新使用

《TIME_WAIT相关知识》里边有相关理论知识。 《TIME_WAIT状态TCP连接导致套接字无法重用实验》有相关实验。 现代Linux的TCP协议栈已经做了许多升级&#xff0c;所以可以让我们直接重用TIME_WAIT状态套接字而不会引起问题。下边是优化的内容&#xff1a; 1.新连接的SYN告知序列…

Java - Stream Filter 多条件筛选过滤

Java Stream流中Filter用于通过设置的条件过滤出元素 &#xff0c;示例如下&#xff1a; List strings Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,"", “jkl”);List filtered strings.stream().filter(string -> !string.isEmpty()).collect(C…