STM32--USART串口

文章目录

  • 通信接口
  • 串口通信
    • 硬件电路
    • 电平标准
    • 参数
    • 时序
  • USART
    • 主要特性
    • 框图
  • 数据帧
    • 发送器
  • 波特率发生器
  • SWART串口发送与接收工程
  • 串口收发数据包

通信接口

通信接口是指连接中央处理器(CPU)和标准通信子系统之间的接口,用于实现数据和控制信息在不同设备之间的传输和交换。通信接口可以是硬件或软件实现,其目的是使不同设备之间能够进行有效地通信。

在这里插入图片描述
上图是常见的通用通信类型。

双工指的是接口能够实现双向数据传输,即可以同时进行发送和接收数据的功能

半双工:数据在同一个通信信道上交替地进行双向传输,但不能同时进行发送和接收。发送方和接收方需要在不同时间段进行数据传输。

全双工:数据可以同时进行双向数据传输,发送方和接收方可以在同一时间段进行数据发送和接收。通信双方可以独立地进行发送和接收工作。

时钟是指在传输数据是否能达到同步传输。

同步传输:发送方和接收方之间使用一个共同的时钟信号来同步数据的传输。发送方根据时钟信号将数据按照固定的速率发送,接收方也按照相同的时钟信号来接收数据。
异步传输:数据的传输不依赖于共同的时钟信号,而是使用起始位、停止位和数据位之间的固定时间间隔进行同步。发送方会在发送数据之前先发送一个起始位作为同步信号,接收方通过检测起始位来确定数据的开始和结束。

电平是指传输信号时的电压信号形式。

单端传输:信号传输使用单个导线进行,信号的电压相对于某个参考电平变化来表示。这意味着信号只有一个极性,数据通过高低电平表示。在单端传输中,由于信号线未与其他导线耦合,容易受到电磁干扰的影响,可能导致信号质量的下降。
差分传输:信号的传输使用两个导线进行,信号通过两个相互补充的电压信号的差异来表示。差分传输具有很强的抗干扰能力,可以减少电磁干扰对信号的影响。

串口通信

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信;适用于近距离的通信。
在这里插入图片描述

单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。

硬件电路

在这里插入图片描述

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

电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
TTL电平:+3.3V或+5V表示1,0V表示0
RS232电平:-3~ -15V表示1,+3~ +15V表示0
RS485电平:两线压差+2~+6V表示1,-2 ~-6V表示0(差分信号)

参数

波特率:串口通信的速率,可以指定每秒传输的位数

起始位:标志一个数据帧的开始,固定为低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

校验位:用于数据验证,根据数据位计算得来

常用奇偶校验位:通过在数据中添加一个附加位(校验位),以确保接收端可以检测到传输过程中的错误
奇校验:如果数据位中1的个数为偶数,则校验位设置为1,使得数据位和校验位中的1的总和保持奇数。如果数据位中1的个数为奇数,那么校验位置0。
偶校验:如果数据位中1的个数为偶数,则校验位置0,使得数据位和校验位的总个数为偶数。如果数据位中1的个数为奇数,校验位置1 。

停止位:用于数据帧间隔,固定为高电平

在这里插入图片描述

时序

在这里插入图片描述
输入不同的数据,显示不同的时序。

USART

通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。

主要特性

1.全双工的,异步通信
2.分数波特率发生器系统
─ 发送和接收共用的可编程波特率,最高达4.5Mbits/s
3.可编程数据字长度(8位或9位)
4.可配置的停止位-支持1或2个停止位
5.校验控制
─ 发送校验位
─ 对接收数据进行校验
6.支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

框图

在这里插入图片描述
先看左上角的接口处,TX与RX就是发送和接收的引脚,下面的三个接口是智能卡和IrDA通信的引脚。
发送脚就是通过发送移位寄存器送出去的,接收脚就是将接收数据送到接收移位寄存器的。

灰色部分就是串口的数据寄存器。有两个数据寄存器,一个用来发送数据,一个用来接收数据;在程序上,只表现为一个寄存器,它们寄存器共用地址进行存储
当你进行写入操作时,数据就写到TDR,当你进行读取操作时,数据就从RDR进行读出。
下面是移位寄存器,作用是把一个字节的数据一位一位进行位移。

