STM32F105串口USART3无法发送数据或数据错误问题

发布者:devilcore最新更新时间:2018-08-12 来源: eefocus关键字:STM32F105  串口  USART3  发送数据  数据错误 手机看文章 扫描二维码
随时随地手机看文章

关于STM32系列的例程网上有很多,大部分是103系列,使用USART3,而且都是直接抄袭书上3.0的固件库或者转载别人的,所以很少又遇到类似我的问题,由于我用105系列芯片,开发板上只有USART3引出来重映射PD8、PD9,用的3.5的固件库,所以调试起来特别麻烦,没有可以运行的例子参考,网上down了一下都发现有问题,自己摸索半天终于发现了解决方案,觉得自己应该做出一点事情,为来源社会略尽微薄之力,所以决定开始写技术博客,一定要我自己原创的,发现别人一般发现不了问题的,绝大多数人转载的那种就算了。



其实103和105/107系列差别很小,只在建立工程的时候要稍微设置一下,有空专门写一篇建工程的,总的来说要使105的USART3要注意几个地方:



1.如果没法收发数据,通常情况是执行printf以后,串口助手只显示空字符串,查看HEX是00,首先要检查硬件,做嵌入式最关键的一点是,在怀疑自己代码之前先看硬件有没有连错,很多时候这样可以省不少事情,像我自己就是刚开始板子上面只连出了RXD和TXD,我就很天真地用3根杜邦线,和9针的电脑串口2、3、5连了,忘了还需要MAX232转电平,调代码搞半天浪费了时间没解决真正的问题,后面找到别的板子的MAX232模块,硬件问题解决。



2.这时候还不能收发数据,查了网上大部分资料,跟预期的一样,都是103的USART1,解决不了我的105的USART3,后面发现有人用USART3出现过类似的问题,常见的代码我就不写出来了,只说发现的关键的地方,USART_Configuration()里面我的代码是:


RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);

GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE); //USART3 remap 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); 

通常例子都会把RCC_APB2Periph_AFIO忽略掉,在用到“复用重映射”的时候要先使能AFIO的时钟,包括一些淘宝上信誉很好的开发板的所谓例子,我真心怀疑那些人有没有真正调试过,或者调试过3.0版本的,为何不更新3.5的。其次是GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE)也会有人忽略,重映射必须要这句,最后是开时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE)新手一般会写成APB2,因为是直接COPY过来的,人家用USART1写的APB2当然没错,可是具体用那个USART自己还需要多去琢磨DataSheet到底要怎么设置。



3.这时候数据终于收到了,可是都是乱码,点开HEX,发现每当我发一个byte的数据,它都会显示3个,怎么调试都不对,后面还是发现网上有人同样问题,但是他解决了,最狗日的是他自己说解决了但是不把方案PO出来,你要不回复就算了,反正大家也不知道,既然回复了说自己解决了干嘛不把解决方案放出来,还美滋滋地说自己解决了,太2了这帮人。数据不对多半是波特率的问题,MCU上使用115200波特率,我尝试着降低sscom33串口助手的波特率,发现在38400波特率可以接受到正常数据,印证了网上有个人的说法,用3.5的库设置USART3会出错,直接操作寄存器就好了,有的人说降低波特率,不知道有没有人知道为何?难道真的是3.5的库有问题?


这个时侯要记住,当你要质疑别人的时候,自己先Debug一下,免得成了嘲笑历史的人最终被历史所嘲笑,你要相信那些写STM固件库的人大都是国外名牌大学电子工程/计算机毕业的博士,不是蓝翔的屌丝,固件库都是经过很多压力测试的,很少会出大错,最多是注释有点误导的地方。所以我仔细分析了一下,波特率不对,USART3_Configuration()应该不会出现问题,估计是时钟出现了问题,可是RCC_Configuration()我都是按照固件库函数来的怎么会出错呢?我从stm32f10x_rcc.h源头开始找起,发现默认初始化时钟函数SystemInit()里面有有问题,分频设置当然不会出现问题,问题出在时钟选择上,105/107属于互联网产品,Preprocessor Symbols用的是STM32F10X_CL,固件很多地方会针对这个STM32F10X_CL做出条件编译,其中SystemInit()默认选择外部时钟HSE,HSE的设置值HSE_VALUE在stm32f10x.h中宏定义默认是25MHz,我的板子用的是8MHz晶振,当然那里要改,所以我注释了原来,把8MHz加上。


