[LOOK] LOOK_ADC_PWM(AD中断发送sem)

[复制链接]
 楼主| wang0225 发表于 2011-8-22 21:43 | 显示全部楼层 |阅读模式
ADC, PWM, se, ST, DCS
本帖最后由 wang0225 于 2011-8-22 21:44 编辑
  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的中断里发送sem实现PWM同步
  15.            在此特别感谢Lee老师的帮助!
  16. 上传日期:   2011/8/22
  17. */
  18. #include "LOOK_ADC_PWM.h"
  19. #define LOOK_H 1
  20. #if LOOK_H == 0
  21. #include "NUC1xx.h"
  22. #include "NUC1xxM051Seriescfg.h"
  23. #else
  24. #include <nuc120re3an.h>
  25. using namespace nuvoton;
  26. #endif
  27. //flag_t flag(0);
  28. uint8_t PWM0_Duty_Cycle = 50;   //PWM初始化占空比为50
  29. class adc_t : public interrupt_t {
  30. public:
  31. __INLINE__ adc_t();
  32. protected:
  33. bool isr(int vector);
  34. void dsr(int vector, uintptr_t count);
  35. };
  36. // adc_t 构造函数
  37. __INLINE__ adc_t::adc_t()
  38. {
  39. attach(ADC_IRQn);
  40. vector_t::enable(ADC_IRQn);
  41. #if LOOK_H == 0
  42. SYSs.IPRSTC2.Bits.ADC_RST = 1;
  43. SYSs.IPRSTC2.Bits.ADC_RST = 0;  /* Reset ADC */
  44. //ADC时钟、分频及配置为AD引脚在look中配置
  45. ADCs.ADCR.Bits.ADEN = 1;   //使能AD模块
  46. ADCs.ADCALR.Bits.CALEN = 1;   //自校正使能
  47. while(!ADCs.ADCALR.Bits.CALDONE); //等待自校正结束
  48. ADCs.ADCR.Bits.DIFFEN = 0;   //单端输入
  49. ADCs.ADCR.Bits.ADST = 0;   //停止AD
  50. ADCs.ADCR.Bits.ADMD = 0;   //单一转换
  51. ADCs.ADCHER.Bits.CHEN = 0x02;  //模拟输入通道1使能
  52. ADCs.ADSR.Bits.ADF = 1;    //清AD中断标志
  53. ADCs.ADCR.Bits.ADIE=1;   // 开启中断
  54. #else
  55. SYS.IPRSTC2().ADC_RST = 1;
  56. SYS.IPRSTC2().ADC_RST = 0; // Reset ADC
  57. //ADC时钟、分频及配置为AD引脚在look中配置
  58. ADC.ADCR().ADEN = 1;   //使能AD模块
  59. ADC.ADCALR().CALEN = 1;   //自校正使能
  60. while(!ADC.ADCALR().CALDONE); //等待自校正结束
  61. ADC.ADCR()
  62.     .DIFFEN(0)   //单端输入
  63.     .ADST(0)   //停止AD
  64.     .ADMD(0);   //单一转换
  65. ADC.ADCHER().CHEN = 0x02;  //模拟输入通道1使能
  66. ADC.ADSR().ADF = 1;    //清AD中断标志
  67. ADC.ADCR().ADIE = 1;            // 开启中断
  68. #endif
  69. }
  70. // adc_t 中断服务例程
  71. bool adc_t::isr(int vector)
  72. {
  73. #if LOOK_H == 0
  74. ADCs.ADSR.Bits.ADF = 1;   // 清中断 flag
  75. uint32_t AD_Result = ADCs.ADDR1.Regs&0xFFF;
  76. PWM0_Duty_Cycle=AD_Result/50;
  77. #else
  78. ADC.ADSR().ADF = 1;    // 清中断 flag
  79. uint32_t AD_Result = ADC.ADDR1&0xFFF;
  80. PWM0_Duty_Cycle=AD_Result/50;
  81. #endif
  82. return true;
  83. }
  84. // adc_t 中断滞后服务例程
  85. void adc_t::dsr(int vector, uintptr_t count)
  86. {
  87. if (vector == ADC_IRQn)//ADC1
  88. {
  89. // flag.do_set_bits(0b001);
  90.   task_LOOK_ADC_PWM.sem.do_post();
  91. }
  92. }
  93. adc_t adc;         // 创建adc对象
  94. // 任务类 task_LOOK_PWM_t 的例程
  95. void task_LOOK_ADC_PWM_t::routine()
  96. {
  97. // TODO: 在此编写 task_LOOK_PWM_t 例程的内容
  98. #if LOOK_H == 0

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

  124. SYSCLK.CLKSEL1().TMR0_S = tmrs_t::XTL12M; //外部12M晶振
  125. PWMA.PCR()
  126.        .CH0INV(0)    //反向关闭
  127.        .CH0MOD(1);    //自动重载
  128. PWMA.PPR().CP01 = 1;    //预分频  1
  129. PWMA.CSR().CSR0 = 0b100;   //分频系数 1
  130. uint16_t u16Duty = 12000000/((1+1)*1*400);//PWM 频率 400HZ
  131. PWMA.CNR0 = u16Duty-1;     //PWM 频率 = PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1);
  132. PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1; //占空比 = (CMR+1)/(CNR+1).
  133. PWMA.POE().PWM0 = 1;    //PWM0输出使能
  134. //PA.12作为PWM0   使用LOOK进行配置
  135. PWMA.PCR().CH0EN = 1;    // 使能PWM功能
  136. while (true)
  137. {
  138.     // TODO: 在此编写 task_ad_t 例程的内容
  139.    ADC.ADCR().ADST = 1; //启动AD
  140.   // int 标志寄存器 = flag.wait(0b001, flag_t::ANY_CONSUME);
  141.    if (sem.wait()){
  142.    
  143.   // PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1;  //更新占空比
  144.    if (PWM0_Duty_Cycle!=0)
  145.      PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1;  //更新占空比
  146.     else PWMA.CMR0 = 0;
  147.     }
  148. }
  149. #endif
  150. }

  151. #ifdef LOOK_SCHEDULING_PRIORITY
  152. instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM(0);
  153. #else
  154. instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM;
  155. #endif

照片参考LOOK_ADC_PWM0。再次感谢Lee老师的帮助!

本帖子中包含更多资源

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

×
john_lee 发表于 2011-8-23 23:36 | 显示全部楼层
点评一下浪子的例程。

这个版本的程序,消除了上个版本的一些忙等操作,从结构上看,更加符合RTOS应用程序的设计思想。
总体来说,整个程序的框架已经没有没啥大的问题了。只有两个小的问题,需要说一下。

1、程序的耦合性问题
在adc_t::isr()函数中,附加了一些与ADC无关的操作(计算PWM的占空比)。这样做使得adc_t类(模块)与PWM功能的耦合性非常强,其它程序(项目)基本无法复用adc_t类的代码。
2、同步对象的选择问题
adc_t类的中断对象,在对任务同步和传递数据时,使用了两个内存对象:一个是sem同步对象,一个是PWM0_Duty_Cycle全局变量。每次通知任务时,都需要操作这两个对象。从简洁性来看,应该使用具有“通信”能力的同步对象(如:mbox),在通知任务时,直接把数据作为同步对象的通信数据发出即可,这将使代码更优雅一些。
电子write_cai 发表于 2011-8-22 23:44 | 显示全部楼层
LOOK。
 楼主| wang0225 发表于 2011-8-23 08:33 | 显示全部楼层
