物联网——USART协议
接口
串口通信
硬件电路
电平标准
串口参数、时序
USART
USART主要框图
TXE: 判断发送寄存器是否为空
RXNE: 判断接收寄存器是否非空
RTS为输出信号,用于表示MCU串口是否准备好接收数据,若输出信号为低电平,则说明MCU串口可以接收数据,请求发送数据。当接收寄存器已满时,RTS将被设置为高电平 CTS为输入信号,用于判断MCU串口是否可以向对方发送数据,若接收信号为低电平,则说明MCU串口可以向对方发送数据。若为高电平则在发送当前数据帧之后停止发送
数据帧
起始位侦测及采样位置对齐
将一个数据周期分为16个采样周期,取中间值作为该周期的电平
波特率发生器
DIV: 分频系数
例子:求波特率为9600的分频系数,9600=72M / 16 / DIV
CH340G 内部结构
串口接线图
数据模式
勾选Use MicroLIB , 重定向printf
封装sprintf()
sprintf函数打印到字符串中(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),而printf函数打印输出到屏幕上。sprintf函数在我们完成其他数据类型转换成字符串类型的操作中应用广泛。
format为要打印的字符串格式,va_list 是参数列表,从format的位置开始接收参数表,存进arg,再将arg打印到string变量中,释放arg,通过串口发送string
需添加头文件: #include <stdarg.h>
串口输出中文防止乱码
--no-multibyte-chars
串口发送实例源码
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>/*** 函 数:串口初始化* 参 数:无* 返 回 值:无*/
void Serial_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/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); //将PA9引脚初始化为复用推挽输出/*USART初始化*/USART_InitTypeDef USART_InitStructure; //定义结构体变量USART_InitStructure.USART_BaudRate = 9600; //波特率USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要USART_InitStructure.USART_Mode = USART_Mode_Tx; //模式,选择为发送模式USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验,不需要USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位,选择1位USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长,选择8位USART_Init(USART1, &USART_InitStructure); //将结构体变量交给USART_Init,配置USART1 /*USART使能*/USART_Cmd(USART1, ENABLE); //使能USART1,串口开始运行
}/*** 函 数:串口发送一个字节* 参 数:Byte 要发送的一个字节* 返 回 值:无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}/*** 函 数:串口发送一个数组* 参 数:Array 要发送数组的首地址* 参 数:Length 要发送数组的长度* 返 回 值:无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数:串口发送一个字符串* 参 数:String 要发送字符串的首地址* 返 回 值:无*/
void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数:次方函数(内部使用)* 返 回 值:返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1; //设置结果初值为1while (Y --) //执行Y次{Result *= X; //将X累乘到结果}return Result;
}/*** 函 数:串口发送数字* 参 数:Number 要发送的数字,范围:0~4294967295* 参 数:Length 要发送数字的长度,范围:0~10* 返 回 值:无*/
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'); //依次调用Serial_SendByte发送每位数字}
}/*** 函 数:使用printf需要重定向的底层函数* 参 数:保持原始格式即可,无需变动* 返 回 值:保持原始格式即可,无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数:自己封装的prinf函数* 参 数:format 格式化字符串* 参 数:... 可变的参数列表* 返 回 值:无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始,接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组(字符串)
}
HEX数据包
传输速度快,包头和包尾与有效数据部分可能重复
文本数据包
传输数据直观,包头包尾与有效数据不会重复,但解析效率低
接收HEX数据包
文本数据包接收 
Hex数据包接收结果
源码
#include "stm32f10x.h" // Device header
#include "MyDelay.h" //自定义延时函数
#include "Delay.h" //官方延迟函数
#include "Button.h" //按键Led驱动
#include "stdio.h"
#include "OLED.h"
#include "Button.h"
#include "Serial.h"int main(void){//环境配置OLED_Init();Serial_Init();Button_Init();OLED_ShowString(1,1,"TxData...");OLED_ShowString(3,1,"RxData..."); Serial_TxPacket[0] = 0x01; Serial_TxPacket[1] = 0x02; Serial_TxPacket[2] = 0x03; Serial_TxPacket[3] = 0x04; uint8_t Key_Num = 0;while(1){Key_Num = Key_GetNum();OLED_ShowNum(1,10,Key_Num,4);if(Key_Num == 1){ //按键按下,执行数据发送,通过OLED展示发送的数据Serial_TxPacket[0]++;Serial_TxPacket[1]++; Serial_TxPacket[2]++; Serial_TxPacket[3]++; Serial_SendPacket();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,11,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,11,Serial_RxPacket[3],2);}} return 0;
}
#include "stm32f10x.h" //Device header
#include <stdio.h>
#include <stdarg.h>
#include <Serial.h>//定义串口接收的数据包和标志位
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];//串口初始化
void Serial_Init(void){//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //Pin_9推挽复用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; //Pin_10上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//USART初始化USART_InitTypeDef UI;UI.USART_BaudRate = 9600;UI.USART_HardwareFlowControl = USART_HardwareFlowControl_None;UI.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;UI.USART_Parity = USART_Parity_No; //无需奇偶校验UI.USART_StopBits = USART_StopBits_1;UI.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&UI);//USART中断输出配置USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//NVIC中断配置分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NI;NI.NVIC_IRQChannel = USART1_IRQn;NI.NVIC_IRQChannelCmd = ENABLE;NI.NVIC_IRQChannelPreemptionPriority = 1;NI.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NI);//USART使能USART_Cmd(USART1,ENABLE);}/*** 函 数:串口发送一个字节* 参 数:Byte 要发送的一个字节* 返 回 值:无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}/*** 函 数:串口发送一个数组* 参 数:Array 要发送数组的首地址* 参 数:Length 要发送数组的长度* 返 回 值:无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数:串口发送一个字符串* 参 数:String 要发送字符串的首地址* 返 回 值:无*/
void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}}/*** 函 数:次方函数(内部使用)* 返 回 值:返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1; //设置结果初值为1while (Y --) //执行Y次{Result *= X; //将X累乘到结果}return Result;
}/*** 函 数:串口发送数字* 参 数:Number 要发送的数字,范围:0~4294967295* 参 数:Length 要发送数字的长度,范围:0~10* 返 回 值:无*/
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'); //依次调用Serial_SendByte发送每位数字}
}/** * 函 数:使用printf需要重定向的底层函数* 参 数:保持原始格式即可,无需变动* 返 回 值:保持原始格式即可,无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数:自己封装的prinf函数* 参 数:format 格式化字符串* 参 数:... 可变的参数列表* 返 回 值:无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始,接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组(字符串)
}/*** 函 数:获取串口接收标志位* 参 数:无* 返 回 值:串口接收标志位,范围:0~1,接收到数据后,标志位置1,读取后标志位自动清零*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1) //如果标志位为1{Serial_RxFlag = 0;return 1; //则返回1,并自动清零标志位}return 0; //如果标志位为0,则返回0
}/*** 函 数:获取串口接收的数据* 参 数:无* 返 回 值:接收的数据,范围:0~255*/
uint8_t Serial_GetRxData(void)
{return Serial_RxData; //返回接收的数据变量
}/*** 函 数:USART1中断函数* 参 数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行* 函数名为预留的指定名称,可以从启动文件复制* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void USART1_IRQHandler(void)
{//在中断函数中,执行状态机转换static uint8_t RxState = 0;static uint8_t nRxPacket; //接收的第n个有效数据载荷 if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET ){ //判断中断是否生效uint8_t RxData = USART_ReceiveData(USART1);//状态机三个状态if(RxState == 0){if(RxData == 0xFF){RxState = 1;nRxPacket = 0;}} else if(RxState == 1){Serial_RxPacket[nRxPacket++] = RxData; //接收第n个载荷数据if(nRxPacket >=4 ) {RxState = 2;} } else if(RxState == 2){if(RxData == 0xFE){ //包尾RxState = 0; //接收一个数据包完成,重新开始一轮状态机Serial_RxFlag = 1; //置完成标志位}} USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志位 }}//发送数据包
void Serial_SendPacket(void){Serial_SendByte(0xFF); //发送包头Serial_SendArray(Serial_TxPacket, 4);Serial_SendByte(0xFE);
}
#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>extern uint8_t Serial_TxPacket[];
extern uint8_t Serial_RxPacket[];void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number,uint8_t Length);
void Serial_Printf(char *format,...);void Serial_SendPacket(void);
uint8_t Serial_GetRxFlag(void);#endif
接收文本数据包 ,点亮小灯
#include "stm32f10x.h" // Device header
#include "MyDelay.h" //自定义延时函数
#include "Delay.h" //官方延迟函数
#include "Button.h" //按键Led驱动
#include "stdio.h"
#include "OLED.h"
#include "Button.h"
#include "Serial.h"int main(void){//环境配置OLED_Init();Serial_Init();Button_Init();OLED_ShowString(1,1,"TxData...");OLED_ShowString(3,1,"RxData..."); Serial_TxPacket[0] = 0x01; Serial_TxPacket[1] = 0x02; Serial_TxPacket[2] = 0x03; Serial_TxPacket[3] = 0x04; uint8_t Key_Num = 0;while(1){if(Serial_GetRxFlag() == 1){ //若接收完成一个数据包,进行相应展示OLED_ShowString(4,1," "); //空白行用于被某些重复数据覆盖OLED_ShowString(4,1,Serial_RxPacket);//根据串口接收到的命令,点亮小灯if(strcmp(Serial_RxPacket,"LED_ON")==0){LED1_ON();Serial_SendString("LED1_ON\r\n"); //开灯} else if(strcmp(Serial_RxPacket,"LED_OFF")==0){LED1_OFF();Serial_SendString("LED1_OFF\r\n"); //关灯} else {Serial_SendString("Error\r\n"); //错误指令} }} return 0;
}
#include "stm32f10x.h" //Device header
#include <stdio.h>
#include <stdarg.h>
#include <Serial.h>//定义串口接收的数据包和标志位
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t Serial_TxPacket[4];
char Serial_RxPacket[100];//串口初始化
void Serial_Init(void){//开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIO初始化GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; //Pin_9推挽复用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; //Pin_10上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//USART初始化USART_InitTypeDef UI;UI.USART_BaudRate = 9600;UI.USART_HardwareFlowControl = USART_HardwareFlowControl_None;UI.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;UI.USART_Parity = USART_Parity_No; //无需奇偶校验UI.USART_StopBits = USART_StopBits_1;UI.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&UI);//USART中断输出配置USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//NVIC中断配置分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NI;NI.NVIC_IRQChannel = USART1_IRQn;NI.NVIC_IRQChannelCmd = ENABLE;NI.NVIC_IRQChannelPreemptionPriority = 1;NI.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NI);//USART使能USART_Cmd(USART1,ENABLE);}/*** 函 数:串口发送一个字节* 参 数:Byte 要发送的一个字节* 返 回 值:无*/
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}/*** 函 数:串口发送一个数组* 参 数:Array 要发送数组的首地址* 参 数:Length 要发送数组的长度* 返 回 值:无*/
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{uint16_t i;for (i = 0; i < Length; i ++) //遍历数组{Serial_SendByte(Array[i]); //依次调用Serial_SendByte发送每个字节数据}
}/*** 函 数:串口发送一个字符串* 参 数:String 要发送字符串的首地址* 返 回 值:无*/
void Serial_SendString(char *String)
{uint8_t i;for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止{Serial_SendByte(String[i]); //依次调用Serial_SendByte发送每个字节数据}}/*** 函 数:次方函数(内部使用)* 返 回 值:返回值等于X的Y次方*/
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{uint32_t Result = 1; //设置结果初值为1while (Y --) //执行Y次{Result *= X; //将X累乘到结果}return Result;
}/*** 函 数:串口发送数字* 参 数:Number 要发送的数字,范围:0~4294967295* 参 数:Length 要发送数字的长度,范围:0~10* 返 回 值:无*/
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'); //依次调用Serial_SendByte发送每位数字}
}/** * 函 数:使用printf需要重定向的底层函数* 参 数:保持原始格式即可,无需变动* 返 回 值:保持原始格式即可,无需变动*/
int fputc(int ch, FILE *f)
{Serial_SendByte(ch); //将printf的底层重定向到自己的发送字节函数return ch;
}/*** 函 数:自己封装的prinf函数* 参 数:format 格式化字符串* 参 数:... 可变的参数列表* 返 回 值:无*/
void Serial_Printf(char *format, ...)
{char String[100]; //定义字符数组va_list arg; //定义可变参数列表数据类型的变量argva_start(arg, format); //从format开始,接收参数列表到arg变量vsprintf(String, format, arg); //使用vsprintf打印格式化字符串和参数列表到字符数组中va_end(arg); //结束变量argSerial_SendString(String); //串口发送字符数组(字符串)
}/*** 函 数:获取串口接收标志位* 参 数:无* 返 回 值:串口接收标志位,范围:0~1,接收到数据后,标志位置1,读取后标志位自动清零*/
uint8_t Serial_GetRxFlag(void)
{if (Serial_RxFlag == 1) //如果标志位为1{Serial_RxFlag = 0;return 1; //则返回1,并自动清零标志位}return 0; //如果标志位为0,则返回0
}/*** 函 数:获取串口接收的数据* 参 数:无* 返 回 值:接收的数据,范围:0~255*/
uint8_t Serial_GetRxData(void)
{return Serial_RxData; //返回接收的数据变量
}/*** 函 数:USART1中断函数* 参 数:无* 返 回 值:无* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行* 函数名为预留的指定名称,可以从启动文件复制* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入*/
void USART1_IRQHandler(void)
{//在中断函数中,执行状态机转换static uint8_t RxState = 0;static uint8_t nRxPacket; //接收的第n个有效数据载荷 if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET ){ //判断中断是否生效uint8_t RxData = USART_ReceiveData(USART1);//状态机三个状态if(RxState == 0){if(RxData == '@'){RxState = 1;nRxPacket = 0;}} else if(RxState == 1){Serial_RxPacket[nRxPacket++] = RxData; //接收第n个载荷数据if(RxData == '\r') {RxState = 2;} } else if(RxState == 2){if(RxData == '\n'){ //包尾RxState = 0; //接收一个数据包完成,重新开始一轮状态机Serial_RxPacket[nRxPacket] = '\0'; //字符串结束标志位Serial_RxFlag = 1; //置完成标志位}} USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志位 }}//发送数据包
void Serial_SendPacket(void){Serial_SendByte(0xFF); //发送包头Serial_SendArray(Serial_TxPacket, 4);Serial_SendByte(0xFE);
}
#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>extern uint8_t Serial_TxPacket[];
extern char Serial_RxPacket[];void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number,uint8_t Length);
void Serial_Printf(char *format,...);void Serial_SendPacket(void);
uint8_t Serial_GetRxFlag(void);#endif
相关文章:

物联网——USART协议
接口 串口通信 硬件电路 电平标准 串口参数、时序 USART USART主要框图 TXE: 判断发送寄存器是否为空 RXNE: 判断接收寄存器是否非空 RTS为输出信号,用于表示MCU串口是否准备好接收数据,若输出信号为低电平,则说明MCU串口可以接收数据&#…...
前端框架对比与选择:如何在现代Web开发中做出最佳决策
随着互联网技术的迅速发展,前端开发在现代Web应用开发中扮演了至关重要的角色。对于开发者来说,选择合适的前端框架不仅能够提高开发效率,还能确保项目的可维护性和可扩展性。目前市面上有多种主流的前端框架和库,每一种都有其独特…...

【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例
【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例 前言问题描述控制方程及数值方法浅水方程及其数值计算方法边界条件的实现 代码框架与关键代码模拟结果 更新于2024年9月17日 前言 这篇博客算是学习浅水方程,并利用MATLAB复刻Liang (2004)1中溃坝流算例的一个记录…...
探索云计算:IT行业的未来趋势
探索云计算:IT行业的未来趋势 在当今快速发展的科技世界,云计算已成为IT行业的核心趋势之一。无论是大企业还是初创公司,越来越多的组织正在转向云计算,以实现更高效的运营和更快的创新。在这篇博文中,我们将探讨云计算…...

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)
前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能,但是遇到了如下问题: 在Unity里面没法串流调试眼动追踪功能,根本获取不到Device,只能将整个场景build成APK,安装到头盔里,才能在…...

