当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 >
STM32F030 Nucleo-开发调试的经验USART的重要性
时间:2018-08-16作者:华清远见

先声明一点,我自己不是高手,也不是大神,只是积累了一点点,想分享一下罢了!

还记得那会我在初学51单片机时,当得知P89V51系列单片机支持在线仿真、跟踪代码时,那是一个兴奋啊,无论如何都要弄一个来玩玩,进行代码跟踪!

当在开始接触和学习STM32是,那时候知道了J-Link的存在,它出了烧录,也能代码跟踪,单步执行。后有知道了St-Link的存在,它针对意法半导体的MCU作调试和烧录!当然了,还有ST-Link和J-Link的各种针对于STM32的兼容用法。但知道当我开始使用别人的代码进行开发的时候,无可想象,使用J-link或者ST-Link进行在线仿真调试(代码跟踪)显得矫情了!

对于底层的硬件驱动调试来说,使用J-link或者ST-Link进行代码跟踪效果是比较可观的,因为只因为我们可以看到寄存器的值进行逻辑的判断和配置正确与否的判断。当然,也可以在某些特殊的情况的要求下,进行代码的优化,也可以使用。至于其他的情况,自我感觉使用J-Link/ST-Link进行代码跟踪显得很矫情了!

通常一个大的项目或者一个产品项目中,整一个软件程序基本上不可能是同一个人写的,可能同事写的,也有可能是芯片原厂提供的方案,而且各个程序员的风格各异(对于对编程风格有要求的公司,情况可能会好一点,总之有些程序员的程序风格可以叫做惨不忍睹,总之,在调试程序一天,你就会骂他娘一天,直到骂到公司不再使用这个方案或者你辞职,也不知道这类程序员是咋想的,为毛原意让人家骂他娘,他都不愿意修正或者学习一下风格),除了这些还有这项技术的难度、算法的复杂程度等等,所以通常会将软件进行分层,底层就是启动之后硬件驱动了,然后就是与硬件无关的功能代码了(当然,我只是随便举个例子,比如Linux、Android这些程序就分成了好几层,而且非常复杂),还有就是,有些技术是原厂或者方案公司不方便外漏的技术,所以他们所提供的二次开发包SDK通常关键技术已经封装成库,那么使用J-Link/ST-Link来调试跟踪代码已经不现实了,因为在一个项目中我们不可能了解到全部的代码,也不可能去看全部的代码,只因为没有时间。通常可能我们只需要知道自己负责的这部分的逻辑流程和进入接口和向外输出接口即可,也就是说,我们自己只能在小小的空间里面做事,万万不能越界。这时候,UART/USART同步/异步串行口通信将起到了巨大的作用。很简单,只需在其接口Tx和Rx与PC机建立串口通信,使用串口调试助手与其通信(打印或者输入标志到MCU),即可通过串口调试助手的打印现象来进行代码的跟踪。说白了,就是在我们代码的某处(需要的地方)将某些标志或者数据打印出来,既可以轻易的对代码进行跟踪。就可以知道代码的执行逻辑和步骤。我现在这可比J-Link/ST-Link简单多了。

所以,基于这样的一个思想,每当我进行新的硬件代码调试时(不管是自己写驱动还是使用SDK包),只要硬件支持UART/USART,第一件事就是点灯(能够控制GPIO口)和调通UART/USART(以便进行代码的调试),这两点自我觉得是非常重要的。

到这里,基本上经验之谈已经结束,下面就记录一下STM32F030 Nucleo板卡的学习 。

首先,有必要搞清楚几点:

(1)UART和USART之间的区别:

UART:Universal Asynchronous Receiver and Transmitter,通用异步收发器,[Bus Signal] Tx , Rx

51单片机上面的就是这个了,ARM架构的MCU/CPU部分也还支持。

USART:Universal Synchronous Asynchronous Receiver and Transmitter,通用同步异步收发器,[Bus Signal]Tx , Rx , CK

