/* 初始化设置: 时钟配置为 XTL12M_EN CPU时钟频率为12MHz 外设时钟配置为PWM01_S : 外部 4~24MHz 晶振使能 外设时钟配置为PWM01_EN : 选上 外设时钟配置为ADC_S : 外部 4~24MHz 晶振使能 外设时钟配置为ADC_N : 3 外设时钟配置为ADC_EN : 选上 PA.1选择多功能管脚选择ADC1,输入 PA.12选择多功能管脚选择PWM0,输出 主要完成功能:产生400Hz的波形,刚开始的占空比会根据助学板上的电位器的情况而定。 旋转电位器可以改变PWM的占空比。 在AD的中断里发送sem实现PWM同步 在此特别感谢Lee老师的帮助! 上传日期: 2011/8/22 */ #include "LOOK_ADC_PWM.h" #define LOOK_H 1 #if LOOK_H == 0 #include "NUC1xx.h" #include "NUC1xxM051Seriescfg.h" #else #include <nuc120re3an.h> using namespace nuvoton; #endif //flag_t flag(0); uint8_t PWM0_Duty_Cycle = 50; //PWM初始化占空比为50 class adc_t : public interrupt_t { public: __INLINE__ adc_t(); protected: bool isr(int vector); void dsr(int vector, uintptr_t count); }; // adc_t 构造函数 __INLINE__ adc_t::adc_t() { attach(ADC_IRQn); vector_t::enable(ADC_IRQn); #if LOOK_H == 0 SYSs.IPRSTC2.Bits.ADC_RST = 1; SYSs.IPRSTC2.Bits.ADC_RST = 0; /* Reset ADC */ //ADC时钟、分频及配置为AD引脚在look中配置 ADCs.ADCR.Bits.ADEN = 1; //使能AD模块 ADCs.ADCALR.Bits.CALEN = 1; //自校正使能 while(!ADCs.ADCALR.Bits.CALDONE); //等待自校正结束 ADCs.ADCR.Bits.DIFFEN = 0; //单端输入 ADCs.ADCR.Bits.ADST = 0; //停止AD ADCs.ADCR.Bits.ADMD = 0; //单一转换 ADCs.ADCHER.Bits.CHEN = 0x02; //模拟输入通道1使能 ADCs.ADSR.Bits.ADF = 1; //清AD中断标志 ADCs.ADCR.Bits.ADIE=1; // 开启中断 #else SYS.IPRSTC2().ADC_RST = 1; SYS.IPRSTC2().ADC_RST = 0; // Reset ADC //ADC时钟、分频及配置为AD引脚在look中配置 ADC.ADCR().ADEN = 1; //使能AD模块 ADC.ADCALR().CALEN = 1; //自校正使能 while(!ADC.ADCALR().CALDONE); //等待自校正结束 ADC.ADCR() .DIFFEN(0) //单端输入 .ADST(0) //停止AD .ADMD(0); //单一转换 ADC.ADCHER().CHEN = 0x02; //模拟输入通道1使能 ADC.ADSR().ADF = 1; //清AD中断标志 ADC.ADCR().ADIE = 1; // 开启中断 #endif } // adc_t 中断服务例程 bool adc_t::isr(int vector) { #if LOOK_H == 0 ADCs.ADSR.Bits.ADF = 1; // 清中断 flag uint32_t AD_Result = ADCs.ADDR1.Regs&0xFFF; PWM0_Duty_Cycle=AD_Result/50; #else ADC.ADSR().ADF = 1; // 清中断 flag uint32_t AD_Result = ADC.ADDR1&0xFFF; PWM0_Duty_Cycle=AD_Result/50; #endif return true; } // adc_t 中断滞后服务例程 void adc_t::dsr(int vector, uintptr_t count) { if (vector == ADC_IRQn)//ADC1 { // flag.do_set_bits(0b001); task_LOOK_ADC_PWM.sem.do_post(); } } adc_t adc; // 创建adc对象 // 任务类 task_LOOK_PWM_t 的例程 void task_LOOK_ADC_PWM_t::routine() { // TODO: 在此编写 task_LOOK_PWM_t 例程的内容 #if LOOK_H == 0 SYSCLKs.CLKSEL1.Bits.TMR0_S = 0b000; //外部12M晶振 PWM0s.PCR.Bits.CH0INV = 0; //反向关闭 PWM0s.PCR.Bits.CH0MOD = 1; //自动重载 PWM0s.PPR.Bits.CP01 = 1; //预分频 1 PWM0s.CSR.Bits.CSR0 = 0b100; //分频系数 1 uint16_t u16Duty = 12000000/((1+1)*1*400);//PWM 频率 400HZ PWM0s.CNR0.Regs = u16Duty-1; //PWM 频率 = PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1); PWM0s.CMR0.Regs = u16Duty*PWM0_Duty_Cycle/100-1; //占空比 = (CMR+1)/(CNR+1). PWM0s.POE.Bits.PWM0 = 1; //PWM0输出使能 //PA.12作为PWM0 使用LOOK进行配置 PWM0s.PCR.Bits.CH0EN = 1; // 使能PWM功能 while (true) { // TODO: 在此编写 task_ad_t 例程的内容 ADCs.ADCR.Bits.ADST = 1; //启动AD // int 标志寄存器 = flag.wait(0b001, flag_t::ANY_CONSUME); if (sem.wait()){ // PWM0s.CMR0.Regs = u16Duty*PWM0_Duty_Cycle/100-1; //更新占空比 if (PWM0_Duty_Cycle!=0) PWM0s.CMR0.Regs = u16Duty*PWM0_Duty_Cycle/100-1; //更新占空比 else PWM0s.CMR0.Regs = 0; } } #else SYSCLK.CLKSEL1().TMR0_S = tmrs_t::XTL12M; //外部12M晶振 PWMA.PCR() .CH0INV(0) //反向关闭 .CH0MOD(1); //自动重载 PWMA.PPR().CP01 = 1; //预分频 1 PWMA.CSR().CSR0 = 0b100; //分频系数 1 uint16_t u16Duty = 12000000/((1+1)*1*400);//PWM 频率 400HZ PWMA.CNR0 = u16Duty-1; //PWM 频率 = PWMxy_CLK/(prescale+1)*(clock divider)/(CNR+1); PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1; //占空比 = (CMR+1)/(CNR+1). PWMA.POE().PWM0 = 1; //PWM0输出使能 //PA.12作为PWM0 使用LOOK进行配置 PWMA.PCR().CH0EN = 1; // 使能PWM功能 while (true) { // TODO: 在此编写 task_ad_t 例程的内容 ADC.ADCR().ADST = 1; //启动AD // int 标志寄存器 = flag.wait(0b001, flag_t::ANY_CONSUME); if (sem.wait()){ // PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1; //更新占空比 if (PWM0_Duty_Cycle!=0) PWMA.CMR0 = u16Duty*PWM0_Duty_Cycle/100-1; //更新占空比 else PWMA.CMR0 = 0; } } #endif } #ifdef LOOK_SCHEDULING_PRIORITY instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM(0); #else instantiate::task<task_LOOK_ADC_PWM_t, LOOK_STACK_SIZE> task_LOOK_ADC_PWM; #endif 照片参考LOOK_ADC_PWM0。再次感谢Lee老师的帮助!
您需要 登录 才可以下载或查看,没有账号?注册
举报
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<j.y.lee@yeah.net> 19:21:56 在adc_t构造函数里,使用attach()函数挂接中断,使用enable()成员允许中断,并且初始化AD硬件。 John Lee<j.y.lee@yeah.net> 19:23:37 在isr()函数里,完成中断的“顶半”(top half)部分的处理。 John Lee<j.y.lee@yeah.net> 19:25:28 对于AD来说,isr()可以读出转换值,并保存到数据成员里。 John Lee<j.y.lee@yeah.net> 19:28:21 简而言之,为了尽量减少中断潜伏时间(interrupt latency),而将普通的中断处理分为了两部分:top half和bottom half。 John Lee<j.y.lee@yeah.net> 19:29:19 top half对应于isr()函数。bottom half对应于dsr()函数。 John Lee<j.y.lee@yeah.net> 19:30:05 在top half处理中,不能使用同步对象,不能访问共享数据。 所以,对于AD来说,isr()可以读出转换值,并保存到数据成员里。 John Lee<j.y.lee@yeah.net> 19:32:42 当中断需要通知任务(访问同步对象)是,isr()函数可以返回true,调度器就会在适当的时候调用该中断对象的dsr()函数“bottom half”。 在dsr()处理中,可以使用各种非阻塞的同步对象访问函数。 ohn Lee<j.y.lee@yeah.net> 19:35:10 例如,可以对一个sem同步对象使用do_post()来释放一个信号量。 John Lee<j.y.lee@yeah.net> 19:36:15 从而使在该sem对象上阻塞的任务进入就绪。 附上Lee老师跟我讲的的一些说明,希望对大家有用!
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
点评一下浪子的例程。 这个版本的程序,消除了上个版本的一些忙等操作,从结构上看,更加符合RTOS应用程序的设计思想。 总体来说,整个程序的框架已经没有没啥大的问题了。只有两个小的问题,需要说一下。 1、程序 ... john_lee 发表于 2011-8-23 23:36
本版积分规则 发表回复 回帖并转播 回帖后跳转到最后一页
人才类勋章
等级类勋章
发帖类勋章
时间类勋章
0
185
1
扫码关注 21ic 官方微信
扫码关注嵌入式微处理器
扫码关注电源系统设计
扫码关注21ic项目外包
扫码浏览21ic手机版
本站介绍 | 申请友情链接 | 欢迎投稿 | 隐私声明 | 广告业务 | 网站地图 | 联系我们 | 诚聘英才
京公网安备 11010802024343号