[LOOK] 根据Lee老师建议修改LOOK_ADC_PWM(邮箱传递数据)

[复制链接]
 楼主| wang0225 发表于 2011-8-24 09:08 | 显示全部楼层 |阅读模式
本帖最后由 wang0225 于 2011-8-24 10:03 编辑

LOOK_ADC_PWM.h

  1. #ifndef __LOOK_ADC_PWM_H
  2. #define __LOOK_ADC_PWM_H
  3. #include "look_config.h"
  4. #include <look.h>
  5. // 任务类 task_LOOK_ADC_PWM_t 的定义
  6. class task_LOOK_ADC_PWM_t : public task_t {
  7. public:
  8. __INLINE__ task_LOOK_ADC_PWM_t(); // 构造函数
  9. bool send_message(int msg);
  10. protected:
  11. void routine();  // 任务例程
  12. mbox_t<int>mbox;
  13. };
  14. // 任务类 LOOK_ADC_PWM 的构造函数
  15. __INLINE__ task_LOOK_ADC_PWM_t::task_LOOK_ADC_PWM_t()
  16. {
  17. // TODO: 在此初始化 task_LOOK_ADC_PWM_t 的类成员
  18. }

  19. extern instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM;
  20. #endif // __LOOK_ADC_PWM_H

