Timer Arduino上的计时器1使串行打印无法工作

Timer Arduino上的计时器1使串行打印无法工作,timer,arduino,Timer,Arduino,运行下面的代码,当我从串行监视器向Arduino发送任何字符时,Arduino不会回打印“a”。我认为timer1代码有问题,但它应该可以工作,因为这段代码是我的老师在C课上给我的 void setup(){ 序列号开始(115200); // http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS 无中断(); TCCR1A=0;//将整个TCCR1A寄存器设置为0 TCCR1B=0;//TCCR1B相同 TCNT1

运行下面的代码,当我从串行监视器向Arduino发送任何字符时,Arduino不会回打印“a”。我认为timer1代码有问题,但它应该可以工作,因为这段代码是我的老师在C课上给我的

void setup(){
序列号开始(115200);
// http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
无中断();
TCCR1A=0;//将整个TCCR1A寄存器设置为0
TCCR1B=0;//TCCR1B相同
TCNT1=0;//将计数器值初始化为0
//使用8位预分频器为1000000MHz增量设置比较匹配寄存器

OCR1A=1;//=(16*10^6)/(1000000*8)-1(必须是您已将此寄存器写入了2次:


TCCR1B |=(1旁注:您对
8位预分频器的代码注释具有误导性。它不是一个8位预分频器,而是一个8的预分频器,意思是十进制值
8
。这意味着计时器的时钟滴答率比主时钟慢8倍,因为您将主时钟频率除以预分频器以获得ti莫尔的时钟频率

现在让我回答: 您设置
TCCR1A
TCCR1B
的方式完全正确

但是,您有两个大问题、一个小问题和一条建议。

如果您想知道从现在开始在哪里查找低级帮助,请参阅660 pg ATmega328数据表pgs.132~135以获取更多帮助和信息

更新:新的ATmega328销售页面位于此处:。其新数据表位于此处:。因此,我在上面和下面提到的页码可能不再完全匹配,因为我在撰写本文时使用的是旧版本的数据表

以下是完全破坏代码的两个主要问题:
  • 由于您正在启用计时器比较匹配1A中断(
    TIMSK1 |=(1字节)
    //可由ISR在以下位置修改的可变变量:
    //任何时间——包括读取变量本身时。
    无符号长numISRcalls\u copy=numISRcalls;
    中断();
    Serial.print(“numISRcalls=”);Serial.println(numISRcalls\u副本);
    }
    //序列号。打印号(“测试”);
    //延迟(1000);
    }
    //由于您正在启用上面的比较匹配1A中断,因此您*必须*
    //包括相应的中断服务程序代码
    ISR(计时器比较程序)
    {
    //在此处插入每次计数器到达时要运行的代码
    //OCR1A
    numISRcalls++;
    }
    
    运行它,看看你的想法

    证明上述“主要问题1”是真实的 (至少据我所知——并基于使用IDE 1.6.0在Arduino Nano上进行的测试):

    下面的代码经过编译,但不会继续打印“a”(但可能会打印一次)。请注意,为了简单起见,我注释了等待串行数据的部分,并简单地告诉它每半秒打印一次“a”:

    void setup(){
    序列号开始(115200);
    TCCR1A=0;//将整个TCCR1A寄存器设置为0
    TCCR1B=0;//TCCR1B相同
    TCNT1=0;//将计数器值初始化为0
    //打开CTC模式
    TCCR1B |=(1,您没有看到“a”的原因是您没有为中断提供ISR处理程序。因此,编译器生成的代码跳回地址0x0000,草图重新启动

    提供“空”ISR处理程序的替代方案如下:

    空中断(定时器比较向量);
    
    有了空的中断处理程序,我得到了一个OCR1A低至1的响应(“a”):

    OCR1A=1;
    
    不过,如果您不打算对中断执行任何操作,那么您必须想知道为什么要启用中断


    关于Arduino的更多信息。

    TCCR1A |=(1根据程序需要如何处理如此快速的中断,例如,在输出引脚上生成高速时钟,可以在硬件中使用
    COM
    位在
    TCCR1A
    中设置它(我的内存中有4个最高有效位)在与计时器关联的管脚上切换输出,而无需写入任何
    ISR()
    回调来处理软件中的计时器中断。

    SO中有arduino论坛吗?是的:还有,你的中断处理程序在哪里?如果你不确认中断,处理程序将无限期运行,你的串行代码所在的主循环将永远不会进行。好吧,编译器会指出你没有的所有中断向量未将的ISR写入虚拟ISR,因此不定义ISR不是问题。就编译而言,您是正确的,但问题是在运行时。一旦TCNT1到达OCR1A,它会将处理器引入由编译器创建的虚拟ISR,该虚拟ISR永远不会存在。因此,最终结果是循环()代码不会继续,当您发送串行数据时,将永远不会打印“a”。Ben Voigt在上面的评论中说了同样的话,我已经在Arduino上验证了这一点。我将在主要回复中发布代码。Ben Voigt:“还有,你的中断处理程序在哪里?如果你不确认中断,处理程序将无限期运行,而你的串行代码所在的主循环将永远无法进行。”–Ben Voigt Mar 5,18:51"我刚刚检查了我的avr gcc 4.7.2的输出,_bad_中断处理程序只是包含一个到重置向量的跳转,所以你是对的,它不会工作,只要中断继续触发,草图就会无限期重新启动。我的想法是它只是返回。只是要指出,如果你拼错了ISR名称,就不会产生错误,但uC仍将进入重置循环。