目录
提示:本文使用的芯片并非STM32系列,利用定时器实现呼吸灯是从寄存器层面讲解的,但是对于不同芯片以及是否使用库函数开发来说,基本原理是相同的。
顾名思义,呼吸灯是指灯能够像人的呼吸一样,实现由暗到亮或由亮到暗的变化,通常用于消息提示功能,或者作为系统正在运行的提示。
其实无论哪种实现方法,基本思想都是通过脉冲宽度调制(PWM)实现,即通过调节占空比来对模拟信号电平进行数字编码。关于何为PWM,何为占空比,这里就不再赘述了,简单理解就是,占空比越高,LED两端电压越大,LED越亮。这里用一张图简单的介绍一下呼吸灯的实现原理。
人眼的分辨率为1秒24帧,即人眼看到的图像滞留时间为0.04s左右,就按40ms计算。也就是说,一个周期为40ms,人眼是看不出其中的亮灭变化的。但是为了让呼吸灯效果看起来更好,建议选则周期长度小于40ms,这里选则25ms。
利用for循环实现呼吸灯主要有两个关键变量,一个是周期T,一个是占空比的值t,他们的含义如下图所示:

图中T为一个周期(脉冲宽度),t为占空比。
利用for循环实现呼吸灯的程序如下:
int main(void)
{
uint32 T = 1600; // 周期(脉冲宽度)
uint32 i=0,m=0,n=0,t=0;
PT0OES_D9 = 1; // 输出使能
PT0DAT_D9 = 1; // 灭
while (1)
{
for (i=0;i<T;i++)
{
PT0DAT_D9 = 0; // 亮
for (m=0;m<t;m++);
PT0DAT_D9 = 1; // 灭
for (n=0;n<T-t;n++);
t++;
if (t >= T)
{
for (i=0;i<T;i++)
{
PT0DAT_D9 = 0; // 亮
for (m=0;m<t;m++);
PT0DAT_D9 = 1; // 灭
for (n=0;n<T-t;n++);
t--;
}
}
}
}
}
这里程序逻辑比较容易理解,就不再赘述,有需要讨论的小伙伴可以留言讨论。虽然利用for循环能够很简单的实现呼吸灯,但是这种方法是利用for循环来控制亮灭时间,时间控制并不精确。
利用定时器中断实现呼吸灯的程序如下:
uint32 count= 0;
uint32 flag = 0;
uint32 t = 0;
int main(void)
{
Osc_Setup(); // 初始化系统时钟
EnableGlobalInterrupt(); // 使能全局中断
PT0OES_D9 = 1; // 输出使能
PT0DAT_D9 = 1; // 灭
TMR1_TCR_CRST = 1; // 复位定时器计数值寄存器和预分频计数值寄存器
while (TMR1_TCR_CRST); // 等待复位完成
TMR1_PR_PR = 49; // 设置预分频系数
TMR1_MCR_MR0I = 1; // 产生匹配中断
TMR1_MCR_MR0R = 1; // 产生计数器复位
TMR1_MCR_MR0S = 0; // 计数器不停止计数
TMR1_MR0 = 250; // 设置匹配值
TMR1_IR = 0xffffffff; // 清除匹配中断标志位
NVIC_ISER_TMR1 = 1;
TMR1_TCR_CEN = 1; //定时器定时,捕捉功能启动
while (1)
{
if (t <= count)
{
PT0DAT_D9 = 1; // 灭
}
else if (t > count)
{
PT0DAT_D9 = 0; // 亮
}
}
}
void __attribute__((isr)) ISR_TMR1(void) // 匹配中断服务函数
{
count = count + 1;
if (count >= 100 && flag <= 100) // 由暗到亮
{
count = 0;
t = t + 1;
flag = flag + 1;
}
if (count >= 100 && flag > 100) // 由亮到暗
{
count = 0;
t = t - 1;
flag = flag + 1;
}
if (flag > 200)
{
count = 0;
t = 0;
flag = 0;
}
TMR1_IR = 0xffffffff;
}
配置TMR1来实现呼吸灯功能,配置TMR1时预分频系数设置为49,匹配值设置为250,配置产生匹配中断,中断后产生计数器复位,计数器不停止计数,然后开启定时器1。这里需要注意的是要配置中断后产生计数器复位,否则计数器会等到计数到最大值后才清零,此时的现象是LED依然可是像呼吸灯一样由暗变亮,再由亮变暗,但是期间会不断闪烁。
假设进入匹配中断的时间为t,系统主时钟频率为Fsys,预分频系数为PR,匹配值为n,那么进入一次匹配中断的时间t= ((PR + 1)/Fsys)*n。因为开头提到过,本程序设置的脉冲宽度为25ms,系统主时钟频率为50MHz,所以这里将预分频系数设置为49和匹配值设置为250,计算后可知,每0.25ms进入一次匹配中断,进入100次更改一次占空比,即25ms更改一次,总的脉冲宽度为25ms。如果想更改脉冲宽度只需要调整count的值即可。
相比于前两种方法来说,初学单片机的人更加熟悉的是利用定时器输出PWM波来实现呼吸灯,因为正点原子或普中科技等等教程中都有详细介绍,这里就不再赘述了。
虽然利用for循环能够比较简单地实现呼吸灯,但是其时间控制没有利用定时器实现准确,建议使用定时器来实现呼吸灯功能。
当然,上面给出的程序存在不好的地方,在中断中执行了太多语句,这是平时开发需要注意的。可以只在中断中保留count自加操作,其他放在主函数地while(1)中进行,这样可以减少在中断中执行的程序。
PS:本人也属于技术小白级别,本文如有写的不合适的地方,欢迎各位在评论区讨论。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2