STM32F103C8T6之通用异步收发器(发送接收中断)

来源:互联网 发布:产品数据分析总结 编辑:程序博客网 时间:2024/06/05 20:09

文档简介:本文档主要讲解了关于STM32F103C8T6 外设之UART数据上传与下发的功能实现以及UART的基本概念。这里对于寄存器的配置不做分析,提供UART标准程序的设计思路。前面几部分着重描述UART通信方式及其特点的一些概念介绍与理解。

一、文档导航

1、什么是串行通信

2、什么是并行通信

3、什么是同步通信

4、什么是异步通信

5、全双工、半双工、单工三者区别

  6、标准UART的通信数据帧格式

7、标准UART程序设计思路

8、STM32F103C8T6 UART内部框架

9、具体实现代码

  10、后续更新

二、什么是串行通信

2.1 概念理解

只有一根数据线的通信方式叫串行通信。就是将数据一个一个位传递,实现串行通信。

2.2 此通信方式特点

        优点:硬件设计非常简单,可靠性高。

缺点:数据传输速度慢,不适合需求数据传输速度快的设备。

三、什么是并行通信

3.1 概念理解
具有多条线的进行数据通信的方式叫并行通信。

3.2 此通信方式特点

  优点:通信速度快。适合需求数据传输速度的设备。

缺点:硬件设计复杂,可靠性低。

四、什么是同步通信

4.1  概念

通信双方具有相同的时钟,并且有时钟线相连接。

  4.2 通讯特点

通信数据会持续输出,不会存在积累误差。

五、什么是异步通信

5.1 概念

  通信双方不具有相同的时钟,没有时钟线相连接。

5.2 通讯特点

通信双方数据输出会存在积累误差。为了解决积累误差,数据不准确的问题,采用数据没传输一帧,下一次数据传输就从帧头开始传输。

六、全双工、半双工、单工三者区别

6.1 全双工

在同一时刻,数据的收发能够同时进行,互不干扰。其数据线为双向单线。

  6.2 单双工

在同一时刻,数据收发只能进行收或者发,相当于独木桥。要么收,要么发,正在进行数据交换时,可以对数据收发的方向进行切换。其数据线为双线单线。

6.3 单工

只具有一个方向的数据通信。具有单向性。其数据线为单向单线。

6.4 UART属于全双工。

七、标准UART的通信数据帧格式

7.1 通信方式

标准UART属于异步串行通信,也是全双工通信。

7.2 帧格式说明

在UART的通信方式中,它的数据或者字符是以帧格式进行数据传送的。帧格式为串口通信的数据格式。其帧格式是以一个起始位“0”表示字符的开始,接着是5-8位的数据位,一般规定低位在前,高位在后;数据位后是奇偶校验位,然后是停止位。停止位一般分为0.5位、1位、1.5位、2.0位。一个完整的帧格式从起始位到停止位。

起始位:通信线上没有数据传送时,为高电平(逻辑1);当要发送数据时,首先发1个低电平信号(逻辑0),此信号称为“起始位”,表示开始传输1帧数据。

数据位:起始位之后就是数据位,数据位一般为5-8位,规定低位在前、高位在后。一般都是从低位开始传送,然后高位传送。

奇偶校验位:数据位之后的位为奇偶校验位(有的方式具有)。此位可用于判别字符传送的正确性,其有3种可能的选择,即奇、偶、无校验,用户可根据需要选择

停止位:它是一个字符数据的结束标志。可以是1位、1.5位(每一位时间是固定,1.5位就是高电平时间 长度是1.5位占用的时间)、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

八、标准UART程序设计思路

8.1 实现UART通信的必备四大元素

        波特率:一秒钟传输的二进制位数。

数据位:实际数据一般存放在数据位。5-8位。

停止位:主要用来消除积累误差

校验位:硬件校验,一般的硬件支持奇偶校验。

8.2 UART通信

常规的UART通信,只需要实现以下几个方面即可通信。

        ①配置UART通信的四大元素--UART初始化;

②数据发送函数

        ③数据接收函数

九、STM32F103C8T6 UART内部框架

9.1内部框架

如果通过配置寄存器的方式,需要对UART内部框架图进行详细分析。

9.2具体配置过程

9.2.1 UART初始化

①开启TX/RX对应IO时钟、开启串口时钟、IO引脚复用时钟

②TX配置成复用推挽输出、RX配置成上下拉输入

③TX/RX复用为串口使能

④计算波特率、写入波特率寄存器

⑤使能UART、配置数据格式(1-start、8-databit、1-stop)、奇偶校验位、停止位

