历史上的今天
返回首页

历史上的今天

今天是:2024年09月04日(星期三)

正在发生

2019年09月04日 | stm32串口通信调试总结

2019-09-04 来源:eefocus

本文分为两部分,即”以USART1为例的串口初始化”和“调试中遇到的问题”


以USART1为例的串口初始化

本程序调用了stm32自带的固件库,工程中具体的文件见下图: 

这里写图片描述

一.GPIO及USART1初始化结构体变量定义


GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;


二.串口时钟及GPIO端口时钟使能 

USART1是挂在APB2总线上的外设。 

TX,RX分别是PA9,PA10端口的复用。


TX,RX分别对应PA9,PA10

要使用到端口复用,就要使能端口的时钟,并使能相应外设的时钟。这里可使用|同时使能这两个时钟。


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);


三.TX,RX配置 

GPIO端口模式的配置包括


确定需要配置的引脚

确定端口速度

确定端口工作模式

初始化该引脚

    //USART1 Tx(PA.09) 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //USART1 Rx(PA.10) 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入

    GPIO_Init(GPIOA, &GPIO_InitStructure);


四.串口参数初始化 

以下为默认的参数:


USART_InitStructure.USART_BaudRate = 9600; //波特率

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_Tx | USART_Mode_Rx; //收发模式

USART_Init(USART1, &USART_InitStructure);//初始化USART1

USART_Cmd(USART1, ENABLE); //USART1使能


至此,串口相关的配置已全部完成,接下来可以写串口程序了。


五.串口程序 

这里以stm32与PC通信为例。 

例1.PC向stm32发送一个字符,stm32再将该字符发回去。


while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=SET);//等待PC的消息

order=USART_ReceiveData(USART1);//读取收到的消息

USART_SendData(USART1,order);//发送消息

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待数据发送完


关于两次等待的说明: 

RXNE和TC都是寄存器USART_SR中的位。当寄存器收到消息后,RXNE会置1,此时读取消息可令其清零。当数据发送完成后,TC会置1,此时读取状态可令其清零。


例2.stm32向PC发一个字符串


字符串内容如下:


#define SENDBUF_LEN 23

unsigned char order[SENDBUF_LEN]="0 1 06 1111/1 1 05 2121";


发送程序如下:


for(i=0;i{   

    USART1->SR;//防止首字符丢失

    USART_SendData(USART1,order[i]);

    while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);

}


关于USART1->SR作用的解释: 

stm32在复位时TC位被置1,因此while语句中的内容直接成立,while语句直接跳出,第一个字符还没发送完,寄存器就发送了第二个字符,导致第一个字符被掩盖。解决方法是在发送前先将TC为清零,方法是读USART->SR。由此可知,在发字符串时,一定要先读一次USART->SR,而例1中发一个字符时就不必要了,因为不会有第二个字符来覆盖第一个字符。


调试中遇到的问题

无论PC发什么,stm32都没有回应。调试过程:我把初始化的程序与网上众多程序员写的初始化程序做了比较,没有发现不一样的地方。接着我就怀疑USART_SendData(USART1,order)这句代码中的order的数据类型有问题。这个函数的定义如下:

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)

{

  /* Check the parameters */

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_DATA(Data)); 


  /* Transmit Data */

  USARTx->DR = (Data & (uint16_t)0x01FF);

}


可知Data的数据类型是uint16_t,我就试着把order的数据类型分别改成了char,uint8_t,uint16_t,但问题仍无法解决(实际上,这个数据类型是没有任何影响的)。


值得一提的是,之前我们设置USART1的参数时,一次发送的数据长度设置的是8位USART_InitStructure.USART_WordLength = USART_WordLength_8b;,那么为什么这里写的却是16位的无符号整型呢?看这句话USARTx->DR = (Data & (uint16_t)0x01FF);,可知理论上发送的内容应该是Data的低9位。然而,由于之前设置了数据长度为8位,故实际发送的内容只有低8位。那么为什么Data会&0x01ff呢?其实这多余的一位是用于奇偶校验的,当需要配置奇偶校验时,需要将数据长度设置为9位即USART_InitStructure.USART_WordLength = USART_WordLength_9b;,记住,stm32的数据位是包括奇偶校验位的,而PC上调试助手上的数据位仍需设置为8位,这样互发数据才不会出问题。