从名字上,就可以看出了,USART比UART高大上多了,只是在UART之上增强了通信协议。

USART支持同步模式,因此USART需要同步信号USART_CK(仔细的观察STM32单片机,就可以发现这样的引脚),通常同步信号通信相对而言是比较少用的,所以通常的调试中,UART和USART的使用方式是一样的,都使用异步模式。

(2)STM32 USART通信的各种模式:

不用多说,我相信看到这个表就一目了然了!

当然,通过MAX485或者RS485等芯片,UART/USART接口可以作为458通信接口。

那么现在就要把牛客板卡的USART1调通,与PC机进行串口通信,

(1)找到使用的USART1引脚。

查看Datasheet,得知如下图:

STM32F030 USATU1的复用第一功能引脚就如上了,其中有GPIOA8作为USART1_CK,同步模式时作为USART同步通信的同步时钟引脚;GPIOA9脚为USART1通信时的发送引脚;GPIOA10脚作为USART1通信时的接收引脚;GPIOA11和GPIOA12引脚作为USART1通信当使用硬件流控时,作为流控控制引脚。然而,在这里咱不玩什么同步模式,也不玩流控,所以只需要配置GPIOA9和GPIOA10引脚即可。

(2)找到牛客板卡的USART1的引脚位置。

查看牛客板卡的用户手册《STM32 Nucleo-64 boards》,找到下图:

(3)在库中找到USART相关的接口。

先确定要调试功能:

打开GPIO时钟和USART1时钟,选择时钟源,配置复用IO模式:

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); //GPIO时钟使能函数

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); //USART1时钟使能函数

void RCC_USARTCLKConfig(uint32_t RCC_USARTCLK);//USART1时钟源选择函数

void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);//IO口复用配置函数。

配置GPIO口:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

USART初始化并启动USART通信:

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);//USART初始化函数

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);//USART使能函数

void USART_ClearFlag(USART_TypeDef* USARTx, uint32_t USART_FLAG);//USART清标志函数

配置中断:

对于USART的接收功能来说,可以使用两种方式,分别是循环检测接收方式和中断方式接收数据,前一种方式会阻塞占用MCU,导致效率低下,而中断方式接收数据则不会阻塞,所以这里使用中断方式接收数据。

void USART_ITConfig(USART_TypeDef* USARTx, uint32_t USART_IT, FunctionalState NewState);//USART中断使能函数

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);//嵌套向量中断控制器初始化配置函数

接收和发送数据:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint32_t USART_FLAG);//获取USART状态标识函数

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);//USART读取数据函数

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);//USART发送数据函数

那么这么多函数是从哪里找的呢??答案是,在keil上搜索得到的,所以这种开发的方式就是,当调试某个功能时,找到与之相关的文件比如:stm32f0xx_usart.c和stm32f0xx_usart.h文件,其由于GPIO相关,又去找stm32f0xx_gpio.c和stm32f0xx_gpio.h文件,其时钟还与RCC相关,就去找stm32f0xx_rcc.c和stm32f0xx_rcc.h文件,又还与NVIC相关,所以又去找stm32f0xx_misc.c和stm32f0xx_misc.h文件。总之就是一句话,它需要什么就给它什么。

还有个问题就是,你咋知道先配置什么,再配置什么的???答案是:其实我也不知道,是参考手册或者编程手册告诉我的,比如下图:

图已经告诉咱数据是怎么传输的了,应该配置啥寄存器等等,那咱不就是知道怎么配置了么》??就是这样的。

(4)配上COMS电平转TTL电平的模块,比如MAX232,MAX3232,RS232,PL2303等。与PC机连接通信。

我用的就是上图这种模块了,连接是:

MCU_Tx---------模块Rx

MCU_Rx---------模块Tx

然后就与PC机连接,再连上串口调试助手。

OK!到这里就还有一点要讲的了!那就是波特率,其实就是单片机或计算机串口通信时的速率。其实在手册当中也给咱讲的一清二楚了,

