STM32 USART串口通信

目录

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 广度优先搜索(bfs)(五十四)【第一篇】

今天我们来学习一下一个新的搜索&#xff0c;广度优先搜索。 1.广度优先搜索的前提 队列&#xff08;queue&#xff09; 是一种 操作受限制 的线性表&#xff0c;其限制&#xff1a; 只允许从表的前端&#xff08;front&#xff09;进行删除操作&#xff1b; 只允许在表的后端…

openssl3.2 - osslsigncode工程的学习

文章目录 openssl3.2 - osslsigncode工程的学习概述笔记工程库地址工程的编译osslsigncodeM工程文件列表osslsigncodeM工程搭建细节原始工程实现的改动自己封装的包含openssl和curl的实现osslsigncodeM工程命令行的用法备注 - VS2019调试环境备注 - 如果要单步openssl的API学学…

OpenCV-37 最小外接矩形和最大外接矩形

一、外接矩形 外接矩形分为最小外接矩形和最大外接矩形。 下图中红色矩形为最小外接矩形&#xff0c;绿色矩形为最大外接矩形。 1. 最小外接矩形 minAreaRect(points) --- 最小外接矩形 point为轮廓&#xff1b; 返回值为元组&#xff0c;内容是一个旋转矩形(RotatedRect…

MySQL简单配置GTID

前期规划 IP地址 角色 系统版本 内核 软件包名称 192.168.2.3 Mysql主服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc2.17-x86_64.tar.xz 192.168.2.4 Mysql从服务器 CentOS Stream 9 5.14.0- 381.el9.x86_64 mysql-8.2.0-linux-glibc…

【Tauri】(2):使用Tauri应用开发,使用开源的Chatgpt-web应用做前端,使用rust 的candle做后端,本地运行小模型桌面应用

视频演示地址 https://www.bilibili.com/video/BV17j421X7Zc/ 【Tauri】&#xff08;2&#xff09;&#xff1a;使用Tauri应用开发&#xff0c;使用开源的Chatgpt-web应用做前端&#xff0c;使用rust 的candle做后端&#xff0c;本地运行小模型桌面应用 1&#xff0c;做一个免…

MIT-Missing Semester_Topic 3:Editors (Vim) 练习题

文章目录 练习一练习二练习三练习四练习五练习六练习七练习八 本 Topic 的 MIT 讲解网页&#xff08;练习题未给解答&#xff09; 练习一 自行完成 vimtutor。vimtutor 是 Vim 本身附带的一个入门教程&#xff0c;在 shell 中直接输入 vimtutor 便能运行。注意该教程在 8024 大…

代码随想录day20--二叉树的应用8

LeetCode669.修剪二叉搜索树 题目描述&#xff1a; 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没…

vector容器

1. vector基本概念 1.1 功能&#xff1a; vector数据结构和数组非常相似&#xff0c;也称为单端数组 vector与普通数组区别&#xff1a; 不同之处在于数组是静态空间&#xff0c;而vector可以动态扩展 动态扩展&#xff1a; 并不是在原空间之后续接新空间&#xff0c;而是找更…

【蓝桥杯Python】试题 算法训练 比较

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 给出一个n长的数列&#xff0c;再进行m次询问&#xff0c;每次询问询问两个区间[L1,R1]&#xff0c;[L2,R2]&#xff0c;   …

C语言特殊指针

1 char型指针 char型指针实质上跟别的类型的指针并无本质区别&#xff0c;但由于C语言中的字符串以字符数组的方式存储&#xff0c;而数组在大多数场合又会表现为指针&#xff0c;因此字符串在绝大多数场合就表现为char型指针。 定义&#xff1a; char *p "abcd"…

爬爬爬——今天是浏览器窗口切换和给所选人打钩(自动化)

学习爬虫路还很长&#xff0c;第一阶段花了好多天了&#xff0c;还在底层&#xff0c;虽然不是我专业要学习的语言&#xff0c;和必备的知识&#xff0c;但是我感觉还挺有意思的。加油&#xff0c;这两天把建模和ai也不学了&#xff0c;唉过年了懒了&#xff01; 加油坚持就是…

ChatGPT高效提问—prompt实践(绘画、Logo设计)

ChatGPT高效提问—prompt实践&#xff08;绘画、logo设计&#xff09; 1.1 绘画工具 ​ Midjourney是一款由Midjourney研究实验室研发的人工智能程序&#xff0c;可根据文本生成图像。你可以通过浏览器在聊天应用程序Discord中向Midjourney机器人发送消息来使用它。不需要安装…

前端 > JS 笔试题面试考题(21-25)

简述请看下面的代码片段并回答以下问题 &#xff1f; for (var i 0; i< 5; i){var btn document.createElement(button);btn.appendChild(document.createTextNode(Button i));btn.addEventListener(click, function(){ console.log(${i} );});document.body.appendChild…

网络专栏目录

大家好我是苏麟 , 这是网络专栏目录 . 图解网络 资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 图解网络目录 基础篇 基础篇 TCP/IP网络模型有几层? : TCP/IP网络模型 键入网址到页面显示,期间发生了什么? : 键入网址到页面显示,期间发生了什么 现阶…

2024-02-12 Unity 编辑器开发之编辑器拓展3 —— EditorGUI

文章目录 1 GUILayout2 EditorGUI 介绍3 文本、层级、标签、颜色拾取3.1 LabelField3.2 LayerField3.3 TagField3.4 ColorField3.5 代码示例 4 枚举选择、整数选择、按下按钮4.1 EnumPopup / EnumFlagsField4.2 IntPopup4.3 DropdownButton4.4 代码示例 5 对象关联、各类型输入…

【Docker】Docker Container(容器)

文章目录 一、什么是容器&#xff1f;二、为什么需要容器&#xff1f;三、容器的生命周期容器OOM容器异常退出容器暂停 四、容器命令详解docker createdocker logsdocker attachdocker execdocker startdocker stopdocker restartdocker killdocker topdocker statsdocker cont…

「数据结构」哈希表1:基本概念

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 基本概念 &#x1f349;哈希表&#x1f349;哈希冲突&#x1f34c;负载因子调节&#x1f34c;解决哈希冲突&#x1f95d;1. 闭散…

HCIA-HarmonyOS设备开发认证V2.0-3.2.轻量系统内核基础-中断管理

目录 一、中断基础概念二、中断管理使用说明三、中断管理模块接口四、代码分析&#xff08;待续...&#xff09; 一、中断基础概念 在程序运行过程中&#xff0c;出现需要由 CPU 立即处理的事务时&#xff0c;CPU 暂时中止当前程序的执行转而处理这个事务&#xff0c;这个过程…

【ES】--Elasticsearch的分词器详解

目录 一、前言二、分词器原理1、常用分词器2、ik分词器模式3、指定索引的某个字段进行分词测试3.1、采用ts_match_analyzer进行分词3.2、采用standard_analyzer进行分词三、如何调整分词器1、已存在的索引调整分词器2、特别的词语不能被拆开一、前言 最近项目需求,针对客户提…