假设你在某时刻给TDR写入数据0x66,在二进制存储就是01100110,此时硬件会检测到你写入的数据,就会检查移位寄存器是否有数据正在移位,如果没有01100110就会立刻放入移位寄存器中,此时也会置出一个标志位TXE,发送寄存器为空;有了这个标志我们就可以在TDR再写入一个数据了。移位寄存器在发送器控制的情况下,将数据一位一位进行传输到TX引脚进行输出(低位先出),当数据全部移位后,新的数据就会再次从TDR转移到移位寄存器中来,如果移位寄存器还没有完成,那么TDR会等移位寄存器完成移位之后才将数据转移。有了TDR和移位寄存器双重缓存,可以保证数据发送时,数据帧之间没有空闲。
而接收部分也是同样的道理,接收移位寄存器由接收器控制,低位先放到移位寄存器的高位,随着数据的增加而右移,当移位寄存器数据达到一个字节后,传输给接收寄存器RDR,此时也会有一个标志位RXNE置1,意味着接收寄存器有数据了,我们可以对DR寄存器的数据进行读走。

接着看到下面,有一个硬件数据流控,如果发送设备发送太快,接收设备来不及处理,可以通过流控来控制传输的速度。
它有两个引脚,一个是nRTS,另一个是nCTS。
nRTS是请求发送,是输出脚,就是告诉别人,我当前能不能接收;
nCTS是清除发送,是输入脚,用于接收别人nRTS的信号;

接着看右边的SCLK,这是一个产生同步的时钟信号,它是配合发送移位寄存器输出的,发送移位寄存器每发送一次,同步时钟电平就跳变一个周期,时钟会告诉对方我已经移出去一个数据了,你看要不要让我这个时钟信号来指导你接收一下?当然这个时钟只支持输出,不支持输入,所以两个SWART不能实现同步的串口通信。
主要用途是兼容别的协议或者做自适应波特率。

接着看到中间的唤醒单元,这部分的作用是实现串口挂载多个设备。
中断控制,支持对标志位标志的地方进行中断。

最下面的波特率发生器部分,其实就是分频器,对APB时钟进行分频,得到发送和接收移位的时钟。

数据帧

字长可以通过编程USART_CR1寄存器中的M位,选择成8或9位(见图249)。在起始位期间, TX脚处于低电平,在停止位期间处于高电平。
在这里插入图片描述

发送器

发送器根据M位的状态发送8位或9位的数据字。当发送使能位(TE)被设置时,发送移位寄存器中的数据在TX脚上输出,相应的时钟脉冲在CK脚上输出。
USART支持多种停止位的配置: 0.5、 1、 1.5和2个停止位。
在这里插入图片描述

波特率发生器

发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
计算公式:波特率 = fPCLK2/1 / (16 * DIV)
在这里插入图片描述
假设我们要输出波特率为9600,那么通过计算DIV=72M/16/9600=468.75
所以置于波特率寄存器中的值为468.75.

SWART串口发送与接收工程

OLED代码链接入口

接线方式:
在这里插入图片描述
发送时需要一个串口助手在电脑来显示内容,我们将实现STM32与电脑之间的数据传输。以STM32为主机。

Serial.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include <stdio.h>

void Serial_Init();
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t* Arr,uint8_t Lenth);
void Serial_SendString(char* String);
void Serial_SendNumber(uint32_t Number,uint8_t Lenth);
uint8_t Serial_GetRxFlag();
uint8_t Serial_GetRxData();

#endif 

Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    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_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    USART_InitTypeDef USART_InitStructure;
    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开启中断
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//中断源RXNE
    
    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);
}

//发送字节
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}

//发送数组
void Serial_SendArray(uint8_t* Arr,uint8_t Lenth)
{
    uint8_t i;
    for(i=0;i<Lenth;i++)
    {
        Serial_SendByte(Arr[i]);
    }
}

