STM32_9(USART串口)

news2024/11/6 7:33:06

一、串口通信

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

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);
    }
}

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

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

相关文章

前缀和算法总结

前缀和思维导图&#xff1a; 一维前缀和算法模版&#xff1a; #include <iostream>using namespace std;const int N 100010;int n, m; int s[N];int main() {scanf("%d%d", &n, &m);for (int i 1; i < n; i){int x;scanf("%d", &…

​无人机石油管道巡检方案新亮点:灵活准确又高效

在当前石油工业的安全管理中&#xff0c;无人机技术逐渐成为一种不可或缺的工具。随着我国油气管道里程的持续增长&#xff0c;确保这些关键基础设施的安全运行变得越来越重要。传统的巡检方法已经无法满足现代油气行业的需求&#xff0c;而无人机石油管道巡检技术的应用提供了…

相同JS代码,多次混淆加密能得到不同的结果吗?

一份相同的JavaScript代码&#xff0c;进行多次混淆加密&#xff0c;能得到不同的结果吗&#xff1f; 答案是肯定的&#xff0c;能。 JShaman可以实现这个效果。即&#xff1a;加密结果具有多态性、变化性。 下面实测展示。 来到JShaman网站&#xff0c;用它默认的示例代码…

计算机网络——数据链路层-数据链路层概述(介绍、三个重要问题、使用广播信道的数据链路层、其他问题)

目录 介绍 三个重要问题 封装成帧 差错检测 可靠传输 使用广播信道的数据链路层 其他问题 介绍 本篇对数据链路层进行概述&#xff0c;我们首先来看看数据链路层在网络体系结构中的地位&#xff1a; 主机H1给主机H2发送数据&#xff0c;中间要经过三个路由器和电话网、…

java选择排序和冒泡排序

1.区别 选择排序和冒泡排序的区别主要在于算法逻辑、稳定性和交换成本。 算法逻辑&#xff1a;选择排序和冒泡排序都属于比较排序&#xff0c;但在具体算法逻辑上有所不同。冒泡排序是通过相邻元素之间的比较和交换&#xff0c;将较大&#xff08;或较小&#xff09;的元素逐…

自动驾驶HWP功能规范

HWP功能规范 Highway Pilot Functional Specification 文件状态&#xff1a; 【√】草稿 【】正式发布 【】正在修改 文件起草分工 撰写&#xff1a; 审核&#xff1a; 编制&#xff1a; 签名&#xff1a; 日期&#xff1a; 审核&#xff1a; 签名&#xff1a; 日期&am…

Leetcode—739.每日温度【中等】

2023每日刷题&#xff08;四十二&#xff09; Leetcode—739.每日温度 单调栈实现思想 从右到左实现代码 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {int n temperatures.size();stack<int> st;vector<i…

深度学习实战61-基于知识图谱与BiLSTM网络实现疾病相关智能问答系统,并支持数据扩展

大家好,我是微学AI,今天给大家介绍一下深度学习实战61-深度学习在医疗领域的应用:疾病相关智能问答系统,并支持数据扩展。本文将详细介绍如何使用Py2neo这个Python库来构建一个医疗领域知识图谱,并将数据导入Neo4j图数据库。我们将提供一些医疗领域的数据样例,并展示如何…

TIME_WAIT状态套接字重新使用

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

原生代码布局

背景&#xff1a; 原生开发移动端&#xff0c;每一个页面的组成部分是哪些呢&#xff1f;在一个项目文件里&#xff0c;每一个页面的组成部分又是哪些呢&#xff1f;参考链接&#xff1a;pages页面的组成 效果展示&#xff1a; 注意&#xff1a; 一、布局代码&#xff1a; <…

33 - MySQL调优之索引:索引的失效与优化

不知道你是否跟我有过同样的经历&#xff0c;那就是作为一个开发工程师&#xff0c;经常被 DBA 叫过去“批评”&#xff0c;而最常见的就是申请创建新的索引或发现慢 SQL 日志了。 记得之前有一次迭代一个业务模块的开发&#xff0c;涉及到了一个新的查询业务&#xff0c;需要…

数据库应用:Ubuntu 20.04 安装MongoDB

目录 一、理论 1.MongoDB 二、实验 1.Ubuntu 20.04 安装MongoDB 三、问题 1.Ubuntu Linux的apt 包管理器更新安装软件报错 2.Ubuntu20.04安装vim报错 3.Ubuntu20.04如何更换阿里源 4.Ubuntu22.04如何更换阿里源 一、理论 1.MongoDB &#xff08;1&#xff09;概念 …

帆软报表 channel 反序列化漏洞复现

0x01 产品简介 FineReport、FineBI 是帆软软件开发的企业级报表设计和数据分析工具与商业智能平台。 0x02 漏洞概述 帆软FineReport、FineBI 存在反序列化漏洞&#xff0c;攻击者可向 /webroot/decision/remote/design/channel 接口发送精心构造的反序列化数据&#xff0c;在目…

2023.11.27【读书笔记】|医疗科技创新流程(前言)

目录 注重价值关键要素如何解决价值问题&#xff1f;注重三个关键点价值探索价值预测价值定位 中国视角背景挑战战术 洞察过程发现需求发现需求筛选 发明概念产生概念选择 发挥战略发展商业计划 注重价值 在美国&#xff0c;医疗费用的增长率已经多年超过GDP增长率&#xff1b…

基于CW32F030单片机的便携式多功能测试笔

一、产品背景 在日常的硬件调试工作中&#xff0c;我们最常使用的仪器仪表可能就是万用表了&#xff0c;虽然万用表号称“万用”&#xff0c;但大部分时候&#xff0c;我们需要使用到的功能无非是电压测量和通断测量。 作为调试的“得力干将”&#xff0c;万用表有时候也会存…

SLURM超算集群资源管理服务的安装和配置-基于slurm22.05.9和centos9stream,配置slurmdbd作为账户信息存储服务

slurm介绍就不再赘述了&#xff0c;这里看官网链接&#xff0c;其他的自己搜索吧。 Slurm Workload Manager - Quick Start User Guide 这里主要将slurm集群配置的一般步骤&#xff0c;重点是slurmd的conf文件的配置&#xff1b;官网的内容比较全但不太好选择哪些是必须的&am…

10、静态数码管显示

数码管介绍 LED数码管:是一种简单、廉价的显示器&#xff0c;是由多个发光二极管封装在一起组成“8”字型的器件 数码管引脚的定义 共阴极、共阳极 例如&#xff1a;显示数字1&#xff08;b,c段&#xff09; 3、8&#xff1a;接VCC或者GND/低电平 10011111 0110000 共阴极、…

智能优化算法应用:基于蝴蝶算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝴蝶算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝴蝶算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝴蝶算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

Open Feign 源码解析(一) --- FactoryBean的妙用

什么是Open Feign? OpenFeign 是 Spring Cloud 全家桶的组件之一&#xff0c; 其核心的作用是为 Rest API 提供高效简洁的 RPC 调用方式 搭建测试项目 服务接口和实体 项目名称 cloud-feign-api 实体类 public class Order implements Serializable {private Long id;p…

Mysql——》int(1)和 int(10)区别

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…