我熟悉Atmega128及其家用微控制器中的PWM生成。我一直在使用预标量和其他寄存器来生成频率。但我必须生成20KHz的pwm信号。我试过,但我无法得到所需的输出。谁能建议我或帮我怎么做?
据我所知,在atmega128中,1条指令需要1个周期。使用16MHz晶振,1指令在1 / 16M秒内完成。 我尝试用25us占空比产生20Khz信号(50 us)。但是我在示波器中获得的频率(277.78 Hz)远低于20KHz 我的计算是 16MH = 20000Hz * 800。 对于0-399计数,我使端口高和 399-799算,我把港口降低了。
void frequency(void){ // 20kHz Frequency
if (cnt1 <= 399){
PORTB |= (1<<7);
} else {
PORTB &= ~(1<<7);
}
cnt1++;
if (cnt1 >= 800) cnt1 = 0;
}
答案 0 :(得分:1)
我无法访问128但已验证其16位定时器1与328和32U4类似,因此下面的内容应该稍作修改(主要的关键点可能是查找什么引脚溢出寄存器绑定到):
#include <avr/io.h>
#include <util/delay.h>
struct CTC1
{
static void setup()
{
// CTC mode with TOP-OCR1A
TCCR1A = 0;
TCCR1B = _BV(WGM12);
// toggle channel A on compare match
TCCR1A = (TCCR1A & ~(_BV(COM1A1) | _BV(COM1A0))) | _BV(COM1A0);
// set channel A bound pin PB1 to output mode
#if defined(__AVR_ATmega32U4__)
DDRB |= _BV(5);
#else
DDRB |= _BV(1);
#endif
}
static void set_freq(float f)
{
static const float f1 = min_freq(1), f8 = min_freq(8), f64 = min_freq(64), f256 = min_freq(256);
uint16_t n;
if (f >= f1) n = 1;
else if (f >= f8) n = 8;
else if (f >= f64) n = 64;
else if (f >= f256) n = 256;
else n = 1024;
prescale(n);
OCR1A = static_cast<uint16_t>(round(F_CPU / (2 * n * f) - 1));
}
static void prescale(uint16_t n)
{
uint8_t bits = 0;
switch (n)
{
case 1: bits = _BV(CS10); break;
case 8: bits = _BV(CS11); break;
case 64: bits = _BV(CS11) | _BV(CS10); break;
case 256: bits = _BV(CS12); break;
case 1024: bits = _BV(CS12) | _BV(CS10); break;
default: bits = 0;
}
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11) | _BV(CS10))) | bits;
}
static inline float min_freq(uint16_t n)
{
return ceil(F_CPU / (2 * n * 65536));
}
};
void setup()
{
CTC1::setup();
CTC1::set_freq(20e3);
}
void loop()
{
// do whatever
_delay_ms(1);
}
int main()
{
setup();
for (;;)
loop();
}
我在我的示波器上进行了测试,并测量了在16MHz运行的328p时的20kHz。如果20kHz是您需要的唯一频率,那么您可以大大简化这一过程。翻译代码以使用其中一个8位定时器也很简单,虽然我还没有确认它可以用这些定时器达到20kHz。
答案 1 :(得分:0)
在C中使用计数器实现PWM或任何时间关键确实不是一个好主意。虽然C将您的代码转换为特定的机器代码,但您并不知道需要多长时间。 您的代码不转换为:
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
,而是像这样(简化,人类可读):
[HttpGet]
[AllowAnonymous]
public string Get(int id)
{
}
如果你从“C”的角度来看,你需要做至少:
make port B high 400 times (PORTB |= (1<<7);)
make port B low 400 times (PORTB &= ~(1<<7);)
然后依赖于编译器优化所有加载和写入的好处(通常非常好)。 如果您真正了解编译器并且不使用太多优化(通常是复杂的),或者通过在汇编程序中编写代码,您可以控制延迟。但是你必须使用类似于我对机器代码的解释的逻辑(汇编程序接近人类可读的机器代码)。
我认为您的解决方案是计时器中断。 atmega128有一个很好的教程here。
你的意思是:
我尝试以25us占空比生成20Khz信号(50 us)。
你的意思是20kHz信号,50%占空比?所以25us低,25 us高?
如果是这种情况,您可以使用一个定时器中断和一个(二进制)计数器来执行此操作。 确切地说,您可以在提供的链接中阅读“8位计时器示例”。