#if !defined  HSE_VALUE

 #ifdef STM32F10X_CL   

//  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */

  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

 #else 

  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

 #endif /* STM32F10X_CL */

#endif /* HSE_VALUE */

然后继续调试,发现还是不行,始终不对,然后继续跟踪SystemInit()函数,最后找到最终决定设置时钟频率的地方,stm32f10x_rcc.h的SetSysClockTo72(),默认选择最高72MHz,根据自己项目的需要的时钟是需要72MHz还是56MHz去跟踪到底是改SetSysClockTo72()还是改SetSysClockTo56(),在里面的条件编译那里:

#ifdef STM32F10X_CL

#if(0) //chenrunshe 20141127  modify

    /* Configure PLLs ------------------------------------------------------*/

    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

        

    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |

                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |

                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

 

#else

   /* PLL2 configuration: PLL2CLK = (HSE / 2) * 10 = 40 MHz */     //HSE = 8MHz 

    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */  

    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL | 

                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC); 

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV2 | RCC_CFGR2_PLL2MUL10 | 

                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5); 

#endif

即原来默认选择25MHz晶振的用的是上面的PLL分频设置,但是实际项目用了8MHz,就要改相应的寄存器设置,反正最后要实现8MHz*9倍分频=72MHz才是标准的,于是我也条件编译一下#if(0)把原来的注释掉,改自己的,这时候最好写上修改信息,涉及到改固件库的,免得后来的人用你的工程文件出问题可以找到原来你修改过这里。修改完以后基本时钟正确了,再来回答之前那个疑问,其实固件库也没有错,网友说的直接改寄存器不用固件库也没有错,但是不能因为改寄存器对就能判断固件库错,其实大家都没错,是你自己错了而已,狗日天杀的谁不按默认晶振设计板子,非得搞跟人家默认不一样,又不标明出来,无语了。


关键字:STM32F105  串口  USART3  发送数据  数据错误 引用地址:STM32F105串口USART3无法发送数据或数据错误问题

上一篇:STM32 USART串口初始化
下一篇:Keil开发STM32更换MCU造成的编译不通过的解决办法

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

