STM32 USART串口通信

目录

USART串口

串口发送

串口发送+接收

串口收发HEX数据包

串口收发文本数据包


USART串口

串口发送

Serial.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "stdio.h"
#include "stdarg.h"

/**
  * @brief  初始化串口以及引脚配置
  * @param  无
  * @retval 无
  */
void Serial_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
    //TX引脚配置
    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);
    
    //串口配置
    USART_InitTypeDef USART_InitStructrue;
    USART_InitStructrue.USART_BaudRate = 9600;//波特率配置
    USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(无)
    USART_InitStructrue.USART_Mode = USART_Mode_Tx;//串口模式(发送)
    USART_InitStructrue.USART_Parity = USART_Parity_No;//校验位(无)
    USART_InitStructrue.USART_StopBits = USART_StopBits_1;//停止位(1位)
    USART_InitStructrue.USART_WordLength = USART_WordLength_8b;//字长(8位)
    USART_Init(USART1,&USART_InitStructrue);
    
    USART_Cmd(USART1,ENABLE);//开启USART1
}

/**
  * @brief  发送一个字节
  * @param  Byte 发送的字节
  * @retval 无
  */
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//完成传输之前进行空循环
    //TXE位置一后,会自动清除标志位,详看手册
}

/**
  * @brief  发送一个数组
  * @param  Array:发送的数组
  * @param  Length:发送数组的长度
  * @retval 无
  */
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)
    {
        Serial_SendByte(Array[i]);
    }
}

/**
  * @brief  发送一个字符串
  * @param  String:发送的字符串
  * @retval 无
  */
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; String[i] != '\0'; i ++)//判断是否为结束标志位
    {
        Serial_SendByte(String[i]);
    }
}

/**
  * @brief  计算X^Y
  * @param  X:底数    Y:幂次
  * @retval Res:X^Y的结果
  */
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Res = 1;
    while(Y --)
    {
        Res *= X;
    }
    return Res;
}

/**
  * @brief  发送一个无符号数字
  * @param  Number:发送的数字
  * @param  Length:数字的长度
  * @retval 无
  */
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 + 0x30);//从最高位开始获取各位数字
        Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
    }
}

int fputc(int ch,FILE *f)//重写fputc函数,将fputc重定向到串口
{
   Serial_SendByte(ch);
   return ch;
}

/**
  * @brief  封装vsprintf可变参数
  * @param  可变参数
  * @retval 无
  */
void Serial_Printf(char *format,...)
{
    char String[100];
    va_list arg;//定义参数列表变量
    va_start(arg , format);//从format位置接收参数表,放入arg中
    vsprintf(String, format ,arg);//打印位置     格式化字符串     参数表
    //sprintf只能接收直接写的参数,封装格式需要vsprintf
    va_end(arg);//释放参数表
    Serial_SendString(String);
}

main.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

int main(void)
{
	OLED_Init();
    
	Serial_Init();
    
	uint8_t MyArray[4] = {0x42, 0x43, 0x44, 0x45};
    Serial_SendByte(0x41);
    Serial_SendArray(MyArray,4);
    Serial_Printf("\r\n");
    Serial_SendString("Hello\r\n");//\r回车 \n换行
    Serial_SendNumber(1234,4);
    Serial_Printf("\r\n");
    //移植printf函数:
    //1.重写fputc函数,将fputc重定向到串口(printf此时只有一个)
    printf("Num = %d\r\n",666);
    //2.使用sprintf函数
    char String[100];
    sprintf(String,"Num = %d\r\n",666);//sptintf可以指定打印位置,不涉及重定向
    Serial_SendString(String);
    //3.封装sprintf函数
    Serial_Printf("Num = %d\r\n",666);
    //输出汉字
    Serial_Printf("你好,世界");//utf8   --no-multibyte-chars
    
	while(1)
	{
			
	}
	
}
串口发送+接收

Serial.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "stdio.h"
#include "stdarg.h"

uint8_t Serial_RxData;//数据存放位置
uint8_t Serial_RxFlag;//数据是否读到标志位

