OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12116|回复: 9

【ALIENTEK 战舰STM32开发板例程系列连载+教学】第九章 串口实验

[复制链接]

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-1-12 17:01:34 | 显示全部楼层 |阅读模式

 第九章 串口实验
    前面两章介绍了STM32IO口操作。这一章我们将学习STM32的串口,教大家如何使用STM32的串口来发送和接收数据。本章将实现如下功能:STM32通过串口和上位机的对话,STM32在收到上位机发过来的字符串后,原原本本的返回给上位机。本章分为如下几个小节:

9.1 STM32串口简介

9.2 硬件设计

9.3 软件设计

9.4 下载验证


9.1 STM32串口简介

       串口作为MCU的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。现在基本上所有的MCU都会带有串口,STM32自然也不例外。

STM32的串口资源相当丰富的,功能也相当强劲。ALIENTEK战舰STM32开发板所使用的STM32F103ZET6最多可提供5路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持LIN、支持调制解调器操作、智能卡协议和IrDA SIR ENDEC规范、具有DMA等。

5.3节对串口有过简单的介绍,接下来我们将从寄存器层面,告诉你如何设置串口,以达到我们最基本的通信功能。本章,我们将实现利用串口1不停的打印信息到电脑上,同时接收从串口发过来的数据,把发送过来的数据直接送回给电脑。战舰STM32开发板板载了1USB串口和1RS232串口,我们本章介绍的是通过USB串口和电脑通信。

串口最基本的设置,就是波特率的设置。STM32的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应IO口的模式,然后配置一下波特率,数据位长度,奇偶校验位等信息,就可以使用了,详见5.3.2节。下面,我们就简单介绍下这几个与串口基本配置直接相关的寄存器。

1,串口时钟使能。串口作为STM32的一个外设,其时钟由外设时钟使能寄存器控制,这里我们使用的串口1是在APB2ENR寄存器的第14位。APB2ENR寄存器在之前已经介绍过了,这里不再介绍。只是说明一点,就是除了串口1的时钟使能在APB2ENR寄存器,其他串口的时钟使能位都在APB1ENR寄存器。

2,串口复位。当外设出现异常的时候可以通过复位寄存器里面的对应位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。串口1的复位是通过配置APB2RSTR寄存器的第14位来实现的。APB2RSTR寄存器的各位描述如图9.1.1所示:


                                                                              
                                                                                     
9.1.1 APB2RSTR寄存器各位描述

从图9.1.1可知串口1的复位设置位在APB2RSTR的第14位。通过向该位写1复位串口1,写0结束复位。其他串口的复位位在APB1RSTR里面。

3,串口波特率设置。在5.3.2节,我们已经介绍过了,每个串口都有一个自己独立的波特率寄存器USART_BRR,通过设置该寄存器就可以达到配置不同波特率的目的。具体实现方法,请参考5.3.2节。

4,串口控制。STM32的每个串口都有3个控制寄存器USART_CR1~3,串口的很多配置都是通过这3个寄存器来设置的。这里我们只要用到USART_CR1就可以实现我们的功能了,该寄存器的各位描述如图9.1.2所示:


9.1.2 USART_CR寄存器各位描述

       该寄存器的高18位没有用到,低14位用于串口的功能设置。UE为串口使能位,通过该位置1,以使能串口。M为字长选择位,当该位为0的时候设置串口为8个字长外加n个停止位,停止位的个数(n)是根据USART_CR2[13:12]位设置来决定的,默认为0PCE为校验使能位,设置为0,则禁止校验,否则使能校验。PS为校验位选择,设置为0则为偶校验,否则为奇校验。TXIE为发送缓冲区空中断使能位,设置该位为1,当USART_SR中的TXE位为1时,将产生串口中断。TCIE为发送完成中断使能位,设置该位为1,当USART_SR中的TC位为1时,将产生串口中断。RXNEIE为接收缓冲区非空中断使能,设置该位为1,当USART_SR中的ORE或者RXNE位为1时,将产生串口中断。TE为发送使能位,设置为1,将开启串口的发送功能。RE为接收使能位,用法同TE

       其他位的设置,这里就不一一列出来了,大家可以参考《STM32参考手册》第542页有详细介绍,在这里我们就不列出来了。

