历史上的今天
返回首页

历史上的今天

今天是:2024年09月17日(星期二)

2019年09月17日 | UART0串口编程(三):中断方式的串口编程;用中断编写发送

2019-09-17 来源:eefocus

一:中断方式的串口编程


1.用中断方式编写串口程序由那几部分组成


2.硬件上的支持


1>UART0 发送FIFO缓冲区


A.UART0含有1个16字节的发送FIFO缓冲区


B.U0THR是UART0发送FIFO的最高字节


C.UART的发送FIFO是一直使能的

2>UART0接收FIFO缓冲区


A. UART0含有一个16字节的接收FIFO缓冲区。


B. 软件设置接收FIFO缓冲区的触发字节。

3> 中断接口:UART0的中断接口包含中断使能寄存器(U0IER)和中断标识寄存器(U0IIR)。


第一:U0IIR:提供状态码用于指示一个挂起中断的中断源和优先级。


第二:U0IER可以控制UART0的4个中断源。


4> UART0有4个中断源:


A. RLS(接收线状态)中断:


(1) 优先级最高


(2) 它在以下条件发生时产生错误


第一:帧错误(FE)


第二:溢出错误(OE)


第三:奇偶错误(PE)


第四:间隔中断(BI)


注:可以通过查看U0LSR[4:1]中的值看到产生该中断的错误条件,读取U0LSR寄存器时清除该中断。


B. RDA(接收数据可用)中断:


(1)与CTI中断并列第二优先级。


(2)在以下情况触发中断:


第一:当接收的有效数据到达接收FIFO设置寄存器(U0FCR)中设置的触发点时,RDA被激活。当接收FIFO中的有效数据少于触发点时,RDA复位。


第二:中断过程:


1>  移位寄存器(U0RSR)从RxD引脚接收串行数据后,送入接收FIFO中


2>  当接收FIFO中的有效数据数量达到预定的触发点时,置位RDA中断。


3>  从U0RBR寄存器中读取FIFO中最早到达的数据,当FIFO中的有效数据小于触发点时,清零RDA中断。


C.  CTI(字符超时指示)中断


(1) 优先级为2.


(2) 在以下情况发生中断:


当接收FIFO中的有效数据少于预定的触发点数量时,如果在一定时间内仍没有接收到新的数据,那将触发该中断。


(3) 上面的时间指的是:3.5~4.5个字节所需要的时间。


(4)  对接收FIFO的任何操作都会清零该中断标志。


(5) 中断过程:


第一:移位寄存器(U0RSR)从RxD0引脚接收串行数据后,送入接收FIFO中。


第二:当接收FIFO中的有效数据少于触发个数,但如果长时间没有数据到达,则触发CTI中断。


第三:从U0RBR中读取接收FIFO中的数据,或者有新的数据送入接收FIFO,都将清零CTI中断。


注:3.5~4.5个字节的时间:指在串口当前的波特率下,发送3.5~4.5个字节所需要的时间。


当接收FIFO中存放多个数据,从U0RBR读取数据,但是没有读完所有数据,那么在经过3.5~4.5个字节的时间后触发CTI中断。


D.  THRE(发送)中断


(1) 优先级为第三级优先级。


(2) 当FIFO为空并且在以下情况触发中断:


第一:系统启动时,虽然发送FIFO为空,但不会产生THRE中断。


第二:在上一次发生THRE中断后,向发送FIFO中写入1个字节数据,将在一个字节加上一个停止位后发生THRE中断


(because:如果发送移位寄存器为空,那么写入发送FIFO的数据将直接进入发送移位寄存器。此时发送FIFO仍然为空,如果立即产生THRE中断,就会影响紧接着写入发送FIFO的数据。所以在发送完该一个字节以及一个停止位后,才产生THRE中断。)


如果在发送FIFO中有过两个字节以上的数据,但是现在发送FIFO为空时,将立即触发THRE中断。当THRE中断为当前有效的最高优先级中断时,往U0THR写数或者对U0IIR的读操作,将使THRE中断复位


