打印
[LOOK]

【M0第四帖||Look第二帖】LOOK的中断详解,实现个串口类

[复制链接]
3000|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nixianmin|  楼主 | 2011-9-28 21:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
终于在几天的学习下又有进一步的突破了,LOOK系统也有个大概的概念了,且在学习LOOK的过程中也在思考用C++如何写程序,和C语言写程序有比较大的不同了,毕竟它的精华是面向对象的思想,刚开始写一直用LOOK里类的派生类,发现自己被LOOK类绑架了:L,没事就用task_t类,唉,没抓住他们特点就有点胡来的感觉,现在没事就自己建个类,要用到LOOK类的功能才从LOOK派生。    最近学了下interrupt_t和mbox<T>类,实现了几个简单的功能,下面来讲讲这些类:
    interrut_t是当使用中断功能时才用该类派生个中断类,该类最重要也就是
   
interrupt_t *  attach (uintptr_t irq) 
                     挂接本中断对象到指定的中断号上
   


    该功能实现当前的中断对象和对应的中断向量类进行相关联,无聊找出了其中的一些关系
    这段是中断的attach函数,看到和vector::table[中断号].attach(this),还有vector_t::attach
  
__OPT_INLINE__ look::interrupt_t* look::interrupt_t::attach(uintptr_t irq)
   {
     return vector_t::table[irq - -1/*SysTick_IRQn*/].attach(this);
   }
    _OPT_INLINE__ look::interrupt_t*
look::vector_t::attach(interrupt_t* intr)

  {

     interrupt_t*
old = interrupt;

     interrupt
= intr;

     return
old;

  }   


    在vector_t类中找到table[], 从这几段代码看出在产生中断时就可以通过table[中断号].interrupt.isr/dsr来调用
对应中断的相关中断函数了,应为每个table[]中都用了interrupt *将其联系起来了,好了中断就讲到这
   
#ifndef __DOXYGEN__
    union {
    struct {
        interrupt_t* interrupt;
        uint16_t count;
        uint8_t next;
    };
      uint64_t data;
   };
  #endif        // __DOXYGEN__

  static vector_t table[] __attribute__((aligned(4)));
  

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面是我写的代码,一个uart0_int_c:public interrupt_t类实现串口的一些功能,可以设置参数,也可以用默认设置
这些代码有些都是照着MO库来改写的,并在一个任务中实现了mmbox_t<T,SIZE>多信息邮箱,如果串口中断接收到数据,则通过
邮箱将数据送到一个任务函数中并通过串口发送出去,邮箱的get()函数在没有信息时会使当前任务进入阻塞状态,只有有信息时,才能
激活任务,并读取邮箱里的数据。
uart.h
/*****************************************
//
//
******************************************/
#ifndef _Uart_h_
#define _Uart_h_
#include"look.h"

/*---------------------------------------------------------------------------------------------------------*/
/* DATA BIT */
/*---------------------------------------------------------------------------------------------------------*/
typedef enum
{
DRVUART_DATABITS_5 = 0x0,
DRVUART_DATABITS_6         =         0x1,
DRVUART_DATABITS_7 =         0x2,
DRVUART_DATABITS_8 =         0x3

} DATABITS_SET;

/*---------------------------------------------------------------------------------------------------------*/
/* PARITY Setting */
/*---------------------------------------------------------------------------------------------------------*/

typedef enum
{
DRVUART_PARITY_NONE = 0x0,
DRVUART_PARITY_ODD         =        0x1,
DRVUART_PARITY_EVEN =        0x3,
DRVUART_PARITY_MARK =        0x5,
DRVUART_PARITY_SPACE =        0x7
} PARITY_SET;

/*---------------------------------------------------------------------------------------------------------*/
/* STOP BIT */
/*---------------------------------------------------------------------------------------------------------*/

typedef enum
{
DRVUART_STOPBITS_1 = 0x0,
DRVUART_STOPBITS_1_5        = 0x1,
DRVUART_STOPBITS_2 = 0x1
} STOPBITS_SET;


/*---------------------------------------------------------------------------------------------------------*/
/* FIFO Select */
/*---------------------------------------------------------------------------------------------------------*/
typedef enum
{
DRVUART_FIFO_1BYTES = 0x0,
DRVUART_FIFO_4BYTES = 0x1,
DRVUART_FIFO_8BYTES = 0x2,
DRVUART_FIFO_14BYTES = 0x3,
DRVUART_FIFO_30BYTES = 0x4,
DRVUART_FIFO_46BYTES = 0x5,
DRVUART_FIFO_62BYTES = 0x6
}FIFO_SET;