5,数据发送与接收。STM32的发送与接收是通过数据寄存器USART_DR来实现的,这是一个双寄存器,包含了TDRRDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。该寄存器的各位描述如图9.1.3所示:


 

                                                                                           9.1.3 USART_DR寄存器各位描述

可以看出,虽然是一个32位寄存器,但是只用了低9位(DR[80]),其他都是保留。

DR[80]为串口数据,包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能。TDR寄存器提供了内部总线和输出移位寄存器之间的并行接口。RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。

当使能校验位(USART_CR1PCE位被置位)进行发送时,写到MSB的值(根据数据的长度不同,MSB是第7位或者第8)会被后来的校验位该取代。

当使能校验位进行接收时,读到的MSB位是接收到的校验位。

6,串口状态。串口的状态可以通过状态寄存器USART_SR读取。USART_SR的各位描述如图9.1.4所示:



9.1.4 USART_SR寄存器各位描述

这里我们关注一下两个位,第56RXNETC

RXNE(读数据寄存器非空),当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取USART_DR,通过读USART_DR可以将该位清零,也可以向该位写0,直接清除。

TC(发送完成),当该位被置位的时候,表示USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:1)读USART_SR,写USART_DR2)直接向该位写0

通过以上一些寄存器的操作外加一下IO口的配置,我们就可以达到串口最基本的配置了,关于串口更详细的介绍,请参考《STM32参考手册》第516页至548页,通用同步异步收发器一章。

9.2 硬件设计

本实验需要用到的硬件资源有:

1)  指示灯DS0

2)  串口1

串口1之前还没有介绍过,本实验用到的串口1USB串口并没有在PCB上连接在一起,需要通过跳线帽来连接一下。这里我们把P6RXDTXD用跳线帽与PA9PA10连接起来。如图9.2.1所示:



9.2.1 硬件连接图示意图

连接上这里之后,我们在硬件上就设置完成了,可以开始软件设计了。

9.3 软件设计

本章的代码设计,比前两章简单很多,因为我们的串口初始化代码和接收代码就是用我们之前介绍的SYSTEM文件夹下的串口部分的内容。这里我们对代码部分稍作讲解。

打开上一章的TEST工程,然后在SYSTEM组下双击usart.c,我们就可以看到该文件里面的代码,先介绍uart_init函数,该函数代码如下:

//初始化IO 串口1

//pclk2CLK2时钟频率(Mhz)

//bound:波特率

void uart_init(u32 pclk2,u32 bound)

{     

       float temp;

       u16 mantissa;

       u16 fraction;     

       temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV

       mantissa=temp;                           //得到整数部分

       fraction=(temp-mantissa)*16; //得到小数部分   

    mantissa<<=4;

       mantissa+=fraction;

       RCC->APB2ENR|=1<<2;   //使能PORTA口时钟 

       RCC->APB2ENR|=1<<14;  //使能串口时钟

       GPIOA->CRH&=0XFFFFF00F;//IO状态设置

       GPIOA->CRH|=0X000008B0;//IO状态设置

               

       RCC->APB2RSTR|=1<<14;   //复位串口1

       RCC->APB2RSTR&=~(1<<14);//停止复位         

       //波特率设置

      USART1->BRR=mantissa; // 波特率设置  

       USART1->CR1|=0X200C;  //1位停止,无校验位.

#if EN_USART1_RX             //如果使能了接收

       //使能接收中断

       USART1->CR1|=1<<8;    //PE中断使能

       USART1->CR1|=1<<5;    //接收缓冲区非空中断使能             

       MY_NVIC_Init(3,3,USART1_IRQChannel,2);//2,最低优先级

#endif

}

从该代码可以看出,其初始化串口的过程,和我们前面介绍的一致。先计算得到USART1->BRR的内容。然后开始初始化串口引脚,接着把USART1复位,然之后设置波特率和奇偶校验等。

