【JZ2440笔记】串口通信(中断方式)

目录

一、前言

二、程序编写


一、前言

本文是在上一篇文章《【JZ2440笔记】串口通信》的基础上写的,上一篇使用的是查询的方式,这一篇使用中断的方式,具体的串口介绍和配置就不写了,都在上一篇了,关于中断方面的设置在《【JZ2440笔记】裸机实验使用中断》中有讲到,这里直接贴出本文代码。

 

二、程序编写

程序分为以下几个文件:

head.S;启动文件。

init.c:关闭看门狗,初始化时钟的函数。

uart.c:串口相关配置。

uart.h:串口头文件。

main.c:主函数。

Makefile:编译程序。

每个文件具体内容如下:

head.S

@*************************************************************************
@ File:head.S
@ 功能:设置FCLK到400MHz,然后初始化串口
@*************************************************************************       
.text
.global _start
_start:
@******************************************************************************       
@ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************       
    b   Reset

@ 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   HandleFIQ
    
Reset: 
	ldr	sp, =4096                       @设置堆栈,因为要调用C语言函数 
	bl	disable_watch_dog               @关WATCH DOG
	bl	init_system_clk                 @初始化系统时钟,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz
    msr cpsr_c, #0xd2       @ 进入中断模式
    ldr sp, =3072           @ 设置中断模式栈指针

    msr cpsr_c, #0xd3       @ 进入管理模式
    ldr sp, =4096           @ 设置管理模式栈指针,
                            @ 其实复位之后,CPU就处于管理模式,
                            @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略
	msr cpsr_c, #0x53       @ 设置I-bit=0,开IRQ中断
    bl	main                            @跳转执行main函数

halt_loop:
    b       halt_loop

HandleIRQ:
    sub lr, lr, #4                  @ 计算返回地址
    stmdb   sp!,    { r0-r12,lr }   @ 保存使用到的寄存器
                                    @ 注意,此时的sp是中断模式的sp
                                    @ 初始值是上面设置的3072
    
    ldr lr, =int_return             @ 设置调用ISR即EINT_Handle函数后的返回地址  
    ldr pc, =UART0_Handle            @ 调用中断服务函数

int_return:
    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr

init.c



/* WOTCH DOG register */
#define REG_WTCON               (*(volatile unsigned long *)0x53000000)

/* Sys Clk Config */
#define REG_CLKDIVN             (*(volatile unsigned long *)0x4C000014)
#define REG_CAMDIVN             (*(volatile unsigned long *)0x4C000018)
#define REG_MPLLCON             (*(volatile unsigned long *)0x4C000004)

void disable_watch_dog();
void init_system_clk();

/*上电后,WATCH DOG默认是开着的,要把它关掉 */
void disable_watch_dog()
{
	REG_WTCON	= 0;
}

void init_system_clk()
{
    //HCLK = FCLK/4, 当 CAMDIVN[9] = 0 时
    //PCLK 设置为 HCLK/2 
    //完成配置FCLK : HCLK : PCLK = 1 : 1/4 : 1/8,DIVN_UPLL是USB的时钟不用管
    REG_CLKDIVN = (2 << 1) | (1 << 0);

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm__(
    "mrc    p15, 0, r1, c1, c0, 0\n"        /* 读出控制寄存器 */ 
    "orr    r1, r1, #0xc0000000\n"          /* 设置为“asynchronous bus mode” */
    "mcr    p15, 0, r1, c1, c0, 0\n"        /* 写入控制寄存器 */
    );

    //m=MDIV+8, p=PDIV+2, s=SDIV, Mpll = ( 2 × m × Fin ) / ( p × 2^s )
    //FCLK = (2 * (92 + 8) * 12000000) / ((1 + 2) * 2) = 400000000 = 400MHz
    //配置完MPLL后时钟停振,CPU停止运行等待时钟输出稳定,之后FCLK=400MHz,HCLK=100MHz,PCLK=50MHz */
    REG_MPLLCON = (92<<12)|(1<<4)|(1<<0);
}

uart.c

#include "uart.h"

