前几天接到了一个任务,用stm32f103的串口读取电子罗盘(北微姿态传感器)的数据,其实也就三个,PITCH,ROLL,HEADING三个方向上的角度,顺带复习了一下串口知识。
    个人觉得熟悉一下串口协议还是很重要的,刚开始学习的时候跟着原子的视频学习还是学习的很认真的,奈何但是是为了比赛速成,所以看完视频就直接用原子的例程了,久而久之不太清楚串口通信的具体实现过程了,就知道怎么使用原子的串口例程。
    下面我们先来回顾一下串口的通信例程(已经会的大佬请略过)
    其实串口说到底就是一个通信工具,也就是说就是两个模块之间传输数据用的工具,那么传输数据,最重要的两个方面就是发送数据和接收数据这两个方面了,所以,我们今天也就着重从这两个方面来讲讲串口通信。
    在开始之前,我觉得有个串口通信的框图我们有必要先了解一下,不要求完全看懂,但至少需要了解一些。

其实最重要的就是两(仅对于发送而言,接收同理的也是两个)

一、USARTx->SR(状态寄存器)

就如图上所说的,控制寄存器主要就是一些使能位以及一些中断标志位,咱们可以看看参考手册,用手册说话

显然,这个寄存器中很多都是一些中断标志位。

二、USARTX->DR(数据寄存器)

可以看出,数据寄存器只有八位有效位,所以咱们串口的数据是一字节一字节(8位)传输的。

关于数据寄存器,还有一个要注意的地方大家一定要注意。大家看数据手册。

也就是说,串口发送与接收的寄存器其实是两个寄存器,一个是TDR寄存器,一个是RDR寄存器(其实我感觉就是一个寄存器,只不过不同时候用处不一样而已,大家可以在MDk中找到USART_TypeDef这个结构体去看看定义,所以这个知识点我觉得有可能是我没有理解手册的意思),但是很爽的是我们在单片机里头的操作一概都是USARTx->DR=0x某某;

下面咱们来看看具体的收发过程

发送

显然,按照参考手册上说的,只需要向USARTx->DR中写数据数据就会自动发送,发送完了,SR寄存器的相应的标志就会置位。我们也可以设置相应的中断。这是单字节发送,在这个基础上,我们也可以非常轻松地实现多字节发送。下面是多字节发送程序。

  1. /************************************************************
    函数功能:连续发送数据
    函数参数  u8 *data  发送数据数组首元素地址times  发送数据字节数
    ·µ»ØÖµ £º  void
    ************************************************************/
    void constant_send(u8 *data,u8 times)
    {int i;for(i=0;i<times;i++){               while((USART2->SR&0X80)==0);USART2->DR=*(data++);}
    }

接收

咱们继续看数据手册,,,这东西确实是个好东西,有耐心一定可以学到很多东西的

从上面可以看出来,我们接收数据也是直接读取DR寄存器就行,我们读取串口接收到的数据一般使用串口接收中断(USART_IT_RXNE),取数据的时候,中断标志位就自动清除了,所以在中断处理函数中我们不用调用清除中断标志位的函数。

接收中断还有个中断我觉得很有必要了解一下,在接受不定长数组中很有作用——USART_IT_IDLE(帧中断),帧中断是检测传输过程中的数据断流,当一组数据传输完成之后,才会进入中断。这样,我们就能很方便接收不定长数据了。下面附上代码

我的协议的代码。

void uart_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);   //使能USART1,GPIOA时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能usart2的时钟//USART1//2_TX  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_2; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9//USART1/2_RX   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_3;//PA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  //Usart1/2 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;       //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   //收发模式
//使能初始化以及中断设置usart1USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE);                    //使能串口1 NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   //收发模式
//使能初始化以及中断设置usart2USART_Init(USART2, &USART_InitStructure); //初始化串口2USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);  //使能串口帧中断  帧中断寄存器的清除,,先读SR寄存器,在读DR寄存器USART_Cmd(USART2, ENABLE);                    //使能串口2
}void USART1_IRQHandler(void)                   //串口1中断服务程序{u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){printf("ha\n");       Res =USART_ReceiveData(USART1);    //读取接收到的数据if((USART1_RX_STA&0x8000)==0)//接收未完成{if(USART1_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始else USART1_RX_STA|=0x8000;  //接收完成了 }else //还没收到0X0D{   if(Res==0x0d)USART1_RX_STA|=0x4000;else{USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ;USART1_RX_STA++;if(USART1_RX_STA>(USART_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收     }      }}          } }
/***************************************************************************************************************
函数功能:串口2接收中断函数
入口参数:void
返回值:void
***************************************************************************************************************/
void USART2_IRQHandler(void)                    //串口1中断服务程序{u8 clear=clear;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)       //等待接收中断{USART2_RX_BUF[recount++]=USART_ReceiveData(USART2);}if(USART_GetITStatus(USART2,USART_IT_IDLE)!=RESET){clear=USART2->SR;clear=USART2->DR;ReceiveState=1;}
}
#endif
/************************************************************
函数功能:连续发送数据
函数参数:*data   u8类型指针,代表要发送的数据数组第一个数的地址times  循环次数
返回值 :  void
************************************************************/
void constant_send(u8 *data,u8 times)
{int i;for(i=0;i<times;i++){               while((USART2->SR&0X80)==0);USART2->DR=*(data++);}
}
///以下为获取传感器数据相关函数/
/**************************************************************
函数功能:获取PITCH角度值
入口参数:void
返回值:  void
描述:发送 77 04 00 01 05(16进制),传感器返籶pitch叵喙厥荩菸辉诘谒奈辶纸冢咛寮蔽⑼ㄐ判?
**************************************************************/
void get_pitch(void)
{u16 data=data;              //这样子的作用可以排除没有使用的警告command_string[0]=0x77;command_string[1]=0x04;command_string[2]=0x00;command_string[3]=0x01;command_string[4]=0x05;constant_send(command_string,5); //循环发送,直到发送完毕   while(1){if(ReceiveState==1){data=(USART2_RX_BUF[4]&0x0f)*10000;    //百位,这儿其实都是乘了100倍换成整数提高代码的效率,同时可以防止一次一次转化成浮点数带来的精度损失的问题data=data+(USART2_RX_BUF[5]&0xf0>>4)*1000+(USART2_RX_BUF[5]&0x0f)*100;          data=data+(USART2_RX_BUF[6]&0xf0>>4)*10+(USART2_RX_BUF[6]&0x0f);direction_angles[0]=(data*1.0)/100;if((USART2_RX_BUF[4]&0xf0)==0x10)direction_angles[0]=-direction_angles[0];ReceiveState=0;recount=0;        break;           }}
}

关于串口收发,手册上还提供了一个更好的方法,用DMA通道(前提是支持DMA)直接进行数据传输。用DMA好处是为CPU减负,在要在开始和结束的阶段CPU参与一下就行,中间的数据传输阶段完全不用CPU参与,此时CPU可以去做其他事情。

关于串口DMA收发,我就写一下收发的要点

发送

1、初始化DMA通道(大家可以去参考原子的教程),使能串口DMA通道(这个容易忘记)

2、打开对应DMA的传输完成中断

3、在DMA的传输模式中,我们选择的是单次模式而不是循环模式,那么,我们如何重新开始发送数据呢,大家看手册。

手册上面说的很明白,我们先失能DMA对应的通道(只有先失能才能更改相应设置),然后重新写入需要传输的字节数,然后打开通道,对于接收而言也是同样的。

接收

1、初始化DMA通道(大家可以去参考原子的教程),使能串口DMA通道(这个容易忘记)

2、对于接收不定长数据,我们不能使用DMA通道的传输完成中断,因为数组的不定长,有可能会使DMA不能产生传输完成中断,这个时候,我们可以使用定时器超时中断,不过建议使用串口接收帧中断。

3、如何重新初始化接收和初始化发送是一样的

下面附上代码

