zoukankan      html  css  js  c++  java
  • LPC2478中断控制器以及串口详解

    LPC2478的中断系统

    LPC2478使用的是ARM PrimeCell向量中断控制器,一共支持32个中断向量,处于AHB空间便于系统快速访问,在中断向量的硬件优先级上还有一层可以用户自己设计的软件优先级,

    由于是ARM7内核,所以,2478的中断有两种,分别是FIQ中断和IRQ中断,IRQ有多个中断通道,FIQ的中断通道却只有一个,中断系统框图如下


    当FIQ中断进入时,会经历多个中断想或的过程,得到的中断状态不管是不是使能了中断,都会存放至RAWINT里面,然后判断中断使能,被使能的中断写入到FIQSTATUS,并向系统发出快速中断请求,系统响应中断的模式则是自动读取FIQSTATUS判断哪个中断发生,并直接跳转到FIQ处理程序,我们可以看到,FIQ是没有中断优先级的,他只需要判断最高位为1是哪一位就能快速跳转到FIQ处理程序了

    当IRQ中断发生的时候,首先会有一个优先级鉴别,只有软件优先级最高的才能进入系统,当有多个中断进入系统的时候,这多个中断优先级相同,则会经过一次硬件优先级鉴别,选出优先级最高的那个进入系统,系统直接到相应的中断处理程序处理

    相关寄存器如下


    在实际的硬件中断没发生的情况下又想调用对应的中断处理程序,这需要用这个软件中断


    移除有软件中断引发的中断


    这个应该叫做中断事件标志位,当有中断发生不管是什么中断不管是否使能对应位都要写1


    中断使能


    清除中断使能


    选择中断的模式,可以看到,初始化的时候都是IRQ中断


    IRQ中断状态,并不是说这是中断标志,只是一种状态表示


    FIQ的中断状态, 并不是说这是中断标志,只是一种状态表示

     

    有32个这样的寄存器,指定中断的服务程序的地址,系统发生中断之后,会自动调用


    中断的优先级,四位优先级,有16个优先级,一共有32个寄存器和中断向量一一映射


    当前正在响应的中断优先级的地址



    将VIC中断寄存器保护起来,防止用户在用户模式下修改,只能在特权模式下修改

    使用VIC向量中断寄存器一般分为以下几步

    1.      关闭对应中断使能以及对应的软件中断

    2.      清除中断状态

    3.      选择中断模式,设置中断级别,设置中断地址,使能中断

    4.      注意将相应的中断优先级屏蔽进行处理

    中断处理时

    1.      清除中断标志

    2.      中断处理

    3.      完成之后将当前处理函数指针清零

    具体代码如下

     

    #ifndef __VIC_H_
    #define __VIC_H_
    #include "common.h"
    #include "lpc24xx.h"
    
    
    
    void InitVic(void);
    
    
    
    
    #endif
    
    
    
    
    

     

    #include "vic.h"
    
    void InitVic(void)
    {
    	//禁止所有中断
    	VICIntEnClr = 0xffffffff;
    	//设置当前中断指向为0
    	VICVectAddr = 0;
    	//所有中断都是IRQ模式
    	VICIntSelect = 0;
    	//软件中断全部清除
    	VICSoftIntClr = 0xffffffff;
    }
    
    
    
    
    

    LPC2478串口使用

    Lpc2478有三个串口,是通用的异步串口,分别是串口0 2 3,都带有FIFO,深度可控制,1 2 4 8 均可触发,同时内置波特率发生器,并有小数波特率分频器用于实现自动波特率

    一般而言,对于串口的控制分为设置格式,设置fifo,设置波特率,配置中断,打开串口

    主要有以下寄存器


    分别用来接收数据,发送数据,选择波特率分频,其中,波特率分频系数的计算需要小数波特率的参与,如下


    计算公式如下


    自动波特率一般用于测量基于AT指令的协议,用的不多,

    配置串口的过程如下


    选择格式,数据位长度,停止位,校验位,同时,里面的除数访问锁关闭,否则无法计算波特率


    配置相应的中断使能,


    配置串口的FIFO

    配置波特率,除数寄存器前面已经描述


    设置发送使能

    具体查看代码



    #ifndef __DEBUGSERIAL_H_
    #define __DEBUGSERIAL_H_
    #include "lpc24xx.h"
    #include "common.h"
    #include "clock.h"
    #include "stdio.h"
    
    #define SERIALS_BUFFER_MAX_LENGTH	0X3FF
    #define SERIAL_RECV_PACKAGE			(1<<15)
    #define SERIAL_RECV_LENGTH			(serialRecvStatus&0X3FF)
    #define SERIAL_RECV_CLEAR			(serialRecvStatus = 0)
    #define SERIAL_RECV_LF				(1<<14)
    
    void DebugSerialInit(u32 baud);
    void DebugSerialSendChar(u8 value);
    void UartSendBuffer(u8* bufferStart,u8 length);
    
    extern u8 serialsBuffer[SERIALS_BUFFER_MAX_LENGTH];
    extern u16 serialRecvStatus;
    
    #endif
    
    
    
    
    
    
    
    
    
    

    #include "debugSerial.h"
    
    
    u8 serialsBuffer[SERIALS_BUFFER_MAX_LENGTH];
    u16 serialRecvStatus = 0;
    
    void __irq UART0_IRQHandler(void)
    {
    	u8 Res;
    	Res = U0RBR;		//读取接收数据
    	IENABLE;			/* handles nested interrupt */	
    	if(serialRecvStatus & SERIAL_RECV_PACKAGE)	//已经收到完整的一包未处理
    	{
    		//丢弃
    	}
    	else if(serialRecvStatus & SERIAL_RECV_LF)	//已经收到0X0D
    	{
    		if('
    ' == Res)//收到0X0A
    		{
    			serialRecvStatus |= SERIAL_RECV_PACKAGE;
    		}
    		else	//没收到,包错误,丢弃
    		{
    			SERIAL_RECV_CLEAR;
    		}
    	}
    	else
    	{
    		if('
    ' == Res)	//收到0X0D 
    		{
    			serialRecvStatus |= SERIAL_RECV_LF;
    		}
    		else	//正常数据
    		{
    			if(SERIAL_RECV_LENGTH >= SERIALS_BUFFER_MAX_LENGTH)
    			{
    				//已经到最大包长度,数据错误
    				SERIAL_RECV_CLEAR;
    			}
    			else
    			{
    				serialsBuffer[serialRecvStatus] = Res;
    				serialRecvStatus++;
    			}
    		}
    	}
    	IDISABLE;
    	VICVectAddr = 0;	/* Acknowledge Interrupt */
    }
    
    
    //加入printf支持
    #if 1
    #pragma import(__use_no_semihosting)                             
    struct __FILE 
    { 
    	int handle; 
    	/* Whatever you require here. If the only file you are using is */ 
    	/* standard output using printf() for debugging, no file handling */ 
    	/* is required. */ 
    }; 
    FILE __stdout;       
    _sys_exit(int x) 
    { 
    	x = x; 
    }  
    int fputc(int ch, FILE *f)
    {      
    	while(!((U0LSR) & 0x20));		//等待判断LSR[5](即THRE)是否是1,1时表示THR中为空		
    	U0THR = (u8)ch;		  			//发送数据     
    	return ch;
    }
    void _ttywrch(int ch)  
    { 
    	while(!((U0LSR) & 0x20));		//等待判断LSR[5](即THRE)是否是1,1时表示THR中为空		
    	U0THR = (u8)ch;		  			//发送数据 
    } 
    #endif 
    
    
    
    void DebugSerialInit(u32 baud)
    {
    	PCLKSEL0  &= ~(0x03<<6);	//选择外设时钟 pclk = sysclock
        PCLKSEL0  |= (0x01<<6);	    
    	PCONP |= (1<<3);				//打开UART0功率、时钟控制位
        
    	PINSEL0 &= ~(0x03<<4);//配置uart0对应io口功能 p02 p03
    	PINSEL0 |= (0x01<<4);//p02 tx0
    	PINSEL0 &= ~(0x03<<6);
    	PINSEL0 |= (0x01<<6);//p03 rx0
    	
    	
    	U0TER &= ~(1<<7);//禁止发送
    	U0IER = 0x00;	//关闭所有中断
    	U0LCR = 0x83;	//设置串口数据格式,8位字符长度,1个停止位,无校验,使能访问除数锁存器 ,设定波特率
    	U0FDR = 0x10;	//小数波特率不工作
    	U0DLM = ((SystemCoreClock/16)/baud) / 256;	//除数高八位  , 没有小数情况
    	U0DLL = ((SystemCoreClock/16)/baud) % 256; 	//除数低八位
    	U0LCR &= ~(1<<7);	  				//禁止访问除数锁存器,锁定波特率
    	U0FCR &= ~(1<<0);				//禁止FIFO
    	U0IER |= (1<<0);					//使能接收中断
    	
    	//中断向量配置
    	VICSoftIntClr |= (1<<6);//清除软件中断,uart0中断源为6 0开始
    	VICIntEnClr |= (1<<6);//禁止中断
    	VICIntSelect &= (1<<6);//选择为IRQ中断
    	VICVectAddr6 = (unsigned)UART0_IRQHandler;//连接中断向量
    	VICVectPriority6 = 0x01;//中断优先级寄存器
    	VICIntEnable |= (1<<6);//中断向量使能有效
    	
    	//启动串口发送
    	U0TER |= (1<<7);
    	
    }
    
    
    void DebugSerialSendChar(u8 value)
    {
        //当检测到UARTn THR已空时,THRE就会立即被设置。写UnTHR会清零THRE
    	//0  -  UnTHR包含有效字符
    	//1  -  UnTHR为空
    	while(!((U0LSR) & 0x20));		//等待判断LSR[5](即THRE)是否是1,1时表示THR中为空		
    	U0THR = value;		  			//发送数据
    }
    
    //串口发送数组
    void UartSendBuffer(u8* bufferStart,u8 length)
    {
        u8 i = 0;
        for(i = 0; i < length; i++)
        {
            DebugSerialSendChar(*(bufferStart+i));
        }
    }
    
    
    
    
    
    
    
    


  • 相关阅读:
    《Redis 垃圾回收》
    python-Day3-set 集合-counter计数器-默认字典(defaultdict) -可命名元组(namedtuple)-有序字典(orderedDict)-双向队列(deque)--Queue单项队列--深浅拷贝---函数参数
    Python--day4
    python--day2
    Python--day1
    Python字符串原理剖析------万恶的+号
    执行脚本传入参数
    字符编码
    css3动画与js动画的区别
    关于FormData及其用法
  • 原文地址:https://www.cnblogs.com/dengxiaojun/p/4279402.html
Copyright © 2011-2022 走看看