物联网——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

串口发送实例源码

c 复制代码
#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;	//设置结果初值为1
	while (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;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_SendString(String);		//串口发送字符数组(字符串)
}

HEX数据包

传输速度快,包头和包尾与有效数据部分可能重复

文本数据包

传输数据直观,包头包尾与有效数据不会重复,但解析效率低

接收HEX数据包

文本数据包接收

Hex数据包接收结果

源码

c 复制代码
#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;
}
c 复制代码
#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;	//设置结果初值为1
	while (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;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_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);
}
  
c 复制代码
#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

接收文本数据包 ,点亮小灯

c 复制代码
#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;
}
c 复制代码
#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;	//设置结果初值为1
	while (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;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_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);
}
  
c 复制代码
#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
相关推荐
TDengine (老段)5 小时前
TDengine 数据函数 ROUND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·1024程序员节
TDengine (老段)5 小时前
TDengine 数学函数 RAND 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
小莞尔6 小时前
【51单片机】【protues仿真】基于51单片机智能温控风扇系统
c语言·单片机·嵌入式硬件·物联网·51单片机·1024程序员节
GIS数据转换器7 小时前
城市基础设施安全运行监管平台
大数据·运维·人工智能·物联网·安全·无人机·1024程序员节
搞科研的小刘选手7 小时前
【云计算专题会议】第二届云计算与大数据国际学术会议(ICCBD 2025)
大数据·人工智能·物联网·5g·云计算·6g·智能通信
电子科技圈7 小时前
芯科科技推出智能开发工具Simplicity Ecosystem软件开发套件开启物联网开发的新高度
mcu·物联网·设计模式·软件工程·软件构建·iot·1024程序员节
taxunjishu8 小时前
欧姆龙 NX1P2 借助 Ethernet/ip 转 Modbus RTU,与德马泰克设备共创仓库精准货位管理方案
人工智能·嵌入式硬件·物联网·工业物联网·工业自动化
DuHz21 小时前
基于MIMO FMCW雷达的二维角度分析多径抑制技术——论文阅读
论文阅读·物联网·算法·信息与通信·毫米波雷达
MicroTech20251 天前
微算法科技(NASDAQ MLGO)基于区块链点阵加密算法的物联网轻量级方案:构建物联网安全基石
科技·物联网·区块链
塔能物联运维1 天前
物联网设备运维中的自动化合规性检查与策略执行机制
java·运维·物联网·struts·自动化