I.MX6ULL UART 串口通信實驗

系列文章目錄

I.MX6ULL UART 串口通信實驗


I.MX6ULL UART 串口通信實驗

  • 系列文章目錄
  • 一、前言
  • 二、I.MX6U 串口簡介
    • 2.1 UART 簡介
    • 2.2 I.MX6U UART 簡介
  • 三、硬件原理分析
  • 四、實驗程序編寫
  • 五、編譯下載驗證
    • 5.1編寫 Makefile 和鏈接腳本
    • 5.2 編譯下載


一、前言

不管是單片機開發還是嵌入式 Linux 開發,串口都是最常用到的外設。可以通過串口將開發板與電腦相連,然后在電腦上通過串口調試助手來調試程序。還有很多的模塊,比如藍牙、GPS、GPRS 等都使用的串口來與主控進行通信的,在嵌入式 Linux 中一般使用串口作為控制臺,所以掌握串口是必備的技能。本節學習如何驅動 I.MX6U 上的串口,并使用串口和電腦進行通信。


二、I.MX6U 串口簡介

2.1 UART 簡介

1、UART 通信格式
串口全稱叫做串行接口,通常也叫做 COM 接口,串行接口指的是數據一個一個的順序傳輸,通信線路簡單。使用兩條線即可實現雙向通信,一條用于發送,一條用于接收。串口通信距離遠,但是速度相對會低,串口是一種很常用的工業接口。
I.MX6U 自帶的 UART 外設就是串口的一種,UART 全稱是 UniversalAsynchronous Receiver/Trasmitter,也就是異步串行收發器。既然有異步串行收發器,那肯定也有同步串行收發器,學過 STM32 的同學應該知道,STM32除了有 UART 外,還有 另外一 個叫做 USART 的東西 。USART 的 全稱是 Universal Synchronous/Asynchronous Receiver/Transmitter,也就是同步/異步串行收發器。相比 UART 多了一個同步的功能,在硬件上體現出來的就是多了一條時鐘線。一般 USART 是可以作為 UART使用的,也就是不使用其同步的功能。
UART 作為串口的一種,其工作原理也是將數據一位一位的進行傳輸,發送和接收各用一條線,因此通過 UART 接口與外界相連最少只需要三條線:TXD(發送)、RXD(接收)和 GND(地線)。圖中就是 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。一般圖中的接口就是 TTL 電平:
在這里插入圖片描述

圖中的模塊就是 USB 轉 TTL 模塊,TTL 接口部分有 VCC、GND、RXD、TXD、RTS 和 CTS。RTS 和 CTS 基本用不到,使用的時候通過杜邦線和其他模塊的 TTL 接口相連即可。

RS-232 電平需要 DB9 接口,I.MX6U-ALPHA 開發板上的 COM3(UART3)口就是 RS-232 接口的,如圖所示:

在這里插入圖片描述

由于現在的電腦都沒有 DB9 接口了,取而代之的是 USB 接口,所以就催生出了很多 USB轉串口 TTL 芯片,比如 CH340、PL2303 等。通過這些芯片就可以實現串口 TTL 轉 USB。I.MX6UALPHA 開發板就使用 CH340 芯片來完成 UART1 和電腦之間的連接,只需要一條USB 線即可,如圖所示

在這里插入圖片描述

2.2 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),此寄存器的結構如圖所示:
在這里插入圖片描述
寄存器 UARTx_UCR1 我們用到的重要位如下:
ADBR(bit14):自動波特率檢測使能位,為 0 的時候關閉自動波特率檢測,為 1 的時候使能自動波特率檢測。
UARTEN(bit0):UART 使能位,為 0 的時候關閉 UART,為 1 的時候使能 UART。
接下來看一下 UART 的控制寄存器 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 寄存器,此寄存器結構如圖所示:
在這里插入圖片描述本章實驗就用到了寄存器 UARTx_UCR3 中的位 RXDMUXSEL(bit2),這個位應該始終為 1,這個在《I.MX6ULL 參考手冊》第 3624 頁有說明。
在這里插入圖片描述

接下來看一下寄存器 UARTx_USR2,這個是 UART 的狀態寄存器 2,此寄存器結構如圖所示:

在這里插入圖片描述
寄存器 UARTx_USR2 用到的重要位如下:
TXDC(bit3):發送完成標志位,為 1 的時候表明發送緩沖(TxFIFO)和移位寄存器為空,也就是發送完成,向 TxFIFO 寫入數據此位就會自動清零。
RDR(bit0):數據接收標志位,為 1 的時候表明至少接收到一個數據,從寄存器UARTx_URXD 讀取數據接收到的數據以后此位會自動清零。
接下來看一下寄存器 UARTx_UFCR 、 UARTx_UBIR 和 UARTx_UBMR ,寄存器UARTx_UFCR 中我們要用到的是位 RFDIV(bit9:7),用來設置參考時鐘分頻,設置如表示:
在這里插入圖片描述
通過這三個寄存器可以設置 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,設置內容包括波特率,奇偶校驗、停止位、數據位等等。
3、使能 UART1
UART1 初始化完成以后就可以使能 UART1 了,設置寄存器 UART1_UCR1 的位 UARTEN為 1。
4、編寫 UART1 數據收發函數
編寫兩個函數用于 UART1 的數據收發操作。


三、硬件原理分析

本試驗用到的資源如下:
①、一個 LED 燈:LED0。
②、串口 1。
LED硬件原理圖參考
在這里插入圖片描述
在做實驗之前需要用 USB 串口線將串口 1 和電腦連接起來,并且還需要設置 JP5 跳線帽,將串口 1 的 RXD、TXD 兩個引腳分別與 P116、P117 連接一起,如圖所示:
在這里插入圖片描述
硬件連接設置好以后就可以開始軟件編寫了,本節實驗我們初始化好 UART1,然后等待SecureCRT 給開發板發送一個字節的數據,開發板接收到 SecureCRT 發送過來的數據以后在同通過串口 1 發送給 SecureCRT。


四、實驗程序編寫

本節實驗在該文章的基礎上完成,更改工程名字為“uart”,然后在 bsp 文件夾下創建名為“uart”的文件夾,然后在 bsp/uart 中新建 bsp_uart.c 和 bsp_uart.h 這兩個文件。在 bsp_uart.h中輸入如下內容:

1 #ifndef _BSP_UART_H
2 #define _BSP_UART_H
3 #include "imx6ul.h"
15 /* 函數聲明 */
16 void uart_init(void);
17 void uart_io_init(void);
18 void uart_disable(UART_Type *base);
19 void uart_enable(UART_Type *base);
20 void uart_softreset(UART_Type *base);
21 void uart_setbaudrate(UART_Type *base,
unsigned int baudrate,
unsigned int srcclock_hz);
22 void putc(unsigned char c);
23 void puts(char *str);
24 unsigned char getc(void);
25 void raise(int sig_nr);
26
27 #endif

文件 bsp_uart.h 內容很簡單,就是一些函數聲明。繼續在文件 bsp_uart.c 中輸入如下所示內容:

1 #include "bsp_uart.h"
2 
3 /*
4 * @description : 初始化串口 1,波特率為 115200
5 * @param : 無
6 * @return : 無
7 */
8 void 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 #if 0
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 */
60 void 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 */
81 void uart_setbaudrate(UART_Type *base,
unsigned int baudrate,
unsigned int srcclock_hz)
82 {
83 uint32_t numerator = 0u; 
84 uint32_t denominator = 0U; 
85 uint32_t divisor = 0U;
86 uint32_t refFreqDiv = 0U;
87 uint32_t divider = 1U;
88 uint64_t baudDiff = 0U;
89 uint64_t tempNumerator = 0U;
90 uint32_t tempDenominator = 0u;
91 
92 /* get the approximately maximum divisor */
93 numerator = srcclock_hz;
94 denominator = baudrate << 4;
95 divisor = 1;
96 
97 while (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 */
109 if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator >
UART_UBIR_INC_MASK))
110 {
111 uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;
112 uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;
113 uint32_t max = m > n ? m : n;
114 numerator /= max;
115 denominator /= max;
116 if (0 == numerator)
117 {
118 numerator = 1;
119 }
120 if (0 == denominator)
121 {
122 denominator = 1;
123 }
124 }
125 divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;
126
127 switch (divider)
128 {
129 case 1:
130 refFreqDiv = 0x05;
131 break;
132 case 2:
133 refFreqDiv = 0x04;
134 break;
135 case 3:
136 refFreqDiv = 0x03;
137 break;
138 case 4:
139 refFreqDiv = 0x02;
140 break;
141 case 5:
142 refFreqDiv = 0x01;
143 break;
144 case 6:
145 refFreqDiv = 0x00;
146 break;
147 case 7:
148 refFreqDiv = 0x06;
149 break;
150 default:
151 refFreqDiv = 0x05;
152 break;
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 */
162 while (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
173 if (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 */
187 void uart_disable(UART_Type *base)
188 {
189 base->UCR1 &= ~(1<<0); 
190 }
191
192 /*
193 * @description : 打開指定的 UART
194 * @param – base : 要打開的 UART
195 * @return : 無
196 */
197 void uart_enable(UART_Type *base)
198 {
199 base->UCR1 |= (1<<0); 
200 }
201
202 /*
203 * @description : 復位指定的 UART
204 * @param – base : 要復位的 UART
205 * @return : 無
206 */
207 void uart_softreset(UART_Type *base)
208 {
209 base->UCR2 &= ~(1<<0); /* 復位 UART */
210 while((base->UCR2 & 0x1) == 0); /* 等待復位完成 */
211 }
212
213 /*
214 * @description : 發送一個字符
215 * @param - c : 要發送的字符
216 * @return : 無
217 */
218 void putc(unsigned char c)
219 {
220 while(((UART1->USR2 >> 3) &0X01) == 0);/* 等待上一次發送完成 */
221 UART1->UTXD = c & 0XFF; /* 發送數據 */
222 }
223
224 /*
225 * @description : 發送一個字符串
226 * @param - str : 要發送的字符串
227 * @return : 無
228 */
229 void puts(char *str)
230 {
231 char *p = str;
232
233 while(*p)
234 putc(*p++);
235 }
236
237 /*
238 * @description : 接收一個字符
239 * @param : 無
240 * @return : 接收到的字符
241 */
242 unsigned char getc(void)
243 {
244 while((UART1->USR2 & 0x1) == 0); /* 等待接收完成 */
245 return UART1->URXD; /* 返回接收到的數據 */
246 }
247
248 /*
249 * @description : 防止編譯器報錯
250 * @param : 無
251 * @return : 無
252 */
253 void 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 中輸入如下所示內容:

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 */
14 int main(void)
15 {
16 unsigned char a=0;
17 unsigned char 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("\r\n");
33
34 /* 顯示輸入的字符 */ 
35 puts("您輸入的字符為:");
36 putc(a);
37 puts("\r\n\r\n");
38 
39 state = !state;
40 led_switch(LED0,state);
41 }
42 return 0;
43 }

第 5 行調用函數 uart_init 初始化 UART1,最終在 while 循環里面獲取串口接收到的數據,并且將獲取到的數據通過串口打印出來。


五、編譯下載驗證

5.1編寫 Makefile 和鏈接腳本

在 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-4.9.4-2017.01-
x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4
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”來指定庫所在的目錄,比如“示例代碼中第 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 這樣的函數了。

鏈接腳本保持不變。


5.2 編譯下載

使用 Make 命令編譯代碼,編譯成功以后使用軟件 imxdownload 將編譯完成的 uart.bin 文件
下載到 SD 卡中,命令如下:

chmod 777 imxdownload //給予 imxdownload 可執行權限,一次即可
./imxdownload uart.bin /dev/sdd //燒寫到 SD 卡中,不能燒寫到/dev/sda 或 sda1 設備里面!

燒寫成功以后將 SD 卡插到開發板的 SD 卡槽中,然后復位開發板。打開 SourceCRT,點擊 File->Quick Connect…,打開快速連接設置界面,設置好相應的串口參數,比如在我的電腦上是COM8(插上你的開發板到電腦上,你電腦噔噔的聲音響查看你多了那個端口就是COM幾)
設置如圖所示:

在這里插入圖片描述
設置好以后就點擊“Connect”就可以了,連接成功以后 SecureCRT 收到來自開發板的數據,但是 SecureCRT 顯示可能會是亂碼,如圖所示:
在這里插入圖片描述

這是因為有些設置還沒做,點擊 Options->Session Options…,打開會話設置窗口,按照圖所示設置:
在這里插入圖片描述

設置好以后點擊“OK”按鈕就可以了,清屏,然后重新復位一次開發板,此時 SecureCRT顯示就正常了,如圖所示:
在這里插入圖片描述
根據提示輸入一個字符,這個輸入的字符就會通過串口發送給開發板,開發板接收到字符
以后就會通過串口提示你接收到的字符是什么,如圖所示:
在這里插入圖片描述至此,I.MX6U 的串口 1 就工作起來了,以后我們就可以通過串口來調試程序。


END
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/22823.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/22823.shtml
英文地址,請注明出處:http://en.pswp.cn/web/22823.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解鎖用Mermaid繪制圖表的神奇力量

在這個快節奏、信息爆炸的時代&#xff0c;我們迫切需要一種簡單、高效且美觀的方式來表達復雜的思想和流程。 幸運的是&#xff0c;Mermaid就是這樣一種工具。無論你是開發者、項目經理還是設計師&#xff0c;Mermaid都能幫助你輕松繪制各種類型的圖表&#xff0c;讓你的文檔…

充電樁軟硬件,賺錢新招數!-慧哥充電樁開源系統

慧哥充電樁開源平臺V2.5.2_----- SpringCloud 汽車 電動自行車 云快充1.5、云快充1.6 https://liwenhui.blog.csdn.net/article/details/134773779?spm1001.2014.3001.5502 充電樁軟件和硬件一體化的盈利方向可以清晰地歸納為以下幾個主要方面&#xff1a; 充電服務收費&…

代碼隨想錄算法訓練營第五十天|198.打家劫舍、213.打家劫舍II、337.打家劫舍III

代碼隨想錄算法訓練營第五十天 198.打家劫舍 題目鏈接&#xff1a;198.打家劫舍 確定dp數組以及下標的含義&#xff1a;dp[i]&#xff1a;考慮下標i&#xff08;包括i&#xff09;以內的房屋&#xff0c;最多可以偷竊的金額為dp[i]。確定遞推公式&#xff1a;max(dp[i - 1],…

開個新專欄,叫吾日三醒吾身,這個我打算得到了感悟就更新

打算開個新專欄&#xff0c;還有4年就30歲了。人生如夢啊&#xff0c;過的真快&#xff0c;家里的寶寶也還有2個月就出生了&#xff0c;都快要當父親啦&#xff0c;感覺這輩子還沒做啥很牛的事情。所以就立個flag吧。 自考還沒考過&#xff0c;就3門了&#xff0c;考了3年了&a…

阻性負載和感性負載的區別

1.阻性負載&#xff1a; 阻性負載是指電路中只包含電阻元件的情況。這種負載會使得電流與電壓之間呈現出線性關系&#xff0c;即滿足歐姆定律。 當負載電流負載電壓沒有相位差時負載為阻性(如負載為白熾燈、電爐)。 2.感性負載&#xff1a; 感性負載指的是電路中含有電感元…

SVN在Linux服務器下部署過程

svn server 基于 ubuntu22.04 的 svn server 安裝 refer&#xff1a;https://developer.aliyun.com/article/1431862#:~:text%E5%A6%82%E4%BD%95%E5%9C%A8Ubuntu%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AESVN%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%B9%B6%E5%AE%9E%E7%8E%B0%E6%97%A0%E5…

ARM功耗管理之功耗狀態及功耗模式

安全之安全(security)博客目錄導讀 目錄 一、功耗狀態定義 ?編輯二、功耗模式定義 三、功耗狀態和功耗模式區別<

6月05日,每日信息差

第一、特斯拉在碳博會上展示了其全品類的可持續能源解決方案&#xff0c;包括首次在國內展出的超大型電化學商用儲能系統 Megapack 和家庭儲能系統 Powerwall。此外&#xff0c;特斯拉還展示了電動汽車三電系統的解構和電池回收技術產品 第二、2024 年第一季度&#xff0c;全球…

用增之Appsflyer(一)

目錄 簡介 一、Appsflyer開發 指南 二、SDK集成 注意點: 代碼部分: Step 1:代碼倉庫配置 Step 2:添加依賴項 Step 3:添加權限 Step 4:添加混淆 Step 5:facebook兼容 Step 6:java代碼部分 1、初始化 一、AppsFlyerConversionListener

免費開源圖片轉文字識別軟件:Umi-OCR

目錄 1.介紹 2.項目亮點 3.項目功能&#xff08;已實現&#xff09; 4.功能體驗 5.項目集成&#xff08;調用接口&#xff09; 6.項目地址 1.介紹 Umi-OCR&#xff1a;免費&#xff0c;開源&#xff0c;可批量的離線OCR軟件&#xff0c;目前適用于 Windows7 x64 及以上。…

自動化辦公02 用openpyxl庫操作excel.xlsx文件(新版本)

目錄 一、文件讀操作 二、文件寫操作 三、修改單元格樣式 openpyxl 是一個處理Excel表格的第三方庫。openpyxl 庫可以處理Excel2010以后的電子表格格式&#xff0c;包括&#xff1a;xlsx/xlsm/xltx/xltm。 openpyxl教程 一、文件讀操作 工作簿(workbook): excel文件 工作表…

word自帶公式編輯器技巧

1.實現多行公式換行且對齊 1.1 準備階段&#xff08;默認Unicode模式&#xff09; 進入公式編輯模式&#xff0c;輸入\eqarray&#xff0c;緊接著按下空格鍵輸入空格&#xff0c;如下 1.2 實現換行和對齊 將要編輯的公式輸入到括號內 &&#xff1a;實現位置對齊 &…

104.網絡游戲逆向分析與漏洞攻防-裝備系統數據分析-篩選與裝備有關的數據包

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 如果看不懂、不知道現在做的什么&#xff0c;那就跟著做完看效果&#xff0c;代碼看不懂是正常的&#xff0c;只要會抄就行&#xff0c;抄著抄著就能懂了 內容…

【Android】PopupWindow焦點控制方式解析

touchable 指定pop是否可觸摸 當設置為false時&#xff0c;pop的所有觸摸事件會直接傳到下方Window&#xff0c;pop會關閉 focusable 指定pop是否可獲得焦點 當設置為true時&#xff0c;如果pop中包含可獲取焦點的控件&#xff0c;舊的Window會自動失去焦點 另外&#xf…

postman教程-15-前置腳本

上一小節我們學習了Postman生成隨機數的方法&#xff0c;本小節我們講解一下Postman前置腳本的使用方法。 Postman中的前置腳本&#xff08;Pre-request Script&#xff09;允許你在發送請求之前運行JavaScript代碼。這可以用于修改請求頭、查詢參數、請求體等&#xff0c;或者…

合作伙伴中心是什么?

目錄 合作伙伴中心介紹 合作伙伴中心的功能 合作伙伴中心介紹 合作伙伴中心,作為Microsoft合作伙伴與Microsoft及其客戶之間關系管理的重要工具,為合作伙伴提供了簡化業務流程的便利。通過合作伙伴中心,合作伙伴可以輕松地管理Microsoft賬戶和用戶,與客戶互動,建立與其他…

web學習筆記(六十二)

目錄 1.鍵盤事件 2.KeepAlive 3.組件傳值 3.1 兄弟組件傳值 3.2 組件樹傳值 3.3 發布訂閱者傳值 1.鍵盤事件 keydown表示鍵盤事件&#xff0c;在不加修飾符的情況下&#xff0c;點擊鍵盤上的任意位置都可以觸發鍵盤事件&#xff0c; <template><div><!--…

word 無法自動檢測拼寫

word 有時候不能分辨是哪種語言,比如把英語錯認為法語 。 例如&#xff1a;Interlaayer spacace,發現誤認為是法語。 1、選中Interlaayer spacace 2、點擊語言下拉按鈕 選擇設置校對語言 發現校對語言為法語 3、手動修改校對語言為英語&#xff0c;并點擊確認。 4、發現現…

什么是 Batch Normalization 批標準化和全連接層

Batch Normalization 神經元在經過激活函數之后會處于飽和狀態&#xff0c;無論后續怎么變化都不會再起作用。 每一層都會進行batch normalization的處理&#xff01; without normalization 會導致數據分布再飽和區 全連接層&#xff1a; 全連接層(fully connected layers&a…

十四、返回Insert操作自增索引值

分為兩部分&#xff0c;解析初始化和使用 拿含有selectkey標簽的insert語句解析來說 解析部分 1.解析時看有沒有selectkey標簽&#xff0c;有的話先解析selectkey的內容&#xff0c;包括對其SQL的解析并封裝成一個MappedStatement和創建KeyGenerator放入configuration中 2.解…