博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
STM32的USART
阅读量:4948 次
发布时间:2019-06-11

本文共 4361 字,大约阅读时间需要 14 分钟。

转载自:http://www.cnblogs.com/TrueElement/archive/2012/09/14/2684298.html

几个问题:

1、状态寄存器(USART_SR)中的TC(Transmission complete)何时置位?它和TXE(Transmit data register empty,发送数据寄存器空)有何区别?可以先看看下面的图:

根据上面的图,TC置位的条件就是在上一个字节发完之后,数据寄存器仍为空(TXE=1)。USART_DR中的数据,只要移位寄存器把上一字节发完,马上就可以移入移位寄存器,而USART_DR可以装入新的数据。

2、波特率(Baud)的设置

从手册知道,stm32的串口可以设置分数波特率,可以从APB时钟得到精确的波特率。查看标准库(v3.5)的设置波特率的部分函数,这种设置的方法精度足够,以及发现一个在手册里面(rev 14)没有提到的位,先看代码:

/* USART OverSampling-8 Mask */#define CR1_OVER8_Set             ((u16)0x8000)  /* USART OVER8 mode Enable Mask */#define CR1_OVER8_Reset           ((u16)0x7FFF)  /* USART OVER8 mode Disable Mask */  uint32_t tmpreg = 0x00, apbclock = 0x00;  uint32_t integerdivider = 0x00;  uint32_t fractionaldivider = 0x00;/*---------------------------- USART BRR Configuration -----------------------*/  /* Configure the USART Baud Rate -------------------------------------------*/  RCC_GetClocksFreq(&RCC_ClocksStatus);  if (usartxbase == USART1_BASE)  {    apbclock = RCC_ClocksStatus.PCLK2_Frequency;  }  else  {    apbclock = RCC_ClocksStatus.PCLK1_Frequency;  }    /* Determine the integer part */  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)  {    /* Integer part computing in case Oversampling mode is 8 Samples */    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));      }  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */  {    /* Integer part computing in case Oversampling mode is 16 Samples */    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));      }  tmpreg = (integerdivider / 100) << 4;  /* Determine the fractional part */  fractionaldivider = integerdivider - (100 * (tmpreg >> 4));  /* Implement the fractional part in the register */  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)  {    tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);  }  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */  {    tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);  }    /* Write to USART BRR */  USARTx->BRR = (uint16_t)tmpreg;
/* USART OverSampling-8 Mask */#define CR1_OVER8_Set             ((u16)0x8000)  /* USART OVER8 mode Enable Mask */#define CR1_OVER8_Reset           ((u16)0x7FFF)  /* USART OVER8 mode Disable Mask */  uint32_t tmpreg = 0x00, apbclock = 0x00;  uint32_t integerdivider = 0x00;  uint32_t fractionaldivider = 0x00;/*---------------------------- USART BRR Configuration -----------------------*/  /* Configure the USART Baud Rate -------------------------------------------*/  RCC_GetClocksFreq(&RCC_ClocksStatus);  if (usartxbase == USART1_BASE)  {    apbclock = RCC_ClocksStatus.PCLK2_Frequency;  }  else  {    apbclock = RCC_ClocksStatus.PCLK1_Frequency;  }    /* Determine the integer part */  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)  {    /* Integer part computing in case Oversampling mode is 8 Samples */    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));      }  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */  {    /* Integer part computing in case Oversampling mode is 16 Samples */    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));      }  tmpreg = (integerdivider / 100) << 4;  /* Determine the fractional part */  fractionaldivider = integerdivider - (100 * (tmpreg >> 4));  /* Implement the fractional part in the register */  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)  {    tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);  }  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */  {    tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);  }    /* Write to USART BRR */  USARTx->BRR = (uint16_t)tmpreg;

a、新的设置位:CR1_OVER8_Set,位于CR1的第15位,但是手册里面没有提到(rev14);根据手册里面提到的波特率计算公式,估计默认这个位是0,代表每个bit采样16次,而置位的时候,每bit采样8次。手册里的计算公式:

这个计算公式即按照每bit采样16周期来计算的,所以上面的代码在采样8周期的时候,除以2了。

b、integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));  的计算与上面公式不一致,这是因为这行代码下面还有这么一句:

tmpreg = (integerdivider / 100) << 4;

所以再除以100,合起来就相当于除以16了,为什么这样子做?因为integerdivider是一个uint32,为了提高精度,所以那里乘以100了。

c、这个精度够不够?乘以100,相当于保留到小数点后两位,而我们知道BRR的分数部分有4位,精度为1/16 = 0.0625,所以可以看到这个精度是够的。那么上面可以不可以改成乘以250再除以1000呢?不行,因为加入apbclock用最高的频率(72M),那么250*apbclock/4将溢出(uint32).

d、如果波特率特别高,而apbclock又较低,导致按照上面公式计算,结果USARTDIV小于1,则这样是不行的,你不能指望USART还能自己提时钟速度。这个时候,CR1_OVER8应该会有些作用,可以将在目前APB时钟下的最大的波特率提升一倍。

转载于:https://www.cnblogs.com/wupengda/p/4092379.html

你可能感兴趣的文章
Java访问修饰符(访问控制符)
查看>>
替换空格_把字符串里面的空格替换成%20
查看>>
AFNetworking content type not support
查看>>
【MSDN】 SqlServer DBCC解析
查看>>
Caused by: java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor
查看>>
VM VirtualBox安装Centos6.5
查看>>
C复习篇 - 使用Posix标准线程库 Porgramming with Pthread
查看>>
socket 通讯 端口绑定 问题 解答
查看>>
关于用户需求的调查
查看>>
云计算时代对传统软件工程的冲击
查看>>
Mahout--(三)相似性度量
查看>>
CodeForces 980 C Posterized
查看>>
C#泛型列表List<T>基本用法总结
查看>>
Drug side effect extraction from clinical narratives of psychiatry and psychology patients
查看>>
linux定时备份mysql并同步到其它服务器
查看>>
浅谈分布式事务
查看>>
Spring MVC专题
查看>>
linux grep命令详解(转)
查看>>
Java下获取可用CPU数
查看>>
JAVA学习笔记
查看>>