STM32库函数void USART_SendData的缺陷和解决方法

发布者:荒火最新更新时间:2017-01-04 来源: eefocus关键字:STM32  库函数 手机看文章 扫描二维码
随时随地手机看文章

问题及现象(STM32F103系列http://www.y-ec.com/cpcp/class/?32.html

使用USART_SendData()函数非连续发送单个字符是没有问题的;当连续发送字符时(两个字符间没有延时),就会发现发送缓冲区有溢出现象。若发送的数据量很小时,此时串口发送的只是最后一个字符,当发送数据量大时,就会导致发送的数据莫名其妙的丢失。

如:

      for(TxCounter = 0;TxCounter < RxCounter; TxCounter++)

      USART_SendData(USART1, RxBuffer[TxCounter]);

原因

此API函数不完善,函数体内部没有一个判断一个字符是否发送完毕的语句,而是把数据直接放入发送缓冲区,当连续发送数据时,由于发送移位寄存器的速度限制(与通信波特率有关),导致发送缓冲区的数据溢出,老的数据还未及时发送出去,新的数据又把发送缓冲区的老数据覆盖了。

解决方法(目前总结的两种方案)

方案1. 加入延时函数(下下策),不需要修改USART_SendData()函数

      for(TxCounter = 0;TxCounter < RxCounter; TxCounter++)

{

              USART_SendData(USART1, RxBuffer[TxCounter]);

              DelayMS(2); //加入一个小的延时

}

方案2. 修改USART_SendData()函数,在其内部加入发送缓冲区的USART_FLAG_TXE状态检测语句,确保一个字符完全发送出去,才进行下一个字符的发送。

实现方法:每发送一个字符都检测状态寄存器,确保数据已经发送完毕。具体操作步骤如下所示。

修改前的函数定义体

void USART_SendData(USART_TypeDef* USARTx, u16 Data)

{

 

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_DATA(Data));

   

 

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

}

修改后的函数定义体

void USART_SendData(USART_TypeDef* USARTx, u16 Data)

{

  assert_param(IS_USART_ALL_PERIPH(USARTx));

  assert_param(IS_USART_DATA(Data)); 

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

  while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符

}

方案3. 不修改原来的库函数,在每一个字符发送后检测状态位。

USART_SendData(USART1, RxBuffer[TxCounter]);

while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符 

ST这么做的原因是:使用发送中断功能。

STM32(Cortex-M3)中的优先级概念

STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。

具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。 

当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。

既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:

所有8位用于指定响应优先级

最高1位用于指定抢占式优先级,最低7位用于指定响应优先级

最高2位用于指定抢占式优先级,最低6位用于指定响应优先级

最高3位用于指定抢占式优先级,最低5位用于指定响应优先级

最高4位用于指定抢占式优先级,最低4位用于指定响应优先级

最高5位用于指定抢占式优先级,最低3位用于指定响应优先级

最高6位用于指定抢占式优先级,最低2位用于指定响应优先级

最高7位用于指定抢占式优先级,最低1位用于指定响应优先级

这就是优先级分组的概念。--------------------------------------------------------------------------------
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:

第0组:所有4位用于指定响应优先级

第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级

第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级

第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级

第4组:所有4位用于指定抢占式优先级

可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:

NVIC_PriorityGroup_0 => 选择第0组

NVIC_PriorityGroup_1 => 选择第1组

NVIC_PriorityGroup_2 => 选择第2组

NVIC_PriorityGroup_3 => 选择第3组

NVIC_PriorityGroup_4 => 选择第4组

接下来就是指定中断源的优先级,下面以一个简单的例子说明如何指定中断源的抢占式优先级和响应优先级:

// 选择使用优先级分组第1组

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

// 使能EXTI0中断

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

// 使能EXTI9_5中断

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

--------------------------------------------------------------------------------
要注意的几点是:(STM32F101系列:http://www.y-ec.com/cpcp/class/?31.html

1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;

2)抢占式优先级别相同的中断源之间没有嵌套关系;

3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。

通信方式

通信方式多种多样,可以从不同的角度划分,按照数据流的组织方式分为并行通信和串行通信;按照传输信号频率范围分为基带传输和宽带传输;按照信息同时传输的方向分为单工通信、半双工和全双工通信三种;按照通信两端通信的同步方式分为异步通信和同步通信

4.2.1  同步和异步通信

所谓同步是指接收端要按照发送端所发送的每个数据的起止时间和重复频率来接收数据,既收发双方在时间上必须一致.数据传输的同步方式有异步传输与同步传输两种。

同步和异步通信区分重点:是否要解决时钟合拍问题

1、异步通信

