zoukankan      html  css  js  c++  java
  • stm32之波特率、USART

    先说一下波特率,下面抄自百度:

    波特率表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。  
    在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。波特率是传输通道频宽的指标。 

    好的,那么怎么配置波特率?

    原理图如下:

     就是用最下面这两个公式去计算和配置波特率。

    配置什么东西,肯定要看看寄存器。。。

     和上面的原理图相似,波特率分为整数和小数部分,分别把这两个和单片机的时钟带进公式,就能得到波特率了

    代码如下:(M4的USART时钟波特率是84MHZ,所以下面写成84000000ul)

        usart_div = (float)84000000ul / (DEBUG_USART_BOUND * 16);
        div_mantissa = (u16)usart_div;    //得到整数部分
        div_fraction = (usart_div - div_mantissa) * 16 + 0.5;//四舍五入
        USART1->BRR = (div_mantissa << 4) + div_fraction;    //设置波特率

    下面说说串口USART:

    代码如下:

    初始化USART(本代码中顺带加入了中断;本例中引脚为PA9)

    void debug_usart_init(void)
    {
        float usart_div = 0;
        u16 div_mantissa = 0;
        u16 div_fraction = 0;
        
        debug_usart_port_init();
        
        RCC->APB2ENR |= (0X1 << 4);        //开启USART1的时钟
    
        usart_div = (float)84000000ul / (DEBUG_USART_BOUND * 16);
        div_mantissa = (u16)usart_div;    //得到整数部分
        div_fraction = (usart_div - div_mantissa) * 16 + 0.5;//四舍五入
        USART1->BRR = (div_mantissa << 4) + div_fraction;    //设置波特率
        
        USART1->CR1 = 0;//清空所有配置
        
        USART1->CR1 |= (0X1 << 3);//发送器使能
        USART1->CR1 |= (0X1 << 2);//接收器使能
        
        USART1->CR1 |= (0X1 << 13);//使能USART1
        
        USART1->CR2 &= ~(0X3 << 12);//停止位为1个位
        
        uint32_t priority = 0;        //保存合成的优先级值
        NVIC_SetPriorityGrouping(7 - 2);
        priority = NVIC_EncodePriority(7 - 2, 2, 2);
        NVIC_SetPriority(USART1_IRQn, priority);    //以USART1为例
    
        //根据外设寄存器配置----需要掌握该外设相关的寄存器
        USART1->CR1 |= (0X1 << 5);//接收中断使能
    
        NVIC_EnableIRQ(USART1_IRQn);    //以USART1为例
    }

    USART的中断服务函数:

    void USART1_IRQHandler(void)
    {
        uint8_t receive_data = 0;
        
        //如果接收到数据,产生接收标志位
        if(USART1->SR & (0x1 << 5))
        {
            USART1->SR &= ~(0x1 << 5);    //清除标志位
            
            //读取接收缓冲区中的数据
            receive_data = USART1->DR;
            
            dubug_usart_write_byte_data(receive_data);    //将接收到的字节数据发送出去
        }
    }

    发送和接受数据函数:

    /*
    ***********************************************************************************************
    * 函数功能: 发送一个字节数据
    * 函数形参: writedata    需要发送的数据
    * 函数返回值: None
    * 备注: None
    * 作者: 
    * 时间: 
    * 修改作者: None
    * 修改时间: None
    ***********************************************************************************************
    */
    void dubug_usart_write_byte_data(uint8_t writedata)
    {
        //等待发送缓冲区空
        while(!(USART1->SR & (0X1 << 7)))
        {
            
        }
        //发送缓冲区已经空了
        
        //发送数据
        USART1->DR = writedata;
    }
    
    
    
    /*
    ***********************************************************************************************
    * 函数功能: 接收一个字节数据
    * 函数形参: None
    * 函数返回值: 接收到的数据
    * 备注: None
    * 作者: 
    * 时间: 
    * 修改作者: None
    * 修改时间: None
    ***********************************************************************************************
    */
    uint8_t dubug_usart_read_byte_data(void)
    {
        //等待接收缓冲区非空
        while(!(USART1->SR & (0X1 << 5)))
        {
            
        }
        //接收缓冲区非空,有数据
        
        //读取数据
        return USART1->DR;
    }
    
    
    /*
    ***********************************************************************************************
    * 函数功能: 接收一串字符数据
    * 函数形参: *string    用来存储接收到的字符串
    * 函数返回值: None
    * 备注: None
    * 作者: 
    * 时间: 
    * 修改作者: None
    * 修改时间: None
    ***********************************************************************************************
    */
    void debug_usart_recivied_string(uint8_t *string)
    {
        while(1)
        {
            //等待接收缓冲区非空
            while(!(USART1->SR & (0X1 << 5)))
            {
                
            }
            //接收缓冲区非空,有数据
            //读取数据
            *string = USART1->DR;
            
            //如果接收到的字符为'
    '或'
    '认为接收字符串完成
            if(*string == '
    ' || *string == '
    ')
            {
                *string = '';    //不存储'
    '或'
    ',存储一个字符串结束标志
                
                break;
            }
            
            string++;
        }
    }

    实现printf()功能的代码 ,直接加进去就好:

    #pragma import(__use_no_semihosting_swi) //取消半主机状态
    
    struct __FILE { int handle; /* Add whatever you need here */ };
    FILE __stdout;
    
    int fputc(int ch, FILE *f) 
    {
        while((USART1->SR &(0X01<<7))==0);  //等待之前的数据发送完毕
            USART1->DR=ch;
      return (ch);
    }
    
    int ferror(FILE *f) {
      /* Your implementation of ferror */
      return EOF;
    }
    
    void _ttywrch(int ch) {
      while((USART1->SR &(0X01<<7))==0);
            USART1->DR=ch;
    }
    
    void _sys_exit(int return_code) {
    label:  goto label;  /* endless loop */
    }
    84000000
  • 相关阅读:
    lrzsz踩坑记
    《西安游记》
    《这世界那么多人》
    Go 日常开发常备第三方库和工具
    Go 里的超时控制
    菜鸟轻松拿offer: 软件测试工程师面试秘笈
    Django 练习教程
    JasperReports入门教程(五):分组打印
    并发的特性和锁的原理,分类
    面试高频算法
  • 原文地址:https://www.cnblogs.com/qifeng1024/p/11734750.html
Copyright © 2011-2022 走看看