STM32 USART串口通信

news2025/5/23 12:54:50

目录

USART串口

串口发送

串口发送+接收

串口收发HEX数据包

串口收发文本数据包


USART串口

串口发送

Serial.c

#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

#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

#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

#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

#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

#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

#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

#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脚起始电平需要给高电平,不然会引起你的疑惑,为何上电就亮

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1451662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode:96.不同的二叉搜索树

解题思路&#xff1a; 输入n3 n 0 1个 n 1 1个 n 2 2个 头1头2头3 头1 左子树0节点&#xff08;个数&#xff09;x右子树2个节点&#xff08;个数&#xff09; 头2 左子树1节点&#xff08;个数&#xff09;x右子树1个节点&#xff08;个数&#xff09; 头3 左子…

Android 13.0 SystemUI下拉状态栏定制二 锁屏页面横竖屏解锁图标置顶显示功能实现

1.前言 在13.0的系统rom定制化开发中,在关于systemui的锁屏页面功能定制中,由于在平板横屏锁屏功能中,时钟显示的很大,并且是在左旁边居中显示的, 由于需要和竖屏显示一样,所以就需要用到小时钟显示,然后同样需要居中,所以就来分析下相关的源码,来实现具体的功能 如图…

租赁香港服务器多少钱一个月?24元

阿里云香港服务器2核1G、30M带宽、40GB ESSD系统盘优惠价格24元/月&#xff0c;288元一年&#xff0c;每月流量1024GB&#xff0c;多配置可选&#xff0c;官方优惠活动入口 https://t.aliyun.com/U/bLynLC 阿里云服务器网aliyunfuwuqi.com分享阿里云香港服务器优惠活动、详细配…

VMware Workstation 17.0 虚拟机的安装、配置、创建运行DOS、Windows、Linux和VMware ESX(详细图文搭建系统教程)

VMware Workstation 17.0 虚拟机的安装、配置、创建运行DOS、Windows、Linux和VMware ESX&#xff08;图文教程&#xff09; 一、VMware Workstation是什么&#xff1f;1.1 VMware Workstation 17.0简介1.2 VMware Workstation 17.0新特性1.3 VMware Workstation 17.0下载地址1…

内容安全审核系统的设计思路

今年负责的APP产品涉及到内容的审核&#xff0c;并且针对性的做了一套内容审核系统和账号安全体系。因此总结了一些经验。 内容审核基础逻辑&#xff1a; 内容类型&#xff1a;文本、图片、视频、音频 审核类型&#xff1a;涉黄、暴恐、涉政、广告、垃圾违禁、辱骂自定义&…

【Git】.gitignore 的匹配规则

每行一个规则&#xff1a;每行只能包含一个规则&#xff0c;多个规则需要分别写在不同的行上。 示例&#xff1a; # 忽略日志文件 logs/ # 忽略临时文件 temp.txt种类匹配&#xff1a; 文件&#xff1a;在规则的开头指定文件名或路径&#xff0c;如 file.txt。 示例&#xff1a…

leetcode hot100不同路径

本题可以采用动态规划来解决。还是按照五部曲来做 确定dp数组&#xff1a;dp[i][j]表示走到&#xff08;i&#xff0c;j&#xff09;有多少种路径 确定递推公式&#xff1a;我们这里&#xff0c;只有两个移动方向&#xff0c;比如说我移动到&#xff08;i&#xff0c;j&#x…

第7章 Page446~449 7.8.9智能指针 std::unique_ptr

“unique_ptr”是“独占式智能指针” 名字透露身份&#xff0c;“unique_ptr”是“独占式智能指针”。使用它管理前面的O类指针&#xff1a; 演示1&#xff1a; 例中 p 是一个智能指针。其中的“<O>”指明它所指向的数据类型是“O”。除了创建方法不太一样&#xff0c;…

Flutter 动画(显式动画、隐式动画、Hero动画、页面转场动画、交错动画)

前言 当前案例 Flutter SDK版本&#xff1a;3.13.2 显式动画 Tween({this.begin,this.end}) 两个构造参数&#xff0c;分别是 开始值 和 结束值&#xff0c;根据这两个值&#xff0c;提供了控制动画的方法&#xff0c;以下是常用的&#xff1b; controller.forward() : 向前…

