5.USART异步串行口输入输出

<需要知道的串行口相关库函数>

1.初始化函数

  void USART_Init(USARTx, USART_InitStruct);

  我的嵌入式开发板STM32f107仅有2个支持RS232协议可以实现全双工的异步串行通信的串口,

  因此x仅可能为1,2

  typedef stuct

  {

    u32 USART_BaudRate;   /*波特率*/

    u16 USART_WordLength; /*传送或者接受数据位数,_8b或者_9b*/

    u16USART_StopBits;    /*传送或者接受停止位数目,_1, _0.5, _2, _1.5*/

    u16 USART_Parity;      /*奇偶模式,_NO, _Even, _Odd*/

 

    u16 USART_HardwareFlowControl; /*硬件流控制,_None, _RTS, _CTS, _RTS_CTS*/

    u16 USART_Mode;         /*接收发送使能, _Tx, _Rx*/

    u16 USART_Clock;        /*USART时钟使能, _Enable, _Disable*/

    u16 USART_CPOL;         /*SLCK时钟输出特性, _High, _Low*/

    u16 USART_CPHA;         /*SLCK时钟输出相位, _1Edge, _2Edge*/

    u16 USART_LastBit;      /*SLCK时钟输出MSB对应时钟, _Disable, _Enable*/

  }USART_InitTypeDef;

  按照上面结构体初始化串口即可。

 

2. 使能函数

   USART_Cmd(USARTx, FunctionalStateNewState);

   NewState: Enable   使能串行口外设

                      Disable 失能串行口外设

3. 接收数据

   u8USART_ReceiveData(USARTx,Data)

   检查指定的串行通讯标志位设定与否

   FlagStatusUSART_GetFlagStatus(USARTx, USART_FLAG)

 

<串行初始化>

1. 串口的初始化,然后使能

    USART_InitTypeDef  USART_IniStructure;

    GPIO_InitTypeDefGPIO_InitStructure;

    USART_DeInit(USART1);

    //设置串口波特率115200

    USART_InitStructure.USART_BaudRate = 115200;                        

    //串口一帧接收8位数据   

    USART_InitStructure.USART_WordLength =USART_WordLength_8b;        

    //数据帧结尾有1个停止位

    USART_InitStructure.USART_StopBits =USART_StopBits_1;              

    //不采用奇偶校验

    USART_InitStructure.USART_Parity= USART_Parity_No;                  

    //不使用硬件流控制

    USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;     

    //串口1输入输出端都使能

    USART_InitStructure.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;     

    USART_Init(USART1&USART_InitStructure);

    USART_Cmd(USART1 , Enable);

  我刚开始以为只要初始化了串口,在使能串口后就可以接受到信息,可试了接近1个小时后PC串口一直没有收到消息,没办法我就只好去百度,原来串口通讯不仅要配置外设模块,对用的GPIO口也要配置,这在以后的各个外设的学习中都要注意(重要),因此RX和TX两个GPIO端初始化程序还需要添加,具体代码如下:     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);          //使能相关时钟,复用是必须要使能的

    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9;       //电路图对应PA9

    GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;

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

GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_10;     //电路图对应PA10

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

    GPIO_Init(GPIOA,&GPIO_InitStructure);

 

  标准Printf执行retarget处理,调用库函数向串口发送信息

 注意:编译前请在工程属性的 "Target“-》”Code Generation“中勾选”Use MicroLIB“,否则没有输出

  USART_SendData(USARTx,u8 Data); 发送字节函数

  USART_GetFlagStatus(USARTx,USART_FLAG_TC); 发送字节完成标志位

  用于判断发送完成,每发送完成一个字节,发送下一字节。

  main.c文件头添加#include,并进行retarget处理

  #ifdef __GNUC__

  /* With GCC/RAISONANCE, small printf (

    option LDLinker->Libraries->Small printf

     set to 'Yes') calls __io_putchar() */

   #define PUTCHAR_PROTOTYPE int__io_putchar(int ch)

   #else

   #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)

   #endif /* __GNUC__ */

   文件中添加结构体                       

   PUTCHAR_PROTOTYPE

   {

  /* Place your implementation of fputc here */

  /* e.g. write a character to the USART */

  USART_SendData(USART1, (uint8_t) ch);

 

  /* Loop until the end of transmission */

  while (USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET)

  {}

  return ch;

  }

 