回到之前的问题上来——更改完发现仍解决不了问题后,我在程序中加了一个LED闪烁程序,即接收数据之前LED亮,发送完数据后LED灭,结果发现LED始终是亮的。后改成LED先灭后亮,发现LED始终是灭的。故猜想程序卡死在了这两句程序之间,接着怀疑到函数delay_ms()上,接着发现这个由淘宝卖家提供的delay_ms()函数需要先初始化才能使用。(这个延时函数不是简单的for循环延时,比较复杂和精准,初始化函数为delay_init();)由于没有初始化,导致程序死在这条语句上。 

2. stm32发回来的内容与PC发送的内容不一致。调试过程:用示波器观测数据,发现收发的数据都是正确的,但电平宽度不一致,由此得知两者的波特率不一致,进一步计算得知是stm32的串口波特率不对。后发现程序默认的外部高速时钟是8MHz,而我的板子上的晶振是11.0592MHz,故波特率计算错误。解决方法是更改头文件stm32f10x.h中的HSE_VAULE,见下图


 

需要说明的是,博主更改这里后仍不能接受到正确消息,当时我设置的波特率是1200,后来改成9600就正常了。博主没有去深入了解寄存器,只能猜想stm32应该不支持过低的波特率吧。 

3.当stm32向c51发送字符串时,c51接收不到正确的数据。我用示波器看了下PC向c51发送的波形,又看了下stm32向c51发送的波形,发送数据所用时间差不多,所以波特率应该是对的,波形由于太长,每个脉冲太窄,不好观察,看起来也差不多。最后我让stm32把之前发的数据发给PC,发现了问题——那就是之前提到的首字符丢失问题。

推荐阅读

史海拾趣

DBS Microwave Inc公司的发展小趣事

DBS Microwave Inc公司起源于XXXX年,当时由几位志同道合的电子工程师创立。他们共同意识到,随着无线通信技术的飞速发展,微波器件的市场需求将会急剧增长。于是,他们凭借丰富的专业知识和对市场趋势的敏锐洞察,决定专注于研发和生产高质量的微波射频器件。起初,公司面临着资金紧张、市场竞争激烈等诸多挑战,但创始人团队凭借坚韧不拔的精神和对技术的执着追求,逐步在市场上崭露头角。

Crowd Supply公司的发展小趣事

为了适应电子行业的快速发展和变化,Crowd Supply不断投入资源进行技术创新和平台升级。他们推出了一系列新功能,如智能推荐、数据分析等,以帮助项目方更好地了解市场需求和支持者偏好。同时,平台也加强了与供应链和生产商的合作,确保项目的顺利推进和产品的高质量交付。

GAIA Converter Inc公司的发展小趣事

随着全球化进程的加速,锋鸣电子(上海总部)于2015年启动了国际化战略。公司首先在东南亚地区设立生产基地,利用当地的成本优势扩大产能。随后,锋鸣电子积极参加国际展会,拓展海外市场,与多家国际知名企业建立了合作关系。通过国际化战略的实施,锋鸣电子不仅提升了品牌知名度,还实现了销售收入的快速增长。

Densitron公司的发展小趣事

人才是企业发展的关键因素。Densitron公司非常重视人才的培养和团队建设。公司建立了一套完善的人才培养机制,通过内部培训、外部学习等方式,不断提升员工的技能水平和综合素质。同时,公司还注重团队文化建设,鼓励员工之间的协作与交流。这些举措使得Densitron公司拥有一支高素质、高效率的团队,为公司的持续发展提供了有力保障。

DOMINANT公司的发展小趣事

