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

发布者:美好的人生最新更新时间:2017-11-01 来源: 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);

 

}

 

 

//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学习笔记:USART串口的使用

上一篇:stm32独立看门狗和窗口看门狗的区别
下一篇:STM32晶振不起振

推荐阅读最新更新时间:2024-03-16 15:42

stm32串口接收中断触发原理
如果在STM32微控制器的串口通信中,接收中断无法触发,可能有以下几个可能的原因: 1. 串口接收中断未使能:在初始化串口时,可能未正确使能接收中断。请确保在初始化代码中设置了正确的控制寄存器位来使能串口接收中断。例如,使用`USART_ITConfig()`函数或设置相应的寄存器位。 2. 中断优先级设置错误:如果其他中断具有更高的优先级,可能会导致串口接收中断无法触发。请确保正确配置了中断优先级,并确保串口接收中断的优先级高于其他中断。 3. 接收缓冲区溢出:如果接收缓冲区溢出,可能会导致串口接收中断无法触发。确保在接收中断处理函数中及时读取接收数据寄存器,以避免缓冲区溢出。 4. 硬件连接错误:检查串口接收引脚是否正确连接,
[单片机]
<font color='red'>stm32</font><font color='red'>串口</font>接收中断触发原理
stm32关于BOOT0和BOOT1
BOOT0和BOOT1 STM32三种启动模式对应的存储介质均是芯片内置的,它们是: 1)用户闪存 = 芯片内置的Flash。 2)SRAM = 芯片内置的RAM区,就是内存啦。 3)系统存储器 = 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。这个区 域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM区。 在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执 行程序,见下表: BOOT1=x BOOT0=0 从用户闪存启动,这是正常的工作模式。 BOOT1=0 BOOT0=1 从系统存储器启
[单片机]
STM32按键长短按:超强移植性,回调函数按键处理机制
1.1 实验简介 按键长按与按键短按在很多产品中都需要应用到,在我们生活中,例如:手机开关机用到的就是按键长按,手机设置音量用的是按键的短按。在本实验平台的综合实验中,也需要用到按键的长短按,所以,我们很有必要学习如何实现按键的程序设计。 设计按键长短按的思路其实很简单,就是计数原理。假设,定时器定时10ms中断一次,在中断函数中,判断按键是否按下,如果按下,然后统计按键按下的时间长度是多少个10ms,如果按下了100个10ms,则表明长按了1秒;如果按下了300个10ms,表示按下了3秒。 1.2 硬件设计 1) KEY2连接到PA8,稳定按下是低电平,稳定松开是高电平。 2) KEY3连接到PB10,稳定按下
[单片机]
STM32看门狗配置(独立看门狗IWDG和窗口看门狗WWDG)
  stm32自带两个看门狗模块,独立看门狗IWDG和窗口看门狗WWDG。   看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种情况的发生。看门狗的作用就是在一定时间内(通过定时计数器实现)没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号) 。   看门狗主要作用是可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。   具体的实现步骤:开启看门狗,设置减计数的初始值,当计数值达到超时值时,产生MCU复位,此时本来运行的程序终止重新启动单片机(发生了故障)。在使用了看门狗
[单片机]
<font color='red'>STM32</font>看门狗配置(独立看门狗IWDG和窗口看门狗WWDG)
STM32入门学习笔记之温湿度采集实验1
11.1 实验简介 11.1.1 温度采集方案概述 本实验采用三种方式来获取温湿度值,一种是STM32芯片内部自带的温度传感器,一种是基于单总线协议的DS18B20温度传感器,还有一种就是温湿度传感器DHT11或者DHT22,但是在成本上DHT22比较高,所以实验仅使用DHT11,DS18B20和内部温度传感器进行。 11.1.2 单线协议 单总线协议是美国的达拉斯公司推出的一款总线通信协议,所谓单线协议,就是通过一根线传输所有的数据,通俗地讲就是根据低电平的时间来判断总线上的数据是0还是1,比如拉低总线10us,就认为发送的是1,拉低总线50us,就认为发送的是0,单总线协议中,有3种时序,即写时序,读时序和检测时序。我们在
[单片机]
<font color='red'>STM32</font>入门学习笔记之温湿度采集实验1
STM32学习之:GPIO最简单操作步骤
需用到的 .c 库函数为 stm32f10x_gpio.c 和stm32f10x_rcc.c 1. 启动相应Port x的RCC(复位始终控制) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); x可以是A到G , GPIO都由APB2(高速外设)时钟控制 2. GPIO初始结构中的三个参数赋值(该结构名需程序前定义: GPIO_InitTypeDef GPIO_InitStructure; ) 三个参数分别为 引脚:GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_
[单片机]
详解STM32的DMA功能
本文将介绍STM32的DMA功能; ①DMA介绍 ②STM32F4-DMA功能框图及详解 ③DMA的增量设置、模式、中断 ①DMA介绍 DMA是direct memory access的缩写,即直接存储器访问;DMA是通过硬件在RAM和IO设备之间开辟一条通道,使得采集到的数据直接存到RAM,使得数据的传输不需要经过CPU读数据再将数据放入RAM、这样极大提高了CPU的效率。 ②STM32F4-DMA功能框图及详解 外设通道: STM32F4具有2个DMA控制器,每个DMA控制器有8个数据流,每个数据流可以从8个外设请求中选择一个作为该数据流的外设通道;外设通道就是数据流的源地址或者目标地址;外设通道的选择可以通过DMA数
[单片机]
详解<font color='red'>STM32</font>的DMA功能
STM32开发板学习笔记--PWM
使用TIM2在PA0口控制发光二极管的亮度,用接在PA3和PA8脚的按键控制PWM宽度 在网上找了一些例程,对我的帮助很大,弄了一上午,当看到发光二极管的亮度随着按键改变时,这种喜悦感是做其他事情感受不到的,这就是我玩单片机的乐趣所在! 不说废话了,先初始化I/O void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; //PWM输出 GPIO_InitStructure.GPIO_Mode = GPIO
[单片机]
热门资源推荐
热门放大器推荐
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

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

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