ARM中断方式串口编程
串口编程(UART0)之中断方式 --------------------------------------------------------- from :blog.csdn.net/tigerjb Email :jibo.tiger@gmail.com --------------------------------------------------------- 三. 中断方式的串口编程 1.用中断方式编写串口程序由那几部分组成 2.硬件上的支持 1 UART0 发送FIFO缓冲区 A. UART0含有1个16字节的发送FIFO缓冲区 B. U0T
[单片机]
ARM中断方式<font color='red'>串口</font>编程
STM32串口USART2程序
简介:对控制LED指示灯的IO口进行了初始化,将端口配置为推挽上拉输出,口线速度为50Mhz。PA2,PA2端口复用为串口2的TX,RX。在配置某个口线时,首先应对它所在的端口的时钟进行使能。否则无法配置成功,由于用到了端口B, 因此要对这个端口的时钟。进行使能,同时由于用到复用IO口功能用于配置串口。因此还要使能AFIO(复用功能IO)时钟。 原理图: 程序分析: int main(void) { uint8_t a=0; /* System Clocks Configuration */ RCC_Configuration();//系统时钟设置 /*嵌套向量中断控制器 说明了U
[单片机]
STM32<font color='red'>串口</font>USART2程序
STM32如何高效接收串口数据
硬件:stm32f103cbt6 软件:STM32F10x_StdPeriph_Lib_V3.5.0 DMA,直接内存存取,可以用它的双手释放CPU的灵魂,所以,本文通过USART3进行串口收发,接受使用DMA的方式,无需CPU进行干预,当接受完成之后,数据可以直接从内存的缓冲区读取,从而减少了CPU的压力。 具体的代码实现如下: usart_driver.h 封装了接口,数据接收回调函数类型,基本数据结构等; usart_driver.c 函数原型实现,中断服务函数实现等; 拷贝这两个文件即可,可以根据目录下的参考用例,进行初始化。 头文件usart_driver.h已经声明了外部函数可能用到的接口; USART3_DR的
[单片机]
STM32如何高效接收<font color='red'>串口</font><font color='red'>数据</font>
STM32输出调试信息-printf重定向到串口
在STM32调试过程中常常需要将调试信息输出到串口,然后通过串口助手查看输出的调试信息。一般来说,串口输出的是指定长度的十六进制字节,对于想打印的调试信息来 说,略显灵活性不足。这时候如果可以将printf重定向到串口输出,则能很好的解决这个问题。 关于printf重定向的方法有很多种,这里只讨论一种我认为相对简单实用的方法。其主要方法步骤如下: 1、配置STM32的串口,确保STM32能输出数据到串口调试助手。 void USART5_Init(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
[单片机]
高速串行数据通信发送芯片CY7B923的原理及应用
    摘要: 文章介绍了CYPRESS半导体公司推出的一种用于点对点之间高速串行数据通信的发送芯片CY7B923的原理及应用。较详细的介绍了CY7B923的管脚功能、内部组成、工作原理及工作方式。同时给出了一个实际电路来说明其具体的应用方法。     关键词: 串行数据通信 CY7B923 IDT7200 基带传输 差分PECL输出 1 概述 CY7B923是CYPRESS半导体公司推出的一种用于点对点之间高速串行数据通信的发送芯片。CY7B923采用的是基带传输通信方式,并支持带电插拔(热接插)。其内部电路主要包括时钟产生器、输入寄存器、编码器、移位寄存器、三对差分PECL输出对以及测试逻辑等。该芯片
[应用]
51单片机串口问题
51单片机的串口,是个全双工的串口,发送数据的同时,还可以接收数据。 当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。 无论 RI 或 TI 出现了 1,只要串口中断处于开放状态,单片机都会进入串口中断处理程序。 在中断程序中,要区分出来究竟是发送引起的中断,还是接收引起的中断,然后分别进行处理。 看到过一些书籍和文章,在串口收、发数据的处理方法上,很多人都有不妥之处。 接收数据时,基本上都是使用 中断方式 ,这是正确合理的。 即:每当收到一个新数据,就在中断函数中,把 RI 清零,并用一个变量,通知主函数,收到了新数据。 发送数据时,很多的程序都是使用的 查询方式 ,就是执行 while(T
[单片机]
STM32基础9--串口通信(UART)
UART传输方式 UART(Universal Asynchronous Receiver Transmitter),异步串口没有时钟信号,也没有硬件控制流信号。只有Tx(串行输出信号)与Rx(串行输入信号)。 在STM32F407中,串口数据传输有两种方式:阻塞与非阻塞。 1)阻塞:轮询的方式,就是发送缓冲器的数据,直到数据传输完成或者超时后,函数才返回; 2)非阻塞:启动发送缓冲区数据后,立即返回,传输完成后可以触发中断。 注:在51单片机中的UART通方式类似,也是通常使用阻塞发送数据, 而非阻塞通常用来接收数据。 PC端与STM32进行串口通讯 在当前的PC(个人电脑),基本上已将不支持串口了。因此需
[单片机]
STM32基础9--<font color='red'>串口</font>通信(UART)
51单片机IO口模拟串口通讯6
/*************************************************************** *模拟接收程序,这个程序的作用从模拟串口接收数据,然后将这些数据发送到实际串口 *在单片机上模拟了一个串口,使用P3.2作为发送和接收端 *以P3.2模拟串口接收端,从模拟串口接收数据发至串口 *本程序来源于《单片机IO口模拟串口程序(发送+接收)》 *硬件环境:11.0592MHz, RXD P3.2 ***************************************************************/ #include reg51.h #include stdio.h
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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