这里需要注意一点,因为我们使用到了串口的中断接收,必须在usart.h里面设置 EN_USART1_RX1(默认设置就是1的) 。该函数才会配置中断使能,以及开启串口1NVIC中断。这里我们把串口1中断放在组2,优先级设置为组2里面的最低。

串口1的中断服务函数USART1_IRQHandler,在5.3.1已经有详细介绍了,这里我们就不再介绍了。

介绍完了这两个函数,我们回到test.c,在test.c里面编写如下代码:

#include "sys.h"

#include "usart.h"         

#include "delay.h" 

#include "led.h"

#include "beep.h"         

#include "key.h"           

int main(void)

{                  

       u16 t;

       u16 len;  

       u16 times=0;                                     

       Stm32_Clock_Init(9);    //系统时钟设置

       uart_init(72,9600);      //串口初始化为9600

       delay_init(72);                  //延时初始化

       LED_Init();               //初始化与LED连接的硬件接口

       BEEP_Init();                //初始化蜂鸣器端口

       KEY_Init();           //初始化与按键连接的硬件接口

      while(1)

       {

              if(USART_RX_STA&0x8000)

              {                                   

                     len=USART_RX_STA&0x3FFF;//得到此次接收到的数据长度

                     printf("\r\n您发送的消息为:\r\n \r\n");

                     for(t=0;t<len;t++)

                     {

                            USART1->DR=USART_RX_BUF[t];

                            while((USART1->SR&0X40)==0);//等待发送结束

                     }

                     printf("\r\n\r\n");//插入换行

                     USART_RX_STA=0;

              }else

              {

                     times++;

                     if(times%5000==0)

                     {

                            printf("\r\n战舰STM32开发板 串口实验\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);  

              }

       }    

}

这段代码比较简单,重点看下以下两句:

USART1->DR=USART_RX_BUF[t];  

while((USART1->SR&0X40)==0);//等待发送结束

第一句,其实就是发送一个字节到串口,通过直接操作寄存器来实现的。第二句呢,就是我们在写了一个字节在USART1->DR之后,要检测这个数据是否已经被发送完成了,通过检测USART1->SR的第6位,是否为1来决定是否可以开始第二个字节的发送。

其他的代码比较简单,我们执行编译之后看看有没有错误,没有错误就可以开始仿真与调试了。整个工程的编译结果如图9.3.1所示:


9.3.1 编译结果

可以看到,编译没有哦任何错误和警告,下面我们可以开始下载验证了。

9.4 下载验证

前面2章实例,我们均介绍了软件仿真,仿真的基本技巧也差不多介绍完了,接下来我们将淡化这部分,因为代码都是经过作者检验,并且全部在ALIENTEK战舰STM32开发板上验证了的,有兴趣的朋友可以自己仿真看看。但是这里要说明几点:

1IO口复用的,信号在逻辑分析窗口是不能显示出来的(看不到波形),这一点请大家注意。比如串口的输出,SPIUSBCAN等。你在仿真的时候在该窗口看不到任何信息。遇到这样的情况,你就不得不准备一个逻辑分析仪,外加一个ULINK或者JTAG来做在线调试。但一般情况,这些都是有现成的例子,不用这几个东西一般也能编出来。

2,仿真并不能代表实际情况。只能从某些方面给你一些启示,告诉你大方向,不能尽信仿真,当然也不能完全没有仿真。比如上面IO口的输出,仿真的时候,其翻转速度可以达到很快,但是实际上STM32IO输出就达不到这个速度。

总之,我们要合理的利用仿真,也不能过于依赖仿真。当仿真解决不了了,可以试试在线调试,在线调试一般都可以知道问题在哪个地方,但是问题要怎么解决还是得各位自己动脑筋、找资料了。

我们把程序下载到战舰STM32开发板,可以看到板子上的DS0开始闪烁,说明程序已经在跑了。串口调试助手,这里我们选择的是SSCOM3.3,是由大虾网版主丁丁(聂小孟)编写,是一个非常好用的串口调试助手。它的优点有:1,绿色,免安装;2,体积小,整个软件才700KB3,支持自动搜索串口;4,支持中文字符收发;5,具有扩展发送功能。以上是一些主要的优点,当然这个软件也有些小bug,比如串口在连接的情况下,如果突然断开,那么程序就死机了,而且无法正常关闭(必须在任务管理器里面强制结束),还有只要该软件打开着,你的电脑就别想关机。不过瑕不掩瑜,该软件总的来说,还是非常适合各位使用的。

接着我们打SSCOM3.3,设置串口为CH340USB串口(根据你自己的电脑选择,我的电脑是COM3),可以看到如图9.4.1所示信息:


                                                                                         9.4.1 串口调试助手收到的信息

从图9.4.1可以看出,STM32的串口数据发送是没问题的了。但是,因为我们在程序上面设置了必须输入回车,串口才认可接收到的数据,所以必须在发送数据后再发送一个回车符,这里SSCOM3.3提供的发送方法是通过勾选发送新行实现,如图9.4.1,只要勾选了这个选项,每次发送数据后,SSCOM3.3都会自动多发一个回车。设置好了发送新行,我们再在发送区输入你想要发送的文字,然后单击发送,可以得到如图9.4.2所示结果:

9.4.2 发送数据后收到的数据

可以看到,我们发送的消息被发送回来了(图中圈圈内)。大家可以试试,如果不发送回车(取消发送新行),在输入内容之后,直接按发送是什么结果。

 

 

实验4 串口实验.rar

28.11 KB, 下载次数: 1347

《STM32开发指南》 第九章 串口实验.rar

685.58 KB, 下载次数: 1354

我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
135
金钱
135
注册时间
2014-1-3
在线时间
0 小时
发表于 2014-9-26 18:50:16 | 显示全部楼层
原子哥,我接上USB转串口的线,PA9 PA10也跳了线,打开串口助手,怎么没有接收呢?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2014-9-26 22:31:01 | 显示全部楼层
回复【2楼】jidian0177:
---------------------------------
用开发板自带的USB_232接么?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

11

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
135
金钱
135
注册时间
2014-1-3
在线时间
0 小时
发表于 2014-9-27 13:13:29 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
是的,接上这个没数据,我又直接将串口线接到PA9 A10上,有数据,但是乱码。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2014-9-27 23:00:57 | 显示全部楼层
回复【4楼】jidian0177:
---------------------------------
接TTL串口才行,RS232不行。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

11

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
135
金钱
135
注册时间
2014-1-3
在线时间
0 小时
发表于 2014-9-28 19:57:08 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
恩,换了就好了。  原子哥,为什么用232接PA9 A10不可以呢?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
 楼主| 发表于 2014-9-28 23:17:17 | 显示全部楼层
回复【6楼】jidian0177:
---------------------------------
因为没连接到RS232上面去。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

11

主题

71

帖子

0

精华

初级会员

Rank: 2

积分
135
金钱
135
注册时间
2014-1-3
在线时间
0 小时
发表于 2014-10-4 19:33:17 | 显示全部楼层
回复【7楼】正点原子:
---------------------------------
哦哦,知道了,谢谢原子哥
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2016-12-16
在线时间
0 小时
发表于 2016-12-16 20:15:05 | 显示全部楼层
原子哥,我用到串口,用的例程就是上面讲的,但是我想发数组,数组里面有0,用printf函数时遇到0就不发后面的数了,不知道怎么解决求教,谢谢
回复 支持 反对

使用道具 举报

23

主题

65

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
255
金钱
255
注册时间
2018-10-21
在线时间
44 小时
发表于 2019-7-12 14:10:34 | 显示全部楼层
捕获1.JPG 捕获2.JPG 第一张图片是你们给的例程,前后发的数据没有相互影响。第二张是我写的串口实验,前后发的数据有影响。你们的例程上我没有看到你们对接受数组的清零。你们怎么做到的?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-10 04:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表