STM32
直播中

吴湛

10年用户 756经验值
擅长:可编程逻辑
私信 关注
[问答]

处理器是怎样与外部设备进行通信的

处理器是怎样与外部设备进行通信的?有哪几种方式?
串行通信的数据传输方向是怎样的?

回帖(1)

孙婧

2021-12-10 13:50:28
1. 概述

1.1 处理器与外部设备通信方式

1.1.1并行通信




  • 传输原理:数据各个位同时传输。
  • 优点:速度快
  • 缺点:占用引脚资源多
1.1.2 串行通信(本文重点讲解此通信方式)




  • 传输原理:数据按位顺序传输
  • 优点:占用引脚资源少
  • 缺点:速度相对较慢
1.2 串行通信的数据传输方向

1.2.1 单工

数据传输只支持数据在一个方向上的传输
1.2.2 半双工

允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,他实际上是一种切换方向的单工通信
1.2.3 全双工

允许数据同时在两个方向上传输,因此,全双工通信时两个单工通信方式的结合,他要求发送设备和接收设备都有独立的接收和发送能力





1.3 串行通信的通信方式

1.3.1 同步通信




  • 带时钟同步信号传输(SPI,IIC通信接口)
1.3.2 异步通信




  • 不带时钟同步信号(UART:通用异步收发器,单总线)





    在STM32中有UART和USART两种收发器,其中UART为通用异步收发器,USART为通用同步异步收发器(即可用与同步或者异步收发)
1.4 UART异步通信

1.4.1 引脚连接方法















1.4.2 特点




  • 全双工异步通信。
  • 分数波特率发生器系统,提供精确的波特率。
    -发送和接受共用的可编程波特率,最高可达4.5Mbits/s
  • 可编程的数据字长度(8位或者9位);
  • 可配置的停止位(支持1或者2位停止位);
  • 可配置的使用DMA多缓冲器通信。
  • 单独的发送器和接收器使能位。
  • 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志
  • 多个带标志的中断源。触发中断。
  • 其他:校验控制,四个错误检测标志。
1.4.3 通信过程











2.思路

异步通信在通信时需要先约定好波特率,才能够确保发送和接收数据的完整。
在程序中需要将串口初始化并且使能串口,若需要接收到数据后产生中断则需要加上中断使能函数。
参考正点原子的教程,其还增加了一个校验的功能(其实正常的通信都应该要加上起始位和结束位,确保数据的正确性),定义了一个函数:
bit13~0:接收到的有效数据个数,bit14:接收到0X0D标志,bit15:接收0X0A完成标志。





3.寄存器说明

3.1 状态寄存器(USART_SR)





RXNE(读数据寄存器非空),当该位被置 1 的时候,就是提示已经有数据被接收到了,并且可以读出来了。这时候我们要做的就是尽快去读取 USART_DR,通过读 USART_DR 可以将该位清零,也可以向该位写 0,直接清除。
TC(发送完成),当该位被置位的时候,表示 USART_DR 内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式: 1)读 USART_SR,写USART_DR。 2)直接向该位写 0。
3.2 数据寄存器(USART_DR)






DR(8:0):包含了发送或接收的数据。
3.2 波特比率寄存器(USART_BRR)
















4.库函数说明

[tr]项目功能[/tr]
void USART_Init()串口初始化:波特率,数据字长奇偶校验,硬件流控以及收发使能
void USART_Cmd()使能串口
void USART_ITConfig()使能相关中断
void USART_SendData()发送数据到串口,DR
uint16_t USART_ReceiveData()接受数据,从DR读取接受到的数据
FlagStatus USART_GetFlagStatus()获取状态标志位
void USART_ClearFlag()清除状态标志位
ITStatus USART_GetITStatus()获取中断状态标志位
void USART_ClearITPendingBit()清除中断状态标志位
5. 串口配置代码




  • 串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
  • 串口复位:USART_DeInit(); 这一步不是必须的
  • GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
  • 串口参数初始化:USART_Init();
  • 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
    NVIC_Init();
    USART_ITConfig();
  • 使能串口:USART_Cmd();
  • 编写中断处理函数:USARTx_IRQHandler();
  • 串口数据收发:
    void USART_SendData();//发送数据到串口,DR
    uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
  • 串口传输状态获取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

void My_USART1_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStrue;
        USART_InitTypeDef USART_InitStrue;
        NVIC_InitTypeDef NVIC_InitStrue;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
       
        GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9;
        GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStrue);
       
        GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING;
        GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10;
        GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz;
  GPIO_Init(GPIOA,&GPIO_InitStrue);
       
        USART_InitStrue.USART_BaudRate=115200;
        USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
        USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
        USART_InitStrue.USART_Parity=USART_Parity_No;
        USART_InitStrue.USART_StopBits=USART_StopBits_1;
        USART_InitStrue.USART_WordLength=USART_WordLength_8b;
       
        USART_Init(USART1,&USART_InitStrue);
       
        USART_Cmd(USART1,ENABLE);
       
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
       
        NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn;
        NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1;
        NVIC_InitStrue.NVIC_IRQChannelSubPriority=1;
        NVIC_Init(&NVIC_InitStrue);
       
       
}


void USART1_IRQHandler(void)
{
        u8 res;
         if(USART_GetITStatus(USART1,USART_IT_RXNE))
{
     res= USART_ReceiveData(USART1);
     USART_SendData(USART1,res);   
  }
}


加上“USART_RX_STA”校验


if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
   {
           Res =USART_ReceiveData(USART1);
          
           if((USART_RX_STA&0x8000)==0)
                   {
                   if(USART_RX_STA&0x4000)
                           {
                           if(Res!=0x0a)USART_RX_STA=0;
                           else USART_RX_STA|=0x8000;       
                           }
                   else
                           {       
                           if(Res==0x0d)USART_RX_STA|=0x4000;
                           else
                                   {
                                   USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                                   USART_RX_STA++;
                                   if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;  
                                   }                 
                           }
                   }                    
    }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分