/**
  * @brief  串口,引脚以及中断初始化
  * @param  无
  * @retval 无
  */
void Serial_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
    //TX引脚配置
    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);
    
    //RX引脚配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//为什么?查表手册推荐(上拉输入)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //串口配置
    USART_InitTypeDef USART_InitStructrue;
    USART_InitStructrue.USART_BaudRate = 9600;//波特率配置
    USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(无)
    USART_InitStructrue.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式(发送接收)
    USART_InitStructrue.USART_Parity = USART_Parity_No;//校验位(无)
    USART_InitStructrue.USART_StopBits = USART_StopBits_1;//停止位(1位)
    USART_InitStructrue.USART_WordLength = USART_WordLength_8b;//字长(8位)
    USART_Init(USART1,&USART_InitStructrue);
    
    //中断方式接收
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//当接收到字节时触发中断
    
    //配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//相应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
    
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(USART1,ENABLE);//开启USART1
    
}

/**
  * @brief  发送一个字节
  * @param  Byte 发送的字节
  * @retval 无
  */
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//完成传输之前进行空循环
    //TXE位置一后,会自动清除标志位,详看手册
}

/**
  * @brief  发送一个数组
  * @param  Array:发送的数组
  * @param  Length:发送数组的长度
  * @retval 无
  */
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)
    {
        Serial_SendByte(Array[i]);
    }
}

/**
  * @brief  发送一个字符串
  * @param  String:发送的字符串
  * @retval 无
  */
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; String[i] != '\0'; i ++)//判断是否为结束标志位
    {
        Serial_SendByte(String[i]);
    }
}

/**
  * @brief  计算X^Y
  * @param  X:底数    Y:幂次
  * @retval Res:X^Y的结果
  */
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Res = 1;
    while(Y --)
    {
        Res *= X;
    }
    return Res;
}

/**
  * @brief  发送一个无符号数字
  * @param  Number:发送的数字
  * @param  Length:数字的长度
  * @retval 无
  */
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 + 0x30);//从最高位开始获取各位数字
        Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
    }
}

int fputc(int ch,FILE *f)//重写fputc函数,将fputc重定向到串口
{
   Serial_SendByte(ch);
   return ch;
}

/**
  * @brief  封装vsprintf可变参数
  * @param  
  * @retval 无
  */
void Serial_Printf(char *format,...)
{
    char String[100];
    va_list arg;//定义参数列表变量
    va_start(arg , format);//从format位置接收参数表,放入arg中
    vsprintf(String, format ,arg);//打印位置     格式化字符串     参数表
    //sprintf只能接收直接写的参数,封装格式需要vsprintf
    va_end(arg);//释放参数表
    Serial_SendString(String);
}

/**
  * @brief  获取读取完成标志位
  * @param  无
  * @retval 0:未读到数据
  * @retval 1:成功读到数据
  */
uint8_t Serial_GetRxFlag(void)
{
    if(Serial_RxFlag == 1)
    {
        Serial_RxFlag  = 0;//将其重新置零,并返回1
        return 1;
    }
   return 0;
}

/**
  * @brief  获取接收到的数据
  * @param  无
  * @retval 接收到的数据
  */
uint8_t Serial_GetRxData(void)
{
    return Serial_RxData;
}

/**
  * @brief  串口1中断函数
  * @param  无
  * @retval 无
  */
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)//说明已经接收到数据
    {
        Serial_RxData = USART_ReceiveData(USART1);//转存
        Serial_RxFlag = 1;//读完后将自己设置标志位置一
        //如果此时没有读取DR,则需要手动清除标志位
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);      
    }
}

main.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RxData;

int main(void)
{
	OLED_Init();
    
    OLED_ShowString(1,1,"RxData:");
    
	Serial_Init();
    
	while(1)    
	{
		//查询方式接收
//        while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)//表示接收到数据
//        {
//            RxData = USART_ReceiveData(USART1);//当读完DR寄存器时,会自动将标志位清除
//            OLED_ShowHexNum(1,1,RxData,2);
//        }
        
        //中断方式接收
        if(Serial_GetRxFlag() == 1)
        {
            RxData = Serial_GetRxData();
            OLED_ShowHexNum(1,8,RxData,2);
            Serial_SendByte(RxData);//数据回传
            
        }
	}
	
}
串口收发HEX数据包

