STM32学习笔记(5) 串口通讯-接收与发送

一 通信的基本概念

  1. 串口并行与串行

    数电课讲过,并行速度快但占用的门电路多,耗费空间

    串行速度慢但节约空间

  2. 数据通信方向

    • 全双工:TX,RX同时收发数据
    • 半双工:不能同时收发数据,可分时收发数据
    • 单工:任何时刻都只能往某一个固定的方向传输数据
  3. 数据同步方式

    • 同步

    • 异步

  4. 通信速率

    • 比特率:每秒钟传输的二进制位数,单位(bit/s)

    • 波特率:每秒中传输的码元个数

      一个码元就是一个脉冲信号,一个脉冲信号有可能携带1bit数据,也有可能携带2bit数据、4bit数据!你发送一个脉冲信号,如果就可以携带4bit数据,肯定发送速率更快啊!

      那么怎么实现一个脉冲信号就能携带多个bit数据呢?就需要一定的技术了,比如设置模拟信号中信号的频率、相位、振幅啥的。举个例子:把振幅分成四种,低(00)、中(01)、高(10)、很高(11),这样我发一个脉冲信号,它的振幅是低,那就说明发送的是00(也就是2bit),它的振幅是中(01),发送的就是01(也就是2bit)……也就实现了一个脉冲信号,携带2bit的功能…(举个不恰当的例子让大家理解而已,明白啥意思就行)

      再说一次,一个码元就是一个脉冲信号!波特率指的就是1秒能发送多少个码元,也就是1秒能发送多少个脉冲信号!

      一个码元能携带1bit数据,那么比特率 = 波特率!

      一个码元能携带2bit数据,那么比特率 = 2倍的波特率!

      一个码元能携4bit数据,那么比特率 =4倍的波特率

      • 一个二进制表示码元

      0V——0

      3.3V——1

      • 两个二进制表示一个码元

        0V——00

        3V——01

        6V——10

        9V——11

      • 通常情况下波特率等于比特率