void usart2_Init(u32 bound)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    //使能GPIO0A时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能串口2时钟//USART1_TX   GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2//USART1_RX     GPIOA.10初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3 //Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   //收发模式USART_Init(USART2, &USART_InitStructure); //初始化串口1USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//开启串口接受帧中断USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE);USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);USART_Cmd(USART2, ENABLE);                    //使能串口1
}
/**************************************************
函数功能:串口2的DMA初始化
函数参数:void
函数返回值:void
**************************************************/
void usart2_dma(void)
{DMA_InitTypeDef  usart2dma;NVIC_InitTypeDef  DMA_NVIC;     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);   //使能DMA1的时钟//中断配置   DMA_NVIC.NVIC_IRQChannel=DMA1_Channel7_IRQn;           //DMA1发送完成中断DMA_NVIC.NVIC_IRQChannelPreemptionPriority=1;          //抢占优先级为最高优先级DMA_NVIC.NVIC_IRQChannelSubPriority=0;DMA_NVIC.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&DMA_NVIC);   //根据指定的参数初始化VIC寄存器
//设置USART-DMA的接收    DMA_DeInit(DMA1_Channel6);                            //USART2的接收DMA设置成缺省位     usart2dma.DMA_PeripheralBaseAddr=(u32)(USART2->DR);    //外设基地址 //在指针面前加一个(u32),数据类型的强制转化,把指针类型的数据转化成u32usart2dma.DMA_MemoryBaseAddr=(u32)USART2_RX_BUF;      //内存基地址usart2dma.DMA_DIR=DMA_DIR_PeripheralSRC;              //外设到内存usart2dma.DMA_BufferSize=20;                          //一次传输10字节usart2dma.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不变,一直为USART2;usart2dma.DMA_MemoryInc=DMA_MemoryInc_Enable;         //内存地址增加usart2dma.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设字节传输usart2dma.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;      //内存字节传输usart2dma.DMA_Mode=DMA_Mode_Normal;                        //不采用循环采集的模式,采集一次便可,需要的花继续采集防止出现错误usart2dma.DMA_Priority=DMA_Priority_High;usart2dma.DMA_M2M=DMA_M2M_Disable; DMA_ClearFlag(DMA1_FLAG_GL6);                          //清除所有的标志位DMA_Init(DMA1_Channel6,&usart2dma);                    //串口2的接收对应着DMA1的channel6DMA_Cmd(DMA1_Channel6, ENABLE);  //使能USART1 TX DMA1 所指示的通道
//设置usart_dma的发送DMA_DeInit(DMA1_Channel7);  usart2dma.DMA_PeripheralBaseAddr=(u32)&(USART2->DR);    //外设基地址 usart2dma.DMA_MemoryBaseAddr=(u32)USART2_TX_BUF;      //内存基地址usart2dma.DMA_DIR=DMA_DIR_PeripheralDST;              //内存外设usart2dma.DMA_BufferSize=0;                         //一次传输0字节,需要的时候更改就行usart2dma.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不变,一直为USART2;usart2dma.DMA_MemoryInc=DMA_MemoryInc_Enable;         //内存地址增加usart2dma.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;  //外设字节传输usart2dma.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;      //内存字节传输usart2dma.DMA_Mode=DMA_Mode_Normal;                        //不采用循环采集的模式,采集一次便可,需要的花继续采集防止出现错误usart2dma.DMA_Priority=DMA_Priority_VeryHigh;usart2dma.DMA_M2M=DMA_M2M_Disable;DMA_ClearFlag(DMA1_FLAG_GL7);                          //清除所有的标志位DMA_Init(DMA1_Channel7,&usart2dma);                    //串口2的接收对应着DMA1的channel6DMA_ITConfig(DMA1_Channel7,DMA_IT_TC,ENABLE);          //DMA传输完成中断}
/***************************************
函数功能:接受重新使能
函数参数:DMA_Channel_TypeDef* DMAy_Channelx    //对应的DMA通道bytes_amount                          //字节数
函数返回值  void
描述:在DMA的正常模式下,DMA传输完一次之后需要重新开始传输的时候
需要先关闭该通道然后向DMA_CNDTRx寄存器写值之后再打开寄存器的值
***************************************/
void Receive_cmd(DMA_Channel_TypeDef* DMAy_Channelx,u16 bytes_amount)
{DMA_Cmd(DMAy_Channelx, DISABLE);  //失能USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMAy_Channelx,bytes_amount);//DMA通道的DMA缓存的大小DMA_Cmd(DMAy_Channelx, ENABLE);  //使能USART1 TX DMA1 所指示的通道
}/**************下面是中断服务函数*********************/
/***************************************
函数作用:串口2中断函数
函数参数:void
函数返回值:void
***************************************/
void USART2_IRQHandler(void)
{u32 temp=temp;u8 i;if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET){temp=USART2->SR;       //先读状态寄存器,然后在读数据寄存器temp=USART2->DR;DMA_Cmd(DMA1_Channel6, DISABLE);  //暂时关闭USART2DMA的接受通道,防止干扰receive_flag=1;}
}
/***************************************
函数功能:DMA接受中断服务函数
函数参数:void
函数返回值:void
***************************************/
void DMA1_Channel7_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_IT_GL7)!=RESET){Receive_cmd(DMA1_Channel6,20);               //开启接收DMA_ClearITPendingBit(DMA1_IT_GL7);          //清除所有中断标志位DMA_Cmd(DMA1_Channel7, DISABLE);  //暂时关闭USART2DMA的接受通道,防止干扰send_flag=1;   //接收完成软标志}
}
/**************************************************************
函数功能:获取heading角度值
入口参数:void
返回值:  void
描述:发送 77 04 00 03 07(16进制),传感器返回heading相关数据,数据位在第四五六字节,具体见北微通信协议
**************************************************************/
void get_heading(void)
{u16 data=data;              //这样子的作用可以排除没有使用的警告USART2_TX_BUF[0]=0x77;USART2_TX_BUF[1]=0x04;USART2_TX_BUF[2]=0x00;USART2_TX_BUF[3]=0x03;USART2_TX_BUF[4]=0x07;Receive_cmd(DMA1_Channel7,5);  delay_ms(1000);while(send_flag);          //等待可以已发送while(1)  {if(send_flag){send_flag=0;break;}}while(1)    {if(receive_flag==1)                           //等待接受完成{receive_flag=0;   break;}}    data=(USART2_RX_BUF[4]&0x0f)*10000;    //百位,这儿其实都是乘了100倍换成整数提高代码的效率,同时可以防止一次一次转化成浮点数带来的精度损失的问题data=data+(USART2_RX_BUF[5]&0xf0>>4)*1000+(USART2_RX_BUF[5]&0x0f)*100;          data=data+(USART2_RX_BUF[6]&0xf0>>4)*10+(USART2_RX_BUF[6]&0x0f);direction_angles[0]=(data*1.0)/100;if((USART2_RX_BUF[4]&0xf0)==0x10)direction_angles[0]=-direction_angles[0];
}