异步传输是以字符为单位的数据传输,每个字符都要附加1位起始位和l位停止位以标记一个字符的开始和结束。此外,还要附加1位寄偶校验位,可以选择奇校验或偶校验方式对该字符实施简单的差错控制。一个字符占用5~8位,具体取决于数据所采用的字符集。例如,电报码字符为5位、ASCll码字符为7位、汉字码则为8位。起始位和停止位结合起来,便可实现字符的同步。

发送端与接收端除了采用相同的数据格式(字符的位数、停止位的位数、有无核验位及校验方式等)外,还必须采用相同的传输速率。典型的速率有: 1200、2400、4800、9600和19200 b/s等。

异步传输又称为起止式异步通信方式。其优点是简单、可靠,常用于面向字符的、低速的异步通信场合。例如,主计算机与终端之间的交互式通信通常采用这种方式。

2、同步通信

同步传输是以数据块为单位的数据传输。每个数据块的头部和尾部都要附加一个特殊的字符或比特序列,标记一个数据块的开始和结束,一般还要附加一个校验序列(如16位或32位CRC校验码),以便对数据块进行差错控制。根据同步通信规程,同步传输又分为面向字符的同步传输和面向位流的同步传输。 

4.2.2  基带传输与频带传输 

基带传输:基带传输是指在线路上直接传输基带信号或略加整形后进行的传输。基带是原始信号所占用的基本频带,当终端把数字,信息转换为适合于传送的电信号时,这个电信号所固有的频带即为基带使用单路数字信号,信号可双向传输。数字信号的基带传输就是以原来的“0”和“1”的形式直接用数字信号在信道上传输。这是一种最简单的传输方式,一般在微机通信中采用。

频带传输:当进行远距离通信时,往往将数字数据转换成模拟信号后传输,在接收端再进行信号的恢复,当调制成频率信号的频率范围在音频范围(200Hz—3.4 kHz)内时,这种传输方式称为频带传输。其频率范围比音频范围宽时,则称之为宽带传输。 

4.2.3  单工与双工通信

一个通信系统至少应含有三部分:发送设备、传输介质、接收设备。其中发送设备用于产生数据,并通过传输介质将数据传送给接收设备,以完成两点之间的数据传送。按照数据传输方向及其时间关系可分为:

l         单工(传呼机、有线电视)

l         半双工(对讲机)

l         双工通信(电话) 

(一)  单工通信

在单工通信中,发送设备和接收设备之间只有一个传输通道,数据单方向的从发送端到接收端,传输通道的方向不能改变。计算机和输出设备之间的通信大多采用单工通信方式。例如,计算机与打印机、计算机与显示器等。该方式的特点是设备简单、造价低,但传输效率也低。

图4.2.3-1  单工通信

(二)  全双工通信

在全双工通信中,两个设备之间有两个传输通道,并且可同时双向传送数据。相当于两个相反方向的单工通信的组合。该方式传输效率高,控制简单,但造价高,同时要求传输通道有足够的带宽给予充分的支持。

(三)半双工通信

