【嵌入式】串口控制
- 1. 操作內容
- 2. 原理解釋
- 3. 操作步驟
- 3. 操作步驟
- 3.1 撰寫鍵控制代碼,將代碼編譯為二進制檔案
- 3.2 安裝 USB 驅動
- 3.3 使用 DNW 軟體下載裸機程式 uart.bin至 SRAM 中運行
- 3.4 修改 main.c 檔案增加蜂鳴器控制功能:鍵盤輸入“a”,蜂鳴器間隔鳴響 10 次,
- 4. 操作結果
- 附件一:start.S 檔案
- 附件二:uart.c檔案
- 附件三:Makefile 檔案
- 附件四:main.c 檔案
- 附件五:clock.c 檔案
- 附件六:LED+buzzer main.c檔案
1. 操作內容
- 掌握串口通信編程步驟
- 掌握串口通信程式的撰寫、編譯、運行
- 熟悉嵌入式系統啟動代碼、頭檔案、Makefile檔案的撰寫
在PC端,由數字鍵盤輸入數字1,利用串口控制LED燈從左往右跑馬燈閃爍10次;輸入時LED燈從右往左跑馬燈閃爍10次,撰寫系統的啟動代碼、串口通信程式、頭檔案以及Makefile檔案,編譯得到可執行檔案,下載至開發板,實作在開發板上啟動系統,
2. 原理解釋
實驗采用UART0實作串口通信,如圖1所示,UART0的資料收發通過復用GPA0實作,其中,GPA0_0復用為UART_0_RXD,GPA0_1復用為UART_0_TXD,如圖2所示暫存器功能表,UART資料通信要求對ULCONn、UCONn、UFCONn、UTRSTATn、UTXHn、URXHn、UBRDIVn、UDIVSLOT0等相關暫存器進行正確配置,暫存器功能詳情參考芯片資料手冊,

3. 操作步驟
3. 操作步驟
3.1 撰寫鍵控制代碼,將代碼編譯為二進制檔案
a) 在 Linux 系統的共享檔案夾 forlinux 中新建 uart 目錄,
b) 切換到 uart 目錄,在 uart 檔案夾中新建啟動檔案 start.S 并添加代碼(參考附錄 1),
c) 新建時鐘配置函式檔案 clock.c 并添加代碼(參考附錄 2),
d) 新建 UART 初始化檔案 uart.c,自行添加代碼,
e) 新建主函式檔案 main.c,自行添加代碼,
f) 新建 Makefile 檔案并添加代碼(參考附錄 3),
g) 執行 make 命令編譯生成二進制檔案 uart.bin,
3.2 安裝 USB 驅動
3.3 使用 DNW 軟體下載裸機程式 uart.bin至 SRAM 中運行
3.4 修改 main.c 檔案增加蜂鳴器控制功能:鍵盤輸入“a”,蜂鳴器間隔鳴響 10 次,
4. 操作結果