我们来看看这些中断源与存储器之间的关系:


注:由上图可知:UART0有4个中断源:分别是RLS(线状态)中断,RDA(接收数据)中断,CTI(字符超时)中断,THRE(发送数据)中断。4个中断源的优先级如下图所示:

3.串口中断接收初始化


1>串口中断接收初始化流程


l  设置I/O引脚连接到UART0


l  置位除数锁存位,配置UART0帧数据格式


l  根据波特率计算分频值


l  设置波特率


l  清除除数锁存位,并设置工作模式


l  使能FIFO,并设置触发点


l  允许RBR中断


注:我们可以发现与轮训方式相比,中断方式只是增加了使能FIFO,并设置中断触发点和允许RBR中断两步。


2>中断串口初始化需要配置的寄存器


     (与轮循方式配置方法相同的寄存器在此处不在涉及)


l  U0FCR(FIFO控制寄存器):U0FCR控制UART0 Rx和Tx FIFO的操作。


l  U0IER(中断使能寄存器):U0IER用于使能4个UART0中断源。


3>具体寄存器的配置


(1) U0FCR


A作用:控制UART0 Rx和Tx的操作。


B长度:8位寄存器。


C:每一位的含义:


l  第0位:表示FIFO使能


置1:表示使能对UART0 Rx和Tx的FIFO以及U0FCR[7:1]的访问。


置0:表示不能使用Rx和Tx的FIFO以及步能对U0FCR[7:1]的访问。


注:该位的任何变化都将使UART0 FIFO清空。


l  第1位:表示Rx FIFO的复位。


置1:会清零UART0 RxFIFO中的所有字节并复位指针逻辑。该位自动清零。


l  第2位:表示Tx FIFO的复位。


置1:会清零UART0 TxFIFO中的所有字节并复位指针逻辑。改位自动清零。


l  第[5:3]位:保留位,用户不能对其进行操作。从保留位读出的值未被定义。


l  第[7:6]位:表示Rx触发选择


00:触发点为0(默认为1字节)


01:触发点为1(默认为4字节)


10:触发点为2(默认为8字节)


11: 触发点为3(默认为14字节)


注:这两个位决定在激活中断之前,接收UART0 FIFO必须写入个字符。


(2) U0IER(中断使能寄存器)


A 作用:U0IER用于使能4个UART0中断源


B 长度:8位寄存器


C每一位的含义:


l  第0位:表示RBR中断使能


置1:使能RDA中断


置0:禁止RDA中断


注:U0IEER 第零位使能UART0接收数据可用中断。它还控制(CTI)字符接收超时中断。


l  第1位:表示THRE中断使能


置1:使能THRE中断


置0:禁止THRE中断


l  第2位:表示Rx线状态中断使能


置1:使能Rx线状态中断


置0:禁止RX线状态中断


注:U0IER第二位使能UART0 Rx线状态中断。该中断的状态可从U0LSR[4:1]读出


l  第[7:3]位:是保留位


注:用户不能向其写入1.


4>串口初始化程序:void   UART0_Init(uint32 bps)


 

4.  中断初始化


先来看一下UART0和VIC之间的关系:




1>中断初始化流程:


l  选择中断为向量中断或快速中断


l  分配中断通道


l  设置UART0向量地址


l  使能UART0中断


