FZK374470412的专栏

串口是个好东西,前几篇裸奔程序由于没有串口,自己调试都是有led等来表示的,比较“苦逼”,终于可以用串口了~~~,这里主要采用上一篇博文(嵌入式学习笔记007-裸奔篇之定时器),也就是串口也是用中断实现的,而且也只是在前一篇博文增加串口的初始化uart0_init(),以及在中断处理函数增加对串口的处理。只要稍微改造前一篇博文就是一个通用的中断处理程序!

这里主要实现在串口输入一个字符,接受后+2再发送到串口,所以在串口输入a 会返回c……….

由于code都有相应的注释,读者自行查看s3c2440手册及注释应该是没有问题的了,共有7个文件,如下: head.S init.c interrupt.c int.lds main.c Makefile s3c24xx.h

head.S

@@ File:head.S@ 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数@.externmain @ 可有可无.text .global _start _start:@@ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用@@ 0x04: 未定义指令中止模式的向量地址HandleUndef: b HandleUndef @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式HandleSWI: b HandleSWI@ 0x0c: 指令预取终止导致的异常的向量地址HandlePrefetchAbort: b HandlePrefetchAbort@ 0x10: 数据访问终止导致的异常的向量地址HandleDataAbort: b HandleDataAbort@ 0x14: 保留HandleNotUsed: b HandleNotUsed@ 0x18: 中断模式的向量地址 b HandleIRQ@ 0x1c: 快中断模式的向量地址HandleFIQ: b HandleFIQReset:on_sdram:halt_loop: b halt_loopHandleIRQ:int_return: ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

init.c

/* * init.c: 进行一些初始化 */ #include “s3c24xx.h”void disable_watch_dog(void);void clock_init(void);void memsetup(void);void copy_steppingstone_to_sdram(void);void init_led(void);void timer0_init(void);void init_irq(void);/* * 关闭WATCHDOG,否则CPU会不断重启 */void disable_watch_dog(void){WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可}/* * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV * 有如下计算公式: * S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s) * S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) * 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV * 对于本开发板,Fin = 12MHz * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:4:8,, * FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */void clock_init(void){// LOCKTIME = 0x00ffffff; // 使用默认值即可CLKDIVN = 0x05;// FCLK:HCLK:PCLK=1:4:8, HDIVN=2,PDIVN=1/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */__asm__();/* 判断是S3C2410还是S3C2440 */if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002)){MPLLCON = S3C2410_MPLL_200MHZ; /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */}else{MPLLCON = S3C2440_MPLL_400MHZ; /* 现在,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */}}/* * 设置存储控制器以使用SDRAM */void memsetup(void){*p = (*)MEM_CTL_BASE;/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到* SDRAM之前就可以在steppingstone中运行*//* 存储控制器13个寄存器的值 */p[0] = 0x22011110;//BWSCONp[1] = 0x00000700;//BANKCON0p[2] = 0x00000700;//BANKCON1p[3] = 0x00000700;//BANKCON2p[4] = 0x00000700;//BANKCON3 p[5] = 0x00000700;//BANKCON4p[6] = 0x00000700;//BANKCON5p[7] = 0x00018005;//BANKCON6p[8] = 0x00018005;//BANKCON7/* REFRESH = 0x008c0000 + R_CNT* R_CNT = 2^11 +1 – HCLK(MHZ)*SDRAM_REF_TIME(us , 7.8125)* HCLK=12MHz: 0x008C07A3,* HCLK=100MHz: 0x008C04f4*/p[9] = 0x008C04f4;p[10] = 0x000000B1;//BANKSIZEp[11] = 0x00000030;//MRSRB6p[12] = 0x00000030;//MRSRB7}void copy_steppingstone_to_sdram(void){*)0;*)0x30000000;while (pdwSrc < (unsigned int *)4096){*pdwDest = *pdwSrc;pdwDest++;pdwSrc++;}}/* * LED1-4对应GPB5、GPB6、GPB7、GPB8 */#define GPB8_out(1<<(8*2))// LED4/* * K1-K4对应GPG11、GPG3、GPF2、GPF3 */#define GPF2_eint(2<<(2*2))// K4,EINT2void init_led(void){GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;}/* * Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value} * {prescaler value} = 0~255 * {divider value} = 2, 4, 8, 16 * 本实验的Timer0的时钟频率=100MHz/(99+1)/(16)=62500Hz * 设置Timer0 0.5秒钟触发一次中断: */void timer0_init(void){TCFG0 = 99;// 预分频器0 = 99TCFG1 = 0x03;// 选择16分频TCNTB0 = 31250;// 0.5秒钟触发一次中断TCON |= (1<<1); // 手动更新TCON = 0x09;// 自动加载,清“手动更新”位,启动定时器0}/* * 定时器0中断使能 */ void init_irq(void){// enable timer0 and uart0INTMSK &= ~((1<<10) | (1<<28));INTSUBMSK &= ~((1<<0) ); //enable uart0 RX interrupt}#define UART_BRD((UART_CLK / (UART_BAUD_RATE * 16)) – 1)/* * 初始化UART0 * 115200,8N1,无流控 */void uart0_init(void){GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0GPHUP = 0x0c;// GPH2,GPH3内部上拉ULCON0 = 0x03;// 8N1(8个数据位,无较验,1个停止位)UCON0 = 0x05;// UART时钟源为PCLKUFCON0 = 0x00;// 不使用FIFOUMCON0 = 0x00;// 不使用流控UBRDIV0 = UART_BRD; // 波特率为115200}当你见过了世界上最美丽的风景,

FZK374470412的专栏

相关文章:

你感兴趣的文章:

标签云: