首页 > 其他分享 >USART-通信详解

USART-通信详解

时间:2023-09-25 22:46:13浏览次数:41  
标签:USART void 通信 NVIC 详解 InitStructe GPIO USART1

目录

一. 通信基本概念

1. 根据数据传输方式划分

  • 串行通信: 一般是8根数据线以下, 数据一位一位的进行传输.
  • 并行通信:一般是指使用8、16、32及64根或更多的数据线进行传输的通讯方式.

2. 根据数据传输方向划分

  • 全双工: 同一时刻, 两个设备之间可以同时收发数据.
  • 半双工: 两设备之间可以收发数据, 但不能同一时刻.
  • 单工: 在任何时刻都只能一个方向通信, 即固定一个设备为发送设备, 另一个固定为接收设备.

3. 根据数据同步方式划分

  • 同步通信: 收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下双方进行协调同步数据.
  • 异步通信: 不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包, 以数据帧的格式传输数据.

二. USART流程分析

1. USART协议

  • 串口通信协议的数据包内容由: 起始位, 主体数据, 校验位以及停止位组成. 双方需要约定好相同的波特率以及数据包格式, 才能正常通信.
  • 波特率: 两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码, 图 串口数据包的基本组成 中用虚线分开的每一格就是代表一个码元。常见的波特率为4800、9600、115200等
  • 起始信号和停止信号: 串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑0的数据位表示, 而数据包的停止信号可由0.5、1(常用)、1.5或2个逻辑1的数据位表示,只要双方约定一致即可。
  • 有效数据: 在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为5、6、7或8位长。(一般是8位)
  • 数据校验: 分为奇校验和偶校验, 奇校验, 0校验和1校验.奇校验8个数据位加上校验位,其1的数量为奇数.(比如一个8位长的有效数据为:01101001,此时总共有4个“1”, 为达到奇校验效果,校验位为“1”) 后者比较好理解(0校验是不管有效数据中的内容是什么,校验位总为“0”,1校验是校验位总为“1”).

2. USART框图分析

  • 从数据发送流程看: 数据从总线进入 ---> 发送数据寄存器(TDR) ---> 发送移位寄存器(移位寄存器不能直接将数据正确发出, 因为他是由发送控制器控制着, 而发送控制器由许多寄存器配置. 以及时钟控制这里也叫波特率)) ---> 最后进入到发送引脚TX(PA9).

3. 寄存器分析

  • 控制发送相关寄存器位分析: 从上图发送控制器可以看出, 对其有影响的位有 '发送时钟BRR', 'UE', 'PCE', 'TE', 'RXNE', 'IDLE'等. 具体描述如下图.

  • 控制接收相关寄存器位分析: 从上图接收控制器可以看出, 对其有影响的为由: '发送时钟', 'UE', 'PCE', 'RE'等. 具体描述如下图.

  • 以上两个公共要用到的寄存器位

三. USART驱动代码

1. 寄存器方式驱动

  • 以接受寄存器接受到上位机数据后, 进入中断后将数据发回给上位机.
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "delay.h"

#define BAUD        115200
char arr[256] = {0};
uint16_t len = 0;

void USART_Baud(uint32_t baud);
void USART_GPIO_Init_M(void);
void USART_Write_Bit(char *arr, uint16_t len);
void USART_Regiser_Init();
char* USART_Read_Bit();
void NVIC_USART1_Config();

int main()
{
    delay_init(72);
    USART_GPIO_Init_M();
    USART_Regiser_Init();
    NVIC_USART1_Config();
    
    while(1)
    {
        //USART_Read_Bit();
    }
}

void USART_GPIO_Init_M(void)
{
    GPIO_InitTypeDef GPIO_InitStructe;
    GPIO_InitTypeDef GPIO_InitStructe_10;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    
    GPIO_InitStructe.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructe.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructe.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_InitStructe_10.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructe_10.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    
    GPIO_Init(GPIOA, &GPIO_InitStructe);
    GPIO_Init(GPIOA, &GPIO_InitStructe_10);
    
}

void USART_Regiser_Init()
{
    USART1->CR1 |= 1 << 3;     //TE: 发送使能
    USART1->CR1 |= 1 << 13;    //UE: USART使能
    USART1->CR1 &= ~(1 << 10); //PCE: 校验位失能
    USART1->CR1 &= ~(1 << 12); //M: 字长8个数据位
    
    USART1->CR1 |= 1 << 2;     //RE使能
    USART1->CR1 |= 1 << 4;     //USART中断使能
    USART1->CR1 |= 1 << 5;     //接受缓冲区中断使能
    
    USART1->CR2 &= ~(0x03 << 12); //STOP: 1个停止位
    USART_Baud(BAUD);
}

void USART_Baud(uint32_t baud)
{
    float usart_div = 72000000 / 16.0 / baud;
    uint16_t div_mantissa = (uint16_t) usart_div;
    uint16_t div_fraction = (usart_div - div_mantissa) * 16 + 0.5;
    
    USART1->BRR = (div_mantissa << 4) + div_fraction;
}