//发送字符串
void Serial_SendString(char* String)
{
    uint8_t i;
    for(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_SendNumber(uint32_t Number,uint8_t Lenth)
{
    uint8_t i;
    for(i=0;i<Lenth;i++)
    {
        Serial_SendByte(Number/Serial_Pow(10,Lenth-1-i)%10+'0');
    }
}

//获取接收状态
uint8_t Serial_GetRxFlag()
{
    if(Serial_RxFlag==1)
    {
        Serial_RxFlag=0;
        return 1;
    }
    return 0;
    
}
//获取接收数据
uint8_t Serial_GetRxData()
{
    return Serial_RxData;
}

void USART1_IRQHandler()
{
    if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
    {
        Serial_RxData=USART_ReceiveData(USART1);
        Serial_RxFlag=1;
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    }
}

初始化输出需要配置复用功能,因为SWART为片上外设。
发送字节需要用TXE标志位来表示已经从DR寄存器发送到移位寄存器中。所以用到while来进行等待;
接收时,利用RNXE产生的标志位来产生中断,在中断函数中获取DR寄存器的数据。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "Serial.h"
#include "OLED.h"
int main()
{
    uint8_t Rxdata;
	OLED_Init();
	Serial_Init();
   
    OLED_ShowString(1,1,"RxData:");
    
    while(1)
    {
        if(Serial_GetRxFlag()==1)
        {
            Rxdata=Serial_GetRxData();
            Serial_SendByte(Rxdata);
            OLED_ShowHexNum(1,8,Rxdata,2);
        }
    }
    
}

串口收发数据包

连接方式:
在这里插入图片描述

利用连续的数据序列来对LED灯的亮灭进行控制;

Serial.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include <stdio.h>
#include <string.h>

extern uint8_t Serial_RxFlag;
extern char Serial_RxPacket[];

void Serial_Init();
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t* Arr,uint8_t Lenth);
void Serial_SendString(char* String);
void Serial_SendNumber(uint32_t Number,uint8_t Lenth);
void Serial_Printf(char* format,...);

#endif 

Serial.c

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>


char Serial_RxPacket[100];
uint8_t Serial_RxFlag;

void Serial_Init()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    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_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    USART_InitTypeDef USART_InitStructure;
    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开启中断
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//中断源RXNE
    
    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);
}

//发送字节
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}

//发送数组
void Serial_SendArray(uint8_t* Arr,uint8_t Lenth)
{
    uint8_t i;
    for(i=0;i<Lenth;i++)
    {
        Serial_SendByte(Arr[i]);
    }
}

//发送字符串
void Serial_SendString(char* String)
{
    uint8_t i;
    for(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_SendNumber(uint32_t Number,uint8_t Lenth)
{
    uint8_t i;
    for(i=0;i<Lenth;i++)
    {
        Serial_SendByte(Number/Serial_Pow(10,Lenth-1-i)%10+'0');
    }
}

void Serial_Printf(char* format,...)
{
    char String[100];
    va_list arg;
    va_start(arg,format);
    vsprintf(String,format,arg);
    va_end(arg);
    Serial_SendString(String);
}




//串口接收中断(接收一位数据中断一次),接收数据包
void USART1_IRQHandler()
{
    static uint8_t RxState=0; //获取当前状态
    static uint8_t pRxPacket=0; //数据包有效位下标
    if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
    {
        uint8_t RxData=USART_ReceiveData(USART1);
        if(RxState==0)
        {
            if(RxData=='&'&& Serial_RxFlag==0)
            {
                RxState=1;
                pRxPacket=0;
            }
        }
        else if(RxState==1)
        {            
            if(RxData=='\r')
            {
                
                RxState=2;
            }
            else
            {
                Serial_RxPacket[pRxPacket++]=RxData;
                
            }
        }
        else if(RxState==2)
        {
            if(RxData=='\n')
            {
                RxState=0;
                Serial_RxPacket[pRxPacket]='\0';
                Serial_RxFlag=1;
            }
        }
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    }
}

对于接收的数据包,利用了一种状态机的方式进行接收
在这里插入图片描述
通过包头和包尾对数据有效位进行保护,可以让一连串重复的数据可以找到数据位,避免找不到数据位的头的情况。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Serial.h"
#include "OLED.h"
int main()
{
    
	OLED_Init();
	Serial_Init();
    LED_Init();
    
    OLED_ShowString(1, 1, "RxPacket:");
   
	         
    while(1)
    {
        
        if(Serial_RxFlag==1)
        {
            
           
            if(strcmp(Serial_RxPacket,"LED_ON")==0)
            {
                LED1_ON();
                OLED_ShowString(2,1,"LED_ON_OK   ");
                Serial_SendString("LED_ON_OK");
            }
            else if(strcmp(Serial_RxPacket,"LED_OFF")==0)
            {
                LED1_OFF();
                OLED_ShowString(2,1,"LED_OFF_OK   ");
                Serial_SendString("LED_OFF_OK");
            }
            else
            {
                OLED_ShowString(2,1,"ERROR_COMMAND");
                Serial_SendString("ERROR_COMMAND");
            }
            Serial_RxFlag=0;
        }
       

    }
    
}

LED.c

#include "stm32f10x.h"                  // Device header

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}

void LED1_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

void LED1_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_1);
}