串口通讯的深入研究

  RZ编码和NRZ编码

  RZ编码其中正电平->归零代表1,负电平->归零代表0,因为每位传输后都要归零,所以接受者只要在信号归零采样即可,这样不需要单独的时钟信号,但是在RZ编码中,大部分的数据带宽,都用来传输“归零”而浪费掉了。

 NRZ 取消了数据归零的过程,直接读取线路上的信号,因此节省了带宽,但同时也就需要时钟连接以保证能够正确的接受数据。 

 USART就是采用了NRZ的异步串行通讯方式

  波特率:串口每秒发送的bit个数

              传输时间的计算(以2k数据b,每帧8位数据,1位停止位,波特率9600,传输完成花费时间)

              T = 2*1024/8*(8+1)/9600 = 0.24s

  数据位:    计算机每发送一个信息包(帧)的位数,8个字是一字节,Cortex-M3提供的有8位和9位,    

              这里要注意下如果选用了奇偶校验,那么数据位必须为9位,否则输出的数据会与实际不符。                  

  停止位:    位于单个包的最后一位,典型值有1,2用于提供校正时间同步的机会

  奇偶校验位:当使能后在串口通讯数据MSB(最高有效位)中插入经计算的校验位,9位时为数据第9位,用           于检错

  硬件流控制:用于数据流控制,通讯的双方由此交换是否停止后继续接收信息,避免因处理数据速度问题而出现的缓存溢出,导致数据的丢失

 CTS:只有CTS输入信号有效(低电平)时才能发送数据。如果在数据传输的过程中,CTS信号                 变成无效,那么发完这个数据后,传输就停止下来。如果当CTS为无效时,向数据寄存器里写数据,则要等到CTS有效时才会发送这个数据。

                RTS:只有接收缓冲区内有空余的空间时才请求下一个数据。当前数据发送完成后,发送操作就                    

                需要暂停下来。如果可以接收数据了,将RTS输出置为有效(拉至低电平)

 

串行通讯传输帧的格式(详见STM32中文参考手册25.3.1):

数据帧:8位/9位,包含起始位(低电平),但不包含停止位(高电平),因此数据帧的长度为8/9(数据长度位)+1/2(停止位)

空闲帧:包含停止位,总线持续高电平(发送使能后将发送一个空闲帧)

断开帧:持续低电平,后跟停止位,因此断开帧的长度为不应大于10/11位,串口TE置1时会发送个断开帧。

 

波特率USART->BRR寄存器的配置(详见STM32中文参考手册25.3.4,用于寄存器控制,需要了解,最好掌握)

根据

可以求出USARTDIV,再根据计算转换为2进制数,即USAER->BRR的值。

以36MHZ,波特率为例9600

则USARTDIV=3.6*10^7/(16*9600) = 234.375

转换为二进制整数部分为)0xEA

小数部分转化为16进制为 0x0.6

则USART->BRR= 0xEA6

 

<串口输入输出实验>

串口的输入输出实验与上诉并没有什么太大区别,为具体流程如下(以串口1为例):

1.串口复位

 USART_DeInit(USART1);

2.使能输入输出口的对应区域的外设时钟以及复用功能时钟,初始化对应GPIO输入输出方式。

  输出方式:复用推挽输出,输入方式:浮空输入

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);

  。。。。。。

 GPIO_Init(GPIOx, &GPIO_Instructure);

3.使能串口时钟,初始化串口

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,  ENABLE);

  。。。。。。

 USART_Init(USART1,&USART_Instructure);

 USART_Cmd(USART1 ,ENABLE);

4.串口输出昨天已经学习,输入调用库函数,即可以接收到数值。

  const int MaxLength= 20;         //缓存区长度

  char StoreSting[MaxLength];

  只要在接受函数中用do /while()循环,以收到回车(\n)表示接收截至。

  大于等于MaxLength仍未收到回车则输出超出申请数组范围,返回

  小于MaxLength收到回车则循环结束返回,将数组传送给printf输出。

你可能感兴趣的:(STM32应用)