Linux裸机开发|UART串口通信

Source

UART串口通信

不管是单片机开发还是嵌入式Linux开发,串口都是最常用到的外设。可以通过串口将开发板与电脑相连,然后在电脑上通过串口调试助手来调试程序。还有很多模块,比如蓝牙、GPS、GPRS等都使用串口来与主控进行通讯的,在嵌入式Linux中一般使用串口作为控制台

1. UART简介

串口全称串行接口,是指数据一个一个的顺序传输,通信线路简单(两条线即可)。UART与外界相连最少只需要三根线:TXD(发送)、RXD(接收)、GND(地线)。其通讯格式如下图示:

在这里插入图片描述

  • 空闲位:数据线在空闲状态时为高电平
  • 起始位:将数据线拉低,表示开始数据传输
  • 数据位:实际要传输的数据
  • 奇偶校验位:对数据中1的位数进行奇偶校验用
  • 停止位:数据传输完成标志位
  • 波特率: 数据传输的速率,即每秒传输的数据位数

UART一般的接口电平有TTL和RS232,TTL用低电平表示逻辑0,高电平表示逻辑1;RS232采用差分线,-3 ~ -15V表示逻辑1, +3 ~ +15V表示逻辑0

IMX6U一共有8个UART,UART功能很多,这里只用到其最基本的串口功能。UART的时钟源由寄存器CCM_CSCDR1的UART_CLK_SEL位来选择,分频值由UART_CLK_PODF位来设置。下面介绍UART几个重要的寄存器:

  • UARTx_UCR1控制寄存器1
    在这里插入图片描述
  • ADBR:自动波特率检测使能位
  • UARTEN:UART使能位
  • UARTx_UCR2控制寄存器2
    在这里插入图片描述
  • IRTS:RTS引脚功能,为0时使用,为1时忽略
  • PREN:奇偶校验使能位
  • PROE:奇偶校验模式选择位
  • STOP:停止位数量,为0时1位停止位,为1时2位停止位
  • WS:数据位长度,为0时7位数据位,为1时8位数据位
  • TXEN:发送使能位,0关闭,1开启
  • RXEN:接收使能位,0关闭,1开启
  • SRST:软件复位
  • UARTx_UCR3控制寄存器3
    在这里插入图片描述
  • RXDMUXSEL:始终置1
  • UARTx_USR2 状态寄存器2
    在这里插入图片描述
  • TXDC:发送完成标志位,为1时表示发送缓冲区和移位寄存器为空(即发送完成)
  • RDR:数据接收标志位,为1时表示至少接收到一个数据
  • UARTx_UFCRUARTx_UBMRUARTx_UBIR这三个寄存器配合可得波特率
    在这里插入图片描述

  • UARTx_URXD接收数据寄存器
    在这里插入图片描述

  • UARTx_UTXD发送数据寄存器
    在这里插入图片描述

综上所述,使用UART1来完成开发板与串口助手之间的通信,UART1的配置步骤如下:

  1. 设置UART1的时钟源
  2. 初始化UART1
  3. 使能UART1
  4. 编写UART1数据收发函数

2. 硬件介绍

本例程需要用到的硬件资源:

  • LED0
  • UART1

在这里插入图片描述
使用USB串口线将串口1和电脑连接后,利用串口调试助手与电脑进行通信

3. 程序编写

  • 新建uart文件夹,编写uart驱动文件bsp_uart.c和bsp_uart.h
