13_I.MX6ULL串口UART实验

目录

UART简介

UART电平标准

I.MX6U UART简介

相关寄存器

UART的配置步骤

实验源码


UART简介

串口全称叫做串行接口,通常也叫做COM接口,串行接口指的是数据一个一个的顺序传输,通信线路简单。使用两条线即可实现双向通信,一条用于发送,一条用于接收。串口通信距离远,但是速度相对会低,串口是一种很常用的工业接口。I.MX6U自带的UART外设就是串口的一种,UART全称是Universal Asynchronous Receiver/Trasmitter,也就是异步串行收发器。既然有异步串行收发器,那肯定也有同步串行收发器,学过STM32的同学应该知道, STM32除了有UART外,还有另外一个叫做USART的东西。

USART的全称是UniversalSynchronous/Asynchronous Receiver/Transmitter,也就是同步/异步串行收发器。相比UART多了一个同步的功能,在硬件上体现出来的就是多了一条时钟线。一般USART是可以作为 UART使用的,也就是不使用其同步的功能。UART作为串口的一种,其工作原理也是将数据一位一位的进行传输,发送和接收各用一条线,因此通过UART接口与外界相连最少只需要三条线: TXD(发送)、RXD(接收)和GND(地线)。

UART的通信格式:

13_I.MX6ULL串口UART实验_第1张图片

空闲位:数据线在空闲状态的时候为逻辑“1”状态,也就是高电平,表示没有数据线空闲,没有数据传输。

起始位:当要传输数据的时候先传输一个逻辑“0”,也就是将数据线拉低,表示开始数据传输。

数据位:数据位就是实际要传输的数据,数据位数可选择5~8位,一般都是按照字节传输数据的,一个字节8位,因此数据位通常是8位的。低位在前,先传输,高位最后传输。

奇偶校验位:这是对数据中“1”的位数进行奇偶校验用的,可以不使用奇偶校验功能。

停止位:数据传输完成标志位,停止位的位数可以选择1位、1.5位或2位高电平,一般都选择1 位停止位。

波特率:波特率就是UART数据传输的速率,也就是每秒传输的数据位数,一般选择9600、19200、115200 等。

UART电平标准

UART一般的接口电平有TTL和RS-232,一般开发板上都有TXD和RXD这样的引脚,这些引脚低电平表示逻辑0,高电平表示逻辑1,这个就是TTL电平。RS-232采用差分线,-3~-15V表示逻辑1,+3~+15V表示逻辑0。

I.MX6U UART简介

I.MX6U的UART接口, I.MX6U一共有8个UART,其主要特性如下:

1.兼容 TIA/EIA-232F 标准,速度最高可到5Mbit/S。

2.支持串行IR接口,兼容IrDA,,最高可到115.2Kbit/s。

3.支持9位或者多节点模式(RS-485)。

4.1或2位停止位。

5.可编程的奇偶校验(奇校验和偶校验)。

6.自动波特率检测(最高支持115.2Kbit/S)。

相关寄存器

UART的控制寄存器即UARTx_UCR1(x=1~8),此寄存器的结构如所示:

13_I.MX6ULL串口UART实验_第2张图片

ADBR(bit14):自动波特率检测使能位,为0的时候关闭自动波特率检测,为1的时候使能自动波特率检测。

UARTEN(bit0): UART使能位,为0的时候关闭UART,为1的时候使能UART。

UART的控制寄存器2,即:UARTx_UCR2,此寄存器结构如图所示:

13_I.MX6ULL串口UART实验_第3张图片

 

IRTS(bit14):为0的时候使用 RTS引脚功能,为1的时候忽略 RTS引脚。

PREN(bit8):奇偶校验使能位,为0的时候关闭奇偶校验,为1的时候使能奇偶校验。

PROE(bit7):奇偶校验模式选择位,开启奇偶校验以后此位如果为0的话就使用偶校验,此位为1的话就使能奇校验。

STOP(bit6):停止位数量,为0的话1位停止位,为1的话2位停止位。

WS(bit5):数据位长度,为0 的时候选择7位数据位,为1的时候选择8位数据位。

TXEN(bit2):发送使能位,为0的时候关闭UART的发送功能,为的时候打开UART的发送功能。

RXEN(bit1):接收使能位,为 0的时候关闭UART的接收功能,为1的时候打开UART的接收功能。

SRST(bit0):软件复位,为0的是时候软件复位UART,为1的时候表示复位完成。复位完成以后此位会自动置1,表示复位完成。此位只能写0,写1会被忽略掉。

RXEN(bit1):接收使能位,为0的时候关闭UART的接收功能,为1的时候打开UART的接收功能。

SRST(bit0):软件复位,为0的时候软件复位UART,为1的时候表示复位完成。复位完成以后此位会自动置1,表示复位完成。此位只能写0,写1会被忽略掉。

UARTx_USR2,这个是UART的状态寄存器2,此寄存器结构如图所示:

13_I.MX6ULL串口UART实验_第4张图片

TXDC(bit3):发送完成标志位,为1的时候表明发送缓冲(TxFIFO)和移位寄存器为空,也就是发送完成,向TxFIFO写入数据此位就会自动清零。