一周热门|比GPT-4强100倍,OpenAI有望年底发布GPT-Next;1个GPU,1分钟,16K图像
大模型周报将从【企业动态】【技术前瞻】【政策法规】【专家观点】四部分,带你快速跟进大模型行业热门动态。 01 企业动态 Ilya 新公司 SSI 官宣融资 10 亿美元 据路透社报道,由 OpenAI 联合创始人、前首席科学家 Ilya Sutskever 在 2 个多月前共同创…...

软考流水线计算
某计算机系统输入/输出采用双缓冲工作方式,其工作过程如下图所示,假设磁盘块与缓冲区大小相同,每个盘块读入缓冲区的时间T为10μs,由缓冲区送至用户区的时间M为6μs,系统对每个磁盘块数据的处理时间C为2μs。若用户需要…...

1份可以派上用场丢失数据恢复的应用程序列表
无论如何,丢失您的宝贵数据是可怕的。您的 Android 或 iOS 设备可能由于事故、硬件损坏、存储卡问题等而丢失了数据。这就是为什么我们编制了一份可以派上用场以恢复丢失数据的应用程序列表。 如果您四处走动,您大多会随身携带手机或其他移动设备。这些…...

MySQL Workbench 超详细安装教程(一步一图解,保姆级安装)
前言: MySQL Workbench 是一款强大的数据库设计和管理工具,它提供了图形化界面,使得数据库的设计、管理、查询等操作变得更加直观和便捷。本文将详细介绍如何在 Windows 系统上安装 MySQL Workbench。相信读者看这篇文章前一定安装了MySQL数…...
深度学习常见面试题及答案(16~20)
算法学习、4对1辅导、论文辅导或核心期刊以及其他学习资源可以通过公众号滴滴我 文章目录 16. 简述深度学习中的批量归一化(Batch Normalization)的目的和工作原理。一、批量归一化的目的1. 加速训练收敛:2. 提高模型泛化能力:3. …...