Serial.c

cpp 复制代码
#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;

/**
  * @brief  串口,引脚以及中断初始化
  * @param  无
  * @retval 无
  */
void Serial_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
    //TX引脚配置
    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);
    
    //RX引脚配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//为什么?查表手册推荐(上拉输入)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //串口配置
    USART_InitTypeDef USART_InitStructrue;
    USART_InitStructrue.USART_BaudRate = 9600;//波特率配置
    USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(无)
    USART_InitStructrue.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式(发送接收)
    USART_InitStructrue.USART_Parity = USART_Parity_No;//校验位(无)
    USART_InitStructrue.USART_StopBits = USART_StopBits_1;//停止位(1位)
    USART_InitStructrue.USART_WordLength = USART_WordLength_8b;//字长(8位)
    USART_Init(USART1,&USART_InitStructrue);
    
    //中断方式接收
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//当接收到字节时触发中断
    
    //配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//相应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
    
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(USART1,ENABLE);//开启USART1
    
}

/**
  * @brief  发送一个字节
  * @param  Byte 发送的字节
  * @retval 无
  */
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//完成传输之前进行空循环
    //TXE位置一后,会自动清除标志位,详看手册
}

/**
  * @brief  发送一个数组
  * @param  Array:发送的数组
  * @param  Length:发送数组的长度
  * @retval 无
  */
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)
    {
        Serial_SendByte(Array[i]);
    }
}

/**
  * @brief  发送一个字符串
  * @param  String:发送的字符串
  * @retval 无
  */
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; String[i] != '\0'; i ++)//判断是否为结束标志位
    {
        Serial_SendByte(String[i]);
    }
}

/**
  * @brief  计算X^Y
  * @param  X:底数    Y:幂次
  * @retval Res:X^Y的结果
  */
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Res = 1;
    while(Y --)
    {
        Res *= X;
    }
    return Res;
}

/**
  * @brief  发送一个无符号数字
  * @param  Number:发送的数字
  * @param  Length:数字的长度
  * @retval 无
  */
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 + 0x30);//从最高位开始获取各位数字
        Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
    }
}

int fputc(int ch,FILE *f)//重写fputc函数,将fputc重定向到串口
{
   Serial_SendByte(ch);
   return ch;
}

/**
  * @brief  封装vsprintf可变参数
  * @param  
  * @retval 无
  */
void Serial_Printf(char *format,...)
{
    char String[100];
    va_list arg;//定义参数列表变量
    va_start(arg , format);//从format位置接收参数表,放入arg中
    vsprintf(String, format ,arg);//打印位置     格式化字符串     参数表
    //sprintf只能接收直接写的参数,封装格式需要vsprintf
    va_end(arg);//释放参数表
    Serial_SendString(String);
}

/**
  * @brief  将载荷数据加上包头与包尾并发送一个数据包
  * @param  无
  * @retval 无
  */
void Serial_SendPacket(void)
{
    Serial_SendByte(0xFF);//发送包头
    Serial_SendArray(Serial_TxPacket,4);//发送载荷数据
    Serial_SendByte(0xFE);//发送包尾
}

/**
  * @brief  读取是否接收到数据包标志位
  * @param  无
  * @retval 0:未读到数据包
  * @retval 1:成功读到数据包
  */
uint8_t Serial_GetRxFlag(void)
{
    if(Serial_RxFlag == 1)
    {
        Serial_RxFlag  = 0;//将其重新置零,并返回1
        return 1;
    }
   return 0;
}

/**
  * @brief  串口1中断函数
  * @param  无
  * @retval 无
  */
