STM32学习笔记(7):USART串口的使用

发布者:朱颜素韵最新更新时间:2015-10-23 来源: eefocus关键字:STM32  学习笔记  USART串口 手机看文章 扫描二维码
随时随地手机看文章
1.     串口的基本概念
 
在STM32的参考手册中,串口被描述成通用同步异步收发器(USART),它提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互联网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。还可以使用DMA方式,实现高速数据通信。
 
USART通过3个引脚与其他设备连接在一起,任何USART双向通信至少需要2个引脚:接受数据输入(RX)和发送数据输出(TX)。
 
RX: 接受数据串行输入。通过过采样技术来区别数据和噪音,从而恢复数据。
 
TX: 发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
 
 
 
2.     串口的如何工作的
 
一般有两种方式:查询和中断。
 
(1)查询:串口程序不断地循环查询,看看当前有没有数据要它传送。如果有,就帮助传送(可以从PC到STM32板子,也可以从STM32板子到PC)。
 
(2)中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着要它帮助传输数据——它就马上进行数据的传送。同样,可以从 PC到STM3板子,也可以从STM32板子到PC。
 
 
 
3.     串口的硬件连接
 
我用的奋斗STM32 V3开发板拥有二路RS-232 接口,CPU 的PA9-US1-TX(P68)、PA10-US1-RX(P69)、PA9-US2-TX(P25)、PA10-US2-RX(P26)通过MAX3232 实现两路RS-232 接口,分别连接在XS5 和XS17 接口上。  USART1 在系统存储区启动模式下,将通过该口通过PC对板上的CPU进行ISP,该口也可作为普通串口功能使用,JP3,JP4 的短路冒拔去,将断开第二路的RS232通信,仅作为TTL 通信通道。
 
 
 
4.     编程实例
 
我们要对串口进行操作,首先要将STM32的串口和CPU进行连接。在Windows操作系统中,有一个自带的系统软件叫“超级终端”。VISTA以上的操作系统去掉了这个软件,不过可以从XP的系统中,复制“hypertrm.dll”和“hypertrm.exe”到“windows/system32”文件夹下,然后双击运行hypertrm.exe,就可以看见超级终端的运行界面了。
 
运行超级终端以后,会弹出“连接描述”,输入名称和选择图标,这个地方随便写个什么名称都可以。然后弹出“连接到”设置,在“连接时使用”选择你自己PC和STM32连接的COMx,如果不知道是哪个COM口的话,可以在PC的设备管理器中找到。在选择好COM口之后,会弹出一个“属性”对话框,在“位/秒”选择和你STM32中设置的波特率一致就好,数据位也是按照STM32的设置来选择,奇偶校验选择无,停止位选择1,数据流控制选择无。注意,以上的选项都必须和STM32中的串口设置相匹配,要不然可能会出现一些未知错误。
 
配置好超级终端之后,我们便可以开始对STM32进行编程了。编程一般按照如下步骤进行:
 
(1)       RCC配置;
 
(2)       GPIO配置;
 
(3)       USART配置;
 
(4)       NVIC配置;
 
(5)       发送/接收数据。
 
在RCC配置中,我们除了常规的时钟设置以外,要记得打开USART相对应的IO口时钟,USART时钟,还有管脚功能复用时钟。
 
在GPIO配置中,将发送端的管脚配置为复用推挽输出,将接收端的管脚配置为浮空输入。
 
在USART的配置中,通过USART_InitTypeDef结构体对USART进行初始化操作,按照自己所需的功能配置好就可以了。注意,在超级终端的设置中,需要和这个里面的配置相对应。由于我是采用中断接收数据的方式,所以记得在USART的配置中药打开串口的中断,同时最后还要打开串口。
 
在NVIC的配置中,主要是USART1_IRQChannel的配置,和以前的笔记中讲述的中断配置类似,不会配置的可以参考以前的笔记。
 
全部配置好之后就可以开始发送/接收数据了。发送数据用USART_SendData()函数,接收数据用USART_ReceiveData()函数。具体的函数功能可以参考固件库的参考文件。根据USART的配置,在发送和接收时,都是采用的8bits一帧来进行的,因此,在发送的时候,先开辟一个缓存区,将需要发送的数据送入缓存区,然后再将缓存区中的数据发送出去,在接收的时候,同样也是先接收到缓存区中,然后再进行相应的操作。
 