2>关于ARM中断编程方法和寄存器的使用在此不做涉及(如果想知道的话,可以看这篇文章http://blog.csdn.net/tigerjb/archive/2010/11/30/6045409.aspx


3>中断初始化程序:void Interrupt_Init (void)


5.用中断编写接收函数


1>  中断服务函数流程


l  清除串口中断标识寄存器(U0IIR)


l  清除中断标志


l  读取接收FIFO中的数据


2>  中断函数服务函数中需要配置的寄存器


(1) U0IIR中断标识寄存器。


l  第0位:表示中断挂起


置1:表示没有挂起的中断


置0:表示至少有一个中断挂起


l  第[3:1]位:中断标识,这三位表示了对应UART0 Rx FIFO的中断。


001:表示发送中断(THRE)


010:  表示接收数据可用中断(RDA)


011:  表示接收线状态中断(RLS)


110:  表示字符超时中断(CTI)


l  第[7:4]:是保留位


注:


1.    U0IIR提供的状态码可用于指示一个挂起中断的中断源和优先级。


2.    在访问U0IIR过程中,中断被冻结


3.    如果在访问U0IIR时,产生了中断,该中断被记录。在下次访问U0IIR时可以读出,避免中断的丢失。


3>  中断服务函数程序:void   __irq IRQ_UART0(void)


6.总程序:通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,把数据又发送回上位机。


(在用中断的时候在Startup.S文件中的InitStack子程序中,修改设置系统模式堆栈处的代码为"MSR CPSR_c,#0x5f",

测试成功 ,在上面上发送16进制数时,每个之间用空格隔开不加前缀。)



#include "config.h"

uint8 recver_buffer[8];    

uint8 rcv_new;     

/**********************************************************

* 名称: UART0_Init()

* 功能: UART0初始化(通讯波特率115200,8位数据位,

1位停止位,无奇偶校验)

* 入口参数: bps     串口波特率

* 出口参数: 无

**********************************************************/

void  UART0_Init(uint32 bps)

{  

    uint16 Fdiv;

    PINSEL0 = 0x00000005;               //设置串口引脚

    U0LCR = 0x83; //置为除数锁存位,进行配置

    Fdiv = (Fpclk >> 4) / bps;     // 设置波特率

    U0DLM = Fdiv >> 8;

    U0DLL = Fdiv & 0xff;

    U0LCR = 0x03;                      //清除除数锁存位,并设置工作模式模式

    U0FCR = 0x81;                     // 使能FIFO,并设置触发点为8字节

    U0IER = 0x01;                     // 允许RBR中断,即接收中断

 

}

/*********************************************************  

* 名    称:    IRQ_UART0

* 功    能: 串口UART0中断接收8个字节的数据

* 入口参数: 无

* 出口参数: 无

**********************************************************/ 

void   __irq IRQ_UART0(void)

{   uint8  i;

    if( 0x04 == (U0IIR&0x0F) ) 

    {

     rcv_new = 1; // 设置接收到新的数据标志,并清除中断标志位

     for(i=0; i<8; i++)

    {

        recver_buffer[i] = U0RBR;       // 读取FIFO的数据

    }

      VICVectAddr = 0;

     }                           //清除中断

}  

/**********************************************************

* 名称:          Interrupt_Init

* 功能:          初始化串口中断,给串口中断选择为向量中断,

*                 分配向量通道号1给串口                        

* 入口参数:      无

* 出口参数:      无

**********************************************************/

void Interrupt_Init (void)

{

    VICIntSelect = 0x00000000;            // 设置所有通道为IRQ中断

    VICVectCntl0 = 0x26;        // UART0中断通道分配到IRQ slot 0,即优先级最高

    VICVectAddr0 = (int)IRQ_UART0;        // 设置UART0向量地址

    VICIntEnable = 0x00000040;            // 使能UART0中断

               

}

/**********************************************************

* 名    称:            UART0_SendByte

* 功    能:            向串口发送字节数据,并等待发送完毕。

* 入口参数:            data              要发送的数据

* 出口参数:            无

**********************************************************/

void   UART0_SendByte(uint8 data)

{

U0THR = data;                 

while(0 == (U0LSR & 0x40));

}

/**********************************************************

* 名称: UART0_SendBuf()

* 功能: 通过串口发送一帧数据

* 入口参数: *buffer  存放一帧数据

* 出口参数: 无

**********************************************************/

void UART0_SendBuf(uint8 *buffer)

{

uint8 *pbuffer;

    uint8 i;

for(pbuffer = buffer,i = 0;i < 8; i++)

UART0_SendByte(*(pbuffer++));

}

 

/**********************************************************

* 名称: main()函数

* 功能: 上位机接收的数据开头两个字符为0x10,0x11,

* 则原样输出,否次输出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27

* 入口参数: *buffer  存放一帧数据

* 出口参数: 无

**********************************************************/

 

int main (void)

                                    

    uint8 send_buffer[8] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27};  //定义发送帧缓冲区

    UART0_Init(115200);

    Interrupt_Init();

    while(1)

    {

      if(1 == rcv_new)  // 是否已经接收到8 Bytes的数据

      {  

            rcv_new = 0;        // 清除标志

      if(0x10 ==recver_buffer[0] && 0x11 == recver_buffer[1])

      {

      UART0_SendBuf(send_buffer);

      }

          else

      {

      UART0_SendBuf(recver_buffer);

      }

          } 

      }        

     return 0;

}

 