void USART1_IRQHandler(void)
{
    static uint8_t Rx_State = 0;
    static uint8_t pRx_Packet = 0;
    if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)//说明已经接收到数据
    {
        uint8_t Rx_Data = USART_ReceiveData(USART1);//获取读到的数据
        if(Rx_State == 0)
        {
            if(Rx_Data == 0xFF)//接收到包头
            {
                Rx_State = 1;//转至下一状态
                pRx_Packet = 0;//将指针清零,为接收做准备
            }
        }
        else if(Rx_State == 1)
        {
           Serial_RxPacket[pRx_Packet] = Rx_Data;//将接收到的数据放入缓冲区
           pRx_Packet ++;//指针加一
           if(pRx_Packet >= 4)//4个载荷数据收完
           {
                Rx_State = 2;//转至下一状态
           }
        }
        else if(Rx_State == 2)
        {
            if(Rx_Data == 0xFE)//判断是否为包尾
             {
                 Rx_State = 0;//清零,为下次做准备
                 Serial_RxFlag= 1;//将接收一个数据包标志位置一
             }
        }
        
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除标志位      
    }
}

main.c

cpp 复制代码
#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();
    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)
        {    
            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,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);
        }
	}
	
}
串口收发文本数据包

Serial.c

cpp 复制代码
#include "stm32f10x.h"                  // Device header
#include "stdio.h"
#include "stdarg.h"

char Serial_RxPacket[100];//接收缓存区
uint8_t Serial_RxFlag;

/**
  * @brief  串口,引脚以及中断初始化
  * @param  无
  * @retval 无
  */
void Serial_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
   
    //TX引脚配置
    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);
    
    //RX引脚配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//为什么?查表手册推荐(上拉输入)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //串口配置
    USART_InitTypeDef USART_InitStructrue;
    USART_InitStructrue.USART_BaudRate = 9600;//波特率配置
    USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制(无)
    USART_InitStructrue.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//串口模式(发送接收)
    USART_InitStructrue.USART_Parity = USART_Parity_No;//校验位(无)
    USART_InitStructrue.USART_StopBits = USART_StopBits_1;//停止位(1位)
    USART_InitStructrue.USART_WordLength = USART_WordLength_8b;//字长(8位)
    USART_Init(USART1,&USART_InitStructrue);
    
    //中断方式接收
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//当接收到字节时触发中断
    
    //配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//相应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
    
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(USART1,ENABLE);//开启USART1
    
}

/**
  * @brief  发送一个字节
  * @param  Byte 发送的字节
  * @retval 无
  */
void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1,Byte);
    while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//完成传输之前进行空循环
    //TXE位置一后,会自动清除标志位,详看手册
}

/**
  * @brief  发送一个数组
  * @param  Array:发送的数组
  * @param  Length:发送数组的长度
  * @retval 无
  */
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
    uint16_t i;
    for(i = 0; i < Length; i ++)
    {
        Serial_SendByte(Array[i]);
    }
}

/**
  * @brief  发送一个字符串
  * @param  String:发送的字符串
  * @retval 无
  */
void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0; String[i] != '\0'; i ++)//判断是否为结束标志位
    {
        Serial_SendByte(String[i]);
    }
}

/**
  * @brief  计算X^Y
  * @param  X:底数    Y:幂次
  * @retval Res:X^Y的结果
  */
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
    uint32_t Res = 1;
    while(Y --)
    {
        Res *= X;
    }
    return Res;
}

/**
  * @brief  发送一个无符号数字
  * @param  Number:发送的数字
  * @param  Length:数字的长度
  * @retval 无
  */
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 + 0x30);//从最高位开始获取各位数字
        Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
    }
}

int fputc(int ch,FILE *f)//重写fputc函数,将fputc重定向到串口
{
   Serial_SendByte(ch);
   return ch;
}

/**
  * @brief  封装vsprintf可变参数
  * @param  
  * @retval 无
  */
void Serial_Printf(char *format,...)
{
    char String[100];
    va_list arg;//定义参数列表变量
    va_start(arg , format);//从format位置接收参数表,放入arg中
    vsprintf(String, format ,arg);//打印位置     格式化字符串     参数表
    //sprintf只能接收直接写的参数,封装格式需要vsprintf
    va_end(arg);//释放参数表
    Serial_SendString(String);
}