/*****************************************
//串口中断类
*****************************************/
class uart0_int_c :public interrupt_t{
public:
uart0_int_c(uint32_t u32Bandrate = 9600 ,PARITY_SET u8cParity=DRVUART_PARITY_NONE,\
STOPBITS_SET u8cStopBits=DRVUART_STOPBITS_1,DATABITS_SET u8cDataBits=DRVUART_DATABITS_8,\
FIFO_SET u8cRxTriggerLevel= DRVUART_FIFO_1BYTES);

void Uart0Close();
void Uart0RxEnableInt();//接收中断使能
void Uart0RxDisableInt();//接受中断失效
uint8_t Wstr(const char *);
uint8_t Write(uint32_t *,uint32_t);//发送数据
uint8_t Read(uint32_t * ,uint32_t);//读接收的数据

protected:
bool isr(int vector);
void dsr(int vector,uintptr_t count);

private:
void BaudRateSet(uint32_t clk, uint32_t baudRate);
};

#endif




uart.cpp串口代码
#include <NUC1xx.h>
#include"NUC1xxM051Seriescfg.h"
#include"LOOK_config.h"
#include"Uart.h"

//构造函数,并可以设置波特率,校验,数据位,停止位,UART_FIFO
uart0_int_c::uart0_int_c(uint32_t u32Bandrate  ,PARITY_SET u8cParity,\
STOPBITS_SET u8cStopBits,DATABITS_SET u8cDataBits,\
FIFO_SET u8cRxTriggerLevel){
  
  //将管脚设置为UART0模式
  SYSs.GPBMFP.Bits.UART0_RX=1;
  SYSs.GPBMFP.Bits.UART0_TX=1;
  SYSs.GPBMFP.Bits.UART0_nRTS_nWRL=1;
  SYSs.GPBMFP.Bits.UART0_nCTS_nWRH=1;  //SYSs.GPBMFP.Regs|=0x0f;
   /* Reset IP */
  SYSs.IPRSTC2.Bits.UART0_RST = 1;
        SYSs.IPRSTC2.Bits.UART0_RST = 0;
               
        /* Enable UART0 clock */
  SYSCLKs.APBCLK.Bits.UART0_EN=1;
  
  UART0s.FCR.Bits.TFR =1;//TX/RX软复位
  UART0s.FCR.Bits.RFR =1;

  /* Set Rx Trigger Level */
        UART0s.FCR.Bits.RFITL = u8cRxTriggerLevel;  
       
        /* Set Parity & Data bits & Stop bits */
        UART0s.LCR.Bits.SPE        =(u8cParity&0x4)?1:0;
        UART0s.LCR.Bits.EPE        =(u8cParity&0x2)?1:0;
        UART0s.LCR.Bits.PBE        =(u8cParity&0x1)?1:0;
               
        UART0s.LCR.Bits.WLS        =u8cDataBits;
        UART0s.LCR.Bits.NSB        =DRVUART_STOPBITS_1;
               
        /* Set Time-Out */
        UART0s.TOR.Bits.TOIC        =0x7f;

  //设置UART时钟为外部12M时钟
  SYSCLKs.CLKSEL1.Bits.UART_S = 0;

  BaudRateSet(F_CPU,u32Bandrate);//设置波特率
  }
//关闭UART0串口
void uart0_int_c::Uart0Close()
{
  while(UART0s.FSR.Bits.TE_FLAG);
  SYSCLKs.APBCLK.Bits.UART0_EN = 0;
  vector_t::disable(UART0_IRQn);
}
//使能UART0接收中断
void uart0_int_c::Uart0RxEnableInt()
{
        UART0s.IER.Bits.RDA_IEN=1; //使能中断
        attach(UART0_IRQn);
        vector_t::enable(UART0_IRQn);
}
//失效
void uart0_int_c::Uart0RxDisableInt()
{
        UART0s.IER.Bits.RDA_IEN=0;
    vector_t::disable(UART0_IRQn);
}

