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攻击场景包括访问内部网络的服务,执行本地文件系统命令&#…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