LOOK_ADC_PWM.cpp

  1. /*
  2. 初始化设置:  时钟配置为 XTL12M_EN
  3.               CPU时钟频率为12MHz
  4.      外设时钟配置为PWM01_S : 外部 4~24MHz 晶振使能
  5.      外设时钟配置为PWM01_EN : 选上
  6.      外设时钟配置为ADC_S : 外部 4~24MHz 晶振使能
  7.      外设时钟配置为ADC_N : 3  
  8.      外设时钟配置为ADC_EN : 选上
  9.      PA.1选择多功能管脚选择ADC1,输入
  10.         PA.12选择多功能管脚选择PWM0,输出
  11.             
  12. 主要完成功能:产生400Hz的波形,刚开始的占空比会根据助学板上的电位器的情况而定。
  13.               旋转电位器可以改变PWM的占空比。
  14.      在AD的中断里通过邮箱把AD值传出去,因为邮箱不能传数据0,故在AD值上加上一基数10.
  15.      按照老师的建议取消 PWM0_Duty_Cycle这个全局变量,在adc_t::isr()函数中,取消了一些与ADC无关的操作(计算PWM的占空比)。
  16.      使用邮箱,在通知任务时,直接把数据作为同步对象的通信数据发出 。
  17.      把 AD_Result封装在adc_t里。
  18.            在此特别感谢Lee老师的帮助!
  19. 上传日期:   2011/8/24
  20. */
  21. #include "LOOK_ADC_PWM.h"
  22. #define LOOK_H 1
  23. #if LOOK_H == 0
  24. #include "NUC1xx.h"
  25. #include "NUC1xxM051Seriescfg.h"
  26. #else
  27. #include <nuc120re3an.h>
  28. using namespace nuvoton;
  29. #endif
  30. class adc_t : public interrupt_t {
  31. public:
  32. __INLINE__ adc_t();
  33. protected:
  34. bool isr(int vector);
  35. void dsr(int vector, uintptr_t count);
  36. private:
  37.      uint32_t AD_Result;
  38. };
  39. // adc_t 构造函数
  40. __INLINE__ adc_t::adc_t()
  41. {
  42. attach(ADC_IRQn);
  43. vector_t::enable(ADC_IRQn);
  44. #if LOOK_H == 0
  45. SYSs.IPRSTC2.Bits.ADC_RST = 1;
  46. SYSs.IPRSTC2.Bits.ADC_RST = 0;  /* Reset ADC */
  47. //ADC时钟、分频及配置为AD引脚在look中配置
  48. ADCs.ADCR.Bits.ADEN = 1;   //使能AD模块
  49. ADCs.ADCALR.Bits.CALEN = 1;   //自校正使能
  50. while(!ADCs.ADCALR.Bits.CALDONE); //等待自校正结束
  51. ADCs.ADCR.Bits.DIFFEN = 0;   //单端输入
  52. ADCs.ADCR.Bits.ADST = 0;   //停止AD
  53. ADCs.ADCR.Bits.ADMD = 0;   //单一转换
  54. ADCs.ADCHER.Bits.CHEN = 0x02;  //模拟输入通道1使能
  55. ADCs.ADSR.Bits.ADF = 1;    //清AD中断标志
  56. ADCs.ADCR.Bits.ADIE=1;   // 开启中断
  57. #else
  58. SYS.IPRSTC2().ADC_RST = 1;
  59. SYS.IPRSTC2().ADC_RST = 0; // Reset ADC
  60. //ADC时钟、分频及配置为AD引脚在look中配置
  61. ADC.ADCR().ADEN = 1;   //使能AD模块
  62. ADC.ADCALR().CALEN = 1;   //自校正使能
  63. while(!ADC.ADCALR().CALDONE); //等待自校正结束
  64. ADC.ADCR()
  65.     .DIFFEN(0)   //单端输入
  66.     .ADST(0)   //停止AD
  67.     .ADMD(0);   //单一转换
  68. ADC.ADCHER().CHEN = 0x02;  //模拟输入通道1使能
  69. ADC.ADSR().ADF = 1;    //清AD中断标志
  70. ADC.ADCR().ADIE = 1;            // 开启中断
  71. #endif
  72. }
  73. // adc_t 中断服务例程
  74. bool adc_t::isr(int vector)
  75. {
  76. #if LOOK_H == 0
  77. ADCs.ADSR.Bits.ADF = 1;   // 清中断 flag
  78.   AD_Result = ADCs.ADDR1.Regs&0xFFF;
  79. //PWM0_Duty_Cycle=AD_Result/50;
  80. #else
  81. ADC.ADSR().ADF = 1;    // 清中断 flag
  82.   AD_Result = ADC.ADDR1&0xFFF;
  83. // PWM0_Duty_Cycle=AD_Result/50;
  84. #endif
  85. return true;
  86. }
  87. // adc_t 中断滞后服务例程
  88. void adc_t::dsr(int vector, uintptr_t count)
  89. {
  90. if (vector == ADC_IRQn)//ADC1
  91. {
  92.   task_LOOK_ADC_PWM.send_message(AD_Result+10);
  93. }
  94. }
  95. adc_t adc;         // 创建adc对象
  96. // 任务类 task_LOOK_PWM_t 的例程
  97. void task_LOOK_ADC_PWM_t::routine()
  98. {
  99. // TODO: 在此编写 task_LOOK_PWM_t 例程的内容
  100. uint8_t PWM0_Duty_Cycle = 50;   //PWM初始化占空比为50
  101. #if LOOK_H == 0

  102. SYSCLKs.CLKSEL1.Bits.TMR0_S = 0b000; //外部12M晶振
  103. PWM0s.PCR.Bits.CH0INV = 0;    //反向关闭
  104. PWM0s.PCR.Bits.CH0MOD = 1;    //自动重载
  105. PWM0s.PPR.Bits.CP01 = 1;    //预分频  1
  106. PWM0s.CSR.Bits.CSR0 = 0b100;   //分频系数 1
  107. uint16_t u16Duty = 12000000/((1+1)*1*400);//PWM 频率 400HZ
  108. PWM0s.CNR0.Regs = u16Duty-1;     //PWM 频率 = PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1);
  109. PWM0s.CMR0.Regs = u16Duty*PWM0_Duty_Cycle/100-1; //占空比 = (CMR+1)/(CNR+1).
  110. PWM0s.POE.Bits.PWM0 = 1;    //PWM0输出使能
  111. //PA.12作为PWM0   使用LOOK进行配置
  112. PWM0s.PCR.Bits.CH0EN = 1;    // 使能PWM功能
  113. while (true)
  114. {
  115.     // TODO: 在此编写 task_ad_t 例程的内容
  116.    ADCs.ADCR.Bits.ADST = 1; //启动AD
  117.    int msg = mbox.get(); // 等待邮箱消息
  118.    if (msg){
  119.    msg-=10;
  120.    if(msg<=0) msg=0;
  121.    PWM0_Duty_Cycle=msg/50;   
  122.    if (PWM0_Duty_Cycle!=0)
  123.     PWM0s.CMR0.Regs = u16Duty*PWM0_Duty_Cycle/100-1;  //更新占空比
  124.    else PWM0s.CMR0.Regs = 0;
  125.    }
  126. }
  127. #else

  128. SYSCLK.CLKSEL1().TMR0_S = tmrs_t::XTL12M; //外部12M晶振
  129. PWMA.PCR()
  130.        .CH0INV(0)    //反向关闭
  131.        .CH0MOD(1);    //自动重载
  132. PWMA.PPR().CP01 = 1;    //预分频  1
  133. PWMA.CSR().CSR0 = 0b100;   //分频系数 1
  134. uint16_t u16Duty = 12000000/((1+1)*1*400);//PWM 频率 400HZ
  135. PWMA.CNR0 = u16Duty-1;     //PWM 频率 = PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1);
  136. PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1; //占空比 = (CMR+1)/(CNR+1).
  137. PWMA.POE().PWM0 = 1;    //PWM0输出使能
  138. //PA.12作为PWM0   使用LOOK进行配置
  139. PWMA.PCR().CH0EN = 1;    // 使能PWM功能
  140. while (true)
  141. {
  142.     // TODO: 在此编写 task_ad_t 例程的内容
  143.    ADC.ADCR().ADST = 1; //启动AD
  144.    int msg = mbox.get(); // 等待邮箱消息
  145.    if (msg){
  146.    msg-=10;
  147.    if(msg<=0) msg=0;
  148.    PWM0_Duty_Cycle=msg/50;
  149.    if (PWM0_Duty_Cycle!=0)
  150.      PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1;  //更新占空比
  151.     else PWMA.CMR0 = 0;
  152.     }
  153. }
  154. #endif
  155. }
  156. bool task_LOOK_ADC_PWM_t::send_message(int msg)
  157. {
  158.     return mbox.do_tryput(msg);
  159. }
  160.   
  161. #ifdef LOOK_SCHEDULING_PRIORITY
  162. instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM(0);
  163. #else
  164. instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM;
  165. #endif
  166. 再次感谢Lee老师的帮助!

