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_UFCR、UARTx_UBMR、UARTx_UBIR这三个寄存器配合可得波特率
-
UARTx_URXD接收数据寄存器
-
UARTx_UTXD发送数据寄存器
综上所述,使用UART1来完成开发板与串口助手之间的通信,UART1的配置步骤如下:
- 设置UART1的时钟源
- 初始化UART1
- 使能UART1
- 编写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卡,使用串口工具连接开发板,复位后提示输入字符,输入字符后会回显出来