STM32学习——USART收发数据
简介
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收发数据相关推荐
- 笔记——STM32串口USART收发数据。
关于上次的串口内容只是知道怎么用,不晓得什么意思,这次就做个笔记详细的来描述一下.关于STM32有许多通信的协议,其中串口也是常用的通信协议,并且串口用来调试和查看信息非常重要的.包括用到阿里云的云智 ...
- STM32的USART发送数据时如何使用TXE和TC标志
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register). ...
- 【STM32】USART收发---内嵌中断向量控制器
目录 几个概念: 1.USART初始化 2.USART中断配置---内嵌中断向量控制器 3.一种串口发送格式化数据方法 几个概念: 内嵌向量中断控制器:Nested Vectored Interrup ...
- 【32单片机学习】(6)STM32串口+DMA收发不定长数据
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...
- 嵌入式学习笔记——STM32的USART通信概述
文章目录 前言 常用通信协议分类及其特征介绍 通信协议 通信协议分类 1.同步异步通信 2.全双工/半双工/单工 3.现场总线/板级总线 4. 串行/并行通信 5. 有线通信.无线通信 STM32通信 ...
- STM32 串口DMA收发(二)
STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...
- STM32学习之串口采用DMA收发数据:需要利用状态机加DMA加串口
写在前面 在学习这一节知识点的时候,真的是感觉太抽象了,没有一个合适的视频讲的我有那种豁然开朗的感觉,直到我看到了这篇文章,大家可以去看看,里面的描述特别形象. 链接:https://blog.csd ...
- STM32学习笔记 | CAN总线收发数据常见问题分析
关注+星标公众号,不错过精彩内容 CAN,Controller Area Network(控制器局域网络),在汽车电子.工业控制领域的应用比较多,通常用于局域组网. CAN总线和UART.I2C.SP ...
- STM32学习——串口数据收发
STM32学习--串口数据收发 ==STM32的串口通信== ==HAL库中串口发送的重要函数== ==STM32定时器实训== STM32的串口通信 异步串行通信:通信双方在没有同步时钟的前提下 ...
最新文章
- python+requests+unittest+excel_接口自动化测试 unittest+request+excel(踩‘坑’)
- Echarts 解决饼图文字过长重叠的问题
- Service Mesh — Overview
- python利用决策树进行特征选择
- LeetCode11:Container With Most Water
- kvm连接服务器显示不全有重影,KVM延长器系列常见问题及解决方法
- Vue实现组件props双向绑定解决方案
- 华为云云原生首次在太空验证,提升“天算星座“卫星计算精度
- Java BufferedWriter close()方法与示例
- asp mysql text_11种ASP连接数据库的方法
- 整理: JAVA错误处理集锦
- 文件包含漏洞的审计(审计思路)
- 【信息系统项目管理师】第12章-项目采购管理 知识点详细整理
- Android WorldWind的使用与添加Geoserver影像(一)
- 华南农业大学C语言程序设计(实验九)
- 淘宝至强cpu为什么那么便宜
- win10 win11 创建共享文件夹 mac 苹果电脑共享 无internet 安全,你的电脑只能访问本地网络中的其它设备 共享文件夹会导致本地电脑无法上网,
- 4行代码实现微信送祝福,这个新年有点不一样
- java中finish什么意思,finish是什么意思(释义详解一览)
- linux终端能显示中文,但是不能输入中文的解决方法