• STM32串口发送接收完结


    前言

    提示:这里可以添加本文要记录的大概内容:

    目前已经学习了GPIO的输入输出,但是没有完整的显示信息,最便宜的显示就是串口。

    000 -111

    AVR单片机 已经学会过了,


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、串口是什么?

    1.串口的基本认识

    https://www.bilibili.com/video/BV1y34y147s5/?spm_id_from=333.337.search-card.all.click
    https://www.bilibili.com/video/BV1PD4y147ts/?spm_id_from=autoNext
    https://www.bilibili.com/video/BV14k4y187e6/?spm_id_from=autoNext
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    目标
    在这里插入图片描述

    2.STM32的串口结构

    1. 对外的就是TX RX
      在这里插入图片描述在这里插入图片描述
      在这里插入图片描述
    2. 读写原理在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    USART_DR类似51单片机的SBUF

    3.实现串口通信最简单的就是配置好和串口助手参数

    二、使用步骤

    1.开启时钟

    • GPIO的时钟
    • UART
      代码如下(示例):
    	//开启串口1和GPIOA.9  10的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1, ENABLE);
    
    • 1
    • 2

    2. 配置引脚

    • 串口1 PA9 PA10
      在这里插入图片描述
      在这里插入图片描述
    	//2.配置GPIO
    	
    	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_9;          //TX
    	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    	
    	GPIO_Init(GPIOA, &GPIO_InitStruct);   //&x
    	
    	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_10;         //RX
    	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	
    	GPIO_Init(GPIOA, &GPIO_InitStruct);   //&x
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3.初始化串口

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    代码如下(示例):

    	// 3.配置USART
    	
    	USART_InitStruct.USART_BaudRate=  9600;
    	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    	USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    	USART_InitStruct.USART_Parity=  USART_Parity_No;
    	USART_InitStruct.USART_StopBits= USART_StopBits_1;
    	USART_InitStruct.USART_WordLength=  USART_WordLength_8b;
    	
    	USART_Init( USART1, &USART_InitStruct);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4. 串口使能

    在这里插入图片描述

    USART_Cmd(USART1, ENABLE);
    
    • 1

    5. 串口如何发送?

    在这里插入图片描述

    5.1发送单个字符

    USART_SendData(USART1, 'A');
    
    • 1

    5.2 发送多个字符

    // 5. 发送	
    	USART_SendData(USART1, 'A');
    	//加入等待发送完成
    	// 没发送完成就一直是0,发送完成就是1
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	//while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
    	//while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
    	
    	USART_SendData(USART1, 'B');
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	USART_SendData(USART1, 'C');
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	USART_SendData(USART1, 'D');
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	USART_SendData(USART1, 'E');
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	USART_SendData(USART1, 'F');
    	while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    5.3 写成一个发送字符串的函数

    字符串最后一位就是 0,NULL

    
    U8 ta[]="123";
    
    send_string(ta); //这时候ta代表装着 123数据的首地址,1的地址,*p就是1,p就是1的地址也首地址,ta;
     void send_string(u8 *p)
    {
    	
    	    while(*p !=0)
    		{
    			USART_SendData(USART1, *p);
    			while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    			p++;
    		}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5.4 发送多类型,采用printf()

    需要重定向一个函数,让printf 发送到串口而不是C语言里面的控制台
    加头文件
    #include “stdio.h”

    int fputc(int ch,FILE *f)
    {
    
    	   USART_SendData(USART1, (u8)ch);
    	   while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	   return ch;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    单独写这个不能发送
    要勾选

    在这里插入图片描述

    printf("STM32简答吗?");
    printf("STM32简答吗?\r\n");
    
    printf("STM32简答吗?能考%d 分?\r\n",60);
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    6. 串口如何接收?

    串口中断数据接收有2种方法,为了节省资源,一般采用中断的方法

    1. 查询
    2. 中断

    6.1 查询的方法,在主函数不断获取标志位,

     void main()
     {
    	while(1)
    	{
    		if(串口接收完成)
    		{
    			temp= 接收函数
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    6.2 中断获取数据的方法

    • 步骤
    1. 中断分组
    2. 配置NVIC优先级管理
    3. 开启串口接收中断
    4. 写中断服务函数
      第一、二步
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
    	NVIC_InitStruct.NVIC_IRQChannelCmd= ENABLE;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority=  1;
    	NVIC_Init(&NVIC_InitStruct);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第三步

    在这里插入图片描述
    在这里插入图片描述

    USART_ITConfig( USART1, USART_IT_RXNE, ENABLE);
    
    • 1

    第四步

    void USART1_IRQHandler()   //中断函数
    {
    	u16 temp;
    	if(USART_GetITStatus( USART1, USART_IT_RXNE))  //判断是否是接收完成中断
    	{
    	
    	     temp=USART_ReceiveData(USART1);      //接收数据
              USART_SendData(USART1, temp);       //发送收据
    		
    		
    		USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清楚接收完成中断
    		
    		
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.是否要中断?要中断有什么好处

    三、测试

    1. 硬件条件

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2. 测试成功发送了一个字符

    在这里插入图片描述

    3.发送多个字符

    在这里插入图片描述

    如何解决问题

    在这里插入图片描述

    在这里插入图片描述
    解决方法:

    在这里插入图片描述
    成功的案列
    在这里插入图片描述

    四、接收字符串比较字符串

    使用串口交互代码问题

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "USART.h"
    #include "LED.h"
    #include "string.h" 
    #include "stdio.h" 
    
    uint8_t Data;//接收一字节数据
    unsigned char RX_Str[100];
    unsigned char ta[100]={"1234我的名字"};
    u16 Rx_FLAG=0; //接收完成标志位 
    
     unsigned char hongdeng[]={"红灯"};
    int main()
    {
    	USART_INT();//串口初始化
    	LED_int();//LED初始化
    	
    	USART_SendData(USART1,'a');//串口能正确接收说明硬件、软件没问题
    	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    	printf("你好吗\r\n");//打印红灯亮信息 红灯亮   \r\n换行
    	//串口能正确发送说明 发送编码没问题
    	while(1)
    	{
    		if(Rx_FLAG==1)//接收完成标志 Rx_FLAG 为 1  
    		{
    			if(strcmp(RX_Str,"红灯")==0)//比对接收的字符是否为 红灯 
    			{
    				LEDR_ON();//红灯亮
    				printf("红灯亮 \r\n");//打印红灯亮信息 红灯亮   \r\n换行
    			}
    			else if(strcmp(RX_Str,"蓝灯")==0)//比对接收的字符是否为 蓝灯 
    			{
    				LEDB_ON();//蓝灯亮
    				printf("蓝灯亮 \r\n");//打印蓝灯亮信息 蓝灯亮
    			}
    			else if(strcmp(RX_Str,"绿灯")==0)//比对接收的字符是否为 绿灯
    			{
    				LEDG_ON();//绿灯亮
    				printf("绿灯亮 \r\n");//打印绿灯亮信息 绿灯亮
    			}
    			else if(strcmp(RX_Str,"关灯")==0)//比对接收的字符是否为 关灯
    			{
    				LED_ALLOFF();//灯全灭
    				printf("已关灯 \r\n");//打印灯灭信息 已关灯
    			}
    			else if(strcmp(RX_Str,"我的学号")==0)//比对接收的字符是否为  我的学号
    			{
    				printf("学号:2015252525225 \r\n");//打印  学号:2015252525225
    			}
    			else if(strcmp(RX_Str,"我的姓名")==0)//比对接收的字符是否为  我的姓名
    			{
    				printf("姓名:xxx \r\n");//打印 
    			}
    			else  //若输入指令都不符合 则打印输入指令错误
    			{
    				printf("输入指令错误!! \r\n");//打印输入指令错误
    			}
    			Rx_FLAG=0;//接收完成标志位置0  
    		}
    	}
    }
    
    
    /*
    通过接收HEX数据包实现交互   包头@ 数据1 数据2 ... 包尾\r\n
    利用状态转换思想接收HEX数据包  相当于数电的状态转换 等待转换信号来临进而转换状态
    */
    void USART1_IRQHandler()    //串口中断函数
    {
    	static u16 RX_zt;//串口接收状态
    	static u16 i;//字符数组下标
    	if (USART_GetITStatus(USART1, USART_IT_RXNE)==SET)//当接收标志位为SET 开始接收
    	{
    		Data=USART_ReceiveData(USART1);//接收数据
    		if(RX_zt==0)//若串口接收状态为状态0
    		{
    			if(Data==' '&&Rx_FLAG==0)//判断接收到的数据是否为包头 @ 在Rx_FLAG=0情况下接收数据防止数据传输过快错乱
    			{
    				RX_zt=1;//转换为状态1
    				i=0;//字符数组下标置0
    			}
    		}
    		// 123132\r\n
    		else if(RX_zt==1)//若串口接收状态为状态1
    		{
    			if(Data=='\r')//判断是否为包尾字符 不定长HEX数据包接收数据需时刻比对包尾信号
    			{
    				RX_zt=2;//转换为状态2
    			}
    			else
    			{
    				RX_Str[i]=Data;//接收数据存入字符数组
    				i++;
    			}
    		}
    		else if(RX_zt==2)//若串口接收状态为状态2
    		{
    			if(Data=='\n')//再次判断是否为包尾字符
    			{
    				RX_zt=0;//转换为状态0
    				RX_Str[i]='\0';//字符串接收结束
    				Rx_FLAG=1;//接收完成标志位置1
    			}
    		}
    		USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接收标志位
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    strcmp函数讲解在这里插入图片描述

    https://baike.baidu.com/item/strcmp/5495571?fr=ge_ala

    4.0 发送无回应如何判断

    • 1.自己声明一个字符串,然后硬件仿真能 发现显示“红灯” 得到编码错误

    在这里插入图片描述

      1. 接收字符串回来数组里面得到数据位 “红灯”显示正确
        在这里插入图片描述
      1. 核心问题:32用的是UTF-8编码 ->上位机用的是ANSI编码

    4.1 老铁给出的错误分析很好

    https://blog.csdn.net/qq_44852376/article/details/128460223

    核心问题:32用的是UTF-8编码 ->上位机用的是ANSI编码

    4.2 怎么解决?

    4.2.1 新建工程重来

    新建工程,一开始就用ANSI编码,中间不要随意改动编码

    4.2.2 强制编码,改回来

    使用nopepad++软件实现

    在这里插入图片描述

    在这里插入图片描述

    总结

    实现对话,发送名字,学号,指定三盏灯的状态,
    最有加入了 发送和回复的功能,为上位机 通信奠定了基础!

  • 相关阅读:
    Nosql的redis概述及基本操作
    esbuild中文文档-路径解析配置项(Path resolution - External、Main fields)
    Spring IOC和AOP
    时光机特效什么app好?建议收藏这些软件
    2022年全球及中国工厂模拟软件行业头部企业市场占有率及排名调研报告
    「PAT甲级真题解析」Advanced Level 1005 Spell It Right
    仅靠阿里 P9 分享的 Redis 工作手册,拿到 60W 年薪 Offer
    命令历史应用
    XSAN数据恢复-存储空间架构迁移时误格式化存储系统的XSAN数据恢复案例
    c#学习笔记-继承
  • 原文地址:https://blog.csdn.net/ganhui13000/article/details/133957564