嵌入式串口按键
Posted 啥也不想,只想搞钱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式串口按键相关的知识,希望对你有一定的参考价值。
【嵌入式】串口按键
1. 操作内容
- 掌握中断服务程序及串口通信程序的编写步骤
- 掌握串口通信程序的编写、编译、运行
- 熟悉嵌入式系统启动代码、头文件、Makefile文件的编写
在开发板上按下按键SW4,LED灯从左往右跑马灯闪烁10次,并在串口工具中显示“SW4 PRESSED”;按下按键SW5,LED灯从右往左跑马灯闪烁10次,并在串口工具中显示“SW5 PRESSED”。编写系统的启动代码、串口通信程序、头文件以及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.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 中运行
4. 操作结果
附件一:start.S 文件
.global _start
.global key_isr
_start:
ldr sp, =0x40000000
mrs r0, cpsr
bic r0, r0, #0x00000080
msr cpsr, r0
@ bl clock_init
bl uart_init
bl main
halt:
b halt
key_isr:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
bl key_handle
ldmfd sp!, {r0-r12, pc}^
附件二: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 GPH0CON (*(volatile unsigned int *)0xE0200C00)
#define GPH0DAT (*(volatile unsigned int *)0xE0200C04)
#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 VIC0INTSELECT *((volatile unsigned int *)0xF200000C)
#define VIC0INTENABLE *((volatile unsigned int *)0xF2000010)
#define VIC0ADDRESS *((volatile unsigned int *)0xF2000F00)
#define VIC0VECTADDR2 *((volatile unsigned int *)0xF2000108)
#define VIC0VECTADDR3 *((volatile unsigned int *)0xF200010C)
#define EXT_INT_0_CON *((volatile unsigned int *)0xE0200E00)
#define EXT_INT_0_MASK *((volatile unsigned int *)0xE0200F00)
#define EXT_INT_0_PEND *((volatile unsigned int *)0xE0200F40)
#define LEDS 1
extern void key_isr(void);
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);
}
void key_handle()
{
volatile unsigned char key_code = EXT_INT_0_PEND & 0xC;
VIC0ADDRESS = 0;
EXT_INT_0_PEND |= 0xC;
if (key_code == 0x04) /* SW4 */
{
int num = 10;
uart_send_string("\\r\\nSW4 PRESSED\\r\\n");
while (num--)
{
GPJ2DAT ^= 1 << 0;
delay(100);
GPJ2DAT ^= 1 << 1;
delay(100);
GPJ2DAT ^= 1 << 2;
delay(100);
GPJ2DAT ^= 1 << 3;
delay(100);
}
}
/* toggle LED1 */
else if (key_code == 0x08) /* SW5 */
{
int num = 10;
uart_send_string("\\r\\nSW5 PRESSED\\r\\n");
while (num--)
{
GPJ2DAT ^= 1 << 3;
delay(100);
GPJ2DAT ^= 1 << 2;
delay(100);
GPJ2DAT ^= 1 << 1;
delay(100);
GPJ2DAT ^= 1 << 0;
delay(100);
}
}
/* toggle LED2 */
}
int main()
{
char byte;
GPJ2CON &= ~(0xFF << 0);
GPJ2CON |= ((0x01 << 0) | (0x01 << 4) | (0x01 << 8) | (0x01 << 12));//((0x01 << 0) | (0x01 << 4));
GPJ2DAT |= (0xFF << 0);
GPH0CON |= 0xFF << 8;
EXT_INT_0_CON &= ~(0xFF << 8);
EXT_INT_0_CON |= (2 << 8) | (2 << 12);
EXT_INT_0_MASK &= ~0xC;
uart_send_string("\\r\\nUART Test in S5PV210\\r\\n");
VIC0INTSELECT &= ~0xC;
VIC0INTENABLE |= 0xC;
VIC0VECTADDR2 = (int)key_isr;
VIC0VECTADDR3 = (int)key_isr;
while(1);
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);
}
以上是关于嵌入式串口按键的主要内容,如果未能解决你的问题,请参考以下文章
51单片机(CC2530)发送按键次数到串口助手显示 实现功能:按1次按键 串口助手显示1 再按一次 显示2 以此