本帖子中包含更多资源

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

×
 楼主| wang0225 发表于 2011-8-24 09:27 | 显示全部楼层
经过我实践,可以把task_LOOK_ADC_PWM.send_message(AD_Result+10);
和bool task_LOOK_ADC_PWM_t::send_message(int msg)合成一个函数,即直接通过邮箱发送数据。
hotpower 发表于 2011-8-24 10:10 | 显示全部楼层
加偏移在这个例程中是不错的,但总归0是个问题。
 楼主| wang0225 发表于 2011-8-24 10:11 | 显示全部楼层
是的,大叔!
 楼主| wang0225 发表于 2011-8-24 10:39 | 显示全部楼层
本帖最后由 wang0225 于 2011-8-24 10:42 编辑

mbox中,存储消息只用了一个32bits的数据,但还有一个关键的状态需要表示,就是mbox中是否有消息,对于此状态的表示方法,有两种设计策略:
1、在mbox中再加一个数据来表示。
2、将32bits数据,隔离出一个特殊值来表示。32bits数据的值域将少一个。
LOOK使用了第2种方法。
以上是对于存储的影响,对于API的影响有:
如果有特殊值(0),那么get()的返回值可以用0表示超时等失败的返回。如果是全值域,那么get()就必须返回两个数据,一个表示是否成功,一个表示数据本身。
全值域的get()可能的形式就是这样的:bool get(T& data);
而特殊值的get(),目前就是:T get();
特殊值的设计,不管是存储还是实现代码,开销都要比全值域的设计小些。
以上是Lee老师关于邮箱的一些说明,希望对大家有用!:)
mbydyjj 发表于 2011-9-30 10:42 | 显示全部楼层
看看
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

185

帖子

1

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

0

主题

185

帖子

1

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