STM32实验之USART串口发送+接受数据(二进制/HEX/文本)
涉及三个实验:
1.USART串口发送和接收数据
我们使用的是将串口封装成为一个Serial.c模块.其中包含了
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);//串口发送数字uint8_t Serial_GetRxFlag(void);//串口接收标志位
uint8_t Serial_GetRxData(void);//接受数据模块
在这次实验中,我们调用中断函数申请中断,中断函数为USART1_IRQHandler(void)
同时也要判断在中断中数据接收标志位,在最后也要清除中断数据接受标志位if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
{
Serial_RxData=USART_ReceiveData(USART1);
Serial_RxFlag=1;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位
}
1.1Serial.c串口模块
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{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_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//引脚9为TX发送端GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//上拉输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//引脚10为RX输入端口GPIO_Init(GPIOB, &GPIO_InitStructure);//USART配置9600波特率 8位字长 1位停止位 无校验位 无硬件流控制 只有发送模式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 ;//发送字长为8bitUSART_Init(USART1,&USART_InitStructure);//开启RXNE标志位到NVIC的输出,一旦RXEN标志位置1,就开始向NVIC申请中断,之后,我们就可以在中断里接受数据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);
}
//串口发送一个字节
void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1,Byte);//将将数据写入发送数据寄存器中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]);}
}//串口发送字符串
void Serial_SendString(char *String)
{uint8_t i;for(i=0;String[i]!='\0';i++){Serial_SendByte(String[i]);}
}//函 数:次方函数(内部使用)//返 回 值:返回值等于X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{uint32_t Result =1;while(Y--){Result *=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');}
}
//fputc为printf的底层,printf在打印的时候不断调用fputc函数
int fputc(int ch,FILE *f)
{Serial_SendByte(ch);//在这里我们把fputc函数重定向到串口,那printf自然输出到串口return ch;
}//将printf打印的内容输出到串口
//将可变参数发送出去
void Serial_Printf(char *format,...)//format参数用来接收格式化字符串,...用来接收后面的可变参数列表
{char String[100];va_list arg;//定义一个参数列表变量va_start(arg,format);//从format位置开始接收参数表,放在arg里vsprintf(String,format,arg);va_end(arg);//释放参数列表Serial_SendString(String);
}
//实现读后自动清除
uint8_t Serial_GetRxFlag(void)
{if(Serial_RxFlag==1)//接受数据标志位置1,接收到数据{Serial_RxFlag=0;return 1;}return 0;
}
//变量封装返回接收到的数据
uint8_t Serial_GetRxData(void)
{return Serial_RxData;
}
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){Serial_RxData=USART_ReceiveData(USART1);Serial_RxFlag=1;USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位}
}
1.2Serial.h函数
#ifndef __SERIAL_H
#define __SERIAL_Hvoid 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,...);
uint8_t Serial_GetRxFlag(void);//接受数据标志位
uint8_t Serial_GetRxData(void);#endif
1.3 main.c函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"uint8_t RxData; //定义用于接收串口数据的变量int main(void)
{OLED_Init(); //OLED初始化OLED_ShowString(1, 1, "RxData:");Serial_Init(); //串口初始化while (1){if (Serial_GetRxFlag() == 1) //检查串口接收数据的标志位{RxData = Serial_GetRxData(); //获取串口接收的数据Serial_SendByte(RxData); //串口将收到的数据回传回去,用于测试OLED_ShowHexNum(1, 8, RxData, 2); //显示串口接收的数据}}
}
2.USART串口发送和接受HEX数据
在接受HEX数据包时使用一个状态机的理念。
2.1状态机代码