什么是自编码器Auto-Encoder?

来源&#xff1a;https://www.bilibili.com/video/BV1Vx411j78H/?spm_id_from333.1007.0.0&vd_sourcef66cebc7ed6819c67fca9b4fa3785d39 为什么要压缩呢&#xff1f; 让神经网络直接从上千万个神经元中学习是一件很吃力的事情&#xff0c;因此通过压缩提取出原图片中最具代…

使用汇编程序恢复C库、动态链接器

文章目录 写在前面背景原理动态链接器C库 汇编代码示例删除C库删除动态链接器 写在前面 上层语言的好处就是方便&#xff0c;但无法触摸规则的底层&#xff0c;所有的规则都是别人制定的 学习底层原理不仅可以让我们对高级语言的规则有更深的理解&#xff0c;而且可以从自己的…

二维数组传参的本质(详解)

目录 一、前言二、分析本质三、总结 一、前言 有时候我们有⼀个⼆维数组的需要传参给⼀个函数的时候&#xff0c;我们是这样写的&#xff1a; #include <stdio.h> void test(int a[3][5], int r, int c) {int i 0;int j 0;for (i 0; i < r; i){for (j 0; j <…

第三百四十八回

文章目录 1. 概念介绍2. 使用方法2.1 List2.2 Map2.3 Set 3. 示例代码4. 内容总结 我们在上一章回中介绍了"convert包"相关的内容&#xff0c;本章回中将介绍collection.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的内容是col…

0102awvs安装-扫描-信息收集

1 安装awvs23.7 解压压缩包&#xff0c;解压密码网站网址&#xff0c;下载地址在最后链接双击acunetix_23.7.230728157.exe安装程序 安装位置默认&#xff0c;如更改位置&#xff0c;后面需要更改bat文件相应内容 设置管理员信息 next直到浏览器跳出登录界面 2 运行运行www.dd…

基于Java (spring-boot)的房屋租赁管理系统

一、项目介绍 基于Java (spring-boot)的房屋租赁管理系统功能&#xff1a;登录、管理员、租客、公告信息管理、房屋信息管理、用户信息管理、租金信息管理、故障信息管理、房屋出租信息详情、个人信息、修改密码、等等等。 适用人群&#xff1a;适合小白、大学生、毕业设计、课…

LV.23 D2 开发环境搭建及平台介绍 学习笔记

一、Keil MDK-ARM简介及安装 Keil MDK&#xff0c;也称MDK-ARM&#xff0c;Realview MDK &#xff08;Microcontroller Development Kit&#xff09;等。目前Keil MDK 由三家国内代理商提供技术支持和相关服务。 MDK-ARM软件为基于Cortex-M、Cortex-R4、ARM7、ARM9处理器设备…

【MATLAB】在图框中加箭头文本注释

1、在图框中加 文本方法 —— text&#xff08;&#xff09;函数 2、使用箭头标注——annotation&#xff08;&#xff09;函数 X、Y是箭头的位置相对于整个方框的比例&#xff0c; [0.32,0.5]是指&#xff1a;x坐标从整个图形32%的地方到50%的地方&#xff08;从左到右&…

【简写MyBatis】01-简单映射器

前言 新开一个坑&#xff0c;为了学习一下MyBatis的源码&#xff0c;写代码是次要的&#xff0c;主要为了吸收一下其中的思想和手法。 目的 关联对象接口和映射类的问题&#xff0c;把 DAO 接口使用代理类&#xff0c;包装映射操作。 知识点 动态代理简单工厂模式Invocati…

为什么电路要设计得这么复杂?

首先提出这个问题就很不容易啊&#xff0c;我们看两个精彩回答。 From 骄建&#xff1a; 假设我们回到第一个实用放大电路诞生之前&#xff1a; 某天你开始做一个CS单管放大器&#xff0c;电阻负载&#xff0c;可是有一大堆问题&#xff0c;电阻做的不准&#xff0c;温度对器…

mpack简明教程

文章目录 摘要MessagePack简介MPACK的简单使用在定长的buffer存储不定长的数据读取截断的数据 摘要 本文先简单介绍MessagePack的基本概念。 然后&#xff0c;介绍一个MessagePack C API - MPack的通常使用。 接着尝试对MPack截断数据的读取。 注&#xff1a;本文完整代码见…