二.用中断编写发送函数

1.中断初始化

同上和用中断接收函数时的中断初始化是一样的

2.串口初始化

 1>串口初始化流程:

l  设置I/O引脚连接到UART0

l  置位除数锁存位,配置UART0帧格式

l  根据波特率计算分频值

l  设置波特率

l  清除除数锁存位,并设置工作模式

l  使能FIFO,并使TxFIFO复位

l  使能THRE中断

  2>串口初始化函数:void   UART0_Init(uint32 bps)


3.中断服务函数:

  1>中断服务函数流程:

l  清除串口中断标识寄存器

l  清除中断控制标识寄存器

  2>中断发送服务函数程序:void   __irq IRQ_UART0(void)


4.用串口中断发送函数的总程序:通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,用中断方式把数据又发送回上位机。


#include "config.h"

uint8 recver_buffer[8];    

uint8 rcv_new;     

/****************************************************************************

* 名称: UART0_Init

* 功能: UART0初始化 通讯波特率115200,8位数据位,1位停止位,无奇偶校验

* 使能TxFIFO,和THRE中断

* 入口参数: bps 串口波特率

* 出口参数: 无

****************************************************************************/

void  UART0_Init(uint32 bps)

{

 

    uint16  Fdiv;

    PINSEL0 = (PINSEL0 & ~(0xf) | 0x05) ;        //设置UART0的引脚

    U0LCR = 0x83;                                //置位除数锁存位,配置UART0帧格式

    Fdiv = (Fpclk>>4)/bps;                       //根据波特率计算分频值

推荐阅读

史海拾趣

Altitude Technology公司的发展小趣事

Altitude Technology公司成立于一个科技迅猛发展的时代,创始人李华怀揣着对电子技术的热爱和对未来科技的憧憬,决定创立一家专注于高度集成和智能化电子产品研发的公司。初期,公司面临着资金短缺、人才匮乏等重重困难,但李华凭借对技术的深刻理解和敏锐的市场洞察力,带领团队开发出了一款具有划时代意义的智能手环,这款产品以其出色的性能和人性化的设计迅速在市场上获得了认可,为Altitude Technology公司赢得了第一桶金。

Blaze Display Technology Co Ltd公司的发展小趣事

随着技术的不断进步,Blaze公司意识到要想在激烈的市场竞争中立于不败之地,必须不断进行技术创新和品质升级。因此,公司加大了研发投入,引进了一批高端技术人才和先进设备,成功研发出了多项具有自主知识产权的核心技术。同时,公司还严格把控产品质量,确保每一块显示屏都达到行业领先水平。

Equinox公司的发展小趣事

随着时间的推移,Equinox的成功吸引了越来越多的投资者。公司开始寻求全球扩张的机会,并在不同国家和地区开设新的健身俱乐部。同时,Equinox还推出了多个子品牌,如E By Equinox、SoulCycle等,以满足不同消费者的需求。这些品牌涵盖了从高端豪华到平价实惠的全方位市场,进一步巩固了Equinox在健身行业的领先地位。

智烽维(CDA)公司的发展小趣事

智烽维(CDA)于2007年成立,专注于超级电容器(法拉电容)的研发和生产。在创立初期,公司面临着资金短缺、技术挑战和市场认知度低等多重困难。然而,凭借对技术的执着追求和对市场的敏锐洞察,智烽维成功推出了卷绕型超级电容器产品,并逐渐在市场上建立起了一定的知名度。

AnDAPT__Inc.公司的发展小趣事

随着技术的不断成熟和市场的不断拓展,智烽维在2015年开始面向全球开展业务。公司凭借卓越的产品质量和优质的服务,成功打入了国际市场,并在多个国家和地区建立了稳定的销售网络。全球业务的拓展不仅为智烽维带来了更多的商机,也进一步提升了公司的品牌影响力和市场竞争力。

CONEC公司的发展小趣事

随着技术的不断进步和市场需求的不断变化,CONEC始终坚持产品创新。1985年,D-SUB滤波连接器的推出,是公司技术实力和市场洞察力的体现。这一创新产品不仅满足了当时市场对高性能连接器的需求,也为公司在电子行业中树立了良好的口碑。此后,CONEC不断推出新产品,逐步扩大市场份额,成为全球电子行业的重要参与者。

问答坊 | AI 解惑

基于ARM的条码精密测量系统

摘要: 本文介绍了一种基于32位高性能处理器的视觉精密测量系统的软硬件设计。图像传感器采集的条码图像通过精密定位算法得到绝对位移值,由以太网接口实现高速图像采集。该系统适用于高精度定位的各种位移测量。 关键词: ARM;嵌入式系统;视觉 ...…

查看全部问答>

LTCC的前景

本人初涉LTCC产品设计,不知基于该工艺的产品前景如何,谢谢讨论。…

查看全部问答>

模拟电子200问

附:pdf文档 1、半导体材料制作电子器件与传统的真空电子器件相比有什么特点? 答:频率特性好、体积小、功耗小,便于电路的集成化产品的袖珍化,此外在坚固抗震可靠等方面也特别突出;但是在失真度和稳定性等方面不及真空器件。 2、什么 ...…

查看全部问答>

NXL LPC系列ARM IIC总线下读写AT24Cxx的总结

       最近应用到NXP LPC系列的ARM IIC总线进行读写AT24Cxx EEPROM,总是出现一下错误,经过查阅资料才发现,原来本人范的全是最基本的错误,感觉很惭愧,现在把容易出错的地方进行总结,希望网友遇到这样的问题时 ...…

查看全部问答>

S3C6410 WINCE6 SD卡升级 求解

最近在思考一个问题,就是有关SD卡升级的。 我看到过三星发布2442下的SD卡升级,但有个缺陷是只支持FAT格式的小容量卡,而且,在EBOOT里面去读写卡的block、sector,简直有点复杂。 我在想,如果是FAT32格式的(现在基本上都是FAT32格式了)SD卡能 ...…

查看全部问答>

串口发送通了 但是始终接收不到数据

        int tmp,i,j;         int receiv,send=0x30;         *ULCON0=0x03;         *UCON0=0x09;         *UBRDIV0=0x280;   ...…

查看全部问答>

一方案打算用FSMC控制彩屏..想请教

从原理上来说..如果用FSMC驱动彩屏..就是把它当作一个外部的存储器件来操作. 1)只有16bit数据线是不是代表每像素就是16bit的?2)需要LCD内带控制器的屏才可以..这样选型范围应该会缩小很多.而且会贵这种屏一般上批量的话能做到多少钱一片. ...…

查看全部问答>

STM8S103配置TIM1为输出比较模式不翻转

用的是103F的片子,想把TIM1设置成翻转输出比较模式,但端口不会发生翻转 配置程序如下: GPIO_Init(GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_FAST); TIM1->CR1 &= 0xFE; // stop TIM1 TIM1->PSCRH = 0; TIM1->PSCRL = 0; ...…

查看全部问答>