RDR(bit0):数据接收标志位,为的时候表明至少接收到一个数据,从寄存器UARTx_URXD读取数据接收到的数据以后此位会自动清零。

寄存器 UARTx_UFCR、UARTx_UBIR和UARTx_UBMR,寄存器UARTx_UFCRRFDIV(bit9:7),用来设置参考时钟分频,设置如表:

13_I.MX6ULL串口UART实验_第5张图片

 通过这三个寄存器可以设置UART的波特率,波特率的计算公式如下:

Ref Freq:经过分频以后进入UART的最终时钟频率。

UBMR:寄存器UARTx_UBMR中的值。

UBIR:寄存器UARTx_UBIR中的值。

通过UARTx_UFCR的RFDIV位、UARTx_UBMR和UARTx_UBIR这三者的配合即可得到我们想要的波特率。比如现在要设置UART波特率为115200,那么可以设置RFDIV为5(0b101),也就是1分频,因此Ref Freq=80MHz。设置UBIR=71, UBMR=3124,根据上面的公式可以得到:

 寄存器UARTx_URXD和UARTx_UTXD,这两个寄存器分别为UART的接收和发送数据寄存器,这两个寄存器的低八位为接收到的和要发送的数据。读取寄存器UARTx_URXD即可获取到接收到的数据,如果要通过UART发送数据,直接将数据写入到寄存器UARTx UTXD即可。

UART的配置步骤

1.设置 UART1的时钟源

设置UART的时钟源为pll3_80m,设置寄存器CCM_CSCDR1的UART_CLK_SEL位为即可。

2.初始化UART

初始化UART所使用IO,设置UART的寄存器UART_UCR1~UART_UCR3,设置内容包括波特率,奇偶校验、停止位、数据位等等。

3.使能UART

UART初始化完成以后就可以使能UART了,设置寄存器UART1_UCR1的位UARTEN

4.编写UART1数据收发函数

编写两个函数用于UART的数据收发操作。

实验源码

#ifndef __BSP_UART_H_
#define __BSP_UART_H_

#include "imx6ul.h"
/*函数声明*/
void uart_IO_init(void);
void uart_disable(UART_Type *base);
void uart_enable(UART_Type *base);
void uart_soft_reset(UART_Type *base);
void uart_init(void);
void puts(char *str);
unsigned char getc(void);
void putc(unsigned char c);
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz);
#endif

 

#include "bsp_uart.h"
#include "bsp_gpio.h"

/*
 * @description	: uart1的IO初始化
 * @param 		: 无
 * @return 		: 无
 */
void uart_IO_init(void)
{
	
	/* 1、初始化IO复用 */
	IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0); /*复用为串口发送引脚 TX*/
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0); /*复用为串口发送引脚 RX*/

	/* 2、、配置UART1 IO属性*/	
	IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10b0);
	IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10b0);

}



/*
 * @description	: 关闭uart
 * @param 		: 无
 * @return 		: 无
 */
 void uart_disable(UART_Type *base)
 {
    base->UCR1 &= ~(1 << 0);
 }



/*
 * @description	: 打开uart
 * @param 		: 无
 * @return 		: 无
 */
 void uart_enable(UART_Type *base)
 {
    base->UCR1 |= (1 << 0);
 }


/*
 * @description	: 软复位uart
 * @param 		: 无
 * @return 		: 无
 */
 void uart_soft_reset(UART_Type *base)
 {
    base->UCR2 &= ~(1 << 0);
    while((base->UCR2 & 0x01) == 0);
 }


/*
 * @description	: 初始化uart1
 * @param 		: 无
 * @return 		: 无
 */
void uart_init(void)
{
    /*初始化uart1的IO*/
    uart_IO_init();
   
    /*初始化uart1*/

    uart_disable(UART1);/*关闭串口*/
    uart_soft_reset(UART1);/*软复位uart*/

    /*配置uart1*/
    UART1->UCR1 = 0;
	/*
     * 设置UART的UCR1寄存器,关闭自动波特率
     * bit14: 0 关闭自动波特率检测,我们自己设置波特率
	 */
	UART1->UCR1 &= ~(1<<14);

	/*
     * 设置UART的UCR2寄存器,设置内容包括字长,停止位,校验模式,关闭RTS硬件流控
     * bit14: 1 忽略RTS引脚
	 * bit8: 0 关闭奇偶校验
     * bit6: 0 1位停止位
 	 * bit5: 1 8位数据位
 	 * bit2: 1 打开发送
 	 * bit1: 1 打开接收
	 */
	UART1->UCR2 |= (1<<14) | (1<<5) | (1<<2) | (1<<1);

    UART1->UCR3 |= (1 << 2);

    /*设置波特率为115200*/
    uart_setbaudrate(UART1,115200,80000000);

    /*使能串口*/
    uart_enable(UART1);
}



/*
 * @description	: uart1发送字节
 * @param 		: 无
 * @return 		: 无
 */
void putc(unsigned char c)
{
    while(((UART1->USR2 >>3) & 0X01) == 0); /*等待数据没发完*/
    UART1->UTXD = c & 0XFF;
}


