茴字的5种写法——djyos应用程序实例,用5中方法实现PWM控制LED亮度的功能
刚刚发布的djyos v0.4.3中,在ekk8962板上提供了5种实现PWM控制led亮度的方法,从多个角度说明如何使用djyos编写应用程序,分别对应5个keil MDK工程文件,这5个程序的功能完全相同,即控制led渐亮渐暗循环不已。源代码:点击此处下载 ourdev_491103.zip(文件大小:1.42M) (原文件名:djysiV0.4.3.zip)prj-ekk8962-1:PWM控制完全用事件,不用中断实现。
prj-ekk8962-2:PWM控制主要用事件,辅以最少量的中断代码实现。
prj-ekk8962-3:PWM控制主要用事件,辅以中等数量的中断代码实现。
prj-ekk8962-4:PWM控制全部用中断代码实现,但用事件触发执行PWM初始化函数。
prj-ekk8962-5:PWM控制全部用中断代码实现,完全不用事件。
下面1~5楼分别说明5个工程。 prj-ekk8962-1工程:
main.c文件的内容是:
#include "inc_os.h"
#include "gpio.h"
#include "sysctl.h"
#include "pwm.h"
uint16_t pg_evtt_flash_led;
void flash_led(struct event_script *my_event)
{
static s32 compare = 0;
static bool_t up = true;
bb_sysctl_rcgc2_gpiof = 1; //使能gpiof
pg_gpio_regf->LOCK = 0x1ACCE551; //解锁CR寄存器
pg_gpio_regf->CR = 1; //允许修改AFSEL的PF0位
pg_gpio_regf->AFSEL |= 0x1; //PF0设为PWM0输出
pg_gpio_regf->LOCK = 0; //重新锁定CR寄存器
pg_gpio_regf->DEN |= 1; //允许PF0
pg_gpio_regf->IM &= 0xfe; //屏蔽掉PF0中断
pg_gpio_regf->DR8R |= 1; //设置PF0=8mA驱动
//配置PWM0
pg_sysctl_reg->RCC &= ~bm_sysctl_rcc_pwmdiv;
pg_sysctl_reg->RCC |= 5<<bo_sysctl_rcc_pwmdiv;//置pwm时钟为系统时钟64分频
bb_sysctl_rcc_enpwmdiv = 1;
bb_sysctl_rcgc0_pwm = 1; //使能pwm
pg_pwm_reg->PWM0CTL = 0;
pg_pwm_reg->PWM0GENA =(0<<bo_pwmx_act_zero)
+(0<<bo_pwmx_act_load)
+(3<<bo_pwmx_act_comp_au)
+(2<<bo_pwmx_act_comp_ad)
+(0<<bo_pwmx_act_comp_bu)
+(0<<bo_pwmx_act_comp_bd);
pg_pwm_reg->PWM0LOAD = 3000; //pwm周期约7.7mS
bb_pwm0_ctl_mode = 1; //增减循环模式
bb_pwm0_ctl_enable = 1; //使能pwm0模块
bb_pwm0_ctl_debug = 1; //使能pwm0输出
bb_pwm_enable_pwm0en = 1;
while(1)
{
if(up == true)
{
compare += 150;
if(compare >= 3000 - 150)
up = false;
}else
{
compare -=150;
if(compare <= 150)
up = true;
}
pg_pwm_reg->PWM0CMPA = compare;
djy_timer_sync(38);
}
}
//本应命名为main的,但调试器总是默认这是整个程序的入口点,罢了
void djy_main(void)
{
pg_evtt_flash_led = djy_evtt_regist(true,true,cn_prio_real,1,
flash_led,10,NULL);
djy_event_pop(pg_evtt_flash_led,0,0,0);
}
说明:djy_main函数是应用程序的入口点,位于工程目录的main目录下。
main函数中首先登记pg_evtt_flash_led,这里没有判断是否成功登记——如果一开始就不成功的话,还玩什么?登记事件类型时制定flash_led函数是本类型事件的处理函数。倒数第二个参数10是flash_led函数运行时需要的栈尺寸,注意djyos中,你为事件处理函数准备栈时,无需考虑系统服务函数所需要的栈。比如djy_timer_sync函数就需要16字节栈,但这里无需考虑。
然后弹出一条pg_evtt_flash_led类型的事件,这个动作会使一条pg_evtt_flash_led类型事件加入就绪事件队列,只要该事件的优先级在就绪队列中变得最高,就会处理该事件,flash_led函数就会被调用。
flash_led函数的功能很简单,初始化硬件后,就进入死循环,每38mS改变一下LED的亮度。注意了,djy_timer_sync相当于其他操作系统的task_delay函数,但事件单位是mS,而不是ticks数,这样可以使应用程序的可移植性更高,改变tick周期时,可以不改应用程序。 prj-ekk8962-2工程:
main.c的内容如下:
#include "inc_os.h"
#include "gpio.h"
#include "sysctl.h"
#include "pwm.h"
uint16_t pg_evtt_flash_led;
uint32_t pwm0_int(ufast_t int_line)
{
pg_pwm_reg->PWM0ISC = 1<<bo_pwm0_intisc_intcntzero;//清过零中断
pg_pwm_reg->PWMISC = 1<<bo_pwm_intisc_pwm0; //清PWM0中断
return 0;
}
void flash_led(struct event_script *my_event)
{
static s32 compare = 0;
static bool_t up = true;
bb_sysctl_rcgc2_gpiof = 1; //使能gpiof
pg_gpio_regf->LOCK = 0x1ACCE551; //解锁CR寄存器
pg_gpio_regf->CR = 1; //允许修改AFSEL的PF0位
pg_gpio_regf->AFSEL |= 0x1; //PF0设为PWM0输出
pg_gpio_regf->LOCK = 0; //重新锁定CR寄存器
pg_gpio_regf->DEN |= 1; //允许PF0
pg_gpio_regf->IM &= 0xfe; //屏蔽掉PF0中断
pg_gpio_regf->DR8R |= 1; //设置PF0=8mA驱动
//配置PWM0
pg_sysctl_reg->RCC &= ~bm_sysctl_rcc_pwmdiv;
pg_sysctl_reg->RCC |= 5<<bo_sysctl_rcc_pwmdiv;//置pwm时钟为系统时钟64分频
bb_sysctl_rcc_enpwmdiv = 1;
bb_sysctl_rcgc0_pwm = 1; //使能pwm
pg_pwm_reg->PWM0CTL = 0;
pg_pwm_reg->PWM0GENA =(0<<bo_pwmx_act_zero)
+(0<<bo_pwmx_act_load)
+(3<<bo_pwmx_act_comp_au)
+(2<<bo_pwmx_act_comp_ad)
+(0<<bo_pwmx_act_comp_bu)
+(0<<bo_pwmx_act_comp_bd);
pg_pwm_reg->PWM0LOAD = 3000; //pwm周期约7.7mS
bb_pwm0_ctl_mode = 1; //增减循环模式
bb_pwm0_ctl_enable = 1; //使能pwm0模块
bb_pwm0_ctl_debug = 1; //使能pwm0输出
bb_pwm_enable_pwm0en = 1;
int_isr_connect(cn_int_line_PWM0,pwm0_int); //中断连接
int_setto_asyn_signal(cn_int_line_PWM0);
int_restore_line(cn_int_line_PWM0);
bb_pwm0_inten_intcntzero = 1; //使能PWM0的过零中断
bb_pwm_inten_pwm0 = 1; //使能PWM0中断
while(1)
{
if(up == true)
{
compare += 150;
if(compare >= 3000 - 150)
up = false;
}else
{
compare -=150;
if(compare <= 150)
up = true;
}
pg_pwm_reg->PWM0CMPA = compare;
djy_evtt_pop_sync(my_event->evtt_id,5,cn_timeout_forever);
}
}
//本应命名为main的,但调试器总是默认这是整个程序的入口点,罢了
void djy_main(void)
{
pg_evtt_flash_led = djy_evtt_regist(true,true,cn_prio_real,1,
flash_led,10,NULL);
djy_event_pop(pg_evtt_flash_led,0,0,0);
int_evtt_connect(cn_int_line_PWM0,pg_evtt_flash_led);
}
说明:这个工程其实跟第一个非常相似,不同的是:
1、main函数中增加了函数调用:int_evtt_connect(cn_int_line_PWM0,pg_evtt_flash_led);含义是,当发生PWM0中断时,自动弹出pg_evtt_flash_led类型的事件。
2、增加了中断响应函数pwm0_int,但该函数只清中断标志,什么都不干,如果中断硬件能自动清中断的话,该函数根本没有必要存在。djyos中,你使用了中断功能,却可以无须编写中断处理函数。
3、flash_led函数中增加了初始化PWM中断的部分。
4、flash_led函数中djy_timer_sync调用换成了djy_evtt_pop_sync系统调用,作用是:当程序运行至此就进入阻塞,直到类型号为my_event->evtt_id的事件发生5(第二个参数)次,然后唤醒,cn_timeout_forever的意思是,如果事件一直不发生,则无限等待。
这样,每次PWM中断,都由djyos的中断系统弹出pg_evtt_flash_led类型的事件,每5次中断,将唤醒事件,flash_led函数继续执行。PWM周期时7.7mS,5次刚好大约38mS,这就是第一个工程中38mS的来由。 prj-ekk8962-3工程:
main.c的内容如下:
#include "inc_os.h"
#include "gpio.h"
#include "sysctl.h"
#include "pwm.h"
uint16_t pg_evtt_flash_led;
uint32_t pwm0_int(ufast_t int_line)
{
pg_pwm_reg->PWM0ISC = 1<<bo_pwm0_intisc_intcntzero;//清过零中断
pg_pwm_reg->PWMISC = 1<<bo_pwm_intisc_pwm0; //清PWM0中断
djy_event_pop(pg_evtt_flash_led,0,0,0);
return 0;
}
void flash_led(struct event_script *my_event)
{
static s32 compare = 0;
static bool_t up = true;
bb_sysctl_rcgc2_gpiof = 1; //使能gpiof
pg_gpio_regf->LOCK = 0x1ACCE551; //解锁CR寄存器
pg_gpio_regf->CR = 1; //允许修改AFSEL的PF0位
pg_gpio_regf->AFSEL |= 0x1; //PF0设为PWM0输出
pg_gpio_regf->LOCK = 0; //重新锁定CR寄存器
pg_gpio_regf->DEN |= 1; //允许PF0
pg_gpio_regf->IM &= 0xfe; //屏蔽掉PF0中断
pg_gpio_regf->DR8R |= 1; //设置PF0=8mA驱动
//配置PWM0
pg_sysctl_reg->RCC &= ~bm_sysctl_rcc_pwmdiv;
pg_sysctl_reg->RCC |= 5<<bo_sysctl_rcc_pwmdiv;//置pwm时钟为系统时钟64分频
bb_sysctl_rcc_enpwmdiv = 1;
bb_sysctl_rcgc0_pwm = 1; //使能pwm
pg_pwm_reg->PWM0CTL = 0;
pg_pwm_reg->PWM0GENA =(0<<bo_pwmx_act_zero)
+(0<<bo_pwmx_act_load)
+(3<<bo_pwmx_act_comp_au)
+(2<<bo_pwmx_act_comp_ad)
+(0<<bo_pwmx_act_comp_bu)
+(0<<bo_pwmx_act_comp_bd);
pg_pwm_reg->PWM0LOAD = 3000; //pwm周期约7.7mS
bb_pwm0_ctl_mode = 1; //增减循环模式
bb_pwm0_ctl_enable = 1; //使能pwm0模块
bb_pwm0_ctl_debug = 1; //使能pwm0输出
bb_pwm_enable_pwm0en = 1;
int_isr_connect(cn_int_line_PWM0,pwm0_int); //中断连接
int_setto_asyn_signal(cn_int_line_PWM0);
int_restore_line(cn_int_line_PWM0);
bb_pwm0_inten_intcntzero = 1; //使能PWM0的过零中断
bb_pwm_inten_pwm0 = 1; //使能PWM0中断
while(1)
{
if(up == true)
{
compare += 150;
if(compare >= 3000 - 150)
up = false;
}else
{
compare -=150;
if(compare <= 150)
up = true;
}
pg_pwm_reg->PWM0CMPA = compare;
djy_evtt_pop_sync(my_event->evtt_id,5,cn_timeout_forever);
}
}
//本应命名为main的,但调试器总是默认这是整个程序的入口点,罢了
void djy_main(void)
{
pg_evtt_flash_led = djy_evtt_regist(true,true,cn_prio_real,1,
flash_led,10,NULL);
djy_event_pop(pg_evtt_flash_led,0,0,0);
}
说明:这个工程和prj-ekk8962-2工程只有很小的差别:
1、main函数中不再调用 int_evtt_connect 函数连接中断和事件。
2、在中断响应函数pwm0_int中调用 djy_event_pop(pg_evtt_flash_led,0,0,0); 弹出事件。
本工程的执行过程和prj-ekk8962-2也非常相似,唯一的差别是,弹出事件由系统执行还是由应用程序执行。系统执行则灵活性差,只能弹出一条事件,且难于灵活控制事件参数,应用程序执行则可以弹出多条事件,以及灵活控制事件参数。 沙发,帮定 prj-ekk8962-4工程的main.c的内容如下:
#include "inc_os.h"
#include "gpio.h"
#include "sysctl.h"
#include "pwm.h"
uint32_t pwm0_int(ufast_t int_line)
{
static s32 compare = 0,delay = 0;
static bool_t up = true;
pg_pwm_reg->PWM0ISC = 1<<bo_pwm0_intisc_intcntzero;//清过零中断
pg_pwm_reg->PWMISC = 1<<bo_pwm_intisc_pwm0; //清PWM0中断
if(delay < 5)
{
delay++;
return 0;
}else
delay = 0;
if(up == true)
{
compare += 150;
if(compare >= 3000 - 150)
up = false;
}else
{
compare -=150;
if(compare <= 150)
up = true;
}
pg_pwm_reg->PWM0CMPA = compare;
return 0;
}
void flash_led(struct event_script *my_event)
{
bb_sysctl_rcgc2_gpiof = 1; //使能gpiof
pg_gpio_regf->LOCK = 0x1ACCE551; //解锁CR寄存器
pg_gpio_regf->CR = 1; //允许修改AFSEL的PF0位
pg_gpio_regf->AFSEL |= 0x1; //PF0设为PWM0输出
pg_gpio_regf->LOCK = 0; //重新锁定CR寄存器
pg_gpio_regf->DEN |= 1; //允许PF0
pg_gpio_regf->IM &= 0xfe; //屏蔽掉PF0中断
pg_gpio_regf->DR8R |= 1; //设置PF0=8mA驱动
//配置PWM0
pg_sysctl_reg->RCC &= ~bm_sysctl_rcc_pwmdiv;
pg_sysctl_reg->RCC |= 5<<bo_sysctl_rcc_pwmdiv;//置pwm时钟为系统时钟64分频
bb_sysctl_rcc_enpwmdiv = 1;
bb_sysctl_rcgc0_pwm = 1; //使能pwm
pg_pwm_reg->PWM0CTL = 0;
pg_pwm_reg->PWM0GENA =(0<<bo_pwmx_act_zero)
+(0<<bo_pwmx_act_load)
+(3<<bo_pwmx_act_comp_au)
+(2<<bo_pwmx_act_comp_ad)
+(0<<bo_pwmx_act_comp_bu)
+(0<<bo_pwmx_act_comp_bd);
pg_pwm_reg->PWM0LOAD = 3000; //pwm周期约7.7mS
bb_pwm0_ctl_mode = 1; //增减循环模式
bb_pwm0_ctl_enable = 1; //使能pwm0模块
bb_pwm0_ctl_debug = 1; //使能pwm0输出
bb_pwm_enable_pwm0en = 1;
int_isr_connect(cn_int_line_PWM0,pwm0_int); //中断连接
int_setto_asyn_signal(cn_int_line_PWM0);
int_restore_line(cn_int_line_PWM0);
bb_pwm0_inten_intcntzero = 1; //使能PWM0的过零中断
bb_pwm_inten_pwm0 = 1; //使能PWM0中断
djy_evtt_unregist(my_event->evtt_id);
}
//本应命名为main的,但调试器总是默认这是整个程序的入口点,罢了
void djy_main(void)
{
uint16_t evtt_flash_led;
evtt_flash_led = djy_evtt_regist(true,true,cn_prio_real,1,
flash_led,10,NULL);
djy_event_pop(evtt_flash_led,0,0,0);
}
说明:这个工程和前面三个工程相比,有明显的不同,前三个工程中,要么没使用中断,即使使用了,中断处理函数也属于跑龙套的角色。在这个工程中却要担起主角的重任了,看官,事件处理函数flash_led其实啥也不干,初始化完硬件就卸磨————函数返回了,返回前还把事件类型注销掉,连磨盘都给砸了。控制led亮度的工作,完全落在中断处理函数上。
由于evtt_flash_led类型事件正在使用,djy_evtt_unregist函数实际上只是在系统中标记了evtt_flash_led事件类型即将注销,真正的注销行为在flash_led返回以后执行的。evtt_flash_led类型注销后,就可以分配给别人用了,不拉屎就不占茅坑,很自觉。 prj-ekk8962-5工程的main.c的内容如下:
#include "inc_os.h"
#include "gpio.h"
#include "sysctl.h"
#include "pwm.h"
uint32_t pwm0_int(ufast_t int_line)
{
static s32 compare = 0,delay = 0;
static bool_t up = true;
pg_pwm_reg->PWM0ISC = 1<<bo_pwm0_intisc_intcntzero;//清过零中断
pg_pwm_reg->PWMISC = 1<<bo_pwm_intisc_pwm0; //清PWM0中断
if(delay < 5)
{
delay++;
return 0;
}else
delay = 0;
if(up == true)
{
compare += 150;
if(compare >= 3000 - 150)
up = false;
}else
{
compare -=150;
if(compare <= 150)
up = true;
}
pg_pwm_reg->PWM0CMPA = compare;
return 0;
}
void set_led(void)
{
bb_sysctl_rcgc2_gpiof = 1; //使能gpiof
pg_gpio_regf->LOCK = 0x1ACCE551; //解锁CR寄存器
pg_gpio_regf->CR = 1; //允许修改AFSEL的PF0位
pg_gpio_regf->AFSEL |= 0x1; //PF0设为PWM0输出
pg_gpio_regf->LOCK = 0; //重新锁定CR寄存器
pg_gpio_regf->DEN |= 1; //允许PF0
pg_gpio_regf->IM &= 0xfe; //屏蔽掉PF0中断
pg_gpio_regf->DR8R |= 1; //设置PF0=8mA驱动
//配置PWM0
pg_sysctl_reg->RCC &= ~bm_sysctl_rcc_pwmdiv;
pg_sysctl_reg->RCC |= 5<<bo_sysctl_rcc_pwmdiv;//置pwm时钟为系统时钟64分频
bb_sysctl_rcc_enpwmdiv = 1;
bb_sysctl_rcgc0_pwm = 1; //使能pwm
pg_pwm_reg->PWM0CTL = 0;
pg_pwm_reg->PWM0GENA =(0<<bo_pwmx_act_zero)
+(0<<bo_pwmx_act_load)
+(3<<bo_pwmx_act_comp_au)
+(2<<bo_pwmx_act_comp_ad)
+(0<<bo_pwmx_act_comp_bu)
+(0<<bo_pwmx_act_comp_bd);
pg_pwm_reg->PWM0LOAD = 3000; //pwm周期约7.7mS
bb_pwm0_ctl_mode = 1; //增减循环模式
bb_pwm0_ctl_enable = 1; //使能pwm0模块
bb_pwm0_ctl_debug = 1; //使能pwm0输出
bb_pwm_enable_pwm0en = 1;
int_isr_connect(cn_int_line_PWM0,pwm0_int); //中断连接
int_setto_asyn_signal(cn_int_line_PWM0);
int_restore_line(cn_int_line_PWM0);
bb_pwm0_inten_intcntzero = 1; //使能PWM0的过零中断
bb_pwm_inten_pwm0 = 1; //使能PWM0中断
}
//本应命名为main的,但调试器总是默认这是整个程序的入口点,罢了
void djy_main(void)
{
set_led();
}
说明:prj-ekk8962-4中,用事件触发flash_led函数执行,只是为了演示事件类型的登记和注销过程,实战中,完全是画蛇添足之举!在main函数中直接调用函数set_led就行了。 您的系统能用到8位机吗?最好有个KEIL的例子啊 帮顶了... 支持,搞个51的应用看看,即使是点灯的,51估计大家都有,但是你的板估计很少人有吧 回9楼:51估计很难运行djyos,晚些时候会发布一个用stm32实现的相似功能例程,也用多种方法对比实现。
回7楼:高端的8位机应该可以,但目前没有移植计划。现在stm32很普及了,晚些出stm32+keil的。
页:
[1]