简介

1.串口通讯的双方若采用不同的电平标准,则需要利用电平转换芯片进行转换。
2.调试程序时可以把一些调试信息“打印”在电脑端的串口调试助手上。
3.硬件原理以后有空再研究,应该跟微机里学的挺类似的。。。

配置一个串口的步骤

1.使能USART时钟,以及RX和TX引脚的GPIO时钟
2.初始化GPIO,配置相关的引脚功能
3.配置USART的工作参数
4.配置中断控制器NVIC,使能串口中断
5.使能USART的接收中断
6.使能USART
7.编写中断服务函数

代码设计

通用代码参考的是野火的代码,自己写的太不规范了。。。

(1)串口初始化

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);
}

(2)NVIC中断控制器的初始化

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);
}

(3)发送一个字符以及发送字符串
对于发送字符,这里封装了库函数并增加了等待发送完成的查询(若无该步,字符串无法发送成功)

/*===================发送一个字符=========================*/
void Usart_SendByte(USART_TypeDef* USARTx, uint8_t Data)
{USART_SendData(USARTx,Data);while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}/*===================发送一个字符串======================*/
void Usart_SendString(USART_TypeDef* USARTx,char *str)
{uint32_t i=0;for(;*(str+i)!='\0';i++){Usart_SendByte(USARTx,*(str+i));}while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}

(4)printf的重定向
为了使用c库中的printf,需要对fputc进行重定向

//注意添加头文件
#include <stdio.h>//……///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);      return (ch);
}///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{/* 等待串口输入数据 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USARTx);
}

(5)发送和接受数据
定义一个缓冲区,利用中断方式接受数据,利用FIFO模式发送数据,分别贴出中断服务函数以及主函数

//中断服务函数extern uint8_t Uart_data[64];
extern uint32_t Rx_Num;void DEBUG_USART_IRQHandler(void)
{uint8_t temp;if(USART_GetITStatus(DEBUG_USARTx , USART_IT_RXNE)!=RESET){temp= USART_ReceiveData(DEBUG_USARTx);Uart_data[Rx_Num]=temp;Rx_Num++;Rx_Num&=0x3f;}
}//主函数
uint8_t Uart_data[64];
uint32_t Rx_Num=0;
uint32_t Tx_Num=0;int main(void)
{DEBUG_USART_Config();printf("hello,world\r");while(1){   if(Tx_Num!=Rx_Num){USART_SendData(DEBUG_USARTx,Uart_data[Tx_Num]);Tx_Num++;Tx_Num&=0x3f;}}
}

上述方法定义了三个外部变量,需要注意用法。

(6)设置指令集(控制LED)
利用上位机发送数据时,只能发送单个字符,发送一串字符时仅能接收到第一个。

/*====================字符串匹配=======================*/
uint8_t Cmp(uint8_t *str,uint8_t num)
{uint8_t i=0;uint8_t   str1[]="111111111";uint8_t str2[]="000000000";for(i=0;i<(num-1);i++){if(*(str1+i)!=*(str+i))break;}if(i==(num-1))return 1;for(i=0;i<(num-1);i++){if(*(str2+i)!=*(str+i))break;}if(i==(num-1))return 2;return 0;
}//中断服务函数
// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{uint8_t ucTemp;u8 i;if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET){     ucTemp = USART_ReceiveData(DEBUG_USARTx);//USART_SendData(DEBUG_USARTx,ucTemp);  Uart_Data[Rx_Num]=ucTemp;Rx_Num++;for(i=0;i<10;i++){printf("%c",Uart_Data[i]);}if(Rx_Num==9){//          for(i=0;i<10;i++)
//          {//              printf("%c",Uart_Data[i]);
//          }Rx_Num=0;}}
}//主函数
int main(void)
{   USART_Config();LED_Config();while(1){   switch(Cmp(Uart_Data,10)){case 1:   LED1_ON;LED2_OFF;break;case 2:  LED1_OFF;LED2_ON;break;case 0:LED2_OFF;LED1_OFF;break;} }
}

填坑

在使用正点原子例程进行接受数据时,出现的问题
功能概述:MCU之间通过USART2进行数据传输,然后主控芯片又通过USART1向电脑端的串口助手发送数据。
存在问题:在高速数据传输的过程中第一位丢失

原因:printf的问题,重定向时存在问题,导致数据高速传输时,使用printf会导致之后的数据丢失(主控向电脑端传输时)
解决方法:原先用printf发送数据的地方改用USART_SendData发送,在用while等待

