zoukankan      html  css  js  c++  java
  • 直接对寄存器操作,实现usart的串口输出寄存器的配置

    就像前面提到的,我用的板子是一款stm32f107系列的板子,在这块板子上,已经开发出了一套比较成熟的库函数,这也就意味着你可以不用直接去操作存储器来实现某些功能。比方说对于USART来说可以直接通过void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)实现对usart始终初始化,复用端口的定义和设置,usart功能的配置及使能。那么后面的寄存器是怎么操作的呢?这是我比较关心的问题,为了能更详细的了解这些东西,我选择了自己通过对那些寄存器操作来实现USART串口打印功能。

    首先我们要知道做USART(我使用的是默认端口USART2)的一些基本配置:

    1. 使用pd5做发送端口,使用PD6做接收端口。通过阅读相关的文档可以知道usart2的默认输入输出端口是PA2和PA3 ,但是这两个端口已经被许多功能所使用,于是我们使用PD5,pd6作为输入输出端口,这里就要使用到端口的复用(AFIO)
    2. 波特率设置为115200
    3. 字长设置为8B
    4. 模式为发送/接收
    5. 停止位为1位
    6. 无错误校验

    接下来就是跟着要完成的东西的顺序,开始配置寄存器。

    1.首先第一个端口复用功能。需要使用到AFIO功能的RMAP寄存器。如图,

    那么RMAP的配置应该为0x00000008;

    2.设置pd5,pd6的端口配置,这里和之前做过的LED灯的配置差不多,只不过两个端口的模式有些不同,pD5端口的模式需要配置为:复用推免输出,50MHz,PD6的配置为浮空输入

    3.设置波特率要通过BRR寄存器,DIV_Mantissa[11:0]是整数部分,DIV_Fraction[3:0]是小数部分。

    计算公式如下

    Tx/Rx波特率就是我们输入的115200,我们需要的结果是通过计算得到的,具体的计算方法将会在下面详述。

    4.字长为8位,模式为发送接收,这些都可以在CR1 寄存器中设置。M为0表示字长为8,为1表示字长为9,PCE为1表示有错误校验,TE和RE分别为1.这里有一个需要特别注意的地方就是UE代表USART EnABLE就是usart功能的使能,将他置为1才可以使用usart功能。表示可以接受可以发送。即CR1的配置为0x0000200C

     

    5.在CR2中Stop[1:0]中设置停止位,00为1位,01为0.5位,10为2位,11为1.5位

    则CR2的配置为0x00000000

     

    到现在为止,我们已经完成了对USART通信的基本原理叙述完毕,并且完成基础配置,剩下的就是用程序去实现功能。接下来就是用程序去实现。

    1.引用stm32f10x.h文件,因为这个文件中包含了我们要用到的对GPIOD,USART2,AFIO,RCC寄存器的描述GPIO_TypeDef,USART_TypeDef,AFIO_TypeDef,RCC_TypeDef。

     2.初始化GPIOD,USART2,AFIO的时钟,通过查看手册,可以知道USART2在APB1总线上,AFIO和GPIOD在APB2总线上。于是初始化时钟就是,

    /*初始化USART2时钟*/
    
    

    RCC->APB1ENR|=RCC_APB1Periph_USART2; /*初始化GPIOD的RCC时钟*/ /*初始化AFIO的rcc时钟*/ RCC->APB2ENR|=RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO;

    2.usart2的功能重映射

    //usart2重映射
    AFIO->MAPR|=0x00000008  ;//GPIO_Remap_USART2

    3.pd5,pd6管脚的设置

    GPIOD->CRL&=0x00000FFF;
    GPIOD->CRL|=0x01E00000;

    4.USART2的使能,字长为8,可接受发送,停止位为1

    //字长为8,可接收,可发射
    USART2->CR1|=0x0000000c;
    
    USART2->CR2|=0x00000000;

    5.波特率的设置

    从上面的公式可以得知,BRR中的最终的DIV=fclk/(波特率*16),然后得到一个实数,其中,他的整数部分写入到BRR的DIV_Man提撒,小数部分*16(取整)的值放入到DIV_Fraction中。于是

    /*获取RCC时钟状态*/
    RCC_GetClocksFreq(&RCC_ClocksStatus);
    /*获取flck1的频率*/
    apbclock=RCC_ClocksStatus.PCLK1_Frequency;
    /*获取100倍的DIV*/
    integerdivider=(25*apbclock)/(4*115200);
    /*获取DIV的整数部分并且左移四位*/
    tmpreg=(integerdivider/100)<<4;
    /*获取小数部分的100值*/
    fractionaldivider=integerdivider-(100*(tmpreg>>4));
    /*存放整数的值*/
    integerdivider=tmpreg;
    /*小数值的100倍乘16,+50(完成四舍五入的功能),然后除100得到小数值,&0x0f防止溢出*/
    fractionaldivider=(((fractionaldivider*16)+50)/100)&(uint8_t)0x0f;
    /*将整数和小数写入到BRR寄存器*/
    USART2->BRR|=integerdivider|fractionaldivider;

    6.配置完成,现在开始输入内容,这里为了满足不同的输入要求,定义了不同的输出函数

    /*!< STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */
    
    #ifdef __GNUC__
      /* With GCC/RAISONANCE, small printf (option LD Linker->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__ */

    7.每次调用Printf函数的时候,将输出到在屏幕的数据流改到串口,调用PUTCHAR_PROTOTYPE函数

    PUTCHAR_PROTOTYPE
    {
      /* Place your implementation of fputc here */
      /* e.g. write a character to the USART */
     USARTx->DR = (Data & (uint16_t)0x01FF);
    
      /* Loop until the end of transmission */
      while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
      {}
    
      return ch;
    }

    到这里基本完成了USAT的串口打印的功能。

  • 相关阅读:
    cuda基础----流
    cuda基础---异步并行执行
    cuda基础---cuda通信机制
    cuda基础-----cuda编程模型/软件体系/存储器模型
    大顶堆 小顶堆应用----中位数查找
    Maven配置阿里云镜像
    C++中bool型变量按位取反总是为true
    区分C++的继承、覆盖、隐藏、重载
    C++Primer第5章 语句
    C++Primer第4章 表达式
  • 原文地址:https://www.cnblogs.com/xiangfeng/p/3450305.html
Copyright © 2011-2022 走看看