第一次写博客,肯定有很多理解不对或者错误的地方,还请各位大佬指正,也希望能给需要的人带来一点帮助,知识需要分享才能发挥更大的价值

stm32f103读取电子罗盘数据相关推荐

  1. 绘制STM32最小系统电路原理图、STM32F103读取SD卡的数据

    绘制STM32最小系统电路原理图.STM32F103读取SD卡的数据 文章目录 绘制STM32最小系统电路原理图.STM32F103读取SD卡的数据 1 AltiumDesigner 软件配置 2 A ...

  2. pycharm读取JY-901S数据

    前言 在家真的好不方便,等了2天的usb转ttl终于到了,也终于可以学习了 一.JY-901S介绍 ● 该产品是基于MEMS技术的高性能三维运动姿态测量系统.它包含三轴陀螺仪.三轴加速度计,三轴电子罗 ...

  3. 机器人底层通讯(3): linux系统下获取电子罗盘数据(上)

    1.已有设备和接口 电子罗盘–1个 RS485转RS232接口–1个 RS232转USB接口-- 1个 2.在window10系统下借助串口调试器可以正常接收数据,说明电子罗盘正常: 3.查看是否已正 ...

  4. TensorFlow csv读取文件数据(代码实现)

    TensorFlow csv读取文件数据(代码实现) 大多数人了解 Pandas 及其在处理大数据文件方面的实用性.TensorFlow 提供了读取这种文件的方法. 前面章节中,介绍了如何在 Tens ...

  5. SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题...

    转:http://blog.csdn.net/miragesky2049/article/details/7204882 SharePoint2010沙盒解决方案基础开发--关于TreeView树形控 ...

  6. Kinect V1读取图像数据(For Windows)

    Kinect V1读取图像数据(For Windows) 这篇博客 Kinect V1介绍 数据读取的基本流程 运行代码和注释 结尾 这篇博客  刚好有一台现成的Kinect V1相机,所以就拿过来学 ...

  7. C++ 简单读写文本文件、统计文件的行数、读取文件数据到数组

    转自:http://hi.baidu.com/ctralt/blog/item/cde79fec87f841302697911c.html fstream提供了三个类,用来实现c++对文件的操作.(文 ...

  8. 图像数据读取及数据扩增方法

    Datawhale干货 作者:王程伟,Datawhale成员 本文为干货知识+竞赛实践系列分享,旨在理论与实践结合,从学习到项目实践.(零基础入门系列:数据挖掘/cv/nlp/金融风控/推荐系统等,持 ...

  9. 操作系统学习:Linux0.12初始化详细流程-进程1调度与读取硬盘数据

    本文参考书籍 1.操作系统真相还原 2.Linux内核完全剖析:基于0.12内核 3.x86汇编语言 从实模式到保护模式 4.Linux内核设计的艺术 ps:基于x86硬件的pc系统 Linux0.1 ...

最新文章

  1. java 日期和字符串互转,根据当天整天时间 得到当天最后一秒的日期时间
  2. CentOS/Linux 卸载MATLAB
  3. B. Lynyrd Skynyrd(倍增 + 区间最小值)
  4. 关于select中fd_set变量的一些通俗宏解释
  5. Github 简明教程 - 添加远程库
  6. !何为脏读、不可重复读、幻读
  7. Python: try finally 与 上下文管理器简介
  8. 【华为云技术分享】云小课 | SAP S/4HANA高可用之实战演练
  9. python装饰器语法糖_最全python装饰器的各种写法
  10. RetinaNet算法详解及其在垃圾检测中的应用
  11. java+整合handwrite_E-signature-master
  12. 常用公差配合表图_车间里常用的测量器具,别说没见过!
  13. 华为悦盒EC6108V9 、EC6108V9C_1080UI_非高安版_鸿蒙动画_免拆卡刷固件
  14. 为什么打工人996会猝死,而老板007不会?
  15. 安岷老师 精益生产管理专家
  16. 关于Linux备份文件和应用的几个命令:tar和cp
  17. oracle热备检查,oracle 手动热备
  18. php狼找兔子问题算法,算法 狼找兔子问题
  19. acer加固态硬盘,hdd放到光驱位,BIOS没有设置固态硬盘启动选项
  20. Qt向MySQL中插入图片

热门文章

  1. python并行计算_《python并行计算(完结篇):并行方法总结》
  2. RBF网络插值、MNIST识别简例
  3. 直播协议HTTP-FLV详解
  4. speechSynthesis.speak()在chrome不执行问题
  5. 最先进的微型计算机,获得《微型计算机》称赞,GPD P2 MAX堪称对便携本的终极追求...
  6. 小米运动和每日瑜伽对比缺陷
  7. x11苹果_Apple中国 - Mac OS X - X11
  8. 运兴ETF:成为50ETF期权赢家必须克服的共性弱点
  9. 霍夫曼树与霍夫曼编码
  10. 头歌C++ 第8章 虚函数与多态性