RxData=USART_ReceiveData(USART1);if(RxState==0)/*当前状态为0,接收数据包包头*/{if(RxData==0xFF)//如果数据确实是包头{RxState = 1; //置下一个状态pRxPacket = 0; //数据包的位置归零}}else if(RxState==1)/*当前状态为1,接收数据包数据*/{Serial_RxPacket[pRxPacket]=RxData;//将数据存入数据包数组的指定位置pRxPacket++;//数据包的位置自增if(pRxPacket>=4)//如果收够4个数据{RxState=2;//置下一个状态}}else if(RxState==2)/*当前状态为2,接收数据包包尾*/{if(RxData==0xFE)//如果数据确实是包尾部{RxState=0;//状态归0Serial_RxFlag=1;//接收数据包标志位置1,成功接收一个数据包}}
2.2Serial.c串口模块
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
//这里的数据只存储发送和接受的载荷数据,包头包尾不包含
uint8_t Serial_TxPacket[4];//发送的数据包
uint8_t Serial_RxPacket[4];//接收的数据包
uint8_t Serial_RxFlag;//收到数据标志位
uint8_t RxData;
void Serial_Init(void)
{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_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//引脚9为TX发送端GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//上拉输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//引脚10为RX输入端口GPIO_Init(GPIOB, &GPIO_InitStructure);//USART配置9600波特率 8位字长 1位停止位 无校验位 无硬件流控制 只有发送模式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 ;//发送字长为8bitUSART_Init(USART1,&USART_InitStructure);//开启RXNE标志位到NVIC的输出,一旦RXEN标志位置1,就开始向NVIC申请中断,之后,我们就可以在中断里接受数据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);
}void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1,Byte);//将将数据写入发送数据寄存器中while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//发送数据寄存器是否发送完成,发送完成跳出循环
}void Serial_SendArray(uint8_t *Array,uint16_t Length)
{uint16_t i;for(i=0;i<Length;i++){Serial_SendByte(Array[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 Length)
{uint8_t i;for(i=0;i<Length;i++){Serial_SendByte(Number/Serial_Pow(10,Length-i-1)%10+'0');}
}
//fputc为printf的底层,printf在打印的时候不断调用fputc函数
int fputc(int ch,FILE *f)
{Serial_SendByte(ch);//在这里我们把fputc函数重定向到串口,那printf自然输出到串口return ch;
}//将printf打印的内容输出到串口
//将可变参数发送出去
void Serial_Printf(char *format,...)//format参数用来接收格式化字符串,...用来接收后面的可变参数列表
{char String[100];va_list arg;//定义一个参数列表变量va_start(arg,format);//从format位置开始接收参数表,放在arg里vsprintf(String,format,arg);va_end(arg);//释放参数列表Serial_SendString(String);
}
//模块:发送HEX数据包
void Serial_SendPacket(void)
{Serial_SendByte(0xFF);Serial_SendArray(Serial_TxPacket,4);Serial_SendByte(0xFE);
}
//实现读后自动清除
uint8_t Serial_GetRxFlag(void)
{if(Serial_RxFlag==1)//接受数据标志位置1,接收到数据{Serial_RxFlag=0;return 1;}return 0;
}void USART1_IRQHandler(void)
{static uint8_t RxState=0;//定义表示当前状态机状态的静态变量static uint8_t pRxPacket=0;//定义表示当前接收数据位置的静态变量if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){//使用状态机机制//接收数据包的状态机RxData=USART_ReceiveData(USART1);if(RxState==0)/*当前状态为0,接收数据包包头*/{if(RxData==0xFF)//如果数据确实是包头{RxState = 1; //置下一个状态pRxPacket = 0; //数据包的位置归零}}else if(RxState==1)/*当前状态为1,接收数据包数据*/{Serial_RxPacket[pRxPacket]=RxData;//将数据存入数据包数组的指定位置pRxPacket++;//数据包的位置自增if(pRxPacket>=4)//如果收够4个数据{RxState=2;//置下一个状态}}else if(RxState==2)/*当前状态为2,接收数据包包尾*/{if(RxData==0xFE)//如果数据确实是包尾部{RxState=0;//状态归0Serial_RxFlag=1;//接收数据包标志位置1,成功接收一个数据包}}USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位}
}
2.3Serial.h函数
#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>
extern uint8_t Serial_TxPacket[4];//外部可调用数组
extern uint8_t Serial_RxPacket[4];
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,...);uint8_t Serial_GetRxFlag(void);//这个函数判断是不是接收到了数据包void Serial_SendPacket(void);void USART1_IRQHandler(void);#endif
2.4 main.c函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"uint8_t KeyNum; //定义用于接收按键键码的变量int main(void)
{OLED_Init(); //OLED初始化Key_Init(); //按键初始化Serial_Init(); //串口初始化OLED_ShowString(1, 1, "TxPacket");OLED_ShowString(3, 1, "RxPacket");/*设置发送数据包数组的初始值,用于测试*/Serial_TxPacket[0] = 0x01;Serial_TxPacket[1] = 0x02;Serial_TxPacket[2] = 0x03;Serial_TxPacket[3] = 0x04;while (1){KeyNum = Key_GetNum(); //获取按键键码if (KeyNum == 1) //按键1按下{Serial_TxPacket[0] ++; //测试数据自增Serial_TxPacket[1] ++;Serial_TxPacket[2] ++;Serial_TxPacket[3] ++;Serial_SendPacket(); //串口发送数据包Serial_TxPacketOLED_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);}}
}
3.USART串口发送和接受文本数据
在接受文本数据包时使用一个状态机的理念
3.1状态机代码

if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断{uint8_t RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量/*使用状态机的思路,依次处理数据包的不同部分*//*当前状态为0,接收数据包包头*/if (RxState == 0){if (RxData == '@' && Serial_RxFlag == 0) //如果数据确实是包头,并且上一个数据包已处理完毕{RxState = 1; //置下一个状态pRxPacket = 0; //数据包的位置归零}}/*当前状态为1,接收数据包数据,同时判断是否接收到了第一个包尾*/else if (RxState == 1){if (RxData == '\r') //如果收到第一个包尾{RxState = 2; //置下一个状态}else //接收到了正常的数据{Serial_RxPacket[pRxPacket] = RxData; //将数据存入数据包数组的指定位置pRxPacket ++; //数据包的位置自增}}/*当前状态为2,接收数据包第二个包尾*/else if (RxState == 2){if (RxData == '\n') //如果收到第二个包尾{RxState = 0; //状态归0Serial_RxPacket[pRxPacket] = '\0'; //将收到的字符数据包添加一个字符串结束标志Serial_RxFlag = 1; //接收数据包标志位置1,成功接收一个数据包}}
3.2Serial.c函数
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
//这里的数据只存储发送和接受的载荷数据,包头包尾不包含char Serial_RxPacket[100];//接收的数据包
uint8_t Serial_RxFlag;//收到数据标志位
uint8_t RxData;void Serial_Init(void)
{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_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//引脚9为TX发送端GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//上拉输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//引脚10为RX输入端口GPIO_Init(GPIOB, &GPIO_InitStructure);//USART配置9600波特率 8位字长 1位停止位 无校验位 无硬件流控制 只有发送模式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 ;//发送字长为8bitUSART_Init(USART1,&USART_InitStructure);//开启RXNE标志位到NVIC的输出,一旦RXEN标志位置1,就开始向NVIC申请中断,之后,我们就可以在中断里接受数据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);
}void Serial_SendByte(uint8_t Byte)
{USART_SendData(USART1, Byte); //将字节数据写入数据寄存器,写入后USART自动生成时序波形while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完成/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}void Serial_SendArray(uint8_t *Array,uint16_t Length)
{uint16_t i;for(i=0;i<Length;i++){Serial_SendByte(Array[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 Length)
{uint8_t i;for(i=0;i<Length;i++){Serial_SendByte(Number/Serial_Pow(10,Length-i-1)%10+'0');}
}
//fputc为printf的底层,printf在打印的时候不断调用fputc函数
int fputc(int ch,FILE *f)
{Serial_SendByte(ch);//在这里我们把fputc函数重定向到串口,那printf自然输出到串口return ch;
}//将printf打印的内容输出到串口
//将可变参数发送出去
void Serial_Printf(char *format,...)//format参数用来接收格式化字符串,...用来接收后面的可变参数列表
{char String[100];va_list arg;//定义一个参数列表变量va_start(arg,format);//从format位置开始接收参数表,放在arg里vsprintf(String,format,arg);va_end(arg);//释放参数列表Serial_SendString(String);
}//实现读后自动清除
uint8_t Serial_GetRxFlag(void)
{if(Serial_RxFlag==1)//接受数据标志位置1,接收到数据{Serial_RxFlag=0;return 1;}return 0;
}void USART1_IRQHandler(void)
{static uint8_t RxState=0;//静态变量只能在本函数内使用static uint8_t pRxPacket=0;if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){//接收数据包的状态机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;pRxPacket++;}}else if(RxState==2){if(RxData=='\n'){RxState=0;Serial_RxPacket[pRxPacket]='\0';Serial_RxFlag=1;}}USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位}
}
3.3Serial.h函数
#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>extern char Serial_RxPacket[];
extern uint8_t Serial_RxFlag;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, ...);#endif
3.4main.c函数
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include "string.h"int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化LED_Init(); //LED初始化Serial_Init(); //串口初始化/*显示静态字符串*/OLED_ShowString(1, 1, "TxPacket");OLED_ShowString(3, 1, "RxPacket");while (1){if (Serial_RxFlag == 1) //如果接收到数据包{OLED_ShowString(4, 1, " ");OLED_ShowString(4, 1, Serial_RxPacket); //OLED清除指定位置,并显示接收到的数据包/*将收到的数据包与预设的指令对比,以此决定将要执行的操作*/if (strcmp(Serial_RxPacket, "LED_ON") == 0) //如果收到LED_ON指令{LED1_ON(); //点亮LEDSerial_SendString("LED_ON_OK\r\n"); //串口回传一个字符串LED_ON_OKOLED_ShowString(2, 1, " ");OLED_ShowString(2, 1, "LED_ON_OK"); //OLED清除指定位置,并显示LED_ON_OK}else if (strcmp(Serial_RxPacket, "LED_OFF") == 0) //如果收到LED_OFF指令{LED1_OFF(); //熄灭LEDSerial_SendString("LED_OFF_OK\r\n"); //串口回传一个字符串LED_OFF_OKOLED_ShowString(2, 1, " ");OLED_ShowString(2, 1, "LED_OFF_OK"); //OLED清除指定位置,并显示LED_OFF_OK}else //上述所有条件均不满足,即收到了未知指令{Serial_SendString("ERROR_COMMAND\r\n"); //串口回传一个字符串ERROR_COMMANDOLED_ShowString(2, 1, " ");OLED_ShowString(2, 1, "ERROR_COMMAND"); //OLED清除指定位置,并显示ERROR_COMMAND}Serial_RxFlag = 0; //处理完成后,需要将接收数据包标志位清零,否则将无法接收后续数据包}}
}
相关文章:
STM32实验之USART串口发送+接受数据(二进制/HEX/文本)
涉及三个实验: 1.USART串口发送和接收数据 我们使用的是将串口封装成为一个Serial.c模块.其中包含了 void Serial_Init(void);//串口初始化 void Serial_SendByte(uint8_t Byte);//串口发送一个字节 void Serial_SendArray(uint8_t *Array,uint16_t Length);//…...
网关(Gateway)- 内置过滤器工厂
官方文档:Spring Cloud Gateway 内置过滤器工厂 AddRequestHeaderGatewayFilterFactory 为请求添加Header Header的名称及值 配置说明 server:port: 8088 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8847username: nacos…...
电风扇如何实现跌倒断电保护功能
电风扇作为日常生活中常用的家电产品,为了提升安全性能,在设计上通常会考虑加入跌倒断电保护功能。其中,光电倾倒开关是实现跌倒断电保护功能的关键组件之一。 光电倾倒开关内置红外发光二极管和光敏接收器,其工作原理非常巧妙。…...
编译原理总结
编译器构成 1. 前端分析部分 1.1 词法分析 确定词性,输出为token序列 1.2 语法分析 识别短语 1.3 语义分析 分析短语在句子中的成分 IR中间代码生成 2. 机器无关代码优化 3. 后端综合部分 目标代码生成 机器相关代码优化 4. 其他 全局信息表 异常输出...
JavaScript:从基础到进阶的全面介绍
JavaScript:从基础到进阶的全面介绍 JavaScript(简称JS)是一种广泛用于Web开发的编程语言。它是一种轻量级的、解释型或即时编译的语言,具有函数优先的特点。JS最初是为了实现网页的动态效果而设计的,如今已发展成为前…...
linux指令-sed
sed 是一个流编辑器,用于对输入流(或文件)进行基本的文本转换。以下是 sed 命令的详细输出说明文档: 1. 基本语法 sed [OPTIONS]... [SCRIPT] [INPUTFILE...] OPTIONS:可选的命令行选项,如 -i 用于直接修…...
Docker部署青龙面板
青龙面板 文章目录 青龙面板介绍资源列表基础环境一、安装Docker二、安装Docker-Compose三、安装青龙面板3.1、拉取青龙(whyour/qinglong)镜像3.2、编写docker-compose文件3.3、检查语法启动容器 四、访问青龙面板五、映射本地部署的青龙面板至公网5.1、…...
【LeetCode】每日一题 2024_6_4 将元素分配到两个数组中 II(二分、离散化、树状数组)
文章目录 LeetCode?启动!!!题目:将元素分配到两个数组中 II题目描述代码与解题思路 每天进步一点点 LeetCode?启动!!! 又有段时间没写每日一题的分享了,原本今…...
JAVA小案例-break练习,随机数,到88停止
JAVA小案例-break练习,随机数,到88停止 代码如下: public class Break {/*** break练习,随机数,到88停止* param args*/public static void main(String[] args) {int count0;//计数器System.out.println("Begi…...
C++第三方库【httplib】断点续传
什么是断点续传 上图是我们平时在浏览器下载文件的场景,下载的本质是数据的传输。当出现网络异常,浏览器异常,或者文件源的服务器异常,下载都可能会终止。而当异常解除后,重新下载文件,我们希望从上一次下载…...
[SaaS] AI+数据,tiktok选品,找达人,看广告数据
TK观察专访丨前阿里“鲁班”创始人用AIGC赋能TikTok获千万融资用AI数据做TikTokhttps://mp.weixin.qq.com/s/xp5UM3ROo48DK4jS9UBMuQ主要还是爬虫做数据的。 商家做内容:1.找达人拍内容,2.商家自己做原生自制内容,3.广告内容。 短视频&…...
A股冲高回落,金属、地产板块领跌,新股N汇成真首日暴涨753%
行情概述 AH股有色金属、教育及地产板块领跌,军工航天及半导体板块逆势走强;锂电池、创新药概念股也走强。创业板新股N汇成真首日暴涨753%,触发二次临停。 周三A股冲高回落,上证指数收跌0.83%,深成指跌0.8%ÿ…...
dns域名解析服务和bond网卡
目录 dns域名解析服务 一、DNS 1、定义 2、以www.baidu.com为例 3、域名体系结构 4、DNS解析使用的协议和端口 5、dns域名解析的过程 6、dns解析的优先级 二、如何实现域名解析 1、域名解析 2、bind配置文件位置 (一)正向解析 (…...
视频生成框架EasyAnimate正式开源!
近期,Sora模型的热度持续上涨,社区中涌现了一些类Sora的开源项目,这些项目均基于Diffusion Transformer结构,使用Transformer结构取代了UNet作为扩散模型的基线,旨在生成更长、更高分辨率、且效果更好的视频。EasyAnim…...
【微机原理与汇编语言】并行接口8255实验
一、实验目的 掌握可编程并行接口芯片8255的工作原理及初始化方法掌握8255在实际应用中的硬件连接及编程应用 二、实验要求 根据实验室现有条件,针对实验任务,设计实验方案并进行实现。 三、实验内容 启动0#计数器,每计5个数(…...
Oracle表分区的基本使用
什么是表空间 是一个或多个数据文件的集合,所有的数据对象都存放在指定的表空间中,但主要存放的是表,所以称为表空间 什么是表分区 表分区就是把一张大数据的表,根据分区策略进行分区,分区设置完成之后,…...
6月5号作业
设计一个Per类,类中包含私有成员:姓名、年龄、指针成员身高、体重,再设计一个Stu类,类中包含私有成员:成绩、Per类对象p1,设计这两个类的构造函数、析构函数 #include <iostream>using namespace std; class Slu { priv…...
中继器、集线器、网桥、交换机、路由器和网关
目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.1.1 认识网桥2.1.2 网桥的工作原理2.1.3 生成树网桥 2.2 交换机2.2.1 交换机的特征2.2.2 交换机的交换模式2.2.3 交换机的功能 三、路由器、网关3.1 路由器的介绍3.2 路由器的工作过程3.2.1 前置知…...
揭秘相似矩阵:机器学习算法中的隐形“纽带”
在机器学习领域,数据的处理和分析至关重要。如何有效地从复杂的数据集中提取有价值的信息,是每一个机器学习研究者都在努力探索的问题。相似矩阵,作为衡量数据之间相似性的数学工具,在机器学习算法中扮演着不可或缺的角色。 相似矩…...
攻防世界—webbaby详解
1.ssrf注入漏洞 ssrf(服务端请求伪造)是一种安全漏洞,攻击者通过该漏洞向受害服务器发出伪造的请求,从而访问并获取服务器上的资源,常见的ssrf攻击场景包括访问内部网络的服务,执行本地文件系统命令&#…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
