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

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


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

  7.   {

  8.      interrupt_t*
  9. old = interrupt;

  10.      interrupt
  11. = intr;

  12.      return
  13. old;

  14.   }   


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

  11.   static vector_t table[] __attribute__((aligned(4)));
  12.   

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

  8. /*---------------------------------------------------------------------------------------------------------*/
  9. /* DATA BIT */
  10. /*---------------------------------------------------------------------------------------------------------*/
  11. typedef enum
  12. {
  13. DRVUART_DATABITS_5 = 0x0,
  14. DRVUART_DATABITS_6         =         0x1,
  15. DRVUART_DATABITS_7 =         0x2,
  16. DRVUART_DATABITS_8 =         0x3

  17. } DATABITS_SET;

  18. /*---------------------------------------------------------------------------------------------------------*/
  19. /* PARITY Setting */
  20. /*---------------------------------------------------------------------------------------------------------*/

  21. typedef enum
  22. {
  23. DRVUART_PARITY_NONE = 0x0,
  24. DRVUART_PARITY_ODD         =        0x1,
  25. DRVUART_PARITY_EVEN =        0x3,
  26. DRVUART_PARITY_MARK =        0x5,
  27. DRVUART_PARITY_SPACE =        0x7
  28. } PARITY_SET;

  29. /*---------------------------------------------------------------------------------------------------------*/
  30. /* STOP BIT */
  31. /*---------------------------------------------------------------------------------------------------------*/

  32. typedef enum
  33. {
  34. DRVUART_STOPBITS_1 = 0x0,
  35. DRVUART_STOPBITS_1_5        = 0x1,
  36. DRVUART_STOPBITS_2 = 0x1
  37. } STOPBITS_SET;


  38. /*---------------------------------------------------------------------------------------------------------*/
  39. /* FIFO Select */
  40. /*---------------------------------------------------------------------------------------------------------*/
  41. typedef enum
  42. {
  43. DRVUART_FIFO_1BYTES = 0x0,
  44. DRVUART_FIFO_4BYTES = 0x1,
  45. DRVUART_FIFO_8BYTES = 0x2,
  46. DRVUART_FIFO_14BYTES = 0x3,
  47. DRVUART_FIFO_30BYTES = 0x4,
  48. DRVUART_FIFO_46BYTES = 0x5,
  49. DRVUART_FIFO_62BYTES = 0x6
  50. }FIFO_SET;

  51. /*****************************************
  52. //串口中断类
  53. *****************************************/
  54. class uart0_int_c :public interrupt_t{
  55. public:
  56. uart0_int_c(uint32_t u32Bandrate = 9600 ,PARITY_SET u8cParity=DRVUART_PARITY_NONE,\
  57. STOPBITS_SET u8cStopBits=DRVUART_STOPBITS_1,DATABITS_SET u8cDataBits=DRVUART_DATABITS_8,\
  58. FIFO_SET u8cRxTriggerLevel= DRVUART_FIFO_1BYTES);

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

  65. protected:
  66. bool isr(int vector);
  67. void dsr(int vector,uintptr_t count);

  68. private:
  69. void BaudRateSet(uint32_t clk, uint32_t baudRate);
  70. };

  71. #endif




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

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

  24.   /* Set Rx Trigger Level */
  25.         UART0s.FCR.Bits.RFITL = u8cRxTriggerLevel;  
  26.        
  27.         /* Set Parity & Data bits & Stop bits */
  28.         UART0s.LCR.Bits.SPE        =(u8cParity&0x4)?1:0;
  29.         UART0s.LCR.Bits.EPE        =(u8cParity&0x2)?1:0;
  30.         UART0s.LCR.Bits.PBE        =(u8cParity&0x1)?1:0;
  31.                
  32.         UART0s.LCR.Bits.WLS        =u8cDataBits;
  33.         UART0s.LCR.Bits.NSB        =DRVUART_STOPBITS_1;
  34.                
  35.         /* Set Time-Out */
  36.         UART0s.TOR.Bits.TOIC        =0x7f;

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

  39.   BaudRateSet(F_CPU,u32Bandrate);//设置波特率
  40.   }
  41. //关闭UART0串口
  42. void uart0_int_c::Uart0Close()
  43. {
  44.   while(UART0s.FSR.Bits.TE_FLAG);
  45.   SYSCLKs.APBCLK.Bits.UART0_EN = 0;
  46.   vector_t::disable(UART0_IRQn);
  47. }
  48. //使能UART0接收中断
  49. void uart0_int_c::Uart0RxEnableInt()
  50. {
  51.         UART0s.IER.Bits.RDA_IEN=1; //使能中断
  52.         attach(UART0_IRQn);
  53.         vector_t::enable(UART0_IRQn);
  54. }
  55. //失效
  56. void uart0_int_c::Uart0RxDisableInt()
  57. {
  58.         UART0s.IER.Bits.RDA_IEN=0;
  59.     vector_t::disable(UART0_IRQn);
  60. }

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

  64.         do{
  65.                 u32delayno = 0;
  66.                 UART0s.DATA.Regs=*wstrbuf++;
  67.                
  68.                    while (UART0s.FSR.Bits.TE_FLAG !=1)                                                            /* Wait Tx empty and Time-out manner */
  69.                {
  70.                    u32delayno++;
  71.                    if ( u32delayno >= 0x1000)                 
  72.                       return 0;                                      
  73.                }
  74.         }while(*wstrbuf!='\0');       

  75.         return 1;
  76. }
  77. //发送数据
  78. uint8_t uart0_int_c::Write(uint32_t        *pu32TxBuf,         uint32_t u32WriteBytes)
  79. {
  80.   uint32_t  u32Count, u32delayno;

  81.   for (u32Count=0; u32Count<u32WriteBytes; u32Count++)
  82.   {
  83.      u32delayno = 0;
  84.            while (UART0s.FSR.Bits.TE_FLAG !=1)                                                            /* Wait Tx empty and Time-out manner */
  85.        {
  86.                    u32delayno++;
  87.                    if ( u32delayno >= 0x1000)                 
  88.                       return 0;                    
  89.                                   
  90.        }
  91.            UART0s.DATA.Regs = pu32TxBuf[u32Count];                                                /* Send UART Data from buffer */
  92.     }

  93.     return 1;
  94.        
  95.   
  96. }

  97. //读数据

  98. uint8_t uart0_int_c::Read(uint32_t        *pu32RxBuf, uint32_t        u32ReadBytes)
  99. {
  100.     uint32_t  u32Count, u32delayno;

  101.     for (u32Count=0; u32Count < u32ReadBytes; u32Count++)
  102.     {
  103.                  u32delayno = 0;
  104.              while (UART0s.FSR.Bits.RX_EMPTY ==1)                                            /* Check RX empty => failed */          
  105.              {
  106.                      u32delayno++;        
  107.                 if ( u32delayno >= 0x1000 )        
  108.                         return 0;               
  109.          }
  110.          pu32RxBuf[u32Count] = UART0s.DATA.Regs;                                            /* Get Data from UART RX  */
  111.     }

  112.     return 1;
  113.        
  114. }



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

  120.         if(((clk / baudRate)%16)<3)              /* Source Clock mod 16 <3 => Using Divider X =16 (MODE#0) */
  121.         {                                                                  
  122.                 UART0s.BAUD.Bits.DIV_X_EN = 0;
  123.           UART0s.BAUD.Bits.DIV_X_ONE   = 0;
  124.                 tmp = clk / baudRate/16  -2;
  125.         }
  126.         else                                                          /* Source Clock mod 16 >3 => Up 5% Error BaudRate */
  127.         {
  128.             UART0s.BAUD.Bits.DIV_X_EN = 1;                          /* Try to Set Divider X = 1 (MODE#2)*/
  129.             UART0s.BAUD.Bits.DIV_X_ONE   = 1;
  130.                 tmp = clk / baudRate  -2;

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

  135.                         for(div = 8; div <16;div++)
  136.                         {
  137.                                 if(((clk / baudRate)%(div+1))<3)
  138.                                 {
  139.                                         UART0s.BAUD.Bits.DIVIDER_X   = div;
  140.                                         tmp = clk / baudRate / (div+1) -2;
  141.                                         break;
  142.                                 }
  143.                         }
  144.                 }
  145.         }

  146.         UART0s.BAUD.Bits.BRD = tmp;

  147. }