Packet Tracer - IPv4 ACL 的实施挑战(完美解析)
目标 在路由器上配置命名的标准ACL。 在路由器上配置命名的扩展ACL。 在路由器上配置扩展ACL来满足特定的 通信需求。 配置ACL来控制对网络设备终端线路的 访问。 在适当的路由器接口上,在适当的方向上 配置ACL。…...
Langchain-chatchat源码部署及测试实验
一年多前接触到Langchain-chatchat的0.2版本,对0.2版本进行了本地部署和大量更新,但0.2版本对最新的大模型支持不够好,部署框架支持也不好且不太稳定,特别是多模态大模型,因此本次主要介绍0.3版本的源码部署,希望对大家有所帮助。Langchain-chatchat从0.3版本开始,支持更…...
【Linux】线程(第十六篇)
目录 线程 1.线程基本概述: 2.线程类型: 3.线程间的共享资源与非共享资源 4.线程原语 1.线程创建函数 2.获取当前线程id的函数 3.回收线程资源 4.将线程设置为分离态 5.结束线程 6.退出线程 线程 1.线程基本概述: 是操作系统能够…...

2024华为杯研赛E题保姆级教程思路分析
E题题目:高速公路应急车道紧急启用模型 今年的E题设计到图像/视频处理,实际上,E题的难度相对来说较低,大家不用畏惧视频的处理,被这个吓到。实际上,这个不难,解决了视频的处理问题,…...