在半双工通信中,两个设备之间有两个传输通道,可以轮流双方向地传送,但不能同时进行。即在某一时刻只能沿着一个方向传输数据。该方式要求每一端都具有发送设备、接收设备及改变数据传输方向的控制器。此方式适用于对话式终端之间或者用在传输通道没有足够的带宽支持双向通道的场合。由于该方式在通信中要不断的改变传输通道的方向,因此控制复杂,传输效率极低。(STM32F105系列:http://www.y-ec.com/cpcp/class/?33.html)


关键字:STM32  库函数 引用地址:STM32库函数void USART_SendData的缺陷和解决方法

上一篇:STM32 printf重定向
下一篇:STM32系统结构、时钟树

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

库函数版本】基于STM32F103的MPU6050的原始数据读取程序详解
因为我的博客已经对I2C协议的详细过程已经做了一个例子!所以这个MPU6050的程序我将使用库函数完成! 第一步:硬件连接: 第二步:初始化I2C端口的函数: /***PB6/PB7 端口初始化****/ static void I2C_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB,ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); GPIO_InitStructure.GP
[单片机]
【<font color='red'>库函数</font>版本】基于STM32F103的MPU6050的原始数据读取程序详解
STM32 USB虚拟串口问题汇总
汇总1:STM32的USB例程修改步骤,来自http://blog.csdn.net/cy757/archive/2010/01/01/5117610.aspx 以下是笔者将ST的Custom_HID例程修改为“自定义USB设备”例程时总结出来的,因为笔者也是刚刚学USB开发不久,某些方面理解错误在所难免,请各位大虾指正。 一、usb_desc.c文件 根据你程序使用的通信方式修改。usb_desc.h文件中定义要根据usb_desc.c文件中的数组的大小;ConfigDescriptor 下添加需要处理的端点;根据需要添加或删除报告描述符(主要用于HID)和CDC接口描述符(主要用于实现USB转串口)等。具体方法可以下载个“
[单片机]
《如何制作STM32开发板》之串口
一说到串口,大家应该在脑海中出现下面这个画面就对了: 看到没有,这就是正儿八经的串口。在现在的工控机上,和以前的家用电脑上,都有串口,现在的家用电脑上,已经没有串口了。(千万不要把VGA口看成串口,VGA口是15针,串口是9针) 我们要搞单片机,就必须会用串口。所以,开发板上,就必须要有学习串口的功能。 串口的硬件应用,现在最多的有3种: USB转TTL串口 232串口 485通信 在我们的开发板上,把这3种功能都实现。 一、USB转TTL串口 这个功能,在讲程序下载方式的那一篇文章已经讲过了。STM32VET6有5个串口,但是只有串口1可以下载程序,所以我们默认把USART1与CH340G转成的RXD和TXD放到一起
[单片机]
《如何制作<font color='red'>STM32</font>开发板》之串口
STM32 之 SysTick
感觉定时1秒还是有点不准,仅为目测,下次用示波器去测量下。 包含文件: (1)Main C语言: Codee#14620 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 实验平台 : ST 官方三合一套件 + 硬件 : STM32F103C8T6 + 开发平台 : IAR For ARM 5.40 + 仿真器 : J-Link + 日期 : 2010-10-26 + 频率 :HSE = 8MHz ,主频 = 72MHz +++++++++++++++++++++++++++++++++++
[单片机]
<font color='red'>STM32</font> 之 SysTick
STM32的输入捕获
实验目的: 在串口调试助手上打印出按键按下的时间 实验步骤: 实验程序: /*******************************timer.c********************************/ #include sys.h #include stm32f4xx.h extern u8 TIM5CHA1_CAPTURE_STA; extern u16 TIM5CHA1_CAPTURE_VAL; /* 本示例的作用就是, 当按键按下时,每次输入捕获的时间差, 然后从串口调试助手中打印出其时间差; */ /*
[单片机]
意法半导体发布STM32 MCU图形界面设计软件TouchGFX 4.20版
STM32 用户界面设计环境新增屏幕旋转和纹理映射功能,支持性能强大的 Neochrom 图形加速器 中国,2022年8月16日---- 服务多重电子应用领域、全球排名前列的半导体公司意法半导体(STMicroelectronics,简称ST;) 公布了STM32 微控制器图形用户界面设计软件TouchGFX 4.20版。最新的软件更新支持意法半导体新推出的 Neochrom 图形加速器。新款图形加速器集成在意法半导体的先进微控制器产品中,例如STM32U5系列。 意法半导体 Chrom-ART Accelerator™ 图形加速技术可以处理像素和形状,源自这项技术的Neochrom支持全屏旋转到任何角度,并支持纹理
[单片机]
意法半导体发布<font color='red'>STM32</font> MCU图形界面设计软件TouchGFX 4.20版
GPIO工作模式详解
STM32中每组由16个IO,不同的型号IO分组不一样,比如STM32F407ZGT6 一共有7组IO口, 每组IO口有16个IO, 一共16X7=112个IO,外加2个PH0和PH1,一共114个IO口。分别是GPIOA,GPIOB---GPIOG,外加2个PH0和PH1 一、GPIO介绍 GPIO:就是一个引脚作为输入或者输出。 GPIO的八种工作模式:输入输出是相对于CPU,四种输入、四种输出模式及四种输出最大速度 输入:外部数据输入到开发板 输出:开发板的数据输出到外部设备 (1) GPIO_Mode_AIN 模拟输入 将IO口作为模拟输入接口,输入的可能是变化的值,接收外部的模拟信号输入 (2) GPIO_Mo
[单片机]
GPIO工作模式详解
STM32待机模式测试
环境: 主机:XP 开发环境:MDK4.10 单片机:STM32F103C8 功能: 开启RTC闹钟,然后进入待机模式,用闹钟唤醒后退出. 说明: 1.RTC闹钟唤醒事件发生时,同时进入闹钟中断,必须在初始化时与外部中断线17关联 2.如果仅想退出待机模式,RTC闹钟事件已经足够,不必与外部中断线17关联 3.退出待机模式后,接下来的流程类似于按下复位按键,程序会从头开始执行 源代码: 初始化时钟,配置时钟为内部时钟LSI,配置RTC闹钟唤醒以及外部中断线17 void RTC_Configuration(void) { //定义中断结构体 NVIC_InitTypeDef NVIC_
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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