人家讲的很清楚,还给咱举了例子,如何计算,如何配置。其实如上图的计算过程只是对于玩操作寄存器的人才需要考虑的计算,如果直接用库函数开发,直接指定波特率就好了。

还有就是,普通的通信应该配置成什么呢???三个字“8N1,无奇偶”,啥意思呢??8个数据为,无流控,1个停止位,无奇偶校验,就是这么简单。

且看库的配置结构体:

指定波特率,设置数据位长度8位,1个停止位,无奇偶校验,输入和输出模式,无流控。如下图:

具体初始化如下:

USART初始化:

NVIC初始化:

初始化就如上了。

那么,咱要发送数据哇!所以,咋就写写:

发送一个字节:

发送字符串:

发送十进制数据:

OK!发送的就是这样,没什么好解释的!哈哈!

但是,如果用来进行调试的话,以上方法好像不太给力哦,为毛呢??比如所咱想发送字符串和数据混杂呢》》按照上面的方法,那可得写好几句打印函数呢!嘿嘿!那咱就把ANSI标准C的printf移植过来用吧!肿么玩呢??其实,两步就好:

(1)包含头文件#include

(2)如下图:

这几个意思呢??而且,明眼人一看就能看见,在咱的工程中,压根就没有调用int fputc(int ch, FILE *f)这个函数,只是写在那里了而已,哈哈!其实呢,int fputc(int ch, FILE *f)函数是printf函数开放的一个从硬件读取数据的接口,那么在哪里调用呢??肯定在C标志库调用啦!只是咱看不到罢了。所以,不用管它,写上就好!哈哈!

这样,咱就能在工程中直接使用printf函数了,至于怎么使用,不会的话,自己好好的去学习C吧。

发送数据讲完了,咱就说说接收数据了,我在这里就简单的表示一下,具体的还要看实际应用的需要修改。

首先咱得找到stm32f0xx_it.c文件,然后再文件中任意位置写函数

void USART1_IRQHandler(void)

{

}

那么这个函数名从哪来的呢??又是干啥的呢??

还记得前面提到的在启动文件建立的中断向量表吗?打开startup_stm32f030.s文件,中断向量表如下:

没错,当发生中断时,MCU会:

(1)将现有数据保存在相应寄存器中,即保存现场

(2)跳转到中断向量表中查询发生中断的外设,并找到中断入口地址

(3)执行中断功能

(4)跳出中断,从相应寄存器中读取数据,即恢复现场

中断的过程就是上面这几个了,那么void USART1_IRQHandler(void)函数就是USART1的中断入口地址了,就是这么简单。再多说一点就是,有些人说,看见别人在函数的任意位置填写任意的函数,他就直接成了中断函数了,为毛这里要有ST规定了名字啊???其实我想说,只要你开心,想怎么样都可以;首先,void USART1_IRQHandler(void)函数可以存在于工程中的任意C文件,再就是,如果想自己命名,那就修改一下中断向量表的名字为你想要的名字即可,只要你开心。

OK!实现就如下图了:

上图首先检测USART1读标志,然后读取数据,再然后将其打印出来个咱看,数据是否发送成功。然后情况标志位。在这里只是验证通信的成功。

所以当我们从串口调试助手发送数据后,发送的数据有会在串口调试助手上面打印出来,有点像回显。哈哈!就是这么简单了!

具体的主程序调用如下:

很简单!一直在输出!哈哈!OK了!

这些只是个人调试和理解,如若有误,请谅解!也可以联系我QQ641251565让我也学习学习。


发表评论

全国咨询电话:400-611-6270,双休日及节假日请致电值班手机:15010390966

在线咨询: 曹老师QQ(3337544669), 徐老师QQ(1462495461), 刘老师 QQ(3108687497)

企业培训洽谈专线:010-82600901,院校合作洽谈专线:010-82600350,在线咨询:QQ(248856300)

Copyright 2004-2018 华清远见教育集团 版权所有 ,京ICP备16055225号,京公海网安备11010802025203号