当前位置: 首页 > news >正文

09:STM32-------USART串口通信+串口数据包

目录

一:串口协议

1:通信接口

2:串口通信

3:硬件电路

4:电平标准

5:串口参数及其时序

二:USART介绍

1:简历

2:USART框图

3:USART的基本结构

4:数据帧

5: 波特率发生器

6:数据模式

三:案例

A:串口发送--单发送

1:连接图

2:函数介绍

3:代码 

B:串口发送+接收 

1:函数介绍

 2:串口发送+接收 -----查询代码

3:函数介绍

4:串口发送+接收 -----中断代码

四:USART串口数据包

1:简历

2:HEX数据包

3: 文本数据包

4:HEX数据包接收

5:文本数据包接收

6: 案例

1:连接图

A:发送HEX数据包---固定数据长度

2:连接图

B:发送文本数据包---数据长度 


一:串口协议

1:通信接口

通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

USART通信:

        TX:  发送数据的引脚

        RX : 接收数据的引脚

I2C通信:

        SCL: 时钟     SDA:数据

SPI通信:

        SCLK:时钟   MOSl:主机输出数据脚    MISO :  主机输入数据脚    CS : 片选,用于指定通信的对象

CAN通信:

        是差分数据脚,用两个引脚表示一个差分数据

USB通信:

        也是 是差分数据脚

 双工

全双工:就是指通信双方能够同时进行双向通信,  两个数据线分别负责发送和接收数据

半双工 : 一根数据线负责发送和接收数据,   eg:I2C通信的SDA线

时钟

同步: 接收方可以在时钟信号的指引下进行采样

异步 : 没有时钟线,  所以需要双方约定一个采样频率,   还需要加一些帧头帧尾等,进行采样位置的对齐

电平

单端: 它们引脚的高低电平都是对GND的电压差,   所以单端信号通信的双方必须要共地,就是把GND接在一起

差分 : 差分信号,   它是靠两个差分引脚的电压差来传输信号的,   在通信的时候,可以不需要GND,   使用差分信号可以极大地提高抗干扰特性

设备

点对点 : 直接传输数据就可以了

多设备 : 一对多,  需要有一个导址的过程,以确定通信的对象

2:串口通信

        串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

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

3:硬件电路

        简单双向串口通信有两根通信线(发送端TX和接收端RX)

        TX与RX要交叉连接

        当只需单向的数据传输时,可以只接一根通信线

        当电平标准不一致时,需要加电平转换芯片-----------相同的电平标准才可以通信

 VCC的连接

        上面的VCG,如果两个设备都有独立供电,  VCC可以不接

        如果一个设备没有独立供电,  需要VCC把他们连接起来

4:电平标准

        电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

        TTL电平:+3.3V或+5V表示1,0V表示0

        RS232电平:-3~-15V表示1,+3~+15V表示0

        RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

5:串口参数及其时序

        波特率:串口通信的速率--------波特率表示单位时间内传送的码元符号的个数.      规定串口通信的速率,   串口一般是使用异步通信,  发送和接收,必须要约定好速率,  速率参数,就是波特率.   双方规定波特率为1000bps,   那就表示,1s要发1000位,每一位的时间就是1ms

        起始位:标志一个数据帧的开始,固定为低电平------串口的空闲状态是高电平,起始位产生一个下降沿, 告诉接收设备要开始传输数据了

        停止位:用于数据帧间隔,固定为高电平-------停止位固定为1,把引脚恢复成高电平,方便下次的数据传输,   可以选择1位、1.5位、2位等

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

        校验位:用于数据验证,根据数据位计算得来------校验可以选择3种方式,无校验、奇校验和偶校验

        串口中,每一个字节都装载在一个数据帧里面,   每个数据帧都由起始位、数据位和停止位组成

        左边: 这里数据位有8个,代表一个字节的8位         (一个字节为8位)

        右边 : 数据帧里面,还可以在数据位的最后,加一个奇偶校验位 ,这样数据位就9位

奇偶校验位----实际是对高电频1的校验

        奇校验 : 发送数据0000 1111 采用右边的数据位为9位, 给第9位补1, 这时候1就为5个为奇数,      接收方一验证,发现1的个数不是奇数,那就认为传输出错,  就可以选择丢弃,或者要求重传

        偶校验: 发送数据0000 1111 采用右边的数据位为9位, 给第9位补0, 这时候1就为4个为偶数, 接收方一验证,发现1的个数不是偶数,那就认为传输出错,  就可以选择丢弃,或者要求重传

        奇偶校验只能保证一定程度上的数据校验