国内可以使用的ChatGPT服务【9月持续更新】
首先基础知识还是要介绍得~ 一、模型知识: GPT-4o:最新的版本模型,支持视觉等多模态,OpenAI 文档中已经更新了 GPT-4o 的介绍:128k 上下文,训练截止 2023 年 10 月(作为对比,GPT-4…...

Linux环境Docker安装Mongodb
Linux环境Docker安装Mongodb 环境要求拉取指定版本镜像创建映射目录(相当于数据存放于容器外,容器被删除不会影响数据)启动容器 进入mongo命令行为指定db创建新用户查看mongodb的容器id进入命令行查看所有db切换db为指定db创建新用户使用新账…...

PyTorch 池化层详解
在深度学习中,池化层(Pooling Layer)是卷积神经网络(CNN)中的关键组成部分。池化层的主要功能是对特征图进行降维和减少计算量,同时增强模型的鲁棒性。本文将详细介绍池化层的作用、种类、实现方法…...
Intel架构的基本知识
1.字节序 CPU的字节序分为LittleEndian和BigEndian。 所谓Endian,就是多字节数据在内存中的排列方式。 例如,假设有一个整数0x11223344: LittleEndian的排列方式是,从内存的低地址开始,依次存放 0x44 0x33 0x22 0x11; BigEndian的排列方式是,从内存的低地址开始,依…...

Element Plus 中Input输入框
通过鼠标或键盘输入字符 input为受控组件,他总会显示Vue绑定值,正常情况下,input的输入事件会正常被响应,他的处理程序应该更新组件的绑定值(或使用v-model)。否则,输入框的值将不会改变 不支…...

大模型中常见 loss 函数
loss 函数 首先,Loss 是允许不降到 0 的,模型计算的 loss 最终结果可以接近 0。 可以成为 loss 函数的条件## 常用 loss 以下函数调用基于 Pytorch,头文件导入: import torch.nn as nn 均方差(MSE) nn.…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...