void LED1_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
	}
}

void LED2_ON(void)
{
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

void LED2_OFF(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_2);
}

void LED2_Turn(void)
{
	if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);
	}
}


LED.h

#ifndef __LED_H__
#define __LED_H__

void LED_Init();
void LED1_ON();
void LED1_OFF();
void LED1_Turn();
void LED2_ON();
void LED2_OFF();
void LED2_Turn();

#endif

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

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

相关文章

GNN学习笔记

GNN 持续更新 实践程序放在了虚拟机里conda中NS环境里了 b站课程跳转------->>>>> 【不愧是公认最好的【图神经网络GNN/GCN教程】&#xff0c;从基础到进阶再到实战&#xff0c;一个合集全部到位&#xff01;-人工智能/神经网络/图神经网络/深度学习。】 https…

ubuntu 20.04 安装 高版本cuda 11.7 和 cudnn最新版

一、安装显卡驱动 参考另一篇文章&#xff1a;Ubuntu20.04安装Nvidia显卡驱动教程_ytusdc的博客-CSDN博客 二、安装CUDA 英伟达官网&#xff08;最新版&#xff09;&#xff1a;CUDA Toolkit 12.2 Update 1 Downloads | NVIDIA Developer CUDA历史版本下载地址&#xff1a;C…

vue3——递归组件的使用

该文章是在学习 小满vue3 课程的随堂记录示例均采用 <script setup>&#xff0c;且包含 typescript 的基础用法 一、使用场景 递归组件 的使用场景&#xff0c;如 无限级的菜单 &#xff0c;接下来就用菜单的例子来学习 二、具体使用 先把菜单的基础内容写出来再说 父…

STM32CubeMX配置STM32G0 Standby模式停止IWDG(HAL库开发)

1.打开STM32CubeMX选择好对应的芯片&#xff0c;打开IWDG 2.打开串口1进行调试 3.配置好时钟 4.写好项目名称&#xff0c;选好开发环境&#xff0c;最后获取代码。 5.打开工程&#xff0c;点击魔术棒&#xff0c;勾选Use Micro LIB 6.修改main.c #include "main.h"…

网络互联与互联网 - TCP 协议详解

文章目录 1 概述2 TCP 传输控制协议2.1 报文格式2.2 三次握手&#xff0c;建立连接2.3 四次挥手&#xff0c;释放连接2.4 四种拥塞控制 3 扩展3.1 实验演示3.2 网工软考 1 概述 在 TCP/IP 协议簇 中有两个传输协议 TCP&#xff1a;Transmission Control Protocol&#xff0c;传…

视频汇聚/视频云存储/视频监控管理平台EasyCVR提升网络稳定小tips来啦!

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

vue+file-saver+xlsx+htmlToPdf+jspdf实现本地导出PDF和Excel

页面效果如下&#xff08;echarts图表按需添加&#xff0c;以下代码中没有&#xff09; 1、安装插件 npm install xlsx --save npm install file-saver --save npm install html2canvas --save npm install jspdf --save2、main.js引入html2canvas import htmlToPdf from …

MyBatis分页思想和特殊字符

目录 一、MyBatis分页思想 1.1 使用场景 1.2 代码演示 二、MyBatis特殊字符 2.1代码演示 一、MyBatis分页思想 1.1 使用场景 Mybatis分页应用场景&#xff1a; MyBatis是一个Java持久层框架&#xff0c;它提供了一种将SQL查询和结果映射到Java对象的简单方式。分页是MyBa…

深度学习环境搭建 cuda、模型量化bitsandbytes安装教程 windows、linux

cuda、cudann、conda安装教程 输入以下命令&#xff0c;查看 GPU 支持的最高 CUDA 版本。 nvidia-smi cuda安装&#xff08;cudatoolkit&#xff09; 前往 Nvidia 的 CUDA 官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer CUDA Toolkit 11.8 Downloads | NVIDIA …

IO day 4