为了进一步提升市场竞争力,统明亮公司在2016年推出了一款新型直角DomiLED产品。这款LED产品具有高光照强度、低热阻等特点,广泛应用于测光照明领域。新型直角DomiLED的推出,不仅丰富了统明亮的产品线,也进一步巩固了其在LED市场的领先地位。这款产品的成功推出,也充分展示了统明亮公司在LED技术创新方面的实力。

Ercona Corp公司的发展小趣事

在LED产业蓬勃发展的背景下,统明亮(DOMINANT)公司在2000年应运而生。它的诞生源于欧司朗(OSRAM)在马六甲工厂的分拆,加上马来西亚财团的加持,这家新公司迅速崭露头角。统明亮公司从成立之初就专注于LED技术的研发和生产,凭借其卓越的技术实力和创新能力,逐渐在电子行业中树立了良好的口碑。经过数年的不懈努力,统明亮在全球贴片式LED领域取得了领先地位,特别是在车用LED封装领域,其产品质量和技术水平均处于行业前列。

问答坊 | AI 解惑

怎用用单片机控制GSM模块实现远程无线控制

大概的思想是:通过现场的检测到的数据,用单片机控制GSM发回到我的服务器上进行数据处理,实现远程的无线监控。现在搞不懂的是除了GSM模块之外是不是还要有另外的一个无线天线之类的东东进行信号的发射?请了解这方面的大侠给我简单讲解一下这个过 ...…

查看全部问答>

单片机IO口出现奇怪现象,求助!

大家好!我用的单片机是C8051F020,我的三个IO口出了问题,设置IO口是漏极开路状态,交叉开关也没问题,没有数字外设。有两个奇怪的现象 一。我写P2=0XFF;,在KEIL中看P2.7始终是0,其它口是1.量单片机P2.7引脚,引脚上也是0V电压,也就是说无法 ...…

查看全部问答>

用什么工具开发wm5.0的应用程序?

vs? 可以用什么语言?  用什么语言比较好?  谢谢…

查看全部问答>

单片机读取usb鼠标数据,并显示坐标

我想用单片机读取鼠标的数据,哪位大侠做过,程序能不接我看看啊。谢谢了。…

查看全部问答>

250元求一套TI 8962开发套件

新手上路求一套 LM3S8962开发套件,套件闲置,有意割爱的朋友请联系我。邮箱:jacmore@163.com 谢谢…

查看全部问答>

【问TI】关于标幺化的困惑,求指点

我准备用28335控制PMSM电机,发现理论和实践有一些脱节,求指点。   1)控制对像有名值模型和标幺化模型的特性是不是一致的?比如零极点位置是不是完全一样。或者换个问法针对有名值模型和标幺化模型设计的补偿器是不是完全一样?   ...…

查看全部问答>

把51单片机红外遥控的程序改成能在Arduino编译环境中运行的程序

我是一个初学者,对于单片机的程序很迷糊,我想用红外遥控来控制一个机器人,板子是Arduino 2009 MEGA168,晶振16M,可是卖家给我的程序只有51单片机的,上面很多库函数 在Arduino的编译环境是没有的,下面是红外遥控的解码程序,烦请各位大神帮忙 ...…

查看全部问答>

求助bdata

我这样定义了一个BDATA,uint bdata port;port^0=P3^5;port^1=P3^6; port^2=P3^7; port^3=P2^6; port^4=P2^7; port^5=P1^6;想用它来操作单片机的端口,可是这样不行,请问我怎样用bdta来操作端口呀?…

查看全部问答>

STM8l最白菜的入门笔记(2)——gpio篇

我们先来观察一下 例程里是怎么操作 gpio的。 我们打开discover这个例程。   我们看到main刚开始的几句就是gpio初始化。 (因为我曾折腾过STM32,所以多少熟一点,一看到这个,我就知道,事情就在这,所以不会再看太多。 ...…

查看全部问答>

基于低功耗的频率计设计

利用MSP430的PWM功能,设计一种可变的频率计,应用于频率发生器  …

查看全部问答>