二 串口通信协议

  1. RS232标准

  2. USB转串口

    用于设备和电脑的通讯,电平转化芯片一般是CH340

  3. 串口到串口:串口一次只能发1个字节的数据( UART_SendByte()

三 串口数据包的组成

起始位 数据位 校验位 停止位
0 位0—位7 1
校验位
  • 奇校验

    有效数据和校验位“1”总的个数为奇数

  • 偶校验

    偶数

四 串口的功能框图

STM32学习笔记(5) 串口通讯-接收与发送_第1张图片
STM32学习笔记(5) 串口通讯-接收与发送_第2张图片

  1. 引脚作用

    • TX:数据发送

    • RX:数据接受

    • SCLK:时钟,仅同步通信使用

    • nRTS:Request to send.请求发送

    • nCTS:Clear to send.允许发送

  2. USART:S是同步。USART1~USART3都有SCLK引脚

    UART:异步。无SCLK引脚

  3. 数据寄存器DR

31——9 bit 8——0 bit
保留 DR[8:0]
  • 31-9 bit:保留位,始终为1
  • 8-0 bit:数据位,由TDR(发送寄存器),RDR(接收寄存器),包含发送和接受功能

五 程序流程

  • 串口初始化结构体
    typedef struct
    {
      uint32_t USART_BaudRate;            //波特率 BRR
      uint16_t USART_WordLength;          //字长	 CR1_M
      uint16_t USART_StopBits;            //停止位 CR2_STOP 
      uint16_t USART_Parity;              //校验位 CR1_PCE CR1_PS
      uint16_t USART_Mode;                //模式选择 CR1_TE CR1_RE
      uint16_t USART_HardwareFlowControl; //硬件流选择 CR3_CTSE,CR3_RTSE
    } USART_InitTypeDef;
    
    • USART_WordLength

    • USART_StopBits

      #define USART_StopBits_1                     ((uint16_t)0x0000)
      #define USART_StopBits_0_5                   ((uint16_t)0x1000)
      #define USART_StopBits_2                     ((uint16_t)0x2000)
      #define USART_StopBits_1_5                   ((uint16_t)0x3000)
      
    • USART_Parity

      #define USART_Parity_No                      ((uint16_t)0x0000)
      #define USART_Parity_Even                    ((uint16_t)0x0400)
      #define USART_Parity_Odd                     ((uint16_t)0x0600) 
      
    • USART_Mode

      #define USART_Mode_Rx                        ((uint16_t)0x0004)
      #define USART_Mode_Tx                        ((uint16_t)0x0008)
      #define IS_USART_MODE(MODE) ((((MODE) & (uint16_t)0xFFF3) == 0x00) && ((MODE) != (uint16_t)0x00))
      
    • USART_HardwareFlowControl

      #define USART_HardwareFlowControl_None       ((uint16_t)0x0000)
      #define USART_HardwareFlowControl_RTS        ((uint16_t)0x0100)
      #define USART_HardwareFlowControl_CTS        ((uint16_t)0x0200)
      #define USART_HardwareFlowControl_RTS_CTS    ((uint16_t)0x0300)
      

硬件流功能:当外设处于准备好的状态时,硬件启动自动控制,而不需要软件再进行干预,在串口中,当串口已经准备好接收新的数据时,硬件流自动把RTS拉低;准备发送数据前,硬件流自动检查CTS是否为低(表示是否可以发送数据)。此功能需要有RTS,CTS两个引脚。

  • 同步时钟结构体
typedef struct
{
  uint16_t USART_Clock;   //同步时钟 CR2_CLKEN
  uint16_t USART_CPOL;    //极性  CR2_CPOL
  uint16_t USART_CPHA;    //相性  CR2_CPHA
  uint16_t USART_LastBit; //最后一个位的时钟脉冲 CR2_LBC
} USART_ClockInitTypeDef;
  • 流程
  1. 初始化串口需要用到的GPIO
  2. 初始化串口,USART_InitTypeDef
  3. 中断配置(接收中断,中断优先级)
  4. 使能串口
  5. 编写发送和接收函数
  6. 编写中断服务函数
  • 发送接收函数
/*
* @函数名:UART_SendByte(USART_TypeDef *p_USARTx, uint8_t ch)
* @功能:发送一个字节
* @入口参数:USARTx,ch(想发送的字节)
*/
static void UART_SendByte(USART_TypeDef *p_USARTx, uint8_t ch)
{
    /*发送一个字节的数据到USART*/
    USART_SendData(p_USARTx,ch);

    /*等待发送数据的寄存器为空*/
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
    
}
/*
* @函数名:UART_SendString(USART_TypeDef *p_USARTx,char *str)
* @功能:发送字符串
* @入口参数:USARTx,str(想发送的字符)
*/
void UART_SendString(USART_TypeDef *p_USARTx,char *str)
{
    unsigned int k=0;
    do
    {
        UART_SendByte(p_USARTx,*(str+k));
        k++;
    } 
    while(*(str+k) != '\0');
    /*等待发送完成*/
    while (USART_GetFlagStatus(USART1,USART_FLAG_TC)== RESET)
    {}
}
USART_FLAG_TC 与 USART_FLAG_TXE的区别:
  • USART_FLAG_TC是干嘛用的呢?

    当发送移位寄存器中的1字节数据已经通过TX脚一位一位的移出去后,该标志位就会被置1,从而引发该事件的中断。所以,其实USART_FLAG_TC就是用来标志“发送移位寄存器中的数据有没有全部发送出去”这件事的。

  • USART_FLAG_TXE是干嘛用的呢?

    当发送数据寄存器中的数据已经取完了,该标志位就会被置1,从而引发该事件的中断。所以,其实USART_FLAG_TXE就是用来标志一个事件的,通过它的值可以知道该事件有没有发生(即发送数据寄存器中的数据有没有被取走)。

  • 对于USART_FLAG_TXE来说,只是说明数据寄存器中的数据已经被发送移位寄存器取走了(但发送移位寄存器中可能还没有启动发送过程),通过中断就可以提醒CPU可以往数据寄存器中填充数据了,发送移位寄存器中的数据往外发送的过程其实还是比较耗时的,相对于C语言代码执行时间来说,这个过程的耗时极大,所以每次发送数据寄存器中的数据被发送移位寄存器取走后,都应该产生中断来提醒CPU对该数据寄存器填写数据;

  • 而对于USART_FLAG_TC来说,没必要每次当发送移位寄存器中的数据发送完成后都发生中断,而应该是整个串口数据帧全部发送完毕,包括最后一个字节也发送出去之后才应该开中断,这代表的就是一个数据帧发送完成事件了

六 知识重难点

  • 当数组作函数形参时,由于形参变量和实参变量是由编译系统分配的两个不同单元。在函数调用的时发生的值传送是把实参变量的值赋予给形参变量。在用数组名作函数参数的时候,不是进行值的传送,既不是把实参数组的每一个元素的值都赋予形参数组的各个元素。因为实际上形参数组并不存在,编译系统不为形参数组分配内存。那么数据的传输是如何实现的呢?数组名就是数组的首地址。因此在数组名作函数参数时所进行的传送知识地址传送,也就是说把实参数组的首地址赋予给形参数组名。形参数组取得该首地址之后,也就等于有了实在的数组。实际上,形参数组和实参数组为同一数组,共同拥有一段内存空间。

  • USART1的TX,RX通过CH340连接micro USB,所以你可以用数据线给电脑发送数据

    但USART2,USART3需要额外接CH340,才能和电脑通信(PCB设计问题)

相关代码:串口的接受与发送

你可能感兴趣的:(STM32,单片机,stm32,物联网,51单片机,c语言)