1、使用两个进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半内容&#xff0c;子进程拷贝后一半内容&#xff0c;并且父进程要阻塞回收子进程资源 #include <myhead.h>int main(int argc, const char *argv[]) {char a[1] {0};pid_t pid;pid fork();//创建一个子进…

学习网络编程No.4【socket编程实战】

引言 北京时间&#xff1a;2023/8/19/23:01&#xff0c;耍了好几天&#xff0c;主要归咎于《我欲封天》这本小说&#xff0c;听了几个晚上之后逐渐入门&#xff0c;在闲暇时间又看了一下&#xff0c;小高潮直接来临&#xff0c;最终在三个昼夜下追完了&#xff0c;哈哈哈&…

开放网关架构演进

作者&#xff1a;庄文弘&#xff08;弘智&#xff09; 淘宝开放平台是阿里与外部生态互联互通的重要开放途径&#xff0c;通过开放的产品技术把阿里经济体一系列基础服务&#xff0c;像水、电、煤一样输送给我们的商家、开发者、社区媒体以及其他合作伙伴&#xff0c;推动行业的…

如何利用SFTP如何实现更安全的远程文件传输 ——【内网穿透】

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《高效编程技巧》《cpolar》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 1. 安装openSSH1.1 安装SSH1.2 启动ssh 2. 安装cpolar2.1 配置termux服务 3. 远程SFTP连接配置3.1 查看生成的随机公…

openGauss学习笔记-46 openGauss 高级数据管理-子查询

文章目录 openGauss学习笔记-46 openGauss 高级数据管理-子查询46.1 SELECT语句中的子查询使用46.2 INSERT语句中的子查询使用46.3 UPDATE语句中的子查询使用46.4 DELETE语句中的子查询使用 openGauss学习笔记-46 openGauss 高级数据管理-子查询 子查询或称为内部查询&#xf…

H3C 无线网络vlan pool架构案例三层组网web配置

实验的是目标就是要实现华为vlan pool那种应用&#xff0c; 整个园区发一种ssid信号&#xff0c;但是连接的客户端可以随机连上后进入不同的vlan&#xff0c;在这大型园区网非常有用。 这种方法也适合同一个ssid情况下&#xff0c;在不同的位置关联不同的vlan 开启自动固化、…

【业务功能篇78】微服务-前端后端校验- 统一异常处理-JSR-303-validation注解

5. 前端校验 我们在前端提交的表单数据&#xff0c;我们也是需要对提交的数据做相关的校验的 Form 组件提供了表单验证的功能&#xff0c;只需要通过 rules 属性传入约定的验证规则&#xff0c;并将 Form-Item 的 prop 属性设置为需校验的字段名即可 校验的页面效果 前端数据…

建议收藏|软考机构推荐看这一篇就够了

需要最近因为软考改革成机考&#xff0c;大家都在问还有没有必要找机构学&#xff1f;本来已经进入自学阶段的考生&#xff0c;也纷纷开始慌张机考改革会不会影响考试难度&#xff1f;今天胖圆给大家总结一下软考要不要报机构&#xff1f;市面上的软考培训机构如何选择&#xf…

SAP ABAPG开发屏幕自动生成日期的搜索帮助

代码如下&#xff1a; REPORT z_jason_test_f4 . TABLES: s031. PARAMETER p_spmon TYPE spmon DEFAULT sy-datum0(6) OBLIGATORY. SELECT-OPTIONS s_spmon FOR s031-spmon DEFAULT sy-datum0(6) OBLIGATORY. AT SELECTION-SCREEN ON VALUE-REQUEST…

gdb call 函数调用

在 gdb 里可以用 call 命令来调用函数&#xff0c;跟代码里调用效果是一样的。在任一断点处都可以用 call 来调用函数&#xff0c;但不知是否需要debug 信息来支持&#xff0c;我这里实际操作的都是带debug信息的程序。首先打一个断点&#xff0c;如&#xff1a; 当断点触发时&…

【Git】代码误推送还原(真实项目环境,非纸上谈兵)

背景 RT&#xff0c; 我今天眼睛花了&#xff0c;不小心把工作分支【合并】到了一个不相干的功能分支上&#xff0c;并且代码已经推送到远程仓库了。于是&#xff0c;只能尝试还原到上一次提交中。 【合并】分支有一个点我们是不可避免的&#xff0c;文字很难描述&#xff0c;…