搜索
bottom↓
回复: 0

【正点原子Linux连载】第二十一章UART串口通信实验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南

[复制链接]

出0入234汤圆

发表于 2020-6-4 11:16:41 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 16:03 编辑


1)实验平台:正点原子阿尔法Linux开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
4)本章实例源码下载:
UART串口通信实验.rar (1.65 MB)

100846f1ce1fg14zbg0va4.png

第二十一章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的通信格式:
image002.gif

图21.1.1.1 UART通信格式

        图21.1.1.1中各位的含义如下:
        空闲位:数据线在空闲状态的时候为逻辑“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电平:
image004.jpg

图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所示:
image006.jpg

图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所示。
image008.jpg

图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所示:
image010.jpg

图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所示:
image012.jpg

图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所示:
image014.jpg

图21.1.2.3 UARTx_UCR3寄存器结构体

        本章实验就用到了寄存器UARTx_UCR3中的位RXDMUXSEL(bit2),这个位应该始终为1,找个在《I.MX6ULL参考手册》第3624页有说明。
        接下来看一下寄存器UARTx_USR2,这个是UART的状态寄存器2,此寄存器结构如图21.1.2.4所示:
image016.gif

图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所示:
21121.png

表21.1.2.1 RFDIV分频表

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

        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,根据上面的公式可以得到:

333.png


        最后来看一下寄存器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所示:
image024.gif

图22.2.1 I.MX6U-ALPHA开发板串口1原理图

        在做实验之前需要用USB串口线将串口1和电脑连接起来,并且还需要设置JP5跳线帽,将串口1的RXD、TXD两个引脚分别于P116、P117连接一起,如图22.2.2所示:
image026.gif