/**
  * @brief  串口1中断函数
  * @param  无
  * @retval 无
  */
void USART1_IRQHandler(void)
{
    static uint8_t Rx_State = 0;
    static uint8_t pRx_Packet = 0;
    //状态机
    if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)//说明已经接收到数据
    {
        uint8_t Rx_Data = USART_ReceiveData(USART1);//获取读到的数据
        
        if(Rx_State == 0)//接收数据包头
        {
            if(Rx_Data == '@' && Serial_RxFlag == 0)//接收到包头并且标志位为零才进行读取  
            {
                Rx_State = 1;//转至下一状态
                pRx_Packet = 0;//将指针清零,为接收做准备
            }
        }
        else if(Rx_State == 1)//接收第一包尾
        {
            if(Rx_Data == '\r')//判断是否为第一包尾
            {
                Rx_State = 2;//跳转至下一状态
            }
            else
            {
                Serial_RxPacket[pRx_Packet] = Rx_Data;//将接收到的数据放入缓冲区
                pRx_Packet ++;//指针加一
            }
        }
        else if(Rx_State == 2)//接收第二包尾
        {
            if(Rx_Data == '\n')//判断是否为第二包尾
             {
                 Rx_State = 0;//清零,为下次做准备
                 Serial_RxPacket[pRx_Packet] = '\0';//在末尾加上结束标志位
                 Serial_RxFlag= 1;//接收一个数据包后标志位置一
             }
        }
        
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除接收寄存器非空标志位      
    }
}

main.c

cpp 复制代码
#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();
    LED_Init();
	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);
           
           if(strcmp(Serial_RxPacket,"LED_ON") == 0)
           {
               LED1_On();
               Serial_SendString("LED_ON_OK\r\n");
               OLED_ShowString(2,1,"                ");
               OLED_ShowString(2,1,"LED_ON_OK");    
           }
           else if(strcmp(Serial_RxPacket,"LED_OFF") == 0)
           {
               LED1_Off();
               Serial_SendString("LED_OFF_OK\r\n");
               OLED_ShowString(2,1,"                ");
               OLED_ShowString(2,1,"LED_OFF_OK");  
           }
           else
           {
               Serial_SendString("COMMAND_ERRO\r\n");
               OLED_ShowString(2,1,"                ");
               OLED_ShowString(2,1,"COMMAND_ERRO");  
           }
           Serial_RxFlag = 0;//准备接收下一个数据包
       }
	}
	
}

注意该实验的PA^1脚起始电平需要给高电平,不然会引起你的疑惑,为何上电就亮

相关推荐
蓝斯4978 小时前
从.到实现一个Windows上的虚拟hid键盘设备
windows·单片机·计算机外设
熙芯XiChip9 小时前
硬实时与软实时RTOS核心区别
嵌入式硬件
伟大的前程9 小时前
unsigned int 定义的变量 在 电脑的 64 位系统中 和 32 位 cortex-m0 和 8 位的 51 单片机
单片机·嵌入式硬件
小渔村的拉线工9 小时前
1.HPM6E80 解析芯片整体工作原理和存储架构
单片机·嵌入式硬件·mcu·架构·hpm6e80
熙芯XiChip10 小时前
CAN与CANopen的本质区别
单片机
lilihewo11 小时前
Altium Designer 封装库的创建(分享pcb 3D封装库)
嵌入式硬件·51单片机
神罚天下ET12 小时前
典型arm位单片机启动流程(从上电到main.c)
c语言·arm开发·单片机
碧海银沙音频科技研究院12 小时前
蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法
嵌入式硬件·算法
Zevalin爱灰灰13 小时前
模拟信号链电路——基于TL431的电压基准电路
单片机·嵌入式硬件
csdn杰哥14 小时前
瑞萨单片机开发教程[二十七] DTC 外部中断触发传输实验
单片机·嵌入式硬件·mongodb·瑞萨·ra6m5