完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:正点原子Linux开发板 2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号,获取更多资料:正点原子 第二十一章 UART串口通信实验 不管是单片机开发还是嵌入式Linux开发,串口都是最常用到的外设。可以通过串口将开发板与电脑相连,然后在电脑上通过串口调试助手来调试程序。还有很多的模块,比如蓝牙、GPS、GPRS等都使用的串口来与主控进行通信的,在嵌入式Linux中一般使用串口作为控制台,所以掌握串口是必备的技能。本章我们就来学习如何驱动I.MX6U上的串口,并使用串口和电脑进行通信。 21.1 I.MX6U串口简介21.1.1UART简介1、UART通信格式 串口全称叫做串行接口,通常也叫做COM接口,串行接口指的是数据一个一个的顺序传输,通信线路简单。使用两条线即可实现双向通信,一条用于发送,一条用于接收。串口通信距离远,但是速度相对会低,串口是一种很常用的工业接口。I.MX6U自带的UART外设就是串口的一种,UART全称是Universal Asynchronous Receiver/Trasmitter,也就是异步串行收发器。既然有异步串行收发器,那肯定也有同步串行收发器,学过STM32的同学应该知道,STM32除了有UART外,还有另外一个叫做USART的东西。USART的全称是Universal Synchronous/Asynchronous Receiver/Transmitter,也就是同步/异步串行收发器。相比UART多了一个同步的功能,在硬件上体现出来的就是多了一条时钟线。一般USART是可以作为UART使用的,也就是不使用其同步的功能。 UART作为串口的一种,其工作原理也是将数据一位一位的进行传输,发送和接收各用一条线,因此通过UART接口与外界相连最少只需要三条线:TXD(发送)、RXD(接收)和GND(地线)。图21.1.1.1就是UART的通信格式: 图21.1.1.1 UART通信格式 空闲位:数据线在空闲状态的时候为逻辑“1”状态,也就是高电平,表示没有数据线空闲,没有数据传输。 起始位:当要传输数据的时候先传输一个逻辑“0”,也就是将数据线拉低,表示开始数据传输。 数据位:数据位就是实际要传输的数据,数据位数可选择5~8位,我们一般都是按照字节传输数据的,一个字节8位,因此数据位通常是8位的。低位在前,先传输,高位最后传输。 奇偶校验位:这是对数据中“1”的位数进行奇偶校验用的,可以不使用奇偶校验功能。 停止位:数据传输完成标志位,停止位的位数可以选择1位、1.5位或2位高电平,一般都选择1位停止位。 波特率:波特率就是UART数据传输的速率,也就是每秒传输的数据位数,一般选择9600、19200、115200等。 2、UART电平标准 UART一般的接口电平有TTL和RS-232,一般开发板上都有TXD和RXD这样的引脚,这些引脚低电平表示逻辑0,高电平表示逻辑1,这个就是TTL电平。RS-232采用差分线,-3~-15V表示逻辑1,+3~+15V表示逻辑0。一般图21.1.1.2中的接口就是TTL电平: 图21.1.1.2 TTL电平接口 图21.1.1.2中的模块就是USB转TTL模块,TTL接口部分有VCC、GND、RXD、TXD、RTS和CTS。RTS和CTS基本用不到,使用的时候通过杜邦线和其他模块的TTL接口相连即可。 RS-232电平需要DB9接口,I.MX6U-ALPHA开发板上的COM3(UART3)口就是RS-232接口的,如图21.1.1.3所示: 图21.1.1.3 I.MX6U-ALPHA开发板RS-232接口 由于现在的电脑都没有DB9接口了,取而代之的是USB接口,所以就催生出了很多USB转串口TTL芯片,比如CH340、PL2303等。通过这些芯片就可以实现串口TTL转USB。I.MX6U-ALPHA开发板就使用CH340芯片来完成UART1和电脑之间的连接,只需要一条USB线即可,如图21.1.1.4所示。 图21.1.1.4 I.MX6U-ALPHA开发板USB转TTL接口 21.1.2 I.MX6U UART简介 上一小节介绍了UART接口,本小节来具体看一下I.MX6U的UART接口,I.MX6U一共有8个UART,其主要特性如下: 、兼容tiA/EIA-232F标准,速度最高可到5Mbit/S。 、支持串行IR接口,兼容IrDA,最高可到115.2Kbit/s。 、支持9位或者多节点模式(RS-485)。 、1或2位停止位。 、可编程的奇偶校验(奇校验和偶校验)。 、自动波特率检测(最高支持115.2Kbit/S)。 I.MX6U的UART功能很多,但是我们本章就只用到其最基本的串口功能,关于UART其它功能的介绍请参考《I.MX6ULL参考手册》第3561页的“Chapter 55 Universal Asynchronous Receiver/Transmitter(UART)”章节。 UART的时钟源是由寄存器CCM_CSCDR1的UART_CLK_SEL(bit)位来选择的,当为0的时候UART的时钟源为pll3_80m(80MHz),如果为1的时候UART的时钟源为osc_clk(24M),一般选择pll3_80m作为UART的时钟源。寄存器CCM_CSCDR1的UART_CLK_PODF(bit5:0)位是UART的时钟分频值,可设置0~63,分别对应1~64分频,一般设置为1分频,因此最终进入UART的时钟为80MHz。 接下来看一下UART几个重要的寄存器,第一个就是UART的控制寄存器1,即UARTx_UCR1(x=1~8),此寄存器的结构如图21.1.2.1所示: 图21.1.2.1寄存器UARTx_UCR1结构 寄存器UARTx_UCR1我们用到的重要位如下: ADBR(bit14):自动波特率检测使能位,为0的时候关闭自动波特率检测,为1的时候使能自动波特率检测。 UARTEN(bit0):UART使能位,为0的时候关闭UART,为1的时候使能UART。 接下来看一下UART的控制寄存器2,即:UARTx_UCR2,此寄存器结构如图21.1.2.2所示: 图21.1.2.2寄存器UARTx_UCR2结构 寄存器UARTx_UCR2用到的重要位如下: 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的发送功能,为1的时候打开UART的发送功能。 RXEN(bit1):接收使能位,为0的时候关闭UART的接收功能,为1的时候打开UART的接收功能。 SRST(bit0):软件复位,为0的是时候软件复位UART,为1的时候表示复位完成。复位完成以后此位会自动置1,表示复位完成。此位只能写0,写1会被忽略掉。 接下来看一下UARTx_UCR3寄存器,此寄存器结构如图21.1.2.3所示: 图21.1.2.3 UARTx_UCR3寄存器结构体 本章实验就用到了寄存器UARTx_UCR3中的位RXDMUXSEL(bit2),这个位应该始终为1,找个在《I.MX6ULL参考手册》第3624页有说明。 接下来看一下寄存器UARTx_USR2,这个是UART的状态寄存器2,此寄存器结构如图21.1.2.4所示: 图21.1.2.4寄存器UARTx_USR2结构 寄存器UARTx_USR2用到的重要位如下: TXDC(bit3):发送完成标志位,为1的时候表明发送缓冲(TxFIFO)和移位寄存器为空,也就是发送完成,向TxFIFO写入数据此位就会自动清零。 RDR(bit0):数据接收标志位,为1的时候表明至少接收到一个数据,从寄存器UARTx_URXD读取数据接收到的数据以后此为会自动清零。 接下来看一下寄存器UARTx_UFCR、UARTx_UBIR和UARTx_UBMR,寄存器UARTx_UFCR中我们要用到的是位RFDIV(bit9:7),用来设置参考时钟分频,设置如表21.1.2.1所示: 表21.1.2.1 RFDIV分频表 通过这三个寄存器可以设置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的寄存器就介绍到这里,关于这些寄存器详细的描述,请参考《I.MX6ULL参考手册》第3608页的55.15小节。本章我们使用I.MX6U的UART1来完成开发板与电脑串口调试助手之间串口通信,UART1的配置步骤如下: 1、设置UART1的时钟源 设置UART的时钟源为pll3_80m,设置寄存器CCM_CSCDR1的UART_CLK_SEL位为0即可。 2、初始化UART1 初始化UART1所使用IO,设置UART1的寄存器UART1_UCR1~UART1_UCR3,设置内容包括波特率,奇偶校验、停止位、数据位等等。 4、使能UART1 UART1初始化完成以后就可以使能UART1了,设置寄存器UART1_UCR1的位UARTEN为1。 5、编写UART1数据收发函数 编写两个函数用于UART1的数据收发操作。 21.2硬件原理分析 本试验用到的资源如下: 、一个LED灯:LED0。 、串口1。 I.MX6U-ALPHA开发板串口1硬件原理图如图22.2.1所示: 图22.2.1 I.MX6U-ALPHA开发板串口1原理图 在做实验之前需要用USB串口线将串口1和电脑连接起来,并且还需要设置JP5跳线帽,将串口1的RXD、TXD两个引脚分别于P116、P117连接一起,如图22.2.2所示: 图22.2.2串口1硬件连接设置图 硬件连接设置好以后就可以开始软件编写了,本章实验我们初始化好UART1,然后等待SecureCRT给开发板发送一个字节的数据,开发板接收到SecureCRT发送过来的数据以后在同通过串口1发送给SecureCRT。 21.3 实验程序编写本实验对应的例程路径为:开发板光盘-> 1、裸机例程->13_uart。 本章实验在上一章例程的基础上完成,更改工程名字为“uart”,然后在bsp文件夹下创建名为“uart”的文件夹,然后在bsp/uart中新建bsp_uart.c和bsp_uart.h这两个文件。在bsp_uart.h中输入如下内容: 示例代码21.3.1 bsp_uart.h文件代码 1 #ifndef _BSP_UART_H 2 #define _BSP_UART_H 3 #include "imx6ul.h" 4/*************************************************************** 5 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 6文件名 : bsp_uart.h 7作者 : 左忠凯 8版本 : V1.0 9描述 : 串口驱动文件头文件。 10其他 : 无 11论坛 : www.openedv.com 12日志 : 初版V1.0 2019/1/15 左忠凯创建 13 ***************************************************************/ 14 15/* 函数声明 */ 16void uart_init(void); 17void uart_io_init(void); 18void uart_disable(UART_Type *base); 19void uart_enable(UART_Type *base); 20void uart_softreset(UART_Type *base); 21void uart_setbaudrate(UART_Type *base, unsignedint baudrate, unsignedint srcclock_hz); 22void putc(unsignedchar c); 23void puts(char*str); 24unsignedchar getc(void); 25void raise(int sig_nr); 26 27 #endif 文件bsp_uart.h内容很简单,就是一些函数声明。继续在文件bsp_uart.c中输入如下所示内容: 示例代码21.3.2 bsp_uart.c文件代码 /*************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : bsp_uart.c 作者 : 左忠凯 版本 : V1.0 描述 : 串口驱动文件。 其他 : 无 论坛 : www.openedv.com 日志 : 初版V1.0 2019/1/15 左忠凯创建 ***************************************************************/ 1 #include "bsp_uart.h" 2 3/* 4 * @description : 初始化串口1,波特率为115200 5 * @param : 无 6 * @Return : 无 7 */ 8void uart_init(void) 9{ 10/* 1、初始化串口IO */ 11 uart_io_init(); 12 13/* 2、初始化UART1 */ 14 uart_disable(UART1); /* 先关闭UART1 */ 15 uart_softreset(UART1); /* 软件复位UART1 */ 16 17 UART1->UCR1 =0; /* 先清除UCR1寄存器 */ 18 UART1->UCR1 &=~(1<<14); /* 关闭自动波特率检测 */ 19 20/* 21 * 设置UART的UCR2寄存器,设置字长,停止位,校验模式,关闭硬件流控 22 * bit14: 1 忽略RTS引脚 23 * bit8: 0 关闭奇偶校验 24 * bit6: 0 1位停止位 25 * bit5: 1 8位数据位 26 * bit2: 1 打开发送 27 * bit1: 1 打开接收 28 */ 29 UART1->UCR2 |=(1<<14)|(1<<5)|(1<<2)|(1<<1); 30 UART1->UCR3 |=1<<2; /* UCR3的bit2必须为1 */ 31 32/* 33 * 设置波特率 34 * 波特率计算公式:Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)) 35 * 如果要设置波特率为115200,那么可以使用如下参数: 36 * Ref Freq = 80M 也就是寄存器UFCR的bit9:7=101, 表示1分频 37 * UBMR = 3124 38 * UBIR = 71 39 * 因此波特率= 80000000/(16 * (3124+1)/(71+1)) 40 * = 80000000/(16 * 3125/72) 41 * = (80000000*72) / (16*3125) 42 * = 115200 43 */ 44 UART1->UFCR =5<<7; /* ref freq等于ipg_clk/1=80Mhz */ 45 UART1->UBIR =71; 46 UART1->UBMR =3124; 47 48 #if0 49 uart_setbaudrate(UART1,115200,80000000);/* 设置波特率 */ 50 #endif 51 52 uart_enable(UART1);/* 使能串口 */ 53} 54 55/* 56 * @description : 初始化串口1所使用的IO引脚 57 * @param : 无 58 * @return : 无 59 */ 60void uart_io_init(void) 61{ 62/* 1、初始化串口IO 63 * UART1_RXD -> UART1_TX_DATA 64 * UART1_TXD -> UART1_RX_DATA 65 */ 66 IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0); 67 IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0); 68 IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0); 69 IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0); 70} 71 72/* 73 * @description : 波特率计算公式, 74 * 可以用此函数计算出指定串口对应的UFCR, 75 * UBIR和UBMR这三个寄存器的值 76 * @param - base : 要计算的串口。 77 * @param - baudrate : 要使用的波特率。 78 * @param - srcclock_hz : 串口时钟源频率,单位Hz 79 * @return : 无 80 */ 81void uart_setbaudrate(UART_Type *base, unsignedint baudrate, unsignedint srcclock_hz) 82{ 83uint32_t numerator =0u; 84uint32_t denominator =0U; 85uint32_t divisor =0U; 86uint32_t refFreqDiv =0U; 87uint32_t divider =1U; 88uint64_t baudDiff =0U; 89uint64_t tempNumerator =0U; 90uint32_t tempDenominator =0u; 91 92/* get the approximately maximum divisor */ 93 numerator = srcclock_hz; 94 denominator = baudrate <<4; 95 divisor =1; 96 97while(denominator !=0) 98{ 99 divisor = denominator; 100 denominator = numerator % denominator; 101 numerator = divisor; 102} 103 104 numerator = srcclock_hz / divisor; 105 denominator =(baudrate <<4)/ divisor; 106 107/* numerator ranges from 1 ~ 7 * 64k */ 108/* denominator ranges from 1 ~ 64k */ 109if((numerator >(UART_UBIR_INC_MASK *7))||(denominator > UART_UBIR_INC_MASK)) 110{ 111uint32_t m =(numerator -1)/(UART_UBIR_INC_MASK *7)+1; 112uint32_t n =(denominator -1)/ UART_UBIR_INC_MASK +1; 113uint32_t max = m > n ? m : n; 114 numerator /= max; 115 denominator /= max; 116if(0== numerator) 117{ 118 numerator =1; 119} 120if(0== denominator) 121{ 122 denominator =1; 123} 124} 125 divider =(numerator -1)/ UART_UBIR_INC_MASK +1; 126 127switch(divider) 128{ 129case1: 130 refFreqDiv =0x05; 131break; 132case2: 133 refFreqDiv =0x04; 134break; 135case3: 136 refFreqDiv =0x03; 137break; 138case4: 139 refFreqDiv =0x02; 140break; 141case5: 142 refFreqDiv =0x01; 143break; 144case6: 145 refFreqDiv =0x00; 146break; 147case7: 148 refFreqDiv =0x06; 149break; 150default: 151 refFreqDiv =0x05; 152break; 153} 154/* Compare the difference between baudRate_Bps and calculated 155 * baud rate. Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)). 156 * baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator). 157 */ 158 tempNumerator = srcclock_hz; 159 tempDenominator =(numerator <<4); 160 divisor =1; 161/* get the approximately maximum divisor */ 162while(tempDenominator !=0) 163{ 164 divisor = tempDenominator; 165 tempDenominator = tempNumerator % tempDenominator; 166 tempNumerator = divisor; 167} 168 tempNumerator = srcclock_hz / divisor; 169 tempDenominator =(numerator <<4)/ divisor; 170 baudDiff =(tempNumerator * denominator)/ tempDenominator; 171 baudDiff =(baudDiff >= baudrate)?(baudDiff - baudrate): (baudrate - baudDiff); 172 173if(baudDiff <(baudrate /100)*3) 174{ 175 base->UFCR &=~UART_UFCR_RFDIV_MASK; 176 base->UFCR |= UART_UFCR_RFDIV(refFreqDiv); 177 base->UBIR = UART_UBIR_INC(denominator -1); 178 base->UBMR = UART_UBMR_MOD(numerator / divider -1); 179} 180} 181 182/* 183 * @description : 关闭指定的UART 184 * @param – base : 要关闭的UART 185 * @return : 无 186 */ 187void uart_disable(UART_Type *base) 188{ 189 base->UCR1 &=~(1<<0); 190} 191 192/* 193 * @description : 打开指定的UART 194 * @param – base : 要打开的UART 195 * @return : 无 196 */ 197void uart_enable(UART_Type *base) 198{ 199 base->UCR1 |=(1<<0); 200} 201 202/* 203 * @description : 复位指定的UART 204 * @param – base : 要复位的UART 205 * @return : 无 206 */ 207void uart_softreset(UART_Type *base) 208{ 209 base->UCR2 &=~(1<<0); /* 复位UART */ 210while((base->UCR2 &0x1)==0); /* 等待复位完成 */ 211} 212 213/* 214 * @description : 发送一个字符 215 * @param - c : 要发送的字符 216 * @return : 无 217 */ 218void putc(unsignedchar c) 219{ 220while(((UART1->USR2 >>3)&0X01)==0);/* 等待上一次发送完成 */ 221 UART1->UTXD = c &0XFF; /* 发送数据 */ 222} 223 224/* 225 * @description : 发送一个字符串 226 * @param - str : 要发送的字符串 227 * @return : 无 228 */ 229void puts(char*str) 230{ 231char*p = str; 232 233while(*p) 234 putc(*p++); 235} 236 237/* 238 * @description : 接收一个字符 239 * @param : 无 240 * @return : 接收到的字符 241 */ 242unsignedchar getc(void) 243{ 244while((UART1->USR2 &0x1)==0); /* 等待接收完成 */ 245return UART1->URXD; /* 返回接收到的数据 */ 246} 247 248/* 249 * @description : 防止编译器报错 250 * @param : 无 251 * @return : 无 252 */ 253void raise(int sig_nr) 254{ 255 256} 文件bsp_uart.c中共有10个函数,我们依次来看一下这些函数都是做什么的,第一个函数是uart_init,这个函数是UART1初始化函数,用于初始化UART1相关的IO、并且设置UART1的波特率、字长、停止位和校验模式等,初始化完成以后就使能UART1。第二个函数是uart_io_init,用于初始化UART1所使用的IO。第三个函数是uart_setbaudrate,这个函数是从NXP官方的SDK包里面移植过来的,用于设置波特率。我们只需将要设置的波特率告诉此函数,此函数就会使用逐次逼近方式来计算出寄存器UART1_UFCR的FRDIV位、寄存器UART1_UBIR和寄存器UART1_UBMR这三个的值。第四和第五这两个函数为uart_disable和uart_enable,分别是使能和关闭UART1。第6个函数是uart_softreset,用于软件复位指定的UART。第七个函数是putc,用于通过UART1发送一个字节的数据。第八个函数是puts,用于通过UART1发送一串数据。第九个函数是getc,用于通过UART1获取一个字节的数据,最后一个函数是raise,这是一个空函数,防止编译器报错。 最后在main.c中输入如下所示内容: 示例代码21.3.3 main.c文件代码 /************************************************************** Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved. 文件名 : mian.c 作者 : 左忠凯 版本 : V1.0 描述 : I.MX6U开发板裸机实验13 串口实验 其他 : 本实验我们学习如何使用I.MX6的串口,实现串口收发数据,了解 I.MX6的串口工作原理。 论坛 : www.openedv.com 日志 : 初版V1.0 2019/1/15 左忠凯创建 **************************************************************/ 1 #include "bsp_clk.h" 2 #include "bsp_delay.h" 3 #include "bsp_led.h" 4 #include "bsp_beep.h" 5 #include "bsp_key.h" 6 #include "bsp_int.h" 7 #include "bsp_uart.h" 8 9/* 10 * @description : main函数 11 * @param : 无 12 * @return : 无 13 */ 14int main(void) 15{ 16 unsignedchar a=0; 17 unsignedchar state = OFF; 18 19 int_init(); /* 初始化中断(一定要最先调用!) */ 20 imx6u_clkinit(); /* 初始化系统时钟 */ 21 delay_init(); /* 初始化延时 */ 22 clk_enable(); /* 使能所有的时钟 */ 23 led_init(); /* 初始化led */ 24 beep_init(); /* 初始化beep */ 25 uart_init(); /* 初始化串口,波特率115200 */ 26 27 while(1) 28 { 29 puts("请输入1个字符:"); 30 a=getc(); 31 putc(a); /*回显功能*/ 32 puts("rn"); 33 34 /*显示输入的字符*/ 35 puts("您输入的字符为:"); 36 putc(a); 37 puts("rnrn"); 38 39 state =!state; 40 led_switch(LED0,state); 41 } 42 return0; 43} 第5行调用函数uart_init初始化UART1,最终在while循环里面获取串口接收到的数据,并且将获取到的数据通过串口打印出来。 21.4编译下载验证21.4.1编写Makefile和链接脚本 在Makefile文件中输入如下内容: 示例代码21.4.1 Makefile文件代码 1 CROSS_COMPILE ?= arm-linux-gnueabihf- 2 TARGET ?= uart 3 4 CC :=$(CROSS_COMPILE)gcc 5 LD :=$(CROSS_COMPILE)ld 6 OBJCOPY :=$(CROSS_COMPILE)objcopy 7 OBJDUMP :=$(CROSS_COMPILE)objdump 8 9 LIBPATH := -lgcc -L /usr/local/arm/gcc-linaro-7.3.1-2018.05- x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/7.3.1 10 11 12 INCDIRS := imx6ul 13 bsp/clk 14 bsp/led 15 bsp/delay 16 bsp/beep 17 bsp/gpio 18 bsp/key 19 bsp/exit 20 bsp/int 21 bsp/epittimer 22 bsp/keyfilter 23 bsp/uart 24 25 SRCDIRS := project 26 bsp/clk 27 bsp/led 28 bsp/delay 29 bsp/beep 30 bsp/gpio 31 bsp/key 32 bsp/exit 33 bsp/int 34 bsp/epittimer 35 bsp/keyfilter 36 bsp/uart 37 38 39 INCLUDE :=$(patsubst %, -I %, $(INCDIRS)) 40 41 SFILES :=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S)) 42 CFILES :=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) 43 44 SFILENDIR :=$(notdir $(SFILES)) 45 CFILENDIR :=$(notdir $(CFILES)) 46 47 SOBJS :=$(patsubst %, obj/%, $(SFILENDIR:.S=.o)) 48 COBJS :=$(patsubst %, obj/%, $(CFILENDIR:.c=.o)) 49 OBJS :=$(SOBJS)$(COBJS) 50 51 VPATH :=$(SRCDIRS) 52 53 .PHONY: clean 54 55$(TARGET).bin:$(OBJS) 56 $(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH) 57 $(OBJCOPY) -O binary -S $(TARGET).elf $@ 58 $(OBJDUMP) -D -m arm $(TARGET).elf >$(TARGET).dis 59 60$(SOBJS): obj/%.o : %.S 61 $(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $< 62 63$(COBJS): obj/%.o : %.c 64 $(CC) -Wall -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $< 65 66 clean: 67 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS)$(SOBJS) 上述的Makefile文件内容和上一章实验的区别不大。将TARGET为uart,在INCDIRS和SRCDIRS中加入“bsp/uart”。但是,相比上一章中的Makefile文件,本章实验的Makefile有两处重要的改变: ①、本章Makefile文件在链接的时候加入了数学库,因为在bsp_uart.c中有个函数uart_setbaudrate,在此函数中使用到了除法运算,因此在链接的时候需要将编译器的数学库也链接进来。第9行的变量LIBPATH就是数学库的目录,在第56行链接的时候使用了变量LIBPATH。 在后面的学习中,我们常常要用到一些第三方库,那么在连接程序的时候就需要指定这些第三方库所在的目录,Makefile在链接的时候使用选项“-L”来指定库所在的目录,比如“示例代码21.4.1”中第9行的变量LIBPATH就是指定了我们所使用的编译器库所在的目录。 ②、在第61行和64行中,加入了选项“-fno-builtin”,否则编译的时候提示“putc”、“puts”这两个函数与内建函数冲突,错误信息如下所示: warning: conflicting types for built-in function ‘putc’ warning: conflicting types for built-in function ‘puts’ 在编译的时候加入选项“-fno-builtin”表示不使用内建函数,这样我们就可以自己实现putc和puts这样的函数了。 链接脚本保持不变。 21.4.2编译下载 使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的uart.bin文件下载到SD卡中,命令如下: chmod 777 imxdownload //给予imxdownload可执行权限,一次即可 ./imxdownload uart.bin /dev/sdd //烧写到SD卡中 烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板。打开SourceCRT,点击File->Quick Connect…,打开快速连接设置界面,设置好相应的串口参数,比如在我的电脑上是COM8,设置如图21.4.2.1所示: 图21.4.2.1 SecureCRT串口设置 设置好以后就点击“Connect”就可以了,连接成功以后SecureCRT收到来自开发板的数据,但是SecureCRT显示可能会是乱码,如图21.4.2.2所示: 图21.4.2.2SecureCRT显示乱码 这是因为有些设置还没做,点击Options->Session Options…,打开会话设置窗口,按照图21.4.2.3所示设置: 图21.4.2.3会话设置 设置好以后点击“OK”按钮就可以了,清屏,然后重新复位一次开发板,此时SecureCRT显示就正常了,如图21.4.2.4所示: 图21.4.2.4显示正常 根据提示输入一个字符,这个输入的字符就会通过串口发送给开发板,开发板接收到字符以后就会通过串口提示你接收到的字符是什么,如图21.4.2.5所示: 图21.4.2.5实验效果 至此,I.MX6U的串口1就工作起来了,以后我们就可以通过串口来调试程序。但是本章只实现了串口最基本的收发功能,如果我们要想使用格式化输出话就不行了,比如最常用的printf函数,下一章就讲解如何移植printf函数。 |
|
相关推荐
|
|
2024 RT-Thread全球巡回线下培训火热来袭!报名提问有奖!
463 浏览 0 评论
1184 浏览 0 评论
IaaS+on+DPU(IoD)+下一代高性能算力底座技术白皮书
2296 浏览 0 评论
飞凌嵌入式-ELFBOARD 常用的USB接口及其不同版本介绍第1期
1095 浏览 0 评论
【Vision Board创客营连载体验】RA8D1-Vision Board上OSPI-Flash实践
1564 浏览 0 评论
65663 浏览 21 评论
嵌入式热门DIY项目:智能机器人开源资料合集(原理图、代码、论文)
67927 浏览 22 评论
58043 浏览 32 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-22 00:35 , Processed in 0.333309 second(s), Total 29, Slave 22 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号