图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中输入如下内容:
  1. 示例代码21.3.1 bsp_uart.h文件代码
  2. 1  #ifndef _BSP_UART_H
  3. 2  #define _BSP_UART_H
  4. 3  #include "imx6ul.h"
  5. 4/***************************************************************
  6. 5  Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  7. 6文件名    : bsp_uart.h
  8. 7作者      : 左忠凯
  9. 8版本      : V1.0
  10. 9描述      : 串口驱动文件头文件。
  11. 10其他      : 无
  12. 11论坛      : www.openedv.com
  13. 12日志      : 初版V1.0 2019/1/15 左忠凯创建
  14. 13 ***************************************************************/
  15. 14
  16. 15/* 函数声明 */
  17. 16void uart_init(void);
  18. 17void uart_io_init(void);
  19. 18void uart_disable(UART_Type *base);
  20. 19void uart_enable(UART_Type *base);
  21. 20void uart_softreset(UART_Type *base);
  22. 21void uart_setbaudrate(UART_Type *base,
  23. unsignedint baudrate,
  24. unsignedint srcclock_hz);
  25. 22void putc(unsignedchar c);
  26. 23void puts(char*str);
  27. 24unsignedchar getc(void);
  28. 25void raise(int sig_nr);
  29. 26
  30. 27 #endif
  31.         文件bsp_uart.h内容很简单,就是一些函数声明。继续在文件bsp_uart.c中输入如下所示内容:
  32. 示例代码21.3.2 bsp_uart.c文件代码
  33. /***************************************************************
  34. Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  35. 文件名   : bsp_uart.c
  36. 作者     : 左忠凯
  37. 版本     : V1.0
  38. 描述     : 串口驱动文件。
  39. 其他     : 无
  40. 论坛     : www.openedv.com
  41. 日志     : 初版V1.0 2019/1/15 左忠凯创建
  42. ***************************************************************/
  43. 1   #include "bsp_uart.h"
  44. 2
  45. 3/*
  46. 4    * @description         : 初始化串口1,波特率为115200
  47. 5    * @param               : 无
  48. 6    * @return              : 无
  49. 7    */
  50. 8void uart_init(void)
  51. 9{
  52. 10/* 1、初始化串口IO         */
  53. 11      uart_io_init();
  54. 12
  55. 13/* 2、初始化UART1        */
  56. 14      uart_disable(UART1);                /* 先关闭UART1               */
  57. 15      uart_softreset(UART1);                /* 软件复位UART1                   */
  58. 16
  59. 17      UART1->UCR1 =0;                /* 先清除UCR1寄存器        */
  60. 18      UART1->UCR1 &=~(1<<14);        /* 关闭自动波特率检测        */
  61. 19
  62. 20/*
  63. 21       * 设置UART的UCR2寄存器,设置字长,停止位,校验模式,关闭硬件流控
  64. 22       * bit14: 1 忽略RTS引脚
  65. 23       * bit8:  0 关闭奇偶校验
  66. 24       * bit6:  0 1位停止位
  67. 25       * bit5:  1 8位数据位
  68. 26       * bit2:  1 打开发送
  69. 27       * bit1:  1 打开接收
  70. 28       */
  71. 29      UART1->UCR2 |=(1<<14)|(1<<5)|(1<<2)|(1<<1);
  72. 30      UART1->UCR3 |=1<<2;                        /* UCR3的bit2必须为1        */
  73. 31
  74. 32/*
  75. 33       * 设置波特率
  76. 34       * 波特率计算公式:Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1))
  77. 35       * 如果要设置波特率为115200,那么可以使用如下参数:
  78. 36       * Ref Freq = 80M 也就是寄存器UFCR的bit9:7=101, 表示1分频
  79. 37       * UBMR = 3124
  80. 38       * UBIR =  71
  81. 39       * 因此波特率= 80000000/(16 * (3124+1)/(71+1))
  82. 40       *           = 80000000/(16 * 3125/72)
  83. 41       *           = (80000000*72) / (16*3125)
  84. 42       *           = 115200
  85. 43       */
  86. 44      UART1->UFCR =5<<7;                        /* ref freq等于ipg_clk/1=80Mhz */
  87. 45      UART1->UBIR =71;
  88. 46      UART1->UBMR =3124;
  89. 47
  90. 48  #if0
  91. 49      uart_setbaudrate(UART1,115200,80000000);/* 设置波特率 */
  92. 50  #endif
  93. 51
  94. 52      uart_enable(UART1);/* 使能串口 */
  95. 53}
  96. 54
  97. 55/*
  98. 56   * @description         : 初始化串口1所使用的IO引脚
  99. 57   * @param               : 无
  100. 58   * @return              : 无
  101. 59   */
  102. 60void uart_io_init(void)
  103. 61{
  104. 62/* 1、初始化串口IO
  105. 63       * UART1_RXD -> UART1_TX_DATA
  106. 64       * UART1_TXD -> UART1_RX_DATA
  107. 65       */
  108. 66      IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);
  109. 67      IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);
  110. 68      IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);
  111. 69      IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);
  112. 70}
  113. 71
  114. 72/*
  115. 73   * @description                       : 波特率计算公式,
  116. 74   *                                 可以用此函数计算出指定串口对应的UFCR,
  117. 75   *                                   UBIR和UBMR这三个寄存器的值
  118. 76   * @param - base                     : 要计算的串口。
  119. 77   * @param - baudrate                 : 要使用的波特率。
  120. 78   * @param - srcclock_hz         : 串口时钟源频率,单位Hz
  121. 79   * @return                              : 无
  122. 80   */
  123. 81void uart_setbaudrate(UART_Type *base,
  124. unsignedint baudrate,
  125. unsignedint srcclock_hz)
  126. 82{
  127. 83uint32_t numerator =0u;
  128. 84uint32_t denominator =0U;
  129. 85uint32_t divisor =0U;
  130. 86uint32_t refFreqDiv =0U;
  131. 87uint32_t divider =1U;
  132. 88uint64_t baudDiff =0U;
  133. 89uint64_t tempNumerator =0U;
  134. 90uint32_t tempDenominator =0u;
  135. 91
  136. 92/* get the approximately maximum divisor */
  137. 93      numerator = srcclock_hz;
  138. 94      denominator = baudrate <<4;
  139. 95      divisor =1;
  140. 96
  141. 97while(denominator !=0)
  142. 98{
  143. 99          divisor = denominator;
  144. 100         denominator = numerator % denominator;
  145. 101         numerator = divisor;
  146. 102}
  147. 103
  148. 104     numerator = srcclock_hz / divisor;
  149. 105     denominator =(baudrate <<4)/ divisor;
  150. 106
  151. 107/* numerator ranges from 1 ~ 7 * 64k */
  152. 108/* denominator ranges from 1 ~ 64k */
  153. 109if((numerator >(UART_UBIR_INC_MASK *7))||(denominator >
  154. UART_UBIR_INC_MASK))
  155. 110{
  156. 111uint32_t m =(numerator -1)/(UART_UBIR_INC_MASK *7)+1;
  157. 112uint32_t n =(denominator -1)/ UART_UBIR_INC_MASK +1;
  158. 113uint32_t max = m > n ? m : n;
  159. 114         numerator /= max;
  160. 115         denominator /= max;
  161. 116if(0== numerator)
  162. 117{
  163. 118             numerator =1;
  164. 119}
  165. 120if(0== denominator)
  166. 121{
  167. 122             denominator =1;
  168. 123}
  169. 124}
  170. 125     divider =(numerator -1)/ UART_UBIR_INC_MASK +1;
  171. 126
  172. 127switch(divider)
  173. 128{
  174. 129case1:
  175. 130             refFreqDiv =0x05;
  176. 131break;
  177. 132case2:
  178. 133             refFreqDiv =0x04;
  179. 134break;
  180. 135case3:
  181. 136             refFreqDiv =0x03;
  182. 137break;
  183. 138case4:
  184. 139             refFreqDiv =0x02;
  185. 140break;
  186. 141case5:
  187. 142             refFreqDiv =0x01;
  188. 143break;
  189. 144case6:
  190. 145             refFreqDiv =0x00;
  191. 146break;
  192. 147case7:
  193. 148             refFreqDiv =0x06;
  194. 149break;
  195. 150default:
  196. 151             refFreqDiv =0x05;
  197. 152break;
  198. 153}
  199. 154/* Compare the difference between baudRate_Bps and calculated
  200. 155      * baud rate. Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).
  201. 156      * baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator /
  202. divider)/ denominator).
  203. 157      */
  204. 158     tempNumerator = srcclock_hz;
  205. 159     tempDenominator =(numerator <<4);
  206. 160     divisor =1;
  207. 161/* get the approximately maximum divisor */
  208. 162while(tempDenominator !=0)
  209. 163{
  210. 164         divisor = tempDenominator;
  211. 165         tempDenominator = tempNumerator % tempDenominator;
  212. 166         tempNumerator = divisor;
  213. 167}
  214. 168     tempNumerator = srcclock_hz / divisor;
  215. 169     tempDenominator =(numerator <<4)/ divisor;
  216. 170     baudDiff =(tempNumerator * denominator)/ tempDenominator;
  217. 171     baudDiff =(baudDiff >= baudrate)?(baudDiff - baudrate):
  218. (baudrate - baudDiff);
  219. 172
  220. 173if(baudDiff <(baudrate /100)*3)
  221. 174{
  222. 175         base->UFCR &=~UART_UFCR_RFDIV_MASK;
  223. 176         base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);
  224. 177         base->UBIR = UART_UBIR_INC(denominator -1);
  225. 178         base->UBMR = UART_UBMR_MOD(numerator / divider -1);
  226. 179}
  227. 180}
  228. 181
  229. 182/*
  230. 183  * @description          : 关闭指定的UART
  231. 184  * @param – base         : 要关闭的UART
  232. 185  * @return                : 无
  233. 186  */
  234. 187void uart_disable(UART_Type *base)
  235. 188{
  236. 189     base->UCR1 &=~(1<<0);
  237. 190}
  238. 191
  239. 192/*
  240. 193  * @description         : 打开指定的UART
  241. 194  * @param – base        : 要打开的UART
  242. 195  * @return              : 无
  243. 196  */
  244. 197void uart_enable(UART_Type *base)
  245. 198{
  246. 199     base->UCR1 |=(1<<0);
  247. 200}
  248. 201
  249. 202/*
  250. 203  * @description         : 复位指定的UART
  251. 204  * @param – base        : 要复位的UART
  252. 205  * @return              : 无
  253. 206  */
  254. 207void uart_softreset(UART_Type *base)
  255. 208{
  256. 209     base->UCR2 &=~(1<<0);                                /* 复位UART          */
  257. 210while((base->UCR2 &0x1)==0);        /* 等待复位完成        */
  258. 211}
  259. 212
  260. 213/*
  261. 214  * @description         : 发送一个字符
  262. 215  * @param - c           : 要发送的字符
  263. 216  * @return              : 无
  264. 217  */
  265. 218void putc(unsignedchar c)
  266. 219{
  267. 220while(((UART1->USR2 >>3)&0X01)==0);/* 等待上一次发送完成        */
  268. 221     UART1->UTXD = c &0XFF;        /* 发送数据                        */
  269. 222}
  270. 223
  271. 224/*
  272. 225  * @description         : 发送一个字符串
  273. 226  * @param - str         : 要发送的字符串
  274. 227  * @return              : 无
  275. 228  */
  276. 229void puts(char*str)
  277. 230{
  278. 231char*p = str;
  279. 232
  280. 233while(*p)
  281. 234         putc(*p++);
  282. 235}
  283. 236
  284. 237/*
  285. 238  * @description         : 接收一个字符
  286. 239  * @param               : 无
  287. 240  * @return              : 接收到的字符
  288. 241  */
  289. 242unsignedchar getc(void)
  290. 243{
  291. 244while((UART1->USR2 &0x1)==0);        /* 等待接收完成                */
  292. 245return UART1->URXD;                /* 返回接收到的数据        */
  293. 246}
  294. 247
  295. 248/*
  296. 249  * @description         : 防止编译器报错
  297. 250  * @param               : 无
  298. 251  * @return              : 无
  299. 252  */
  300. 253void raise(int sig_nr)
  301. 254{
  302. 255
  303. 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中输入如下所示内容:
  1. 示例代码21.3.3 main.c文件代码
  2. /**************************************************************
  3. Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  4. 文件名   : mian.c
  5. 作者     : 左忠凯
  6. 版本     : V1.0
  7. 描述     : I.MX6U开发板裸机实验13 串口实验
  8. 其他     : 本实验我们学习如何使用I.MX6的串口,实现串口收发数据,了解
  9.            I.MX6的串口工作原理。
  10. 论坛     : www.openedv.com
  11. 日志     : 初版V1.0 2019/1/15 左忠凯创建
  12. **************************************************************/
  13. 1  #include "bsp_clk.h"
  14. 2  #include "bsp_delay.h"
  15. 3  #include "bsp_led.h"
  16. 4  #include "bsp_beep.h"
  17. 5  #include "bsp_key.h"
  18. 6  #include "bsp_int.h"
  19. 7  #include "bsp_uart.h"
  20. 8
  21. 9/*
  22. 10  * @description        : main函数
  23. 11  * @param                : 无
  24. 12  * @return               : 无
  25. 13  */
  26. 14int main(void)
  27. 15{
  28. 16        unsignedchar a=0;
  29. 17        unsignedchar state = OFF;
  30. 18
  31. 19        int_init();        /* 初始化中断(一定要最先调用!)        */
  32. 20        imx6u_clkinit();        /* 初始化系统时钟        */
  33. 21        delay_init();        /* 初始化延时                        */
  34. 22        clk_enable();        /* 使能所有的时钟        */
  35. 23        led_init();        /* 初始化led                             */
  36. 24        beep_init();        /* 初始化beep                            */
  37. 25        uart_init();        /* 初始化串口,波特率115200         */
  38. 26
  39. 27        while(1)
  40. 28        {
  41. 29        puts("请输入1个字符:");
  42. 30        a=getc();
  43. 31        putc(a);                        /*回显功能*/
  44. 32        puts("\r\n");
  45. 33
  46. 34        /*显示输入的字符*/
  47. 35        puts("您输入的字符为:");
  48. 36        putc(a);
  49. 37        puts("\r\n\r\n");
  50. 38
  51. 39        state =!state;
  52. 40        led_switch(LED0,state);
  53. 41        }
  54. 42        return0;
  55. 43}
复制代码

        第5行调用函数uart_init初始化UART1,最终在while循环里面获取串口接收到的数据,并且将获取到的数据通过串口打印出来。
21.4编译下载验证
21.4.1编写Makefile和链接脚本
        在Makefile文件中输入如下内容:
  1. 示例代码21.4.1 Makefile文件代码
  2. 1  CROSS_COMPILE        ?= arm-linux-gnueabihf-
  3. 2  TARGET                  ?= uart
  4. 3
  5. 4  CC        :=$(CROSS_COMPILE)gcc
  6. 5  LD        :=$(CROSS_COMPILE)ld
  7. 6  OBJCOPY        :=$(CROSS_COMPILE)objcopy
  8. 7  OBJDUMP        :=$(CROSS_COMPILE)objdump
  9. 8
  10. 9  LIBPATH        := -lgcc -L /usr/local/arm/gcc-linaro-7.3.1-2018.05-
  11. x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/7.3.1
  12. 10
  13. 11
  14. 12 INCDIRS        :=        imx6ul \
  15. 13                bsp/clk \
  16. 14                bsp/led \
  17. 15                bsp/delay  \
  18. 16                bsp/beep \
  19. 17                bsp/gpio \
  20. 18                bsp/key \
  21. 19                bsp/exit \
  22. 20                bsp/int \
  23. 21                bsp/epittimer \
  24. 22                bsp/keyfilter \
  25. 23                bsp/uart
  26. 24
  27. 25 SRCDIRS        :=        project \
  28. 26                bsp/clk \
  29. 27                bsp/led \
  30. 28                bsp/delay \
  31. 29                bsp/beep \
  32. 30                bsp/gpio \
  33. 31                bsp/key \
  34. 32                bsp/exit \
  35. 33                bsp/int \
  36. 34                bsp/epittimer \
  37. 35                 bsp/keyfilter \
  38. 36                bsp/uart
  39. 37
  40. 38
  41. 39 INCLUDE        :=$(patsubst %, -I %, $(INCDIRS))
  42. 40
  43. 41 SFILES        :=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
  44. 42 CFILES        :=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
  45. 43
  46. 44 SFILENDIR        :=$(notdir  $(SFILES))
  47. 45 CFILENDIR        :=$(notdir  $(CFILES))
  48. 46
  49. 47 SOBJS        :=$(patsubst %, obj/%, $(SFILENDIR:.S=.o))
  50. 48 COBJS        :=$(patsubst %, obj/%, $(CFILENDIR:.c=.o))
  51. 49 OBJS        :=$(SOBJS)$(COBJS)
  52. 50
  53. 51 VPATH        :=$(SRCDIRS)
  54. 52
  55. 53 .PHONY: clean
  56. 54
  57. 55$(TARGET).bin:$(OBJS)
  58. 56        $(LD) -Timx6ul.lds -o $(TARGET).elf $^ $(LIBPATH)
  59. 57        $(OBJCOPY) -O binary -S $(TARGET).elf $@
  60. 58        $(OBJDUMP) -D -m arm $(TARGET).elf >$(TARGET).dis
  61. 59
  62. 60$(SOBJS): obj/%.o : %.S
  63. 61        $(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ [        DISCUZ_CODE_30        ]lt;
  64. 62
  65. 63$(COBJS): obj/%.o : %.c
  66. 64        $(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ [        DISCUZ_CODE_30        ]lt;
  67. 65
  68. 66 clean:
  69. 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”这两个函数与内建函数冲突,错误信息如下所示:
  1. warning: conflicting types for built-in function ‘putc’
  2. warning: conflicting types for built-in function ‘puts’
复制代码

        在编译的时候加入选项“-fno-builtin”表示不使用内建函数,这样我们就可以自己实现putc和puts这样的函数了。
        链接脚本保持不变。
21.4.2编译下载
        使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的uart.bin文件下载到SD卡中,命令如下:
  1. chmod 777 imxdownload                        //给予imxdownload可执行权限,一次即可
  2. ./imxdownload uart.bin /dev/sdd                //烧写到SD卡中
复制代码

        烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板。打开SourceCRT,点击File->Quick Connect…,打开快速连接设置界面,设置好相应的串口参数,比如在我的电脑上是COM8,设置如图21.4.2.1所示:
image028.jpg

图21.4.2.1 SecureCRT串口设置

        设置好以后就点击“Connect”就可以了,连接成功以后SecureCRT收到来自开发板的数据,但是SecureCRT显示可能会是乱码,如图21.4.2.2所示:
image030.gif

图21.4.2.2SecureCRT显示乱码

        这是因为有些设置还没做,点击Options->Session Options…,打开会话设置窗口,按照图21.4.2.3所示设置:
image032.gif

图21.4.2.3会话设置

        设置好以后点击“OK”按钮就可以了,清屏,然后重新复位一次开发板,此时SecureCRT显示就正常了,如图21.4.2.4所示:
image034.gif

图21.4.2.4显示正常

        根据提示输入一个字符,这个输入的字符就会通过串口发送给开发板,开发板接收到字符以后就会通过串口提示你接收到的字符是什么,如图21.4.2.5所示:
image036.jpg

图21.4.2.5实验效果

        至此,I.MX6U的串口1就工作起来了,以后我们就可以通过串口来调试程序。但是本章只实现了串口最基本的收发功能,如果我们要想使用格式化输出话就不行了,比如最常用的printf函数,下一章就讲解如何移植printf函数。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 13:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表