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攻击场景包括访问内部网络的服务,执行本地文件系统命令&#…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
