• 首页
  • 中国
  • 【JZ2440笔记】串口通信(中断方式)

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

2023-11-01 159浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。

一、前言

本文是在上一篇文章《【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:

ldrsp, =4096 @设置堆栈,因为要调用C语言函数

bldisable_watch_dog @关WATCH DOG

blinit_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中断

blmain @跳转执行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, 0n" /* 读出控制寄存器 */

"orr r1, r1, #0xc0000000n" /* 设置为“asynchronous bus mode” */

"mcr p15, 0, r1, c1, c0, 0n" /* 写入控制寄存器 */

);

//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 != '')

{

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

百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台