c - 如何使用 pwm atmega avr 增加亮度或调暗 LED
问题描述
我不知道为什么,但不是增加亮度,而是 LED 脉冲,每个脉冲之间的周期越来越短。这是从教程中复制的代码,在他的视频中它运行良好,但对我来说它没有,即使在模拟器中也是如此。怎么会这样?
使用 avr 328p。
#define F_CPU 20000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
double dutyCycle = 0;
int main(void)
{
DDRD = (1 << PORTD6);
TCCR0A = (1 << COM0A1) | (1 << WGM00) | (1 << WGM01);
TIMSK0 = (1 << TOIE0);
OCR0A = (dutyCycle/100.0)*255.0;
sei();
TCCR0B = (1 << CS00) | (1 << CS02);
while(1)
{
_delay_ms(100);
dutyCycle += 10;
if(dutyCycle > 100){
dutyCycle = 0;
}
}
}
ISR(TIMER0_OVF_vect){ OCR0A = (dutyCycle/100.0)*255;}
解决方案
1) 如果某个变量在主代码和中断中同时使用,则必须将其标记为volatile
。然后对它的每次读取或写入都将被编译为相应存储单元的读取/写入。否则,编译器可以优化,最小化内存访问。因此,写入主程序中的变量将在中断中不可见。
2)你为什么使用double
?除非非常必要,否则不要使用浮点数。AVR 对浮点运算没有硬件支持,因此每个浮点运算将表示为多个运算。在您的示例中,使用从 0 更改为 255 的整数变量没有任何限制。即使您想使用 0-100 范围变量,您也可以使用整数算术重新计算它。
3) 注意更新长度超过 1 个字节的变量。AVR 是 8 位架构。这意味着,更新内存中超过 8 位宽的变量需要一系列多次操作。double
它有 8 个字节长,需要太多这样的操作。中断可能在该系列中间的任何时刻触发,这意味着,在 ISR 中获得的变量值将仅部分更新,从而导致不可预测的结果。在主代码中包含cli()
-sei()
在 ISR 内部使用且超过 1 个字节宽的变量的任何更新。
3) 避免在 ISR 中进行硬计算。根据经验:任何 ISR 都应尽快完成,所有密集计算都应放在 ISR 之外。
4) 在这个例子中,你根本不需要 ISR!您可以在主代码中编写 OCR0A。
推荐阅读
- ruby-on-rails-4 - validate_unique_of().scoped_to() 导致 RecordNotFound 错误
- node.js - 如何将 Dialogflow 输入移交给 Interactive Canvas
- python - 在 Apache Beam 的窗口中聚合数据
- python - 张量运算的导数
- r - 在绘制时间序列的因子值时,如何在 ggplot 中设置我自己的刻度标签?
- c++ - 如何为抽象类重载运算符?
- python - 有没有办法在 Python 中删除用户的特定文本?
- javascript - 为 Google Adsense 找到预加载链接,但浏览器未使用
- javascript - html5多人游戏中无法将filltext()改为fillRect
- python-3.x - 无法检查电子邮件的内容