本帖最后由 wang0225 于 2011-8-23 08:42 编辑
  1. 1、定义中断类:
  2. 从interrupt_t类派生一个新类
  3. class adc_t : public interrupt_t {
  4. public:
  5.     adc_t();

  6. protected:
  7.     bool isr(int vector);
  8.     void dsr(int vector, uintptr_t count);
  9. };
  10. John Lee<j.y.lee@yeah.net>  19:21:56
  11. 在adc_t构造函数里,使用attach()函数挂接中断,使用enable()成员允许中断,并且初始化AD硬件。
  12. John Lee<j.y.lee@yeah.net>  19:23:37
  13. 在isr()函数里,完成中断的“顶半”(top half)部分的处理。
  14. John Lee<j.y.lee@yeah.net>  19:25:28
  15. 对于AD来说,isr()可以读出转换值,并保存到数据成员里。
  16. John Lee<j.y.lee@yeah.net>  19:28:21
  17. 简而言之,为了尽量减少中断潜伏时间(interrupt latency),而将普通的中断处理分为了两部分:top half和bottom half。
  18. John Lee<j.y.lee@yeah.net>  19:29:19
  19. top half对应于isr()函数。bottom half对应于dsr()函数。
  20. John Lee<j.y.lee@yeah.net>  19:30:05
  21. 在top half处理中,不能使用同步对象,不能访问共享数据。
  22. 所以,对于AD来说,isr()可以读出转换值,并保存到数据成员里。
  23. John Lee<j.y.lee@yeah.net>  19:32:42
  24. 当中断需要通知任务(访问同步对象)是,isr()函数可以返回true,调度器就会在适当的时候调用该中断对象的dsr()函数“bottom half”。
  25. 在dsr()处理中,可以使用各种非阻塞的同步对象访问函数。
  26. ohn Lee<j.y.lee@yeah.net>  19:35:10
  27. 例如,可以对一个sem同步对象使用do_post()来释放一个信号量。
  28. John Lee<j.y.lee@yeah.net>  19:36:15
  29. 从而使在该sem对象上阻塞的任务进入就绪。
附上Lee老师跟我讲的的一些说明,希望对大家有用!
hotpower 发表于 2011-8-23 23:42 | 显示全部楼层
1、定义中断类:
从interrupt_t类派生一个新类
class adc_t : public interrupt_t {
public:
    adc_t();

protected:
    bool isr(int vector);
    void dsr(int vector, uintptr_t count);
};
John Lee  19:21 ...
wang0225 发表于 2011-8-23 08:33


可惜下午手机收不到老师的信息。

受教了!!!
hotpower 发表于 2011-8-23 23:43 | 显示全部楼层
点评一下浪子的例程。

这个版本的程序,消除了上个版本的一些忙等操作,从结构上看,更加符合RTOS应用程序的设计思想。
总体来说,整个程序的框架已经没有没啥大的问题了。只有两个小的问题,需要说一下。

1、程序 ...
john_lee 发表于 2011-8-23 23:36


mbox不能发送0的问题用+偏移解决是个不是办法的好办法。
hotpower 发表于 2011-8-24 07:47 | 显示全部楼层
以后多多点评,促进提高。
 楼主| wang0225 发表于 2011-8-24 08:36 | 显示全部楼层
本帖最后由 wang0225 于 2011-8-24 18:16 编辑

谢谢老师的点评!我把老师说的两点修改下,一会再上传一个,只是有点咱地方啦,大叔,见谅啊!修改后的见http://bbs.21ic.com/frame.php?frameon=yes&referer=http%3A//bbs.21ic.com/iclist-78-1.html
 楼主| wang0225 发表于 2011-8-24 08:38 | 显示全部楼层
大叔,我认为mbox不能发送0的问题用+偏移或者基数可以解决啊!不对忘大叔指出
Cortex-M0 发表于 2011-8-25 07:19 | 显示全部楼层
路过帮顶~~~
huang2607885 发表于 2011-8-30 20:07 | 显示全部楼层
看看
fanchaojiaolong 发表于 2011-8-31 17:26 | 显示全部楼层
我认为mbox不能发送0的问题用+偏移或者基数可以解决啊!
 楼主| wang0225 发表于 2011-9-3 02:32 | 显示全部楼层
同意楼上,哈哈
guipo123 发表于 2011-9-9 00:06 | 显示全部楼层
学 问 要顶
YANG668 发表于 2011-9-30 11:00 | 显示全部楼层
看看,学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

185

帖子

1

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

0

主题

185

帖子

1

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