精华内容
下载资源
问答
  • 代码部分我是在别人博客进行复制的:链接: 基于 stm32 的应用实例 —— USART 串口通讯stm32 与主机通讯). 需要输入的内容在bsp_usart.c当中进行修改即可,其它的文件都是库,不需要更改 1.代码分析 bsp_usa

    一、简介

    在上一次我们学习了如何使用查询的方式进行串口通讯——发送数据,以及中断的方式,在本次我们使用中断来进行串口通讯。
    可以参考以前的博客:
    串口通讯:STM32串口通讯实现——USB转串口.
    中断:STM32使用中断方式读取按键控制LED灯的亮灭.

    二、代码编写

    代码部分我是在别人博客进行复制的:链接: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯).
    需要输入的内容在bsp_usart.c当中进行修改即可,其它的文件都是库,不需要更改

    1.代码分析

    bsp_usart.c文件程序:

    #include "bsp_usart.h"
    
    // 串口中断服务函数
    void DEBUG_USART_IRQHandler(void)
    {
      uint8_t ucTemp;
    	//串口一接收中断
    	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
    	{
    		//获取接收到的数据
    		ucTemp = USART_ReceiveData(DEBUG_USARTx);
    		//如果接收标志为 0 ,则执行下面的部分
    		if((USART_RX_FLAG & 0x8000) == 0)
    		{
    			//接收到了0x0d
    			if(USART_RX_FLAG & 0x4000)
    			{
    				//接收错误,重新开始
    				if(ucTemp != 0x0a)
    					USART_RX_FLAG=0;
    				//接收完成
    				else
    					USART_RX_FLAG |= 0x8000;
    			}
    			//还未接收到0x0d
    			else
    			{
    				//接收到回车
    				if(ucTemp == 0x0d)
    				{
    					USART_RX_FLAG |= 0x4000;
    				}
    				else
    				{
    					USART_RX_BUF[USART_RX_FLAG & 0x3FFF] = ucTemp;
    					USART_RX_FLAG++;
    					//接收数据错误,重新开始接收
    					if(USART_RX_FLAG > 99)
    						USART_RX_FLAG = 0;
    				}
    			}
    		}
    	}	 
    }
    
    static void NVIC_Configuration(void)
    {
      NVIC_InitTypeDef NVIC_InitStructure;
      
      /* 嵌套向量中断控制器组选择 */
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      
      /* 配置USART为中断源 */
      NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
      /* 抢断优先级*/
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      /* 子优先级 */
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      /* 使能中断 */
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      /* 初始化配置NVIC */
      NVIC_Init(&NVIC_InitStructure);
    }
    
    void USART_Config(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    
    	// 打开串口GPIO的时钟
    	DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    	
    	// 打开串口外设的时钟
    	DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
    
    	// 将USART Tx的GPIO配置为推挽复用模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
    
      // 将USART Rx的GPIO配置为浮空输入模式
    	GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
    	
    	// 配置串口的工作参数
    	// 配置波特率
    	USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    	// 配置针数据字长
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    	// 配置停止位
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;
    	// 配置校验位
    	USART_InitStructure.USART_Parity = USART_Parity_No ;
    	// 配置硬件流控制
    	USART_InitStructure.USART_HardwareFlowControl = 
    	USART_HardwareFlowControl_None;
    	// 配置工作模式,收发一起
    	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    	// 完成串口的初始化配置
    	USART_Init(DEBUG_USARTx, &USART_InitStructure);
    	
    	// 串口中断优先级配置
    	NVIC_Configuration();
    	
    	// 使能串口接收中断
    	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	
    	
    	// 使能串口
    	USART_Cmd(DEBUG_USARTx, ENABLE);	    
    }
    
    /* 发送一个字节 */
    void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
    {
    	//发送数据函数(串口一,数据)
    	USART_SendData(pUSARTx, data);
    	//发送数据寄存器为空,则退出
    	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    }
    
    /* 发送字符串 */
    void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
    {
    	uint8_t i = 0;
    	do
    	{
    		Usart_SendByte(pUSARTx, *(str+i));
    		i++;
    	}while(*(str+i) != '\0');
    	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
    }
    
    //微秒级的延时
    void delay_us(uint32_t delay_s)
    {    
      volatile unsigned int i;
      volatile unsigned int t;
      for (i = 0; i < delay_s; i++)
      {
        t = 11;
        while (t != 0)
        {
          t--;
        }
      }
    }
    
    //毫秒级的延时函数
    void delay_ms(uint16_t delay_ms)
    {    
      volatile unsigned int num;
      for (num = 0; num < delay_ms; num++)
      {
        delay_us(1000);
      }
    }
    
    //连续发送数据
    void Usart_SendString(void)
    {
    	uint8_t i = 0;
    	
    	while(1)
    	{
    		if(USART_RX_FLAG & 0x8000)
    		{
    			// 获取接收到的数据长度
    			len = USART_RX_FLAG & 0x3FFF;
    			Usart_SendStr(DEBUG_USARTx, "\n");
    			for(i=0; i<len;i++)
    			{
    				// 向串口发送数据
    				USART_SendData(DEBUG_USARTx, USART_RX_BUF[i]);
    				//等待发送结束
    				while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TC)!=SET);
    			}
    			Usart_SendStr(DEBUG_USARTx, "\n\n");
    			//比较字符串
    			if(strcmp((char *)USART_RX_BUF,"stop,stm32!")==0)
    			{
    				Usart_SendStr(DEBUG_USARTx, "stm32已停止发送!");
    				break;//退出循环
    			}
    			//初始化
    			USART_RX_FLAG=0;
    			memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));
    		}
    		else
    		{
    			//循环发送数据
    			Usart_SendStr(DEBUG_USARTx, "梓宝带我走吧\n");
    			delay_ms(800);
    		}
    	}
    }
    

    在程序当中定义了一个串口中断服务函数用于控制中断,以及NVIC的嵌套向量中断控制器函数。

    2.程序烧录

    接线之后,打开mcuisp软件,将生成的.hex文件烧录到芯片当中
    在这里插入图片描述

    三、实验效果

    在这里插入图片描述
    在输入框当中输入stop,stm32!然后换行,发送,就可以看到数据发送停止了

    四、总结

    通过此次实验,使用中断的方式进行串口通讯后,以及学习了三种串口通讯方式了:查询,中断和DMA。在实际的通讯过程当中,我们可以根据需求进行选择,在传输比较大的数据的时候采用DMA方式,可以解放CPU,让CPU进行别的工作。中断方式是通过中断服务函数不断将数据放到串口进行传送。每一种方式都有优缺点,我们学习完这些方法后要学会在不同场景下进行使用。
    参考资料: 基于 stm32 的应用实例 —— USART 串口通讯(stm32 与主机通讯)

    展开全文
  • 代码实现功能实现:与上位机进行通信宏定义需要的GPIO//头文件中的引脚 宏定义// 串口1-USART1#ifndef _USART_H#define _USART_H#include "stm32f10x.h"#include "stdio.h"// 串口1-USART1#define USART1_TX USART1#...

    代码实现

    功能实现:与上位机进行通信

    宏定义需要的GPIO

    //头文件中的引脚 宏定义

    // 串口1-USART1

    #ifndef _USART_H

    #define _USART_H

    #include "stm32f10x.h"

    #include "stdio.h"

    // 串口1-USART1

    #define USART1_TX USART1

    #define USART1_TX_CLK RCC_APB2Periph_USART1

    #define USART1_TX_APBxClkCmd RCC_APB2PeriphClockCmd

    #define USART1_TX_BAUDRATE 115200

    // USART GPIO 引脚宏定义

    #define USART1_GPIO_CLK (RCC_APB2Periph_GPIOA)

    #define USART1_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd

    #define USART1_TX_GPIO_PORT GPIOA

    #define USART1_TX_GPIO_PIN GPIO_Pin_9

    #define USART1_RX_GPIO_PORT GPIOA

    #define USART1_RX_GPIO_PIN GPIO_Pin_10

    #define USART1_IRQ USART1_IRQn

    #define USART1_IRQHandler USART1_IRQHandler

    void USART_Config(void);

    void Usart_SendByte(USART_TypeDef *TX, uint8_t data);

    void Usart_Two_SendByte(USART_TypeDef *TX_usart, uint16_t data);

    void Usart_SendArray(USART_TypeDef *TX_usart, uint8_t *array, uint8_t num);

    void Usart_SendStr(USART_TypeDef *TX_usart, uint8_t *str);

    #endif

    串口初始化配置

    //这里只在这个函数使用 可用static限制一下

    //中断分组配置函数

    static void NVIC_Configuration(void)

    {

    NVIC_InitTypeDef NVIC_InitStructure;

    /* 嵌套向量中断控制器组选择 */

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    /* 配置USART为中断源 */

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQ;

    /* 抢断优先级*/

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    /* 子优先级 */

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    /* 使能中断 */

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    /* 初始化配置NVIC */

    NVIC_Init(&NVIC_InitStructure);

    }

    //串口初始化函数

    void USART_Config(void)

    {

    GPIO_InitTypeDef GPIO_InitStructure;

    USART_InitTypeDef USART_InitStructure;

    // 打开串口GPIO的时钟

    //DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);

    RCC_APB2PeriphClockCmd(USART1_GPIO_CLK, ENABLE);

    // 打开串口外设的时钟

    //DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

    RCC_APB2PeriphClockCmd(USART1_TX_CLK, ENABLE);

    //将USART TX的GPIO配置为推挽复用模式

    GPIO_InitStructure.GPIO_Pin = USART1_TX_GPIO_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(USART1_TX_GPIO_PORT,&GPIO_InitStructure);

    //将USART RX的GPIO配置为浮空输入模式

    GPIO_InitStructure.GPIO_Pin = USART1_RX_GPIO_PIN;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStructure);

    //配置串口的工作参数

    //波特率

    USART_InitStructure.USART_BaudRate = USART1_TX_BAUDRATE;

    // 配置 针数据字长

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;

    // 配置停止位

    USART_InitStructure.USART_StopBits = USART_StopBits_1;

    // 配置校验位

    USART_InitStructure.USART_Parity = USART_Parity_No ;

    // 配置硬件流控制

    USART_InitStructure.USART_HardwareFlowControl =

    USART_HardwareFlowControl_None;

    // 配置工作模式,收发一起

    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    // 完成串口的初始化配置

    USART_Init(USART1_TX, &USART_InitStructure);

    // 串口中断优先级配置

    NVIC_Configuration();

    // 使能串口接收中断

    USART_ITConfig(USART1_TX, USART_IT_RXNE, ENABLE);

    // 使能串口

    USART_Cmd(USART1_TX, ENABLE);

    }

    给上位机发送数据

    提示:下面这些函数 都在usart.c中哦(⊙o⊙)

    发送一个字节

    void Usart_SendByte(USART_TypeDef *TX_usart, uint8_t data)

    {

    USART_SendData(TX_usart,data);

    //检测串口发送的数据

    //若没有数据来 就会一直等待

    while(USART_GetFlagStatus(TX_usart,USART_FLAG_TXE) == RESET);

    发送两个字节

    void Usart_Two_SendByte(USART_TypeDef *TX_usart, uint16_t data)

    {

    uint8_t temp_h,temp_l;

    temp_h = (data&0xff00) >> 8;

    temp_l = data&0xff;

    //发送高八位

    USART_SendData(TX_usart,temp_h);

    while(USART_GetFlagStatus(TX_usart,USART_FLAG_TXE) == RESET);

    //发送低八位

    USART_SendData(TX_usart,temp_l);

    while(USART_GetFlagStatus(TX_usart,USART_FLAG_TXE) == RESET);

    }

    发送八位数组

    void Usart_SendArray(USART_TypeDef *TX_usart, uint8_t *array, uint8_t num)

    {

    uint8_t i;

    for(i=0; i

    {

    Usart_SendByte(TX_usart,array[i]);

    }

    while(USART_GetFlagStatus(TX_usart,USART_FLAG_TC) == RESET);

    }

    发送字符串

    void Usart_SendStr(USART_TypeDef *TX_usart, uint8_t *str)

    {

    uint8_t i = 0;

    do

    {

    Usart_SendByte(TX_usart,str[i]);

    i++;

    }while(str[i] != '\0');

    while(USART_GetFlagStatus(TX_usart,USART_FLAG_TC) == RESET);

    }

    注意:要勾选keil中的 ues MicroLIB选项

    重定向c库函数调用

    int fputc(int ch, FILE *f)

    {

    /* 发送一个字节数据到串口 */

    USART_SendData(USART1_TX, (uint8_t) ch);

    /* 等待发送完毕 */

    while (USART_GetFlagStatus(USART1_TX, USART_FLAG_TXE) == RESET);

    return (ch);

    }

    //重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数

    int fgetc(FILE *f)

    {

    /* 等待串口输入数据 */

    while (USART_GetFlagStatus(USART1_TX, USART_FLAG_RXNE) == RESET);

    return (int)USART_ReceiveData(USART1_TX);

    }

    主程序测试

    #include "stm32f10x.h"

    #include "usart.h"

    int main(void)

    {

    uint8_t array[] = {0x00,0x01,0x03,0x04,0x05};

    //串口初始化

    USART_Config();

    //发送一个字节

    Usart_SendByte(DEBUG_USARTx,100);

    //发送两个字节

    Usart_Two_SendByte(DEBUG_USARTx , 0xff00);

    //发送一个八位字节

    Usart_SendArray(DEBUG_USARTx,array,5);

    //发送字符串

    Usart_SendStr(USART1_TX,"陈一一哇龘\n");

    printf("陈一一哇\n\n\n\n");

    while(1)

    {

    }

    }

    展开全文
  • stm32串口通信流程图

    2020-12-18 19:37:51
    1.写在前面首先,你要知道STM32启动文件中启动流程,你就需要掌握一点汇编基础知识。汇编语言属于机器语言,或者说低级语言,C语言属于高级语言,所以,汇编和C语言在语法上差异很大。如果你学底层开发,汇编的一些...

    1.写在前面

    首先,你要知道STM32启动文件中启动流程,你就需要掌握一点汇编基础知识。

    汇编语言属于机器语言,或者说低级语言,C语言属于高级语言,所以,汇编和C语言在语法上差异很大。

    如果你学底层开发,汇编的一些基础知识需要掌握。不需要精通,但需要看懂常见的汇编代码。

    2.说明

    STM32的启动文件与编译器有关,不同编译器,它的启动文件不同。

    虽然启动文件(汇编)代码各有不同,但它们原理类似,都属于汇编程序。

    我们拿基于MDK-ARM的启动文件来举例,说一下要点内容。

    3.分配堆栈

    在基于MDK的启动文件开始,有一段汇编代码是分配堆栈大小的。

    这里重点知道堆栈数值大小就行。还有一段AREA(区域),表示分配一段堆栈数据段。

    数值大小可以自己修改,也可以使用STM32CubeMX数值大小配置:

    在IAR中,是通过工程配置堆栈大小:

    4.向量表

    相信大家都知道向量表,先看汇编代码:

    这个向量表就是对应手册中的那些内容:

    我们需要知道这个地方中的复位,程序上电之后,是跳到Reset_Handler这个位置。

    5.执行代码

    上面知道代码是从Reset_Handler开始执行,我们看Reset_Handler汇编代码:

    在启动的时候,执行了SystemInit这个函数。

    之前标准外设库在SystemInit这个函数初始化了系统时钟,后面HAL库单独把那部分代码提出来了。

    执行完SystemInit函数,就跳转到我们的main函数执行了。

    打开APP阅读更多精彩内容

    点击阅读全文

    展开全文
  • 正点原子STM32串口通讯实验详解

    万次阅读 多人点赞 2020-12-24 23:30:10
    这几天看完了正点原子STM32串口通讯部分的内容,总感觉很多东西似是而非,前后花了好几天研究了下,这篇博客很多内容是从其他博客上整理来的,并非完全原创,只希望自己整理的内容能帮到其他的初学者。 1、实验...

    这几天看完了正点原子STM32的串口通讯部分的内容,总感觉很多东西似是而非,前后花了好几天研究了下,这篇博客很多内容是从其他博客上整理来的,并非完全原创,由于前后查了几天好多篇博客,摘抄的谁的也不好找了,看到的可以提醒一下,只希望自己整理的内容能帮到其他的初学者。

    经提醒第二部分来源于这篇博客 ,感兴趣的可以去原文看看。

    1、实验内容梳理

    首先结合串口调试助手对实验进行说明,以便后续结合代码熟悉整个流程。整个实验其实就是通过串口调试助手向单片机发送数据,然后单片机将接收到的数据返回给上位机并加以显示。

    简单来串口调试助手说其实就是用于上位机和下位机通信用的一个桥梁软件,功能主要有两个这也是本实验的两个步骤:

    1. 人工发送数据给单片机处理,即通过串口调试助手的下方窗口编辑数据,然后点击发送按钮,就能发送数据给单片机;
    2. 接受单片机发送的数据显示给你看,即通过串口调试助手上方窗口,将单片机发回给上位机的数据进行显示;

    关于串口调试助手,还应知道:

    • 发送英文字符需要用一个字符即8位,发送汉字需要两个字符即16位,如上图,发送汉字“宋”实际是发送“CB(1100 1011)CE(1100 1110)”而发送英文字符S实际是发送“53(0101 0011)”,本质上没有太大区别;
    • 勾选了下方“发送新行”后,XCOM就会再你输入的需要发送的数据后自动加上一个回车(0X0D+0X0A),如果不勾选则我们在手动输入完“宋S”后还需敲一个回车键只有这样点击发送后,调试助手上方窗体才能将其显示,这是因为我们在程序的串口中断中自定义了一个数据接收协议,即只有当接受的数据以回车结尾(0X0D+0X0A),串口才认可数据接受完毕。

    2、对于串口中断函数(自定义数据接收协议)的理解

    正点原子的例程中通过语句USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)开启相关中断,当读数据寄存器非空,即单片机一接收到数据时,便会触发串口1的中断函数。

    改协议的核心是定义了一个16位的变量USART_RX_STA,该变量的0-13位用于存储接收到的数据,最后的14、15两位作用在于,当14、15位依次接收到da0x0d和0x0a时,依次将这两位置1,作为判断数据是否接收完的标志位。

    以下是我看到的一个注释比较详细的代码,和一个实例,结合两者就可以很好的理解这个过程和代码,

    void USART1_IRQHandler(void)                	//串口1中断服务程序
    	{
    	u8 Res;     //定义unsigned char型字符Res
    
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
    		//接收中断(接收到的数据必须是0x0d 0x0a结尾)
    		//这里判断发送接收完成的依据就是串口数据0x0d 0x0a,
    		//0x0d是CR(carriage return)回车的意思,光标回到最左边,
    		//0x0a是LF(line feed)换行的意思,光标到达下一行,
    		//但是在PC上回车和换行是在一起的就是按下回车按键
    		//当然可以更改程序使用其他进行判断例如使用0x2a也就是*进行结束判断
    		{
    		Res =USART_ReceiveData(USART1);//(USART1->DR);	
    		//读取接收到的数据,存放到变量Res中
    		if((USART_RX_STA&0x8000)==0)
    			//判断接收是否未完成
    			//接收完成未清除标志位,还是会不断进入到接收中断,所以使用标志进行判断,
    		  //当接收完成便不会跳入到判断,从而不执行任何指令,空等待
    			//使用条件判断是否已经接收完数据,这里判断接收完的依据就是收到了0x0a;
    			//具体判断在后面
    			{
    			if(USART_RX_STA&0x4000)
    			//如果接收到了0x0d,那么再进一步执行是否接收到0x0a的判断
    				{
    				if(Res!=0x0a)USART_RX_STA=0;
    			//没有接收到0x0a那么说明,数据未正确传输或者接收错误,重新开始判断,
    			//但是这里没有将接收到的数据进行清空,也没有退出接收中断,此程序只是从头开始执行接收判断
    				else USART_RX_STA|=0x8000;	
    			//接收完成了,收到了0x0a那么标志位USART_RX_STA将会变成0x8000,将不再进行数据检测与存储
    				}
    			else 
    				//还没收到0X0D,说明数据还未发送结束继续进行数据的检测与存储
    				{	
    				if(Res==0x0d)USART_RX_STA|=0x4000;
    				//收到了数据0x0d,标志位USART_RX_STA变成0x4000
    				else
    					{
    				//如果没有接收到数据0x0d,执行判断是否存储数组已满,已满则重新开始接收
    					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    				//将接收到的数据写进数组,标志位USART_RX_STA与上0X3FFF清除前两位以防止标志位与8000和4000冲突
    					USART_RX_STA++;
    				//数组地址加一,向后排
    					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
    				//接收数据错误,超出数组大小,又开始接收向数组重新写  
    					}		 
    				}
    			}   		 
         } 
    
    } 

    假设我们发送的数据是“abcd”经过串口调试助手加上0X0D+0X0A后发送给单片机,即单片机要接受的数据是“abcd”+“0X0D+0X0A”

    (1)当接收到“a”时读寄存器非空,RXNE为1,第一次进入串口中断处理函数,我们先判断是否接是因为USART1接受到了数据产生的中断,如果是,则将USART1接受到的一位数据“a”存入变量Res里(Res = “a”)

    if(USART_GetFlagStatus(USART1, USART_IT_RXNE) != RESET)

    (2)然后我们来判断接收的一系列数据是否没接收完(即)。(当然没有啦,我们还有b、c、d三个数据没有接收)。这个时候呢,USART_RX_STA——这个在全部函数之间实现消息传递的变量的值仍然为0,和0x8000相与以后为0,那么执行该if语句的内层函数。

    if((USART_RX_STA&0x8000)==0) //接收未完成

    (3)进入该if语句的内层语句后判断语句如下,这里判断USART_RX_STA的第14位是否为1,如果我们接收到了回车,即0x0d那么USART_RX_STA的第14位会置1。在我们接收第一个数据a时USART_RX_STA当然还为0,(我们后面的的b、c、d、3个数据还都没接收了,当然不会收到0x0d)USART_RX_STA和0x400相与为0,该判断语句就为假,执行下面的else语句。

    if(USART_RX_STA&0x4000)//接收到了0x0d

    (4)该else语句的内层语句是一个if-else语句

    if(Res==0x0d)USART_RX_STA|=0x4000; 

    这里我就不再赘述,我们接收的是数据a,还没有接收到0x0d,执行else语句。

    USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; // 0x3ff = 0011 1111 1111 1111
    
    USART_RX_STA++;
    
    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收

    USART_RX_STA的bit0~bit13代表的是接收到的有效数据个数,这里USART_RX_STA值仍为0,USART_RX_STA & 0X3FFF = 0 ,然后USART_RX_BUF[USART_RX_STA&0X3FFF]=Res,意思就是将Res里的数据存放到USART_RX_BUF[0]里了,并且USART_RX_STA自增1。

    此时USART_RX_STA = 1这样在接收到下一个数据b后USART_RX_STA&0X3FFF = 1,将b存入到了USART_RX_BUF[1]里,一直循环下去,直到我们接收到了0x0d(Res = 0x0d)。

    我们可以从上面程序里找到如下代码:

    else //还没收到0X0D
    				{	
    				if(Res==0x0d)USART_RX_STA|=0x4000; //再次判断这次接收到的是不是0x0d

    当接收到0x0d并且程序执行到这一步一时USART_RX_STA = 4,此时该if语句成立,执行USART_RX_STA|=0x4000,即0000 0000 0000 0100 | 0100 0000 0000 0000 = 0100 0000 0000 0100 ,我们可以清晰的看到bit13~0位是4,代表接收到了4个数据(a,b,c,d),第14位为1,是因为接收到了数据0x0d,也和最上面给的表对上了,然后程序向下执行,接收到了0x0d(回车),那下一个就是接收0x0a(换行)了,Res = 0x0a:         

    if(USART_RX_STA&0x4000)//接收到了0x0d     0100 0000 0000 0000
    				{
    				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始--接收到了0X0d但是没有接受到0x0a
    				else USART_RX_STA|=0x8000;	//接收完成了--0x0d后面是0x0a  
    				}
    

    这里第一个判断语句if(USART_RX_STA&0x4000),当然为真,因为Res = 0x0a,那么执行else语句USART_RX_STA|=0x8000,即0100 0000 0000 0100 | 1000 0000 0000 0000 = 1100 0000 0000 0100。到了这一步,就说明这一串数据已经完完全全的接收完了USART_RX_STA = 1100 0000 0000 0100,最高位为1:代表接收到了0x0a,第十四位为1:代表接收到了0x0d,第0位到第13位为4,代表接收到了4位有效数据(a、b、c、d)

    3、对main函数的理解

    main函数如下,大致的执行流程为:

    int main(void)
    { 
     
    	u8 t;
    	u8 len;	
    	u16 times=0;  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    	delay_init(168);		//延时初始化 
    	uart_init(115200);	//串口初始化波特率为115200
    	LED_Init();		  		//初始化与LED连接的硬件接口  
    	while(1)
    	{
    		if(USART_RX_STA&0x8000)
    		{					   
    			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
    			printf("\r\n您发送的消息为:\r\n");
    			while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
    			for(t=0;t<len;t++)
    			{
    				
    				USART_SendData(USART1, USART_RX_BUF[t]);         //向串口1发送数据
    				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
    			}
    			printf("\r\n\r\n");//插入换行
    			USART_RX_STA=0;
    		}else
    		{
    			times++;
    			if(times%300==0)
    			{
    				printf("\r\nALIENTEK 探索者STM32F407开发板 串口实验\r\n");
    				printf("正点原子@ALIENTEK\r\n\r\n");
    			}
    			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
    			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
    			delay_ms(10);   
    		}
    	}
    }
    
    
    1. 完成串口的相关设置,使能相应中断,以及初始化过程,然后进入while等待;
    2. 当在串口调试助手的想窗体输入想要发送的数据,并点击发送后,当单片机开始接受数据时便会触发中断函数USART1 IRQHandler( )对数据进行接收并最终存储进缓存RX_BUF_USART中,其在usart.h中的生命为extern u8  USART_RX_BUF[USART_REC_LEN]。其中USART_REC_LEN=200
    3. 通过语if(USART RX STA&0x8000)判断数据是否完成接受存入缓存数组RX_BUF_USART中,如果完成了,则利用重定向的printf函数向上位机发送语句“\r\n您发送的消息为:\r\n” , 如下图标号1区域(此处实验现象异常,后面会有解释)然后通过for循环将缓存RX_BUF_USART中的数据依次通过USART_SendData()函数发给上位机,发给上位机的数据将在串口调试助手上显示。所有数据发送完毕后,再次通过printf函数向上位机发送"\r\n\r\n"即在串口调试助手上窗体光标在原来位置的基础上下移两行。如下图标号2区域所示。
    4. 当数据没有接受完,或者没有向单片机发送数据时,单片机便会通过printf函数向上位机按照一定时间间隔发送“\r\nALIENTEK 探索者STM32F407开发板 串口实验\r\n”、“正点原子@ALIENTEK\r\n\r\n”和“请输入数据,以回车键结束\r\n”语句。

    注意:重定向的printf()函数本质上还是通过USART_SendData()向上位机发送数据,且此处发送的“\r\n”与中断函数里的需要作为接受完成标志位的“\r\n”(0X0D+0X0A),只是单纯的表示换行的转义字符,电脑上位机接收到后会将光标下移两行,视觉上就是空一行显示在串口调试助手上。

    4、实验异常现象及解决办法

    上面有提到过图片标号1的区域出现了异常实验现象,即单片机利用printf("\r\n您发送的消息为:\r\n")语句显示的结果中语句末尾的“\r\n”并没有起到作用,即让光标移至下一行后再显示“逆光”。

    这种现象的原因是因为printf语句中的“\r\n”发送未完成,寄存器又被后面要发送的数据覆盖,解决方法就是在USART_SendData(USART1, USART_RX_BUF[t]);前面在多加一句 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束

    for(t=0;t<len;t++)
    			{
    				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
    				USART_SendData(USART1, USART_RX_BUF[t]);         //向串口1发送数据
    				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
    			}

    修改后实验现象恢复正常如下:

    我尝试过在printf语句的后面利用延时的方式解决问题,但是只有第一次能够正常显示,后面再次发送,现实的数据就会存在乱码的问题。

    5、USART-FLAG-TXE与USART-FLAG-TC标志位

    我觉得这两个标志位的使用应当严格区分开,当个附加知识记录一下:

    USART-FLAG-TXE发送缓冲区空标志:说明可以往数据寄存器写入数据了,但并不代码数据发送完成了。

    USART-FLAG-TC发送完成标志:这个才是代表USART在缓冲区的数据发送完成了,即从机接收到了数据。

    这两个标志的区别在于:它们分别表示数据在发送过程中,在两个不同的阶段中的完成情况.TXE表示数据被从发送缓冲区中取走,转移到的移位寄存器中,此时发送缓冲是空的,可以向其中补充新的数据了。而 TC则表示最后放入发送缓冲区的数据已经完成了从移位寄存器向发送信号线Tx上的转移。所以,判定数据最终发送完成的标志是TC,而不是IXE.

    展开全文
  • STM32串口通信简介

    2021-10-23 22:27:52
    目录 前言 一、串口协议是什么?...STM32串口通信,发送Hello Windows示例_噗噗的罐子博客-CSDN博客https://blog.csdn.net/qq_46467126/article/details/120841504参考资料: 零死角玩转STM32-F103指南者
  • STM32串口通信详解以及通信异常或者卡死常见问题分析 目录 STM32串口通信详解以及通信异常或者卡死常见问题分析 一、常见的异常问题 二、STM32的串口简介 1.串口的通讯方式 ①按数据传输方向 ②串行通讯的通信方式 ...
  • STM32 串口通信实验

    2021-05-29 10:04:25
    stm32串口通信实验UART通信实验(通用异步收发器)UART串口通信原理:UART的通信过程实验功能:软件设计:完整工程下载 实验器材:F103开发板 F407开发板 USB转RS232母线 USB转RS485线 在F103环境下进行UART通信实验...
  • STM32串口通信配置细节

    千次阅读 2021-01-21 23:55:53
    2021-01-12 学习日志STM32f1库函数开发学习实战二 · 串口通信1. 背景知识2. usart文件夹介绍 STM32f1库函数开发学习 实战二 · 串口通信 1. 背景知识 DMA 通信方式 LIN总线 DMA,Direct Memory Access,...
  • 优点:实现简单,对于快速相应和长度不长的通讯可以使用此方法 缺点:(1)在非实时环境中,由于延时的存在会影响系统的响应效率 (2)串口在收发不定长度数据时候可能会接受数据不完整 2、超时接收 原理:设置...
  • STM32串口通信

    2021-01-26 22:23:20
    STM32串口通信串口通信简介编程代码 注意:本文参考STM32F10XXX数据手册 串口通信简介 USART为通用同步异步接收/发送器,我们常用的是异步通信,下面也重点讲解异步通信 问:同步异步有什么区别呢? 答:具体区别...
  • STM32串口通信协议

    2021-07-28 06:51:26
    好文网为大家准备了关于STM32串口通信协议范文,好文网里面收集了五十多篇关于好STM32串口通信协议好文,希望可以帮助大家。更多关于STM32串口通信协议内容请关注好文网篇一:STM32串口中断接收方式详细比较串口中断...
  • 基于MDK5实现STM32串口通信

    千次阅读 2021-10-27 16:56:21
    串口通信(Serial Communication), 是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。 串口通信协议是指规定了数据包的内容,内容包含了起始位、主体数据、校验位及停止位,...
  • STM32串口通信实例

    千次阅读 2021-11-09 21:06:32
    串口配置的一般步骤: ①:串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd(); 串口作为外设,首先要使能时钟,使能串口引脚,譬如使能GPIOA的时钟 ②:串口复位:USART_Delnit();这一步不是必须的。 ③:...
  • STM32串口通信基本原理

    千次阅读 多人点赞 2021-05-22 18:41:36
    通信方式 并行通信 传输原理:数据各个位同时传输 优点:速度快(一个引脚传输一个位) 缺点:占用引脚资源多 串行通信 传输原理:数据按位顺序传输 优点:占用引脚资源少(一个引脚都可以) 缺点:速度相对较慢 ...
  • OpenMV和STM32串口通讯

    2021-07-26 22:15:43
    利用串口进行OpenMV与STM32(其他单片机同理)进行通讯 OpenMV程序: from pyb import UART import struct def sending_data(x1,y1): data =struct.pack("<bbhhb", #格式为四个字符俩个短整型(2字节) 0x2C, #...
  • 基于stm32CubeMX(Hal库)的stm32串口通信

    千次阅读 2021-10-19 11:09:40
    一、安装环境 1.1安装jdk 由于STM32CubeMX是Java实现的,...下载地址:STM32CubeMX - STM32Cube initialization code generator - STMicroelectronics 我们选择for windows next 两个都勾选 选择安...
  • 在系统开机完成后,可以往串口发送指定格式的指令,系统接收到指令后会执行该 指令,并将指令执行结果返回到串口和系统主界面上的系统信息区 通过串口发送<GetTime>指令给系统,系统返回当前的时间至...
  • STM32串口通讯协议

    2021-10-10 10:26:09
    下面我来说说STM32中的这个通讯协议: 一般情况下我们一次不会发送一大串太长的东东,所以我们先规定最大接收字节数,一般设为200,可以根据需要调整,大于这个数,我们就判断为接收出错,重新接收,我们接收到的...
  • STM32串口通信代码正确串口却没反应

    千次阅读 2021-03-31 22:25:46
    在使用stm32f103c8t6进行串口通信实验时,将资料包中的代码下载进去。打开串口,按下复位,发现啥反应都没有,代码也没错误。无论发送什么都是没有反应。 解决方法 将keil5中的Use MicroLIB勾选上(网上下载下来的...
  • 二、完成一个STM32的USART串口通讯程序 (1)创建新工程并编写代码 (2)生成hex文件 (3)结果演示 三、使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形 (1)观察3个GPIO端口的输出波形 (2)串口输出...
  • STM32串口通讯实现——USB转串口

    千次阅读 2021-10-22 16:35:06
    一、RS232,TTL简介 RS232是个人计算机的通讯接口之一,一般会有两组...了解了RS232和TTL两种通信标准后,就可以开始了解串口通信USART了。 UART :通用异步收发传输器,它将要传输的资料在串行通信与并行通信之间加以
  • 本文主要描述串口协议和RS-232标准,RS232电平与TTL电平的区别,以及"USB/TTL转232"模块(以CH340芯片模块为例)的工作原理。
  • #include "stm32f10x.h" #include // 串口初始化函数 void My_USART1_Init(void) { GPIO_InitTypeDef GPIO_InitStrue; USART_InitTypeDef USART_InitStrue; NVIC_InitTypeDef NVIC_InitStrue; // 1,使能GPIOA,USART1...
  • STM32串口通信编程

    2021-10-24 11:57:37
    使用STM32CUBEMX生成代码(1)下载依赖包(2)创建项目主函数代码三、STM32的USART串口通讯程序UART简介创建项目四、使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形总结 一、串口协议和RS-232标准 1.串口通讯...
  • OPENMV-STM32串口通信

    千次阅读 2021-10-08 11:27:50
    OPENMV-STM32串口通信 目录标题OPENMV-STM32串口通信前言硬件选择硬件的通信连接OPENMV软件分析效果展示图 前言 最近要准备工巡赛,突然要发现需要进行视觉传动,所以我最近几天又温顾了一下Openmv,以前学习Openmv都...
  • stm32串口通信

    2021-01-11 14:32:27
    学习和阅读“零死角玩转STM32F103–指南者”文档中的第20、21章内容,完成STM32的USART窗口通讯程序,要求: 1)设置波特率为115200,1位停止位,无校验位。 2)STM32系统给上位机(win10)连续发送“hello ...
  • STM32串口通讯协议

    千次阅读 2021-10-21 16:16:13
    1.1 串口通信协议简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。 在...
  • STM32串口通信UART使用

    2021-05-09 05:53:08
    STM32串口通信UART使用uart使用的过程为:1. 使能GPIO口和UART对应的总线时钟2. 配置GPIO口的输出模式3. 配置uart口相关的基本信息4. 使能uart口的相关的中断,如接收中断、空闲中断等5. 编写中断接收函数配置对应的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,696
精华内容 9,078
关键字:

stm32串口通信

友情链接: VUAMT for 3D PDA of FRP.zip