注意在对数据进行发送和接收的时候,要检查USART的状态,只有等到数据发送或接收完毕之后才能进行下一帧数据的发送或接收。采用USART_GetFlagStatus()函数。
 
同时还要注意的是,在发送数据的最开始,需要清除一下USART的标志位,否则,第1位数据会丢失。因为在硬件复位之后,USART的状态位TC是置位的。当包含有数据的一帧发送完成之后,由硬件将该位置位。只要当USART的状态位TC是置位的时候,就可以进行数据的发送。然后TC位的置零则是通过软件序列来清除的,具体的步骤是“先读USART_SR,然后写入USART_DR”,只有这样才能够清除标志位TC,但是在发送第一帧数据的时候,并没有进行读USART_SR的操作,而是直接进行写操作,因此TC标志位并没有清空,那么,当发送第一帧数据,然后用USART_GetFlagStatus()检测状态时返回的是已经发送完毕(因为TC位是置1的),所以程序会马上发送下一帧数据,那么这样,第一帧数据就被第二帧数据给覆盖了,所以看不到第一帧数据的发送。
 
按照上面的方法编程后,我们便可以在超级终端上查看串口通信的具体状态了。我的这个例程,在硬件复位以后,可以马上在超级终端上看见“Welcome to my STM32! Please press any key!”字样,然后如果在超级终端中通过PC机键盘按下相应的键,则这个键会发送到STM32中,并且马上返回到PC机的超级终端上,因此可以马上从超级终端的页面中看到按下的相应的键。
 
 
 
5.     程序源代码
 
 
 
#include "stm32f10x_lib.h"
 
 
 
FlagStatus RX_status;
 
 
 
void RCC_cfg();
 
void GPIO_cfg();
 
void USART_cfg();
 
void NVIC_cfg();
 
 
 
 
 
 
 
int main()
 
{
 
       int i;
 
       unsigned char TxBuf1[] = "Welcome to my STM32! Please press any key!";
 
       RCC_cfg();
 
       GPIO_cfg();
 
       NVIC_cfg();
 
       USART_cfg();
 
 
 
       //清除标志位,否则第1位数据会丢失
 
       USART_ClearFlag(USART1,USART_FLAG_TC);
 
 
 
       //发送数据
 
       //PB5的作用是显示正在发送数据
 
       //当有数据在发送的时候,PB5会亮
 
       for( i=0;TxBuf1[i]!='';i++)
 
       {
 
              USART_SendData(USART1,TxBuf1[i]);
 
              GPIO_SetBits(GPIOB,GPIO_Pin_5);
 
              //等待数据发送完毕
 
              while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
 
              GPIO_ResetBits(GPIOB,GPIO_Pin_5);
 
       }
 
 
 
       while(1);
 
 
 
}
 
[page]
 
 
 
//RCC时钟配置
 
void RCC_cfg()
 
{
 
       //定义错误状态变量
 
       ErrorStatus HSEStartUpStatus;
 
      
 
       //将RCC寄存器重新设置为默认值
 
       RCC_DeInit();
 
 
 
       //打开外部高速时钟晶振
 
       RCC_HSEConfig(RCC_HSE_ON);
 
 
 
       //等待外部高速时钟晶振工作
 
       HSEStartUpStatus = RCC_WaitForHSEStartUp();
 
       if(HSEStartUpStatus == SUCCESS)
 
       {
 
              //设置AHB时钟(HCLK)为系统时钟
 
              RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
 
 
              //设置高速AHB时钟(APB2)为HCLK时钟
 
              RCC_PCLK2Config(RCC_HCLK_Div1);
 
 
 
              //设置低速AHB时钟(APB1)为HCLK的2分频
 
              RCC_PCLK1Config(RCC_HCLK_Div2);
 
             
 
              //设置FLASH代码延时
 
              FLASH_SetLatency(FLASH_Latency_2);
 
 
 
              //使能预取指缓存
 
              FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
 
 
 
              //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz
 
              RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
 
 
 
              //使能PLL
 
              RCC_PLLCmd(ENABLE);
 
 
 
              //等待PLL准备就绪
 
              while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
 
 
 
              //设置PLL为系统时钟源
 
              RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 
 
 
              //判断PLL是否是系统时钟
 
              while(RCC_GetSYSCLKSource() != 0x08);
 
       }
 
         //打开GPIO时钟,复用功能,串口1的时钟
 
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
 
}
 
 
 