void USART_Write_Bit(char *arr, uint16_t len)
{
    int i;
    USART1->SR;
    for(i = 0; i < len; i ++)
    {
        while((USART1->SR & (1 << 6)) == 0x00); // !!! 等待上一位发送完成需要在前面判断
        USART1->DR = arr[i];
        //while((USART1->SR & (1 << 7)) == 0x00); // !!! 放后面判断应该是发送寄存器空
    
    }
}

char* USART_Read_Bit()
{
    
    if(((USART1->SR & (1 << 5)) != 0x00))
    {
        arr[len] = USART1->DR;
        len ++;
    }
    
     if(((USART1->SR & (1 << 4)) != 0x00))
    {
        USART1->DR;
        USART_Write_Bit(arr, len);
        len = 0;
    }
    return arr;
}

void USART1_IRQHandler()
{

    if(((USART1->SR & (1 << 5)) != 0x00))
    {
        arr[len] = USART1->DR;
        len ++;
    }
    
     if(((USART1->SR & (1 << 4)) != 0x00))
    {
        USART1->DR;
        USART_Write_Bit(arr, len);
        len = 0;
    }
}

void NVIC_USART1_Config()
{
    NVIC_InitTypeDef NVIC_InitStructe;
    //NVIC分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitStructe.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructe.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructe.NVIC_IRQChannelSubPriority = 1;
    
    NVIC_Init(&NVIC_InitStructe);

}

2. 固件库方式驱动

标签:USART,void,通信,NVIC,详解,InitStructe,GPIO,USART1
From: https://www.cnblogs.com/Deng-S/p/17729041.html

相关文章

  • 拦截器详解
       ......
  • python操作windows桌面实现鼠标、键盘操作,python之pyautogui库文档详解
    文章目录一、概述1、概述2、安装二、屏幕操作1、获取屏幕分辨率2、某个坐标是否在屏幕上3、获取当前鼠标位置三、鼠标操作1、移动鼠标2、点击操作3、滚轮操作4、记录光标小程序5、鼠标拖拽6、缓动/渐变(Tween/Easing)函数99、保护措施(FAILSAFE)99、延迟操作(PAUSE)四、键盘操作1、......
  • 初阶指针详解
    (目录)1.内存和地址内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的所以为了有效的使用内存,就把内存划分成一个个小块,这每一个小块被称为内存单元,每个内存单元的大小是1个字节为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该......
  • Java容器类详解
    Java的容器在Java中,我们想要保存对象可以使用很多种手段。最简单的就是数组。但是数组具有固定的尺寸,而通常来说,程序总是在运行时根据条件来创建对象,我们无法预知将要创建对象的个数以及类型,所以Java推出了容器类来解决这一问题。Java容器的基本概念Java容器类库是用来保存对象的,他......
  • dxf格式详解与在线打开、查看
    dxf格式简介dxf是一种CAD文件格式,是AutoCAD使用的一种内部文件格式。它用于存储AutoCAD图形的几何形状、图层、样式、标注等元素。dxf文件格式是AutoCAD社区中使用最为广泛的文件格式之一,因为它是一种免费的文件格式,并且可以很好地支持AutoCAD的版本更新。dxf格式文件结......
  • stp格式详解与在线打开、查看
    stp格式简介stp(StandardfortheExchangeofProductmodeldata)文件是CAD绘图软件的3D图形文件的格式(扩展名),其中包含三维对象的数据;提供对产品模型数据交换的支持。stp文件是基于ASCII格式符合stp应用协议ISO10303-21标准的正文编码的交换结构的三维图像数据。stp格式数据组成s......
  • Shp格式详解与在线打开、查看
    Shp格式简介shp格式是一种矢量数据格式,用于存储地理信息系统(GIS)数据。shp文件由Esri公司开发,用于表示点、线和多边形等要素,并记录它们的坐标和属性信息。shp格式通常用于存储和共享各种类型的GIS数据,如地图、地形、人口数据等。Shp格式数据组成shp文件由一系列有序的文件组成,这些文......
  • Windows 安装Redis(图文详解)
    https://www.cnblogs.com/smile008/p/16676723.html Windows安装Redis(图文详解) 一、Redis是什么数据库?RemoteDictionaryServer(Redis)是一个开源的使用ANSIC语言编写、遵守BSD协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提......
  • Java LinkedList与ArrayList源码解析:根本区别和表面区别的详解
    在Java中,LinkedList和ArrayList是两个常见的集合类。它们都实现了List接口,但它们在实现方式上有很大的区别。本篇博客将详细解析LinkedList和ArrayList的源码,解释它们的根本区别和表面区别,并提供详细的代码解释。LinkedList与ArrayList的根本区别:数据结构:LinkedList是基于链表......
  • Linux内核Makefile系统文件详解
    MakefileLinux内核的Makefile系统非常复杂,因为内核包含了许多不同的配置选项、架构和模块。以下是Linux内核Makefile系统中一些重要的文件和目录,以及它的作用。顶层Makefile(Makefile)顶层Makefile是整个内核编译过程的入口点它包含了全局选置选项,如目标体系结构、编译......