/*
 * @description	: uart1接受字节
 * @param 		: 无
 * @return 		: 无
 */ 
unsigned char getc(void)
{
	while((UART1->USR2 & 0x1) == 0);/* 等待接收完成 */
	return UART1->URXD;				/* 返回接收到的数据 */
}

/*
 * @description	: uart1发送多个字节
 * @param 		: 无
 * @return 		: 无
 */
void puts(char *str)
{
	char *p = str;

	while(*p)
		putc(*p++);
}


/*
 * @description 		: 波特率计算公式,
 *    			  	  	  可以用此函数计算出指定串口对应的UFCR,
 * 				          UBIR和UBMR这三个寄存器的值
 * @param - base		: 要计算的串口。
 * @param - baudrate	: 要使用的波特率。
 * @param - srcclock_hz	:串口时钟源频率,单位Hz
 * @return		: 无
 */
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz)
{
    uint32_t numerator = 0u;		//分子
    uint32_t denominator = 0U;		//分母
    uint32_t divisor = 0U;
    uint32_t refFreqDiv = 0U;
    uint32_t divider = 1U;
    uint64_t baudDiff = 0U;
    uint64_t tempNumerator = 0U;
    uint32_t tempDenominator = 0u;

    /* get the approximately maximum divisor */
    numerator = srcclock_hz;
    denominator = baudrate << 4;
    divisor = 1;

    while (denominator != 0)
    {
        divisor = denominator;
        denominator = numerator % denominator;
        numerator = divisor;
    }

    numerator = srcclock_hz / divisor;
    denominator = (baudrate << 4) / divisor;

    /* numerator ranges from 1 ~ 7 * 64k */
    /* denominator ranges from 1 ~ 64k */
    if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator > UART_UBIR_INC_MASK))
    {
        uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;
        uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;
        uint32_t max = m > n ? m : n;
        numerator /= max;
        denominator /= max;
        if (0 == numerator)
        {
            numerator = 1;
        }
        if (0 == denominator)
        {
            denominator = 1;
        }
    }
    divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;

    switch (divider)
    {
        case 1:
            refFreqDiv = 0x05;
            break;
        case 2:
            refFreqDiv = 0x04;
            break;
        case 3:
            refFreqDiv = 0x03;
            break;
        case 4:
            refFreqDiv = 0x02;
            break;
        case 5:
            refFreqDiv = 0x01;
            break;
        case 6:
            refFreqDiv = 0x00;
            break;
        case 7:
            refFreqDiv = 0x06;
            break;
        default:
            refFreqDiv = 0x05;
            break;
    }
    /* Compare the difference between baudRate_Bps and calculated baud rate.
     * Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).
     * baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator).
     */
    tempNumerator = srcclock_hz;
    tempDenominator = (numerator << 4);
    divisor = 1;
    /* get the approximately maximum divisor */
    while (tempDenominator != 0)
    {
        divisor = tempDenominator;
        tempDenominator = tempNumerator % tempDenominator;
        tempNumerator = divisor;
    }
    tempNumerator = srcclock_hz / divisor;
    tempDenominator = (numerator << 4) / divisor;
    baudDiff = (tempNumerator * denominator) / tempDenominator;
    baudDiff = (baudDiff >= baudrate) ? (baudDiff - baudrate) : (baudrate - baudDiff);

    if (baudDiff < (baudrate / 100) * 3)
    {
        base->UFCR &= ~UART_UFCR_RFDIV_MASK;
        base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);
        base->UBIR = UART_UBIR_INC(denominator - 1); 
        base->UBMR = UART_UBMR_MOD(numerator / divider - 1);
        
    }

}

/*
 * @description : 防止编译器报错
 * @param 		: 无
 * @return		: 无
 */
void raise(int sig_nr) 
{

}
#include "bsp_clk.h"

#include "bsp_delay.h"

#include "bsp_led.h"

#include "bsp_beep.h"

#include "bsp_key_filter.h"

#include "bsp_interrupt.h"

#include "bsp_uart.h"

#include "stdio.h"

/*

 * @description	: main函数

 * @param 		: 无

 * @return 		: 无

 */

int main(void)

{

	unsigned char state = OFF;

	int a ,b ;

	int_init(); 		/* 初始化中断(一定要最先调用!)*/

	imx6u_clkinit();	/* 初始化系统时钟*/

	clk_enable();		/* 使能所有的时钟*/

	delay_init();		/* 延时初始化 */

	uart_init();		/*初始化串口*/	

	led_init();			/* 初始化led*/

	beep_init();		/* 初始化凤鸣器*/







	while(1)			

	{	

		printf("请输入2个整数,使用空格隔开:");

		scanf("%d %d", &a,&b);

		printf("\r\n 数据%d+%d=%d\r\n",a, b, a+b);



		state =! state;

		led_switch(LED0, state);



	}



	return 0;

}

13_I.MX6ULL串口UART实验_第6张图片

 

你可能感兴趣的:(ARM(IMX6U)裸机,嵌入式硬件,I.MX6ULL,linux)