while(1){/*====================MCU之间串口通信的数据显示=========================*///功能说明//MCU之间通过USART2进行通信,主控芯片将数据存入缓冲区,并通过串口1发送到电脑端//数组有效数据长度为9if(USART2_RX_STA&0x8000)                                           //如果发送完成{len=(USART2_RX_STA&0x3fff);USART_SendData(USART1,len);//发长度while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);for(i=0;i<len;i++)                //将数据通过串口1发送{USART_SendData(USART1,USART2_RX_BUF[i]);while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);}while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);USART_SendData(USART1,'\r');//插入换行while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);USART_SendData(USART1,'\n');//插入换行while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);USART2_RX_STA=0;}/*==========================================================================*/    }

注意:一定要取一中间变量len,在for循环发送数据时USART2_RX_STA可能会进入中断从而改变数据长度
正点原子串口数据接收的思路:
1.利用缓冲区
2.设置状态变量USART2_RX_STA,低13位表示数据长度,14位表示接收到0x0d,15位表示接收到0x0a(接收完成)(通信协议,发送的数据最后需要加’\r\n’才能接受)

void USART2_IRQHandler(void)                 //串口2中断服务程序
{u8 Res;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){USART_ClearITPendingBit(USART2, USART_IT_RXNE);Res =USART_ReceiveData(USART2);//(USART1->DR);  //读取接收到的数据if((USART2_RX_STA&0x8000)==0)//接收未完成{if(USART2_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART2_RX_STA=0;//接收错误,重新开始else USART2_RX_STA|=0x8000;  //接收完成了 }else //还没收到0X0D{   if(Res==0x0d)USART2_RX_STA|=0x4000;else{USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;USART2_RX_STA++;if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;//接收数据错误,重新开始接收    }      }}}
}

STM32学习——USART收发数据相关推荐

  1. 笔记——STM32串口USART收发数据。

    关于上次的串口内容只是知道怎么用,不晓得什么意思,这次就做个笔记详细的来描述一下.关于STM32有许多通信的协议,其中串口也是常用的通信协议,并且串口用来调试和查看信息非常重要的.包括用到阿里云的云智 ...

  2. STM32的USART发送数据时如何使用TXE和TC标志

    在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register). ...

  3. 【STM32】USART收发---内嵌中断向量控制器

    目录 几个概念: 1.USART初始化 2.USART中断配置---内嵌中断向量控制器 3.一种串口发送格式化数据方法 几个概念: 内嵌向量中断控制器:Nested Vectored Interrup ...

  4. 【32单片机学习】(6)STM32串口+DMA收发不定长数据

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...

  5. 嵌入式学习笔记——STM32的USART通信概述

    文章目录 前言 常用通信协议分类及其特征介绍 通信协议 通信协议分类 1.同步异步通信 2.全双工/半双工/单工 3.现场总线/板级总线 4. 串行/并行通信 5. 有线通信.无线通信 STM32通信 ...

  6. STM32 串口DMA收发(二)

    STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...

  7. STM32学习之串口采用DMA收发数据:需要利用状态机加DMA加串口

    写在前面 在学习这一节知识点的时候,真的是感觉太抽象了,没有一个合适的视频讲的我有那种豁然开朗的感觉,直到我看到了这篇文章,大家可以去看看,里面的描述特别形象. 链接:https://blog.csd ...

  8. STM32学习笔记 | CAN总线收发数据常见问题分析

    关注+星标公众号,不错过精彩内容 CAN,Controller Area Network(控制器局域网络),在汽车电子.工业控制领域的应用比较多,通常用于局域组网. CAN总线和UART.I2C.SP ...

  9. STM32学习——串口数据收发

    STM32学习--串口数据收发 ==STM32的串口通信== ==HAL库中串口发送的重要函数== ==STM32定时器实训== STM32的串口通信   异步串行通信:通信双方在没有同步时钟的前提下 ...

最新文章

  1. python+requests+unittest+excel_接口自动化测试 unittest+request+excel(踩‘坑’)
  2. Echarts 解决饼图文字过长重叠的问题
  3. Service Mesh — Overview
  4. python利用决策树进行特征选择
  5. LeetCode11:Container With Most Water
  6. kvm连接服务器显示不全有重影,KVM延长器系列常见问题及解决方法
  7. Vue实现组件props双向绑定解决方案
  8. 华为云云原生首次在太空验证,提升“天算星座“卫星计算精度
  9. Java BufferedWriter close()方法与示例
  10. asp mysql text_11种ASP连接数据库的方法
  11. 整理: JAVA错误处理集锦
  12. 文件包含漏洞的审计(审计思路)
  13. 【信息系统项目管理师】第12章-项目采购管理 知识点详细整理
  14. Android WorldWind的使用与添加Geoserver影像(一)
  15. 华南农业大学C语言程序设计(实验九)
  16. 淘宝至强cpu为什么那么便宜
  17. win10 win11 创建共享文件夹 mac 苹果电脑共享 无internet 安全,你的电脑只能访问本地网络中的其它设备 共享文件夹会导致本地电脑无法上网,
  18. 4行代码实现微信送祝福,这个新年有点不一样
  19. java中finish什么意思,finish是什么意思(释义详解一览)
  20. linux终端能显示中文,但是不能输入中文的解决方法

热门文章

  1. SpringBoot核心注解@SpringBootApplication一二
  2. 调参1——随机森林贝叶斯调参
  3. DTW(动态时间归整)算法与DTW,fastDTW的python算例
  4. Quartz是一个任务调度
  5. 解开Future的神秘面纱之任务执行
  6. BZOJ 3876 支线剧情
  7. CSS中文乱码解决方法
  8. 多行文本溢出显示省略号(…) text-overflow: ellipsis
  9. 【软件工程】复利计算器--结对编程
  10. 2015 03 03 复习 上课笔记(一)