main.cpp主文件
  1. #include <NUC1xx.h>
  2. #include"NUC1xxM051Seriescfg.h"
  3. #include "main.h"
  4. #include"M0Base.h"
  5. #include"Uart.h"



  6. /******************************************/
  7. //声明对象
  8. ///////////////////////////////////////////
  9. //key_int_c key;
  10. led_ctl_c led1;
  11. uart0_int_c uart0;

  12. #ifdef LOOK_SCHEDULING_PRIORITY
  13. instantiate::task<task1_main_t, LOOK_STACK_SIZE> task1_main(0);
  14. instantiate::task<task2_uart0_c,LOOK_STACK_SIZE> task2_uart0(1);
  15. #else
  16. instantiate::task<task1_main_t, LOOK_STACK_SIZE> task1_main;
  17. instantiate::task<task2_uart0_c,LOOK_STACK_SIZE> task2_uart0;
  18. #endif


  19. /*************************************
  20. //task1任务类的任务函数
  21. **************************************/
  22. void task1_main_t::routine()
  23. {
  24.         led_ctl_c led;
  25.         // TODO: 在此编写 task1_main_t 例程的内容
  26.         while (true) {

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

  32. /***************************************
  33. //
  34. ***************************************/
  35. void task2_uart0_c::routine()
  36. {
  37.         uart0.Uart0RxEnableInt();  //使能接受中断

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

  46.         }
  47. }
  48. /***************************************
  49. *按键中断类成员函数
  50. ****************************************/
  51. inline key_int_c::key_int_c()
  52. {
  53.   attach(EINT0_IRQn); //将中断号和本对象挂钩
  54.   attach(EINT1_IRQn);
  55.   GPIOBs.IEN.Regs = (1 << Pin15) | (1 << Pin14);   // 开启中断
  56.   vector_t::enable(EINT0_IRQn);//必须在有main.h的头文件中
  57.   vector_t::enable(EINT1_IRQn);
  58. }
  59. // Keyboard_t 中断服务例程
  60. bool key_int_c::isr(int vector)
  61. {
  62.   GPIOBs.ISRC.Regs = GPIOBs.ISRC.Regs;   // 清中断 flag
  63.   return true;
  64. }
  65. // Keyboard_t 中断滞后服务例程
  66. void key_int_c::dsr(int vector, uintptr_t count)
  67. {
  68.   if (vector == EINT0_IRQn)
  69.   {
  70.   //  led1.Led4to1();   
  71.   }
  72.   else if (vector == EINT1_IRQn)
  73.   {
  74.    //  led1.Led1to4();  
  75.   }
  76. }

  77. /*********************************
  78. //uart0类的成员函数
  79. ***********************************/
  80. bool uart0_int_c::isr(int vector)
  81. {
  82.         #ifdef _DEBUG_
  83.                 uart0.Wstr("Into uart0 isr\n");
  84.         #endif       

  85.         return true;
  86. }

  87. void uart0_int_c::dsr(int vector, uintptr_t count)
  88. {
  89.         uint32_t buf=0;
  90.         if(UART0s.ISR.Bits.RDA_INT==1)
  91.         {
  92.                 #ifdef _DEBUG_
  93.                         uart0.Wstr("Into uart0 dsr\n");
  94.                 #endif
  95. //                do{
  96.       buf=UART0s.DATA.Regs;
  97.                         task2_uart0.uart_megs.do_tryput(buf);        //读取接收的数据
  98. //      task2_uart0.uart_megs.do_tryput('a');       
  99. //                }while(UART0s.ISR.Bits.RDA_IF!=0);       
  100.         }
  101.                
  102. }



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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
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:
 楼主| nixianmin 发表于 2011-9-29 08:10 | 显示全部楼层
Swallow_0322 嘿嘿,我都是参考你的帖子写的,希望能多带小弟玩玩
hotpower 发表于 2011-9-29 08:30 | 显示全部楼层
不错学习,交流和进步!
 楼主| nixianmin 发表于 2011-9-29 10:13 | 显示全部楼层
刚才想了好多,很多机制没想通,关于老师第三个问题我想老师是想我用其他机制,像事件标志类,如果有中断发生则标志事件,并在任务中判断标志来进行
 楼主| nixianmin 发表于 2011-9-29 16:29 | 显示全部楼层
刚才发现mmbox在接收字符串很有优势,尤其是命令,晚上发帖解说下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

40

主题

431

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部