数据位的2中表示方法

        一种是把校验位作为数据位的一部分,  分为8位数据和9位数据,   其中9位数据,就是8位有效载荷和1位校验位,   另一种就是把数据位和校验位独立开,  数据位就是有效载荷,校验位就是独立的1位

二:USART介绍

1:简历

        USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器

        USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里

        自带波特率发生器,最高达4.5Mbits/s 可配置数据位长度(8/9)、停止位长(0.5/1/1.5/2)

        可选校验位(无校验/奇校验/偶校验)

        支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

STM32F103C8T6 USART资源: USART1、 USART2、 USART3

        硬件流控制,-----------比如A设备有个TX向B设备的RX发送数据,   A设备一直在发,发的太快了,  如果没有硬件流控制,   那B就只能抛弃新数据或者覆盖原数据了.     如果有硬件流控制,在硬件电路上,会多出一根线,   如果B没准备好接收,就置高电平,如果准备好了,就置低电平;    A接收到了B反馈的准备信号,就只会在B准备好的时候,才发数据

        硬件流控制,可以防止因为B处理慢而导致数据丢失的问题

2:USART框图

寄存器

        DR寄存器 : TDR和RDR数据寄存器占用同一个地址,在程序上他们表现为一个寄存器DR寄存器,   TDR是只写的RDR是只读的,  当你进行写操作时 数据就写入到TDR寄存器.   当你进行读操作时,数据就是从RDR读出来的

        发送(接收)移位寄存器:  发送移位寄存器的作用就是,把个字节的数据一位一位地移出去

标志位-----移位完成产生标志位

        TXE : 在存器里就是二进制存储,0101 0101,   硬件检测到你写入数据了,  就会检查,当前移位寄存器是不是有数据正在移位;   如果没有,这个0101 0101就会立刻全部移动到发送移位寄存器,  准备发送.  当数据从TDR移动到移位寄存器时会置一个标志位(TXE置1),叫TXE,  发送寄存器空,  就可以在TDR写入下一个数据了

        当TXE标志位置1时,  数据其实还没有发送出去,    只要数据从TDR转移到发送移位寄存器了   ,   TXE就会置1,我们就可以写入新的数据了

        

while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);

        检查标志位USART1的TEX标志为是否等于0-----TDR寄存器的数据有没有移动到发送移位寄存器里面去

        RXNE: 和TXE相同的道理:   当数据从接收移位寄存器,    移动到移位RDR寄存器时会置一个标志位(RXNE置1),  这个也不用手动清除标志位, 和TXE原理相同

3:USART的基本结构

4:数据帧

5: 波特率发生器

        发送器和接收器的波特率由波特率寄存器BRR里的DIV确定

        计算公式:波特率 = fPCLK2/1 / (16 * DIV)

        配置USART1为9600的波特率

6:数据模式

        HEX模式/十六进制模式/二进制模式:以原始数据的形式显示

        文本模式/字符模式:以原始数据编码后的形式显示

三:案例

A:串口发送--单发送

1:连接图

2:函数介绍

在stm32f10x usart.h文件中-----配置USART

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)

在stm32f10x usart.h文件中-----发送数据

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

 在stm32f10x usart.h文件中-----检查某个寄存器的中断标志位

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

USART_GetFlagStatus :      获取标志位状态的函数

3:代码 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include <stdarg.h>
void serial_init(void){//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置TI的GPIOGPIO_InitTypeDef GPIO_structinit;GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设GPIO_structinit.GPIO_Pin=GPIO_Pin_9;GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);//USART的配置USART_InitTypeDef USART_structinit;USART_structinit.USART_BaudRate=9600;//通信的波特率USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用USART_structinit.USART_Mode=USART_Mode_Tx;//配置GPIO为TX发送数据模式USART_structinit.USART_Parity=USART_Parity_No;  //选择校验方式---无校验USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为USART_Init(USART1,&USART_structinit);//启动USARTUSART_Cmd(USART1,ENABLE);
}//发送数据
void Serial_SendByte(uint8_t Byte)
{	//发送数据的函数USART_SendData(USART1,Byte);//检查某个寄存器的中断标志位while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);/*在完成数据发送的时候,TXE置1;下次发送数据自动置0,所以不用手动清除中断标志位.TXE:发送数据寄存器:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。0:数据还没有被转移到移位寄存器1:数据已经被转移到移位寄存器。注意:单缓冲器传输中使用该位。*/
}	//发送一个数组;Array:传递的数组,Length数组的长度
void Serial_SendArray(uint8_t *Array, uint16_t Length){for(uint16_t i=0;i<Length;i++){Serial_SendByte(Array[i]);}}//发送一个字符串
//发送字符串时自带结束标志位
void Serial_Sendstr(char *str)
{for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'Serial_SendByte(str[i]);}
}//取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
//12345取3 12345/100(10^2)%10=3   x:从左往右数,不包含要取的数字
uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}
//传输数字,把数字中的每一位取出,然后发送出去
//Number:传输的数字;   Length:传输数字的长度
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}//printf函数的底层
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}//spinrf函数的封装
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);
}int main(void)
{OLED_Init();serial_init();Serial_SendByte(0x41);uint8_t Array[]={0x01,0x08,0x43,0x45};Serial_SendArray(Array,4);//换行的话需要加上\r\nSerial_Sendstr("Helloword\r\n");Serial_Sendstr("123\r\n");Serial_SendNumber(231,3);//使得printf函数移植方法printf("NUM=%d,",123);char String[100];sprintf(String, "\r\nNum3=%d", 333);Serial_Sendstr(String);Serial_Printf("\r\nNum4=%d", 444);Serial_Printf("\r\n");printf("你好世界");while (1){}
}