uint8_t uart0_int_c::Wstr(const char *wstrbuf)
{
        uint32_t u32delayno=0;

        do{
                u32delayno = 0;
                UART0s.DATA.Regs=*wstrbuf++;
               
                   while (UART0s.FSR.Bits.TE_FLAG !=1)                                                            /* Wait Tx empty and Time-out manner */
               {
                   u32delayno++;
                   if ( u32delayno >= 0x1000)                 
                      return 0;                                      
               }
        }while(*wstrbuf!='\0');       

        return 1;
}
//发送数据
uint8_t uart0_int_c::Write(uint32_t        *pu32TxBuf,         uint32_t u32WriteBytes)
{
  uint32_t  u32Count, u32delayno;

  for (u32Count=0; u32Count<u32WriteBytes; u32Count++)
  {
     u32delayno = 0;
           while (UART0s.FSR.Bits.TE_FLAG !=1)                                                            /* Wait Tx empty and Time-out manner */
       {
                   u32delayno++;
                   if ( u32delayno >= 0x1000)                 
                      return 0;                    
                                  
       }
           UART0s.DATA.Regs = pu32TxBuf[u32Count];                                                /* Send UART Data from buffer */
    }

    return 1;
       
  
}

//读数据

uint8_t uart0_int_c::Read(uint32_t        *pu32RxBuf, uint32_t        u32ReadBytes)
{
    uint32_t  u32Count, u32delayno;

    for (u32Count=0; u32Count < u32ReadBytes; u32Count++)
    {
                 u32delayno = 0;
             while (UART0s.FSR.Bits.RX_EMPTY ==1)                                            /* Check RX empty => failed */          
             {
                     u32delayno++;        
                if ( u32delayno >= 0x1000 )        
                        return 0;               
         }
         pu32RxBuf[u32Count] = UART0s.DATA.Regs;                                            /* Get Data from UART RX  */
    }

    return 1;
       
}



//M0库中的波特率设置函数
void uart0_int_c::BaudRateSet(uint32_t clk, uint32_t baudRate)
{
  int32_t tmp;
        int32_t div;

        if(((clk / baudRate)%16)<3)              /* Source Clock mod 16 <3 => Using Divider X =16 (MODE#0) */
        {                                                                  
                UART0s.BAUD.Bits.DIV_X_EN = 0;
          UART0s.BAUD.Bits.DIV_X_ONE   = 0;
                tmp = clk / baudRate/16  -2;
        }
        else                                                          /* Source Clock mod 16 >3 => Up 5% Error BaudRate */
        {
            UART0s.BAUD.Bits.DIV_X_EN = 1;                          /* Try to Set Divider X = 1 (MODE#2)*/
            UART0s.BAUD.Bits.DIV_X_ONE   = 1;
                tmp = clk / baudRate  -2;

                if(tmp > 0xFFFF)                          /* If Divider > Range  */
                {
                        UART0s.BAUD.Bits.DIV_X_EN = 1;                  /* Try to Set Divider X up 10 (MODE#1) */
                        UART0s.BAUD.Bits.DIV_X_ONE   = 0;

                        for(div = 8; div <16;div++)
                        {
                                if(((clk / baudRate)%(div+1))<3)
                                {
                                        UART0s.BAUD.Bits.DIVIDER_X   = div;
                                        tmp = clk / baudRate / (div+1) -2;
                                        break;
                                }
                        }
                }
        }

        UART0s.BAUD.Bits.BRD = tmp;

}



main.cpp主文件
#include <NUC1xx.h>
#include"NUC1xxM051Seriescfg.h"
#include "main.h"
#include"M0Base.h"
#include"Uart.h"



/******************************************/
//声明对象
///////////////////////////////////////////
//key_int_c key;
led_ctl_c led1;
uart0_int_c uart0;

#ifdef LOOK_SCHEDULING_PRIORITY
instantiate::task<task1_main_t, LOOK_STACK_SIZE> task1_main(0);
instantiate::task<task2_uart0_c,LOOK_STACK_SIZE> task2_uart0(1);
#else
instantiate::task<task1_main_t, LOOK_STACK_SIZE> task1_main;
instantiate::task<task2_uart0_c,LOOK_STACK_SIZE> task2_uart0;
#endif


/*************************************
//task1任务类的任务函数
**************************************/
void task1_main_t::routine()
{
        led_ctl_c led;
        // TODO: 在此编写 task1_main_t 例程的内容
        while (true) {

                led.Led1to4();
                scheduler.yield();
                // TODO: 在此编写 task1_main_t 例程的内容
        }
}