//IO口配置
 
void GPIO_cfg()
 
{
 
       GPIO_InitTypeDef GPIO_InitStructure;
 
 
 
       //PA9作为US1的TX端,打开复用,负责发送数据
 
       GPIO_StructInit(&GPIO_InitStructure);
 
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 
       GPIO_Init(GPIOA , &GPIO_InitStructure);
 
 
 
       //PA10作为US1的RX端,负责接收数据
 
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
 
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
 
       GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 
 
       //LED显示串口正在发送/接收数据
 
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
 
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
 
       GPIO_Init(GPIOB, &GPIO_InitStructure);
 
}
 
 
 
//串口初始化
 
void USART_cfg()
 
{
 
       USART_InitTypeDef USART_InitStructure;
 
       //将结构体设置为缺省状态
 
       USART_StructInit(&USART_InitStructure);
 
    //波特率设置为115200
 
       USART_InitStructure.USART_BaudRate = 115200;
 
       //一帧数据的宽度设置为8bits
 
       USART_InitStructure.USART_WordLength = USART_WordLength_8b;
 
       //在帧结尾传输1个停止位
 
       USART_InitStructure.USART_StopBits = USART_StopBits_1;
 
       //奇偶失能模式,无奇偶校验
 
       USART_InitStructure.USART_Parity = USART_Parity_No;
 
       //发送/接收使能
 
       USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 
       //硬件流控制失能
 
       USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
 
       //设置串口1
 
       USART_Init(USART1, &USART_InitStructure);
 
      
 
       //打开串口1的中断响应函数
 
       USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
 
 
 
       //打开串口1
 
       USART_Cmd(USART1, ENABLE);
 
}
 
 
 
//配置中断
 
void NVIC_cfg()
 
{
 
        NVIC_InitTypeDef NVIC_InitStructure;
 
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                               //选择中断分组2
 
        
 
        
 
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;                              //选择串口1中断
 
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;                                 //抢占式中断优先级设置为0
 
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                                            //响应式中断优先级设置为0
 
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                 //使能中断
 
        NVIC_Init(&NVIC_InitStructure);
 
}
 
 
 
 
 
然后在stm32f10x_it.c文件中找到相应的中断处理函数,并填入一下内容。注意在stm32f10x_it.c中,要声明一下外部变量RX_status
 
 
 
extern FlagStatus RX_status;
 
 
 
void USART1_IRQHandler(void)
 
{
 
      
 
       GPIO_SetBits(GPIOB, GPIO_Pin_5);
 
 
 
       //确认是否接收到数据
 
       RX_status = USART_GetFlagStatus(USART1, USART_FLAG_RXNE);
 
       //接收到数据
 
       if(RX_status == SET)
 
       {
 
              //将数据回送至超级终端
 
              USART_SendData(USART1, USART_ReceiveData(USART1));
 
              //等待数据发送完毕
 
              while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
 
              GPIO_ResetBits(GPIOB, GPIO_Pin_5);
 
       }
 
 
 
 
 
}
 
关键字:STM32  学习笔记  USART串口 引用地址:STM32学习笔记(7):USART串口的使用

上一篇:STM32F407VG IO位操作
下一篇:CS5550读写程序

推荐阅读最新更新时间:2024-03-16 14:37