printf函数三中移植的方法----使得可以通过串口通信打印到其他外设:

1:通过重写printf函数的底层,使他通过串口

//printf函数的底层
#include <stdio.h>
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}

2:直接使用sprintf函数

    char String[100];sprintf(String, "\r\nNum3=%d", 333);Serial_Sendstr(String);

3:对sprintf函数进行封装

//spinrf函数的封装
#include <stdarg.h>void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);  //调用的Serial_Sendstr函数在代码里面可查询
}Serial_Printf("\r\nNum4=%d", 444);

B:串口发送+接收 

对于串口接收来说,可以使用查询和中断两种方法

1:函数介绍

在stm32f10x usart.h文件中-----返回外设最近接收的数据

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

USART_ReceiveData :  返回USARTx外设最近接收到的数据

 2:串口发送+接收 -----查询代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include <stdio.h>
#include <stdarg.h>
void serial_init(void){//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置TI的GPIOGPIO_InitTypeDef GPIO_structinit;GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);//USART的配置USART_InitTypeDef USART_structinit;USART_structinit.USART_BaudRate=9600;//通信的波特率USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式USART_structinit.USART_Parity=USART_Parity_No;  //选择校验方式---无校验USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为USART_Init(USART1,&USART_structinit);//启动USARTUSART_Cmd(USART1,ENABLE);
}//发送数据
void Serial_SendByte(uint8_t Byte)
{	//发送数据的函数USART_SendData(USART1,Byte);//检查某个寄存器的中断标志位while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);/*在完成数据发送的时候,TXE置1;下次发送数据自动置0,所以不用手动清除中断标志位.TXE:发送数据寄存器:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。0:数据还没有被转移到移位寄存器1:数据已经被转移到移位寄存器。注意:单缓冲器传输中使用该位。*/
}	//发送一个数组;Array:传递的数组,Length数组的长度
void Serial_SendArray(uint8_t *Array, uint16_t Length){for(uint16_t i=0;i<Length;i++){Serial_SendByte(Array[i]);}}//发送一个字符串
//发送字符串时自带结束标志位
void Serial_Sendstr(char *str)
{for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'Serial_SendByte(str[i]);}
}//取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
//12345取3 12345/100(10^2)%10=3   x:从左往右数,不包含要取的数字
uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}
//传输数字,把数字中的每一位取出,然后发送出去
//Number:传输的数字;   Length:传输数字的长度
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}//printf函数的底层
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}//spinrf函数的封装
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);
}uint8_t RXdata;int main(void)
{	OLED_Init();serial_init();while (1){if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){RXdata=USART_ReceiveData(USART1);//返回外设最近接收的数据OLED_ShowHexNum(1,1,RXdata,3);}}
}

PA9口和PA10口的GPIO的模式不同

引脚的定义

PA9-----TX发送引脚;          PA10--------Rx接收引脚     

GPIO工作模式的选择          

        输入工作模式----------将引脚的信号读取到微型控制器---PA10

        输出工作模式---------将微型控制器信号读取到阴极段--PA9

发送输出;   接收输入

3:函数介绍

在stm32f10x usart.h文件中-----使能中断输出信号

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

USART_ITConfig : 启用或禁用指定的USART中断

配置NVIC在misc.h文件中的函数-----配置NVIC

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

NVIC_PriorityGroupConfig:用来中断分组的,参数是中断分组的方式

NVIC_Init: 根据结构体里面指定的参数初始化NMIC

 在stm32f10x usart.h文件中-----检查某个寄存器的中断标志位

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

 在stm32f10x usart.h文件中-----清除中断标志位

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)

 USART_ClearITPendingBit  :        清除USARTx的中断挂起位

4:串口发送+接收 -----中断代码

        在开启USART之前