附件一:start.S 檔案
.global _start
_start:
@ bl clock_init
bl uart_init
bl main
halt:
b halt
附件二:uart.c檔案
#define GPA0CON *((volatile unsigned int *)0xE0200000)
#define ULCON0 *((volatile unsigned int *)0xE2900000)
#define UCON0 *((volatile unsigned int *)0xE2900004)
#define UFCON0 *((volatile unsigned int *)0xE2900008)
#define UTRSTAT0 *((volatile unsigned int *)0xE2900010)
#define UTXH0 *((volatile unsigned int *)0xE2900020)
#define URXH0 *((volatile unsigned int *)0xE2900024)
#define UBRDIV0 *((volatile unsigned int *)0xE2900028)
#define UDIVSLOT0 *((volatile unsigned int *)0xE290002C)
/*
** UART0初始化
*/
void uart_init()
{
/*
** 配置GPA0_0為UART_0_RXD
** 配置GPA0_1為UART_0_TXD
*/
GPA0CON &= ~0xFF;
GPA0CON |= 0x22; //0b 00100010
/* 8-bits/One stop bit/No parity/Normal mode operation */
/*每次8位,1個停止位,無奇偶驗證,正常發送模式(非紅外)*/
ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6); // 0b 0 0xx 0 11
/* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
/*發送和接受引腳采用中斷和輪詢查詢模式,正常發送,常規操作,時鐘選擇為PCLK*/
UCON0 = 1 | (1 << 2) | (0 << 10);
/* 禁止FIFO */
UFCON0 = 0;
/*
** 波特率計算:115200bps
** PCLK = 66MHz
** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
** UBRDIV0 = 34 (DIV_VAL的整數部分)
** (num of 1's in UDIVSLOTn)/16 = 0.8 (DIV_VAL的小數部分)
** (num of 1's in UDIVSLOTn) = 12
** UDIVSLOT0 = 0xDDDD (在資料手冊上880頁查表)
*/
UBRDIV0 = 34;//波特率分度值
UDIVSLOT0 = 0xDDDD;
}
void uart_send_byte(unsigned char byte)
{
while (!(UTRSTAT0 & (1 << 2))); /* 等待發送緩沖區為空 */
UTXH0 = byte; /* 發送一位元組資料 */
}
unsigned char uart_recv_byte()
{
while (!(UTRSTAT0 & 1)); /* 等待接識訓沖區有資料可讀 */
return URXH0; /* 接收一位元組資料 */
}
void uart_send_string(char *str)
{
char *p = str;
while (*p)
uart_send_byte(*p++);
}
附件三:Makefile 檔案
uart.bin: start.o clock.o uart.o main.o
arm-linux-ld -Ttext 0xD0020010 -o uart.elf $^
arm-linux-objcopy -O binary uart.elf $@
arm-linux-objdump -D uart.elf > uart.dis
%.o : %.c
arm-linux-gcc -c $< -o $@ -nostdlib
%.o:%.S
arm-linux-gcc -c $< -o $@ -nostdlib
clean:
rm *.o *.elf *.bin *.dis
附件四:main.c 檔案
#define GPJ2CON (*(volatile unsigned long *) 0xE0200280)
#define GPJ2DAT (*(volatile unsigned long *) 0xE0200284)
#define GPD0CON (*(volatile unsigned long *)0xE02000A0)
#define GPD0DAT (*(volatile unsigned long *)0xE02000A4)
extern void uart_send_byte(unsigned char byte);
extern unsigned char uart_recv_byte();
extern void uart_send_string(char *str);
void delay(volatile unsigned int t)
{
volatile unsigned int t2 = 0xFFFF;
while (t--)
for (; t2; t2--);
}
void led_init()
{
GPJ2CON &= ~(0xFF << 0);
GPJ2CON |= ((0x01 << 0) | (0x01 << 4) | (0x01 << 8) | (0x01 << 12));//((0x01 << 0) | (0x01 << 4));
GPJ2DAT |= (0xFF << 0);
}
int main()
{
char byte;
led_init();
uart_send_string("\r\nUART Test in S5PV210\r\n");
while (1)
{
uart_send_string("\r\n1.LED1 Toggle\r\n");
uart_send_string("\r\n2.LED2 Toggle\r\n");
uart_send_string("\r\nPlease select 1 or 2 to Toggle the LED\r\n");
byte = uart_recv_byte();
uart_send_byte(byte);
if (byte == '1')
{
GPJ2DAT ^= 1 << 3;
delay(1000);
GPJ2DAT ^= 1 << 2;
delay(1000);
GPJ2DAT ^= 1 << 1;
delay(1000);
GPJ2DAT ^= 1 << 0;
delay(2000);
GPJ2DAT = 0xFF;
}
else if (byte == '2')
{
GPJ2DAT ^= 1 << 0;
delay(1000);
GPJ2DAT ^= 1 << 1;
delay(1000);
GPJ2DAT ^= 1 << 2;
delay(1000);
GPJ2DAT ^= 1 << 3;
delay(2000);
GPJ2DAT = 0xFF;
}
delay(1000);
}
return 0;
}
附件五:clock.c 檔案
#define APLLCON0 *((volatile unsigned int *)0xE0100100)
#define MPLLCON *((volatile unsigned int *)0xE0100108)
#define EPLLCON0 *((volatile unsigned int *)0xE0100110)
#define VPLLCON *((volatile unsigned int *)0xE0100120)
#define CLK_SRC0 *((volatile unsigned int *)0xE0100200)
#define CLK_DIV0 *((volatile unsigned int *)0xE0100300)
#define CLK_DIV1 *((volatile unsigned int *)0xE0100304)
#define CLK_DIV2 *((volatile unsigned int *)0xE0100308)
#define CLK_DIV3 *((volatile unsigned int *)0xE010030C)
void clock_init()
{
/* 1、設定PLL_LOCK暫存器(這里使用默認值) */
/* 2、設定PLL_CON暫存器(使用芯片手冊推薦的值) */
APLLCON0 = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31); /* FOUTAPLL = 1000MHz */
MPLLCON = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31); /* FOUTMPLL = 667MHz */
EPLLCON0 = (2 << 0) | (3 << 8) | (48 << 16) | (1 << 31); /* FOUTEPLL = 96MHz */
VPLLCON = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31); /* FOUTVPLL = 54MHz */
/* 3、選擇PLL為時鐘輸出 */
/* MOUT_MSYS = SCLKAPLL = 1000MHz
** MOUT_DSYS = SCLKMPLL = 667MHz
** MOUT_PSYS = SCLKMPLL = 667MHz
*/
CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
/* 4、設定系統時鐘分頻值 */
/* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
*/
CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
}
附件六:LED+buzzer main.c檔案
#define GPJ2CON (*(volatile unsigned long *) 0xE0200280)
#define GPJ2DAT (*(volatile unsigned long *) 0xE0200284)
#define GPD0CON (*(volatile unsigned long *)0xE02000A0)
#define GPD0DAT (*(volatile unsigned long *)0xE02000A4)
#define GPC1CON (*((volatile unsigned long *)0xE0200060))
#define GPC1DAT (*((volatile unsigned long *)0xE0200064))
#define GPC1PUD (*((volatile unsigned long *)0xE0200068))
#define LEDS 1
extern void uart_send_byte(unsigned char byte);
extern unsigned char uart_recv_byte();
extern void uart_send_string(char *str);
void delay(volatile unsigned int t)
{
volatile unsigned int t2 = 0xFFFF;
while (t--)
for (; t2; t2--);
}
void buzzer_init(void)
{
GPD0CON |= 1<<8;
}
void buzzer_on(void)
{
GPD0DAT |= 1<<2;
}
void buzzer_off(void)
{
GPD0DAT &= ~(1<<2);
}
int main()
{
buzzer_init();
char byte;
GPJ2CON &= ~(0xFF << 0);
GPJ2CON |= ((0x01 << 0) | (0x01 << 4) | (0x01 << 8) | (0x01 << 12));//((0x01 << 0) | (0x01 << 4));
GPJ2DAT |= (0xFF << 0);
uart_send_string("\r\nUART Test in S5PV210\r\n");
while (1)
{
uart_send_string("\r\n1.LED1 Toggle\r\n");
uart_send_string("\r\n2.LED2 Toggle\r\n");
uart_send_string("\r\nPlease select 1 or 2 to Toggle the LED\r\n");
byte = uart_recv_byte();
uart_send_byte(byte);
if (byte == '1')
{
GPJ2DAT ^= 1 << 3;
delay(1000);
GPJ2DAT ^= 1 << 2;
delay(1000);
GPJ2DAT ^= 1 << 1;
delay(1000);
GPJ2DAT ^= 1 << 0;
delay(2000);
GPJ2DAT = 0xFF;
}
else if (byte == '2')
{
GPJ2DAT ^= 1 << 0;
delay(1000);
GPJ2DAT ^= 1 << 1;
delay(1000);
GPJ2DAT ^= 1 << 2;
delay(1000);
GPJ2DAT ^= 1 << 3;
delay(2000);
GPJ2DAT = 0xFF;
}
else if (byte == 'a')
{
int num = 5;
while (num--)
{
buzzer_on();
delay(10000);
buzzer_off();
delay(10000);
}
}
delay(1000);
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/286688.html
標籤:其他