⑥发送使能、接收使能

⑦若需中断,开启UART总中断,开启接收空闲中断,NVIC控制器配置。

        ⑧中断服务处理

        9.2.2 数据发送

等待发送完成、将发送的data写入register;

9.2.3 数据接收

等待接收完成,将register的值传递到buff;

十、具体实现代码

#include "uart.h"
#include <stdio.h>
#include <rt_misc.h>

volatile uint8_t uart_interrupt_flag = UART_RECE_DATA_NO_FLAG;
char uart_frame_buffer[UART_RECE_LENGTH];
#if 1  
#pragma import(__use_no_semihosting_swi)

struct __FILE
{
    int handle; 
};

FILE __stdout;       
int fputc(int ch, FILE *f)
{
    return ( send_data(ch));
}

int ferror(FILE *f)
{
    /* Your implementation of ferror */
    return EOF;
}

void _ttywrch(int ch)
{
    send_data(ch);
}

void _sys_exit(int return_code)
{
label:
    goto label;  /* endless loop */
}
#endif

#if UART_INTERRUPT

void uart_interrupt_init(void)
{
uint32_t Priority;
USART1->CR1 |= 1 << 5;
USART1->CR1 |= 1 << 4;
NVIC_SetPriorityGrouping(7-2);
Priority=NVIC_EncodePriority(7-2,3,1);
NVIC_SetPriority(USART1_IRQn,Priority);
NVIC_EnableIRQ(USART1_IRQn);          
}

#endif

void uart1_init(uint32_t baund,uint32_t clk)
{
float temp;
uint16_t mantissa;
uint16_t fraction;

RCC->APB2ENR |= 1 << 2;
RCC->APB2ENR |= 1 << 14;

RCC->APB2ENR |= 1 << 0; 
GPIOA->CRH &= ~(0xFF << 4);
GPIOA->CRH |=  (0x4B << 4);

AFIO->MAPR2 &= ~(0X1 << 2);

temp =  (float)(clk)/ (baund * 16.0);
mantissa = temp ;                    
fraction =(int)(temp -mantissa)*16 + 0.5f;

mantissa <<= 4;
mantissa |= fraction;
USART1->BRR = mantissa;

USART1->CR1 |= 1 << 13 |  
              0 << 12 |  
  0 << 10 |  
  0 << 8  |  
  1 << 2  |   //receiver enable
  1 << 3  ;   //transform enable
USART1->CR2 |= (0 << 12);
USART1->CR2 |= (0 << 13);

USART1->CR3 = 0;
#if UART_INTERRUPT
uart_interrupt_init();
#endif
}

char send_data(char buff)
{
while(!( (USART1->SR) & (1 << 7)  ))
{
;
}
USART1->DR = buff;
return buff;
}

char rece_data(void)
{
while(!( (USART1->SR) & (1 << 5)))
{
;
}
return USART1->DR;
}

void send_data_string(char *string)
{
while(*string)
{
send_data(*string++);
}
send_data('\r');
send_data('\n');
}

char* rece_data_string(char *string)
{
uint8_t r_data;
uint8_t i=0;
while(1)
{
r_data = rece_data();
string[i++]=r_data;
if(r_data == '\n')
{
break;
}
#if 1
#if (ECHO == ECHO_ON)


send_data(r_data) ;
#endif
#endif      
    }
#if 1
#if (ECHO == ECHO_ON)
send_data('\r') ;
send_data('\n') ;
#endif
#endif
string[i]=0;
return string;
}

void USART1_IRQHandler(void)
{

uint32_t ch_data;
    static uint32_t i=0;

if( (USART1->SR)  & (1 << 5))
{
ch_data=USART1->DR;
uart_frame_buffer[i++]=ch_data;
if(i >= UART_RECE_LENGTH)
{
uart_frame_buffer[i++]='\0';
uart_interrupt_flag = UART_RECE_DATA_NO_FLAG;//Òç³ö±êÖ¾
i=0;
}
}
if( (USART1->SR) & (1 << 4))
{
ch_data=USART1->DR;
uart_frame_buffer[i++]='\0';
i=0;
uart_interrupt_flag = UART_RECE_DATA_OK_FLAG;
}
}

在实现过程中,波特率配置出现问题,写入寄存器没有注意到小数部分为前面四位,刚开始理解成前面8位,导致串口上传failed;

另外还有volatile 此关键词在应用,不管在哪里都需要将它放在变量前。

十一、后续更新会继续更新 大笑


原创粉丝点击