/* 函数声明 */
void uart_init(void);
void uart_io_init(void);
void uart_disable(UART_Type *base);
void uart_enable(UART_Type *base);
void uart_softreset(UART_Type *base);
void putc(unsigned char c);
void puts(char *str);
unsigned char getc(void);
/* 初始化串口1,波特率为115200 */
void uart_init(void){
    
      
	uart_io_init();	//初始化串口IO
	/* 初始化UART1 */
	uart_disable(UART1);	//先关闭UART1
	uart_softreset(UART1);	//软件复位UART1
	UART1->UCR1 = 0;		//先清除UCR1寄存器	
	/* 设置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寄存器
     * bit2: 1 必须设置为1!参考IMX6ULL参考手册3624页 */
	UART1->UCR3 |= 1<<2; 
	/* 设置波特率
	 * 波特率计算公式:Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)) 
	 * 如果要设置波特率为115200,那么可以使用如下参数:
	 * Ref Freq = 80M 也就是寄存器UFCR的bit9:7=101, 表示1分频
	 * UBMR = 3124
 	 * UBIR =  71
 	 * 因此波特率= 80000000/(16 * (3124+1)/(71+1))=80000000/(16 * 3125/72) = (80000000*72) / (16*3125) = 115200 */
	UART1->UFCR = 5<<7; //ref freq等于ipg_clk/1=80Mhz
	UART1->UBIR = 71;
	UART1->UBMR = 3124;

	/* 使能串口 */
	uart_enable(UART1);
}
/* 初始化串口1所使用的IO引脚 */
void uart_io_init(void){
    
      
	/* 1、初始化IO复用 
     * UART1_RXD -> UART1_TX_DATA
     * UART1_TXD -> UART1_RX_DATA */
	IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);	/* 复用为UART1_TX */
	IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);	/* 复用为UART1_RX */
	/* 2、配置UART1_TX_DATA、UART1_RX_DATA的IO属性 
 	*bit 16:0 HYS关闭
 	*bit [15:14]: 00 默认100K下拉
 	*bit [13]: 0 keeper功能
 	*bit [12]: 1 pull/keeper使能
 	*bit [11]: 0 关闭开路输出
 	*bit [7:6]: 10 速度100Mhz
 	*bit [5:3]: 110 驱动能力R0/6
 	*bit [0]: 0 低转换率 */
	IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);
	IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);
}
/* @description : 关闭指定的UART
 * @param - base: 要关闭的UART
 * @return		: 无 */
void uart_disable(UART_Type *base){
    
      
	base->UCR1 &= ~(1<<0);	
}
/* @description : 打开指定的UART
 * @param - base: 要打开的UART
 * @return		: 无 */
void uart_enable(UART_Type *base){
    
      
	base->UCR1 |= (1<<0);	
}
/* @description : 复位指定的UART
 * @param - base: 要复位的UART
 * @return		: 无  */
void uart_softreset(UART_Type *base){
    
      
	base->UCR2 &= ~(1<<0); 			/* UCR2的bit0为0,复位UART */
	while((base->UCR2 & 0x1) == 0); /* 等待复位完成 			  */
}
/* @description : 发送一个字符
 * @param - c	: 要发送的字符
 * @return		: 无 */
void putc(unsigned char c){
    
      
	while(((UART1->USR2 >> 3) &0X01) == 0);/* 等待上一次发送完成 */
	UART1->UTXD = c & 0XFF; 				/* 发送数据 */
}
/* @description : 发送一个字符串
 * @param - str	: 要发送的字符串
 * @return		: 无 */
void puts(char *str){
    
      
	char *p = str;
	while(*p)
		putc(*p++);
}
/* @description : 接收一个字符
 * @param 		: 无
 * @return		: 接收到的字符 */
unsigned char getc(void){
    
      
	while((UART1->USR2 & 0x1) == 0);/* 等待接收完成 */
	return UART1->URXD;				/* 返回接收到的数据 */
}
  • 主程序main.c编写
int main(void){
    
      
	unsigned char a = 0;
	unsigned char state = OFF;
	int_init(); 				/* 初始化中断(一定要最先调用!) */
	imx6u_clkinit();			/* 初始化系统时钟 			*/
	delay_init();				/* 初始化延时               */
	clk_enable();				/* 使能所有的时钟 			*/
	led_init();					/* 初始化led 			*/
	beep_init();				/* 初始化beep	 		*/
	uart_init();				/* 初始化串口,波特率115200 */
	while(1){
    
      	
		puts("请输入1个字符:");
		a = getc();
		putc(a);	//回显功能

		puts("您输入的字符为:");
		putc(a);
		puts("\r\n\r\n");
		
		state = !state;
		led_switch(LED0, state);
	}
	return 0;
}

4. 下载验证

  • 修改Makefile文件:修改TARGET为uart,追加“bsp/uart”文件夹,还需修改如下代码
$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
$(SOBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<
#加入了“-fno-builtin”选项,表示不使用内建函数,使用自已实现的函数
#如果不加该选项,编译的时候回提示“putc”“puts”这两个函数与内建函数冲突
  • 使用imxdownload软件将bin文件下载到SD卡中
  • 烧写成功后,插入SD卡,使用串口工具连接开发板,复位后提示输入字符,输入字符后会回显出来

在这里插入图片描述