/***************************************
//
***************************************/
void task2_uart0_c::routine()
{
        uart0.Uart0RxEnableInt();  //使能接受中断

        while(true){
                #ifdef _DEBUG_
                        uart0.Wstr("before uart_megs");
                #endif
                uint32_t msg=uart_megs.get();
                uart0.Wstr("接收的内容:");
                uart0.Write(&msg,1);          //发送接收的数据
    uart0.Wstr("\n");

        }
}
/***************************************
*按键中断类成员函数
****************************************/
inline key_int_c::key_int_c()
{
  attach(EINT0_IRQn); //将中断号和本对象挂钩
  attach(EINT1_IRQn);
  GPIOBs.IEN.Regs = (1 << Pin15) | (1 << Pin14);   // 开启中断
  vector_t::enable(EINT0_IRQn);//必须在有main.h的头文件中
  vector_t::enable(EINT1_IRQn);
}
// Keyboard_t 中断服务例程
bool key_int_c::isr(int vector)
{
  GPIOBs.ISRC.Regs = GPIOBs.ISRC.Regs;   // 清中断 flag
  return true;
}
// Keyboard_t 中断滞后服务例程
void key_int_c::dsr(int vector, uintptr_t count)
{
  if (vector == EINT0_IRQn)
  {
  //  led1.Led4to1();   
  }
  else if (vector == EINT1_IRQn)
  {
   //  led1.Led1to4();  
  }
}

/*********************************
//uart0类的成员函数
***********************************/
bool uart0_int_c::isr(int vector)
{
        #ifdef _DEBUG_
                uart0.Wstr("Into uart0 isr\n");
        #endif       

        return true;
}

void uart0_int_c::dsr(int vector, uintptr_t count)
{
        uint32_t buf=0;
        if(UART0s.ISR.Bits.RDA_INT==1)
        {
                #ifdef _DEBUG_
                        uart0.Wstr("Into uart0 dsr\n");
                #endif
//                do{
      buf=UART0s.DATA.Regs;
                        task2_uart0.uart_megs.do_tryput(buf);        //读取接收的数据
//      task2_uart0.uart_megs.do_tryput('a');       
//                }while(UART0s.ISR.Bits.RDA_IF!=0);       
        }
               
}



其他代码不贴了,要的大家看程序,希望老师、大叔和大家多多提提意见,好让我提高下
有问题也可以一起多多交流下

LOOK实现串口类.rar

958.37 KB

相关帖子

沙发
john_lee| | 2011-9-29 00:14 | 只看该作者
首先肯定一下楼主的进步,对LOOK的中断处理有了比较深刻的认识。

然后谈谈楼主程序中存在的一些问题:
最严重的,是在uart0_int_c::isr()函数,该函数并没有对UART硬件有任何操作,而是直接返回了true,RDA_IF会一直存在,中断发生的条件没有消失,这将导致中断返回后再次进入中断。
其次,程序中有忙等存在,没有使用同步对象。
第三,使用邮箱来传递单字节数据,效率较低。

以上只是指出了主要的错误所在,我先不给出解决的方法,希望楼主自己能想出。
再次鼓励一下。

使用特权

评论回复
板凳
nixianmin|  楼主 | 2011-9-29 07:16 | 只看该作者
2# john_lee 老师,串口的RDA_IF位是只读的,当RxFIFO跌落到极限级别该位清除,所以当我dsr读数据时就会使该位自动清除了,我试了也没遇到重复进入中断的情况。

2、忙等待是指在LED里的吧,差点忘了,是因为以前两个灯的任务一用look::delay函数任务就会进入就绪态,运行另一个灯的任务,这样灯就显示不错我要的效果,这个程序可以用delay函数来延时了

3、邮箱这个倒是可以不同邮箱直接将数据发送,我就是想试试邮箱的阻塞效果,当邮箱没信息get()所在的任务会阻塞,当邮箱就收到消息时,该任务激活,并通过get()获得消息发送

使用特权

评论回复
地板
Swallow_0322| | 2011-9-29 08:04 | 只看该作者
值得学习,加油!:victory:

使用特权

评论回复
5
nixianmin|  楼主 | 2011-9-29 08:10 | 只看该作者
Swallow_0322 嘿嘿,我都是参考你的帖子写的,希望能多带小弟玩玩

使用特权

评论回复
6
hotpower| | 2011-9-29 08:30 | 只看该作者
不错学习,交流和进步!

使用特权

评论回复
7
nixianmin|  楼主 | 2011-9-29 10:13 | 只看该作者
刚才想了好多,很多机制没想通,关于老师第三个问题我想老师是想我用其他机制,像事件标志类,如果有中断发生则标志事件,并在任务中判断标志来进行

使用特权

评论回复
8
nixianmin|  楼主 | 2011-9-29 16:29 | 只看该作者
刚才发现mmbox在接收字符串很有优势,尤其是命令,晚上发帖解说下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:电机控制,TI InstaSpin Foc交流群:335663930

40

主题

431

帖子

6

粉丝