void init_uart(DWORD buadrate)
{
    //Step1,配置GPIO,GPH3(RXD0),GPH2(TXD0)
    //清除相关配置位
    REG_GPHCON &= ~((DWORD)(3 << (2*3)) | (3 << (2*2)));
    REG_GPHDAT &= ~((DWORD)(1 << 3) | (1 << 2));
    REG_GPHUP &= ~((DWORD)(1 << 3) | (1 << 2));
    //设置相关配置位
    REG_GPHCON |= ((DWORD)2 << (2*3)) | (2 << (2*2));
    REG_GPHDAT |= ((DWORD)1 << 3) | (1 << 2);
    REG_GPHUP |= ((DWORD)1 << 3) | (1 << 2);

    //无校验,1个停止位,8个数据位
    REG_ULCON0 = 0x03;
    //发送和接受设置为查询/中断模式
    REG_UCON0 = 0x05;
    // REG_UCON0 |= 1 << 5;  //环回模式
    //不使用FIFO
    REG_UFCON0 = 0;
    //不使用流控
    REG_UMCON0 = 0;

    //UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
    REG_UBRDIV0 = (PCLK_SPEED / (115200 * 16)) - 1;

    //中断配置
    REG_INTMSK &= ~((DWORD)1 << 28);    //开UART0中断
    REG_INTSUBMSK &= ~((DWORD)1 << 0);    //开RXT0中断
}

void uart_send(BYTE ch)
{
    while(!(REG_UTRSTAT0 & (1 << 2)))
    {
        ;
    }

    REG_UTXH0 = ch;
}

BYTE uart_receive()
{
    while(!(REG_UTRSTAT0 & (1 << 0)))
    {
        ;
    }

    return REG_URXH0;
}

void uart_sendString(BYTE *str)
{
    while(*str != '\0')
    {
        uart_send(*str);
        str++;
    }
}

uart.h

#ifndef _UART_H_
#define _UART_H_

#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned int

/* Uart Config */
#define PCLK_SPEED              50000000

#define REG_GPHCON              (*(volatile unsigned long *)0x56000070)
#define REG_GPHDAT              (*(volatile unsigned long *)0x56000074)
#define REG_GPHUP               (*(volatile unsigned long *)0x56000078)

#define REG_ULCON0              (*(volatile unsigned long *)0x50000000)
#define REG_UCON0               (*(volatile unsigned long *)0x50000004)
#define REG_UFCON0              (*(volatile unsigned long *)0x50000008)
#define REG_UMCON0              (*(volatile unsigned long *)0x5000000C)

#define REG_UTXH0               (*(volatile unsigned long *)0x50000020)
#define REG_URXH0               (*(volatile unsigned long *)0x50000024)

#define REG_UBRDIV0             (*(volatile unsigned long *)0x50000028)

#define REG_UTRSTAT0            (*(volatile unsigned long *)0x50000010)

#define REG_INTMSK		        (*(volatile unsigned long *)0X4A000008)
#define REG_INTOFFSET	        (*(volatile unsigned long *)0x4A000014)

#define REG_INTSUBMSK	(*(volatile unsigned long *)0X4A00001C)
#define REG_SUBSRCPND	(*(volatile unsigned long *)0X4A000018)

#define REG_SRCPND		(*(volatile unsigned long *)0X4A000000)
#define REG_INTPND		(*(volatile unsigned long *)0X4A000010)

void init_uart(DWORD buadrate);
void uart_send(BYTE ch);
BYTE uart_receive();
void uart_sendString(BYTE *str);

#endif

main.c

#include "uart.h"

int main()
{
	init_uart(115200);

	while(1)
	{		
		;
	}
	
	return 0;
} 

void UART0_Handle()
{
	uart_send(REG_URXH0);

	//清中断
	REG_SUBSRCPND |= (1 << 0);
	REG_SRCPND |= (DWORD)1 << REG_INTOFFSET;
	REG_INTPND |= (DWORD)1 << REG_INTOFFSET;
}

Makefile

objs := head.o init.o uart.o main.o

uart.bin: $(objs)

	arm-linux-ld -Ttext 0x0000000 -g -o uart_elf $^
	arm-linux-objcopy -O binary -S uart_elf $@
	arm-linux-objdump -D -m arm uart_elf > uart.dis
	
%.o:%.c
	arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S
	arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:
	rm -f uart.bin uart_elf uart.dis *.o	
 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值