1: 启动USART的RXNE中断,  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

2: 配置NVIC

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void serial_init(void){//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置TI的GPIOGPIO_InitTypeDef GPIO_structinit;GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);//USART的配置USART_InitTypeDef USART_structinit;USART_structinit.USART_BaudRate=9600;//通信的波特率USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式USART_structinit.USART_Parity=USART_Parity_No;  //选择校验方式---无校验USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为USART_Init(USART1,&USART_structinit);//启动USART的RXNE中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_initstruct;NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;NVIC_initstruct.NVIC_IRQChannelSubPriority=1;NVIC_Init(&NVIC_initstruct);//启动USARTUSART_Cmd(USART1,ENABLE);
}//发送数据
void Serial_SendByte(uint8_t Byte)
{	//发送数据的函数USART_SendData(USART1,Byte);//检查某个寄存器的中断标志位while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);/*在完成数据发送的时候,TXE置1;下次发送数据自动置0,所以不用手动清除中断标志位.TXE:发送数据寄存器:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。0:数据还没有被转移到移位寄存器1:数据已经被转移到移位寄存器。注意:单缓冲器传输中使用该位。*/
}	//发送一个数组;Array:传递的数组,Length数组的长度
void Serial_SendArray(uint8_t *Array, uint16_t Length){for(uint16_t i=0;i<Length;i++){Serial_SendByte(Array[i]);}}//发送一个字符串
//发送字符串时自带结束标志位
void Serial_Sendstr(char *str)
{for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'Serial_SendByte(str[i]);}
}//取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉
//12345取3 12345/100(10^2)%10=3   x:从左往右数,不包含要取的数字
uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}
//传输数字,把数字中的每一位取出,然后发送出去
//Number:传输的数字;   Length:传输数字的长度
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}//printf函数的底层
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}//spinrf函数的封装
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);
}uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}uint8_t Serial_GetRxData(void)
{return Serial_RxData;
}//USART的中断函数----在启动文件中找
void USART1_IRQHandler(){//判断RXNE的中断标志位if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){Serial_RxData = USART_ReceiveData(USART1);Serial_RxFlag = 1;USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);}
}uint8_t RxData;int main(void)
{OLED_Init();OLED_ShowString(1, 1, "RxData:");serial_init();while (1){if (Serial_GetRxFlag() == 1){RxData = Serial_GetRxData();Serial_SendByte(RxData);OLED_ShowHexNum(1, 8, RxData, 3);}}
}

四:USART串口数据包

1:简历

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

需要把多个字节打包为一个整体进行发送, 极大的方便了我们的使用

2:HEX数据包

        数据包的包头和包尾是可以自己进行设定的,  它并不是一个固定的

        固定包长, 含包头包尾 : 每个数据包的长度都固定不变 (自己定数据包的长度) ,  数据包前面是包头,后面是包尾

        可变包长,含包头包尾 : 每个数据包的长度可以是不一样的,  数据包前面是包头,后面是包尾

包头包尾和数据载荷重复的问题 

        当包头包尾的数据和传输的数据重复时-----定义FF为包头,FE为包尾,  如果我传输的数据本身就是FF和FE,  可能会引起误判 

        解决:

        A: 限制载荷数据的范围-------可以在发送的时候,对数据进行限幅.   比如XYZ,3个数据,变化范围都可以是0~100.   我们可以在载荷中只发送0~100的数据

        B:无法避免载荷数据和包头包尾重复-----尽量使用固定长度的数据包,  由于载荷数据是固定的,  只要通过包头和包尾对齐的数据.   就可以哪个数据应该是包头包尾,哪个数据应该是载荷数据.        在接收载荷数据的时候,我们并不会判断它是否是包头包尾,   而在接收包头包尾的时候,我们会判断它是不是确实是包头包尾

        C:增加包头包尾的数量---------尽量呈现出载荷数据出现不了的状态

固定包长和可变包长的选择问题 

        载荷会出现和包头包尾重复的情况--------最好选择固定包长

        反之选择可变包长

3: 文本数据包

在HEX数据包里面,数据都是以原始的字节数据本身呈现的,   而在文本数据包里面,每个字节就经过了一层编码和译码,  最终表现出来的,就是文本格式.   其实都还是一个字节的HEX数据

4:HEX数据包接收

        每收到一个字节,程序都会进一遍中断 .

状态机:

        最开始,S=0,  收到一个数据,进中断,   判断数据是不是包头FF,  如果是FF,则代表收到包头,  之后置S=1,退出中断,结束.   下次再进中断,根据S=1,就可以进行接收数据的程序了.   这时再收到数据,我们就直接把它存在数组中,  另外再用一个变量,记录收了多少个数据,  如果没收够规定的数据,就一直是接收状态, 如果收够了,就置S=2.   下次中断时,就可以进入下一个状态了.       最后一个状态就是等待包尾了,判断数据是不是FE,  这样就可以置S=0,回到最初的状态,开始下一个轮回

5:文本数据包接收

6: 案例

1:连接图

A:发送HEX数据包---固定数据长度


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"
#include <stdio.h>
#include <stdarg.h>uint8_t Serial_RxFlag;//一个数据包发送完成的标志位uint8_t Serial_TXPacket[4];//存放发送的数据---STM32向外设发送
uint8_t Serial_RXPacket[4];//存放接收的数据---外设向STM32发送数据void serial_init(void){//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置TI的GPIOGPIO_InitTypeDef GPIO_structinit;GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);//USART的配置USART_InitTypeDef USART_structinit;USART_structinit.USART_BaudRate=9600;//通信的波特率USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式USART_structinit.USART_Parity=USART_Parity_No;  //选择校验方式---无校验USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为USART_Init(USART1,&USART_structinit);//启动USART的RXNE中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_initstruct;NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;NVIC_initstruct.NVIC_IRQChannelSubPriority=1;NVIC_Init(&NVIC_initstruct);//启动USARTUSART_Cmd(USART1,ENABLE);
}/*** @brief  发送一个字节的数据--8位STM32向外设发送===通过USARTx外设传输单个数据* @param  需要发送的数据* @retval 无*/
void Serial_SendByte(uint8_t Byte)
{	//发送数据的函数USART_SendData(USART1,Byte);//检查某个寄存器的中断标志位while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);/*在完成数据发送的时候,TXE置1;下次发送数据自动置0,所以不用手动清除中断标志位.TXE:发送数据寄存器:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。0:数据还没有被转移到移位寄存器1:数据已经被转移到移位寄存器。注意:单缓冲器传输中使用该位。*/
}	/*** @brief  发送一个数组* @param  Array:传递的数组* @param  Length数组的长度* @retval 无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length){for(uint16_t i=0;i<Length;i++){Serial_SendByte(Array[i]);}}/*** @brief  发送一个字符串* @param  需要发送的字符串* @retval 无*/
void Serial_Sendstr(char *str)
{	//发送字符串时自带结束标志位for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'Serial_SendByte(str[i]);}
}/*** @brief  取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉12345取3 12345/100(10^2)%10=3   x:从左往右数,不包含要取的数字* @param  X:底数* @param  Y:指数* @retval 无*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}/*** @brief  输数字,把数字中的每一位取出,然后发送出去* @param  传输的数字* @param  传输数字的长度* @retval 无*/
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}//printf函数的底层
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}//spinrf函数的封装
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);
}/*** @brief  知道把中断标志位置位0* @retval 无*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}//------------------HEX包----------------------------
/*** @brief  发送HEX数据包---STM32发送到其他外设* @retval 无*/
uint16_t Send_HEX()
{Serial_SendByte(0XFF);Serial_SendArray(Serial_TXPacket,4);Serial_SendByte(0XFE);
}/**
* @brief  接收HEX数据包---其他外设发送到STM32上面* @retval 无*/
void USART1_IRQHandler(){//每收到一个字节,程序都会进一遍中断 //static---- 函数进入只会初始化一次,在函数退出后,数据仍然有效static uint8_t RxState = 0;//状态机的标志位static uint8_t pRxPacket = 0;//数据的包长//判断RXNE的中断标志位if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){uint8_t data=USART_ReceiveData(USART1);//32接收的数据if (RxState==0){if (data==0XFF){RxState=1;}		}else if (RxState==1){Serial_RXPacket[pRxPacket]=data; //右边的值赋值给等号的左边pRxPacket++;if (pRxPacket>=4){pRxPacket=0;RxState=2;}	}else if (RxState==2){if (data==0xFE){RxState=0;Serial_RxFlag=1;//一个数据包发送完成的标志位}}USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);}
}uint8_t RxData;
uint8_t num;
int main(void)
{Key_Init();OLED_Init();serial_init();OLED_ShowString(1,1,"RX_Data:");OLED_ShowString(3,1,"TX_Data:");Serial_TXPacket[0]=0x01;Serial_TXPacket[1]=0x02;Serial_TXPacket[2]=0x03;Serial_TXPacket[3]=0x04;while (1){	num=Key_GetNum();if (num==1){//发送数据Serial_TXPacket[0]++;Serial_TXPacket[1]++;Serial_TXPacket[2]++;Serial_TXPacket[3]++;Send_HEX();OLED_ShowHexNum(2, 1, Serial_TXPacket[0], 2);OLED_ShowHexNum(2, 4, Serial_TXPacket[1], 2);OLED_ShowHexNum(2, 7, Serial_TXPacket[2], 2);OLED_ShowHexNum(2, 10, Serial_TXPacket[3], 2);}//接收数据if (Serial_GetRxFlag()==1){OLED_ShowHexNum(4, 1, Serial_RXPacket[0], 2);OLED_ShowHexNum(4, 4, Serial_RXPacket[1], 2);OLED_ShowHexNum(4, 7, Serial_RXPacket[2], 2);OLED_ShowHexNum(4, 10, Serial_RXPacket[3], 2);}}
}

2:连接图

B:发送文本数据包---数据长度 


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"
#include "LED.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>uint8_t Serial_RxFlag;//一个数据包发送完成的标志位uint8_t Serial_TXPacket[4];//存放发送的数据---STM32向外设发送
char Serial_RXPacket[100];//存放接收的数据---外设向STM32发送数据void serial_init(void){//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置TI的GPIOGPIO_InitTypeDef GPIO_structinit;GPIO_structinit.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出:把控制权交给片上外设GPIO_structinit.GPIO_Pin=GPIO_Pin_9; //PA9在引脚定义中为TX发送GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);GPIO_structinit.GPIO_Mode=GPIO_Mode_IPU;//上拉输入GPIO_structinit.GPIO_Pin=GPIO_Pin_10; PA9在引脚定义中为RX接收GPIO_structinit.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_structinit);//USART的配置USART_InitTypeDef USART_structinit;USART_structinit.USART_BaudRate=9600;//通信的波特率USART_structinit.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流控制--不使用USART_structinit.USART_Mode=USART_Mode_Tx |USART_Mode_Rx;//配置GPIO为TX发送数据模式USART_structinit.USART_Parity=USART_Parity_No;  //选择校验方式---无校验USART_structinit.USART_StopBits=USART_StopBits_1;//停止的位数USART_structinit.USART_WordLength=USART_WordLength_8b;//发送或接收的数据位---我们使用8为USART_Init(USART1,&USART_structinit);//启动USART的RXNE中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_initstruct;NVIC_initstruct.NVIC_IRQChannel=USART1_IRQn; //通道NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=1;NVIC_initstruct.NVIC_IRQChannelSubPriority=1;NVIC_Init(&NVIC_initstruct);//启动USARTUSART_Cmd(USART1,ENABLE);
}/*** @brief  发送一个字节的数据--8位STM32向外设发送===通过USARTx外设传输单个数据* @param  需要发送的数据* @retval 无*/
void Serial_SendByte(uint8_t Byte)
{	//发送数据的函数USART_SendData(USART1,Byte);//检查某个寄存器的中断标志位while (USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);/*在完成数据发送的时候,TXE置1;下次发送数据自动置0,所以不用手动清除中断标志位.TXE:发送数据寄存器:当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART DR的写操作,将该位清零。0:数据还没有被转移到移位寄存器1:数据已经被转移到移位寄存器。注意:单缓冲器传输中使用该位。*/
}	/*** @brief  发送一个数组* @param  Array:传递的数组* @param  Length数组的长度* @retval 无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length){for(uint16_t i=0;i<Length;i++){Serial_SendByte(Array[i]);}}/*** @brief  发送一个字符串* @param  需要发送的字符串* @retval 无*/
void Serial_Sendstr(char *str)
{	//发送字符串时自带结束标志位for (uint8_t i=0 ; str[i]!=0;i++){//也可写为str[i]!='\0'Serial_SendByte(str[i]);}
}/*** @brief  取数字的某一位:数字/10^x/%10 ----/10^x就是把这一位的右边去掉,%10就是把左边去掉12345取3 12345/100(10^2)%10=3   x:从左往右数,不包含要取的数字* @param  X:底数* @param  Y:指数* @retval 无*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y) //X^Y
{uint32_t Result = 1;while (Y --){Result *= X;}return Result;
}/*** @brief  输数字,把数字中的每一位取出,然后发送出去* @param  传输的数字* @param  传输数字的长度* @retval 无*/
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{uint8_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');}
}//printf函数的底层
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}//spinrf函数的封装
void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_Sendstr(String);
}/*** @brief  知道把中断标志位置位0* @retval 无*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1){Serial_RxFlag = 0;return 1;}return 0;
}//------------------HEX包----------------------------
/*** @brief  发送HEX数据包---STM32发送到其他外设* @retval 无*/
uint16_t Send_HEX()
{Serial_SendByte(0XFF);Serial_SendArray(Serial_TXPacket,4);Serial_SendByte(0XFE);
}/**
* @brief  接收HEX数据包---其他外设发送到STM32上面* @retval 无*/void USART1_IRQHandler(){//每收到一个字节,程序都会进一遍中断 //static---- 函数进入只会初始化一次,在函数退出后,数据仍然有效static uint8_t RxState = 0;//状态机的标志位static uint8_t pRxPacket = 0;//数据的包长//判断RXNE的中断标志位if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){uint8_t data=USART_ReceiveData(USART1);//32接收的数据if (RxState==0){if (data=='@'){RxState=1;pRxPacket=0;}		}else if (RxState==1){if (data=='\r') //\r 的意思是: 回车。将当前位置移到本行的开头。{RxState=2;}else{Serial_RXPacket[pRxPacket]=data; //右边的值赋值给等号的左边pRxPacket++;}}else if (RxState==2){if (data=='\n')//\n 的意思是:回车换行。将当前位置移到下一行的开头。{RxState=0;Serial_RXPacket[pRxPacket]='\0';Serial_RxFlag=1;//一个数据包发送完成的标志位}}USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);}
}uint8_t RxData;
uint8_t num;
int main(void)
{OLED_Init();serial_init();LED_Init();OLED_ShowString(1,1,"RX_Data:");OLED_ShowString(3,1,"TX_Data:");while (1){//接收数据if (Serial_RxFlag==1){	OLED_ShowString(4,1,"                ");			OLED_ShowString(4,1,Serial_RXPacket);if (strcmp(Serial_RXPacket, "LED_ON")==0){LED1_ON();Serial_Sendstr("LED_ON_OK\r\n");//使用32把数据发送到外设中去OLED_ShowString(2, 1, "                ");OLED_ShowString(2, 1, "LED_ON_OK");}else if(strcmp(Serial_RXPacket, "LED_OFF")==0){LED1_OFF();Serial_Sendstr("LED_Off_OK\r\n");//使用32把数据发送到外设中去OLED_ShowString(2, 1, "                ");OLED_ShowString(2, 1, "LED_Off_OK");}else{	Serial_Sendstr("ERROR_COMMAND\r\n");//使用32把数据发送到外设中去OLED_ShowString(2, 1, "                ");OLED_ShowString(2,1,"ERROR_COMMAND");}Serial_RxFlag = 0;}}
}

相关文章:

09:STM32-------USART串口通信+串口数据包

目录 一:串口协议 1:通信接口 2:串口通信 3:硬件电路 4:电平标准 5:串口参数及其时序 二:USART介绍 1:简历 2:USART框图 3:USART的基本结构 4:数据帧 5: 波特率发生器 6:数据模式 三:案例 A:串口发送--单发送 1:连接图 2:函数介绍 3:代码 B:串口发送接收 1…...

“安全即服务”为网络安全推开一道门

8月30日&#xff0c;三六零&#xff08;下称“360”&#xff09;集团发布了2023年半年报&#xff0c;其中安全业务第二季度收入6.54亿元&#xff0c;同比增长98.76%&#xff0c;环比增长157.16%&#xff0c;安全第二增长曲线已完全成型&#xff01;特别值得一提的是&#xff0c…...

vue3的生命周期

1.vue3生命周期官方流程图 2.vue3中的选项式生命周期 vue3中的选项式生命周期钩子基本与vue2中的大体相同&#xff0c;它们都是定义在 vue实例的对象参数中的函数&#xff0c;它们在vue中实例的生命周期的不同阶段被调用。生命周期函数钩子会在我们的实例挂载&#xff0c;更新…...

[E2E Test] Python Behave Selenium 一文学会自动化测试

前言 本文将使用Python Behave与Selenium&#xff0c;和同学们一起认识自动化测试&#xff0c;并附上完整的实践教程。 项目源码已上传&#xff1a;CSDN 郭麻花 Azure Repo python-behave-selenium 核心概念 1. 什么是E2E Test E2E即End-to-end&#xff0c;意思是从头到尾…...

Knowledge Graph Prompting for Multi-Document Question Answering

本文是LLM系列文章&#xff0c;针对《Knowledge Graph Prompting for Multi-Document Question Answering》的翻译。 多文档问答中的知识图谱提示 摘要1 引言2 符号3 知识图谱构建4 LM引导的图形遍历器5 实验6 相关工作7 结论 摘要 大型语言模型的“预训练、提示、预测”范式…...

ElMessageBox.prompt 点击确认校验成功后关闭

ElMessageBox.prompt(, 验证取货码, {inputPattern: /^.{1,20}$/,inputErrorMessage: 请输入取货码,inputPlaceholder: 请输入取货码,beforeClose: (action, instance, done) > {if (action confirm) {if (instance.inputValue) {let flag false;if (flag) {done()} else …...

调整Windows11桌面图标间隔

调整Windows11桌面图标间隔 WinR 快捷键如何使用 在Windows系统中&#xff0c;通过 WinR 的快捷键可以快速打开Windows系统的“运行”窗口&#xff0c;然后在这里输入相应的命令就可以快速执行指定的任务。 具体的操作方法是&#xff0c;同时按下键盘上的Windows键和R键即可。…...

Spring最佳实践: 构建高效可维护的Java应用程序

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

stable diffusion webui中的sampler

Stable Diffusion-采样器篇 - 知乎采样器&#xff1a;Stable Diffusion的webUI中&#xff0c;提供了大量的采样器供我们选择&#xff0c;例如Eular a&#xff0c; Heum&#xff0c;DDIM等&#xff0c;不同的采样器之间究竟有什么区别&#xff0c;在操作时又该如何进行选择&…...

MySQL表的内连和外连

文章目录 MySQL表的内连和外连1. 内连接(1) 显示SMITH的名字和部门名称 2. 外连接2.1 左外连接(1) 查询所有学生的成绩&#xff0c;如果这个学生没有成绩&#xff0c;也要将学生的个人信息显示出来 2.2 右外连接(1) 对stu表和exam表联合查询&#xff0c;把所有的成绩都显示出来…...

StatefulSets In K8s

摘要 StatefulSets是Kubernetes的一种资源对象&#xff0c;用于管理有状态应用程序的部署。与Deployment不同&#xff0c;StatefulSets保证应用程序的有序部署和有状态的维护&#xff0c;确保每个Pod都有唯一的标识和稳定的网络标识。这些特性使得StatefulSets非常适合部署需要…...

leetcode刷题笔记——单调栈

1.模板&#xff1a; stack<int> st; for(int i 0; i < nums.size(); i){while(!st.empty() && st.top() > nums[i]){st.pop();//计算、存放结果}st.push(nums[i]); }2.注意事项&#xff1a;需要注意单调栈中stack存放元素为nums数组的『下标』还是nums数…...

关于 ogbg-molhi数据集的个人解析

cs224w_colab2.py这个图属性预测到底咋预测的 dataset.meta_info.T Out[2]: num tasks 1 eval metric rocauc download_name …...

RabbitMQ:hello结构

1.在Linux环境上面装入rabbitMQ doker-compose.yml version: "3.1" services:rabbitmq:image: daocloud.io/library/rabbitmq:managementrestart: alwayscontainer_name: rabbitmqports:- 6786:5672- 16786:15672volumes:- ./data:/var/lib/rabbitmq doker-compos…...

SpringBoot整合Redis 并 展示使用方法

步骤 引入依赖配置数据库参数编写配置类构造RedisTemplate创建测试类测试 1.引入依赖 不写版本号&#xff0c;也是可以的 在pom中引入 <!--redis配置--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-…...

js中如何实现字符串去重?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Set 数据结构⭐ 使用循环遍历⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感…...

Axure RP仿QQ音乐app高保真原型图交互模板源文件

Axure RP仿QQ音乐app高保真原型图交互模板源文件。本套素材模板的机型选择华为的mate30&#xff0c;在尺寸和风格方面&#xff0c;采用标准化制作方案&#xff0c;这样做出来的原型图模板显示效果非常优秀。 原型中使用大量的动态面板、中继器、母版&#xff0c;涵盖Axure中技…...

2023牛客暑假多校第四场(补题向题解:J)

终于有时间来慢慢补补题了 J Qu’est-ce Que C’est? 作为队内的dp手&#xff0c;赛时想了好久&#xff0c;等学弟学妹都出了还是不会&#xff0c;羞愧&#xff0c;还好最终队友做出来了。 链接J Qu’est-ce Que C’est? 题意 长度为 n n n 的数组 a a a&#xff0c;每…...

第 362 场 LeetCode 周赛题解

A 与车相交的点 数据范围小直接暴力枚举 class Solution { public:int numberOfPoints(vector <vector<int>> &nums) {unordered_set<int> vis;for (auto &p: nums)for (int i p[0]; i < p[1]; i)vis.insert(i);return vis.size();} };B 判断能否…...

C++ if 语句

一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。 语法 C 中 if 语句的语法&#xff1a; if(boolean_expression) {// 如果布尔表达式为真将执行的语句 }如果布尔表达式为 true&#xff0c;则 if 语句内的代码块将被执行。如果布尔表达式为 false&#xff0c;则 if 语…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

goreplay

1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具&#xff0c;可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长&#xff0c;测试它所需的工作量也会呈指数级增长。GoRepl…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...