ARM9学习笔记之——汇编
ARM系列芯片与PC系列(可能我说法不太准确)芯片在指令设计上就有本质的区别。ARM中每条指令是精简指令集要么是32位,要么是16位。而PC的指令是复杂指令集,一条指令可以由多个字节组成。 在写ARM汇编程序时,发现ARM的指令非常的灵活,同样一个功能可以使用多种方式实现。给开发者更多DIY的地方。以下是一些小总结,如有不正确的地方欢迎指正。 1. 关于函数调用方法 在ARM汇编中,函数调用非常灵活。 (1)BL指令 bl initmem ;调用 mem .... mov pc , lr ;返回 BL指令在编译时,是以当前指令地址为基准相对跳转
[单片机]
STM32—DMA使用
DMA简介   DMA:Direct memory access controller,直接存储器存储。DMA可以实现数据在外设与存储器、存储器与存储器之间的快速转换,且不需要CPU的干预,这样就可以释放CPU的资源,让CPU干其他的事情,提高效率。有的STM32芯片有两个DMA,有的就只有一个DMA,这个要查具体的芯片手册。 DMA 的主要特性 DMA的功能框图 DMA参数与函数解析 上一篇文章(链接)中利用USART DMA 实现接收任意长度数据,下面分析下DMA里面的参数和函数。首先查看DMA的结构体定义。 DMA_HandleTypeDef hdma_usart1_rx; * @bri
[单片机]
<font color='red'>STM32</font>—DMA使用
MSP430F5438学习笔记 basic io
1.熟悉MSP430的时钟系统 2.操作GPIO // 时钟默认情况 // FLL时钟 FLL选择 XT1 // 辅助时钟 ACLK选择 XT1 32768Hz // 主系统时钟 MCLK选择 DCOCLKDIV 1048576Hz // 子系统时钟 SMCLK选择 DCOCLKDIV 1048576Hz // 请如果XT1启动失败,ACLK自动切换到REFO, // FLL自动切换到REFO // XT1启动失败的情况,未初始化P7.0和P7.1外设功能 #include msp430.h int main(void) { WDT
[单片机]
STM32串口的使用
1、为什么要用串口? 自上一篇写的时间是1月20号,今6月7号了,半年没更新了。 这半年发生了什么?过完年就去找公司实习,在那里自我感觉进步很大。其实在公司大多都是自学,师傅基本不会给你说什么。但这并不能说明你的师傅对你不好,带我的那个师傅只比我高一届,但他的水平比我高的好多届。他也是自学,也没人告诉他该怎么做,因为老板也不太懂。所以自学能力很重要,当然有人带你的话,这样会更好。 不说这些了,串口在调试的时候作用非常大。也学我们在学51的时候,只是将程序下载到开发板,看看是否能运行起来,通过数码管将结果显示出来,从而就知道程序设计的正确性。以前我也是这样做的,没什么不好。 在公司实习的时候,他们调试都是使用串口打印输出
[单片机]
<font color='red'>STM32</font>之<font color='red'>串口</font>的使用
STM32开发笔记8: STM32CubeF0介绍
单片机型号:STM32CubeF0 本文介绍 STM32CubeF0。 STM32CubeF0 gathers, in a single package, all the generic embedded software components required to develop an application on STM32F0 microcontrollers. In line with the STMCube™ initiative(首创), this set of components is highly portable, not only within STM32F0 Series but al
[单片机]
<font color='red'>STM32</font>开发<font color='red'>笔记</font>8: STM32CubeF0介绍
stm32的可编程电压检测PVD
配置PVD的顺序如: 注意一般使能PVD在系统初始化完毕开启。 /** * @brief Configures EXTI Lines. * @param None * @retval None */ static void EXTI_Configuration(void) { EXTI_InitTypeDef EXTI_InitStructure; /* Configure EXTI Line16(PVD Output) to generate an interrupt on rising and falling edges */ EXTI_ClearITPendingBit(EXTI_Line16
[单片机]
STM32的USB多包数据传送
因为我看到STM32的USB都没有对发送状态进行检测,当多于传送缓冲器的数据要传送时,估计就会出错了,所以找下这篇文章,但没有找到原始作者,但也在此谢过了! STM32的多包数据传送(转贴) SMT32F103,根据例程 Custom_HID 修改,利用 EP1 以 EP_INTERRUPT 的方式发送包, 原来的例程每次发送 2 个字节,现在修改后包的长度不超过 64 字节时发送是正常的,但当 一个包长超过 64 字节时就发送失败,没有数据出来(程序没有死机),该改的地方都已经修 改了,不知道哪个地方还没有改到位,谢谢! 现 象 就 是 超 过 63 字 节 的 包 死 活 也 发 不 出 去 , 而 且 发 送 包
[单片机]
STM32硬件IIC操作解析
  IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。   I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。   为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或
[单片机]
<font color='red'>STM32</font>硬件IIC操作解析
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved